* [PATCH net-next 03/14] net: enetc: convert ndo_set_rx_mode() to ndo_set_rx_mode_async()
From: wei.fang @ 2026-06-30 7:20 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260630072036.382761-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
The current ndo_set_rx_mode() is called under netif_addr_lock spinlock
with BHs disabled, which prevents drivers from sleeping. To work around
this limitation, the enetc driver uses a dedicated workqueue to defer
MAC address list updates to a sleepable context.
Since commit 3554b4345d85 ("net: introduce ndo_set_rx_mode_async and
netdev_rx_mode_work") introduced the ndo_set_rx_mode_async() callback,
drivers can now handle address list updates directly in a sleepable
context.
Therefore, convert the enetc driver to use ndo_set_rx_mode_async() and
remove the dedicated workqueue and the deferred work item accordingly.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc.h | 2 -
.../net/ethernet/freescale/enetc/enetc4_pf.c | 178 ++++++------------
2 files changed, 58 insertions(+), 122 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 04a5dd5ea6c7..06a9f1ee0970 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -324,8 +324,6 @@ struct enetc_si {
const struct enetc_drvdata *drvdata;
const struct enetc_si_ops *ops;
- struct workqueue_struct *workqueue;
- struct work_struct rx_mode_task;
struct dentry *debugfs_root;
struct enetc_msg_swbd msg; /* Only valid for VSI */
};
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 48a74db90ed5..a02b01753ff2 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -101,24 +101,23 @@ static void enetc4_pf_clear_maft_entries(struct enetc_pf *pf)
}
static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,
- struct enetc_mac_addr *mac,
- int mac_cnt)
+ struct netdev_hw_addr_list *uc)
{
struct maft_entry_data maft = {};
+ struct netdev_hw_addr *ha;
u16 si_bit = BIT(0);
- int i, err;
+ int err;
maft.cfge.si_bitmap = cpu_to_le16(si_bit);
- for (i = 0; i < mac_cnt; i++) {
- ether_addr_copy(maft.keye.mac_addr, mac[i].addr);
- err = ntmp_maft_add_entry(&pf->si->ntmp_user, i, &maft);
- if (unlikely(err)) {
- pf->num_mfe = i;
+ netdev_hw_addr_list_for_each(ha, uc) {
+ ether_addr_copy(maft.keye.mac_addr, ha->addr);
+ err = ntmp_maft_add_entry(&pf->si->ntmp_user, pf->num_mfe,
+ &maft);
+ if (unlikely(err))
goto clear_maft_entries;
- }
- }
- pf->num_mfe = mac_cnt;
+ pf->num_mfe++;
+ }
return 0;
@@ -128,23 +127,29 @@ static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,
return err;
}
-static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
+static void enetc4_pf_set_uc_hash_filter(struct enetc_pf *pf,
+ struct netdev_hw_addr_list *uc)
{
- int max_num_mfe = pf->caps.mac_filter_num;
- struct enetc_mac_filter mac_filter = {};
- struct net_device *ndev = pf->si->ndev;
- struct enetc_mac_addr *mac_tbl;
- struct enetc_si *si = pf->si;
+ struct enetc_mac_filter *mac_filter = &pf->mac_filter[UC];
struct netdev_hw_addr *ha;
- int i = 0, err;
- int mac_cnt;
u64 hash;
- netif_addr_lock_bh(ndev);
+ enetc_reset_mac_addr_filter(mac_filter);
+ netdev_hw_addr_list_for_each(ha, uc)
+ enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
+
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_uc_hash_filter(pf->si, 0, hash);
+}
+
+static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,
+ struct netdev_hw_addr_list *uc)
+{
+ int mac_cnt = netdev_hw_addr_list_count(uc);
+ struct enetc_si *si = pf->si;
- mac_cnt = netdev_uc_count(ndev);
if (!mac_cnt) {
- netif_addr_unlock_bh(ndev);
/* clear both MAC hash and exact filters */
enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
@@ -152,79 +157,42 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
return 0;
}
- if (mac_cnt > max_num_mfe) {
- err = -ENOSPC;
- goto unlock_netif_addr;
- }
-
- mac_tbl = kzalloc_objs(*mac_tbl, mac_cnt, GFP_ATOMIC);
- if (!mac_tbl) {
- err = -ENOMEM;
- goto unlock_netif_addr;
- }
-
- netdev_for_each_uc_addr(ha, ndev) {
- enetc_add_mac_addr_ht_filter(&mac_filter, ha->addr);
- ether_addr_copy(mac_tbl[i++].addr, ha->addr);
- }
-
- netif_addr_unlock_bh(ndev);
+ if (mac_cnt > pf->caps.mac_filter_num)
+ return -ENOSPC;
/* Set temporary unicast hash filters in case of Rx loss when
* updating MAC address filter table
*/
- bitmap_to_arr64(&hash, mac_filter.mac_hash_table,
- ENETC_MADDR_HASH_TBL_SZ);
- enetc_set_si_uc_hash_filter(si, 0, hash);
+ enetc4_pf_set_uc_hash_filter(pf, uc);
enetc4_pf_clear_maft_entries(pf);
- if (!enetc4_pf_add_maft_entries(pf, mac_tbl, i))
+ if (!enetc4_pf_add_maft_entries(pf, uc)) {
+ enetc_reset_mac_addr_filter(&pf->mac_filter[UC]);
enetc_set_si_uc_hash_filter(si, 0, 0);
-
- kfree(mac_tbl);
+ }
return 0;
-
-unlock_netif_addr:
- netif_addr_unlock_bh(ndev);
-
- return err;
}
-static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
+static void enetc4_pf_set_mc_hash_filter(struct enetc_pf *pf,
+ struct netdev_hw_addr_list *mc)
{
- struct net_device *ndev = pf->si->ndev;
- struct enetc_mac_filter *mac_filter;
- struct enetc_si *si = pf->si;
+ struct enetc_mac_filter *mac_filter = &pf->mac_filter[MC];
struct netdev_hw_addr *ha;
u64 hash;
- netif_addr_lock_bh(ndev);
- if (type & ENETC_MAC_FILTER_TYPE_UC) {
- mac_filter = &pf->mac_filter[UC];
- enetc_reset_mac_addr_filter(mac_filter);
- netdev_for_each_uc_addr(ha, ndev)
- enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
-
- bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
- ENETC_MADDR_HASH_TBL_SZ);
- enetc_set_si_uc_hash_filter(si, 0, hash);
- }
+ enetc_reset_mac_addr_filter(mac_filter);
+ netdev_hw_addr_list_for_each(ha, mc)
+ enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
- if (type & ENETC_MAC_FILTER_TYPE_MC) {
- mac_filter = &pf->mac_filter[MC];
- enetc_reset_mac_addr_filter(mac_filter);
- netdev_for_each_mc_addr(ha, ndev)
- enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
-
- bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
- ENETC_MADDR_HASH_TBL_SZ);
- enetc_set_si_mc_hash_filter(si, 0, hash);
- }
- netif_addr_unlock_bh(ndev);
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_mc_hash_filter(pf->si, 0, hash);
}
-static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
+static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
{
/* Currently, the MAC address filter table (MAFT) only has 4 entries,
* and multiple multicast addresses for filtering will be configured
@@ -232,15 +200,16 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
* unicast filtering. If the number of unicast addresses exceeds the
* table capacity, the MAC hash filter will be used.
*/
- if (type & ENETC_MAC_FILTER_TYPE_UC && enetc4_pf_set_uc_exact_filter(pf)) {
+ if (type & ENETC_MAC_FILTER_TYPE_UC &&
+ enetc4_pf_set_uc_exact_filter(pf, uc)) {
/* Fall back to the MAC hash filter */
- enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_UC);
+ enetc4_pf_set_uc_hash_filter(pf, uc);
/* Clear the old MAC exact filter */
enetc4_pf_clear_maft_entries(pf);
}
if (type & ENETC_MAC_FILTER_TYPE_MC)
- enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_MC);
+ enetc4_pf_set_mc_hash_filter(pf, mc);
}
static const struct enetc_pf_ops enetc4_pf_ops = {
@@ -467,17 +436,17 @@ static void enetc4_pf_free(struct enetc_pf *pf)
enetc4_free_ntmp_user(pf->si);
}
-static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
+static int enetc4_pf_set_rx_mode(struct net_device *ndev,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
{
- struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task);
- struct enetc_pf *pf = enetc_si_priv(si);
- struct net_device *ndev = si->ndev;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct enetc_si *si = priv->si;
bool uc_promisc = false;
bool mc_promisc = false;
int type = 0;
- rtnl_lock();
-
if (ndev->flags & IFF_PROMISC) {
uc_promisc = true;
mc_promisc = true;
@@ -500,17 +469,9 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
enetc_set_si_mc_hash_filter(si, 0, 0);
/* Set new MAC filter */
- enetc4_pf_set_mac_filter(pf, type);
-
- rtnl_unlock();
-}
+ enetc4_pf_set_mac_filter(pf, type, uc, mc);
-static void enetc4_pf_set_rx_mode(struct net_device *ndev)
-{
- struct enetc_ndev_priv *priv = netdev_priv(ndev);
- struct enetc_si *si = priv->si;
-
- queue_work(si->workqueue, &si->rx_mode_task);
+ return 0;
}
static int enetc4_pf_set_features(struct net_device *ndev,
@@ -540,7 +501,7 @@ static const struct net_device_ops enetc4_ndev_ops = {
.ndo_start_xmit = enetc_xmit,
.ndo_get_stats = enetc_get_stats,
.ndo_set_mac_address = enetc_pf_set_mac_addr,
- .ndo_set_rx_mode = enetc4_pf_set_rx_mode,
+ .ndo_set_rx_mode_async = enetc4_pf_set_rx_mode,
.ndo_set_features = enetc4_pf_set_features,
.ndo_vlan_rx_add_vid = enetc_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = enetc_vlan_rx_del_vid,
@@ -983,19 +944,6 @@ static void enetc4_link_deinit(struct enetc_ndev_priv *priv)
enetc_mdiobus_destroy(pf);
}
-static int enetc4_psi_wq_task_init(struct enetc_si *si)
-{
- char wq_name[24];
-
- INIT_WORK(&si->rx_mode_task, enetc4_psi_do_set_rx_mode);
- snprintf(wq_name, sizeof(wq_name), "enetc-%s", pci_name(si->pdev));
- si->workqueue = create_singlethread_workqueue(wq_name);
- if (!si->workqueue)
- return -ENOMEM;
-
- return 0;
-}
-
static int enetc4_pf_netdev_create(struct enetc_si *si)
{
struct device *dev = &si->pdev->dev;
@@ -1036,12 +984,6 @@ static int enetc4_pf_netdev_create(struct enetc_si *si)
if (err)
goto err_link_init;
- err = enetc4_psi_wq_task_init(si);
- if (err) {
- dev_err(dev, "Failed to init workqueue\n");
- goto err_wq_init;
- }
-
err = register_netdev(ndev);
if (err) {
dev_err(dev, "Failed to register netdev\n");
@@ -1051,8 +993,6 @@ static int enetc4_pf_netdev_create(struct enetc_si *si)
return 0;
err_reg_netdev:
- destroy_workqueue(si->workqueue);
-err_wq_init:
enetc4_link_deinit(priv);
err_link_init:
enetc_free_msix(priv);
@@ -1070,8 +1010,6 @@ static void enetc4_pf_netdev_destroy(struct enetc_si *si)
struct net_device *ndev = si->ndev;
unregister_netdev(ndev);
- cancel_work(&si->rx_mode_task);
- destroy_workqueue(si->workqueue);
enetc4_link_deinit(priv);
enetc_free_msix(priv);
free_netdev(ndev);
--
2.34.1
^ permalink raw reply related
* [PATCH v4 08/10] arm64: kdump: exclude non-dumpable reserved memory regions from vmcore
From: Wandun Chen @ 2026-06-30 7:47 UTC (permalink / raw)
To: chenhuacai, kernel, pjw, palmer, aou, robh, saravanak, bhe, rppt,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing
Cc: catalin.marinas, will, alex, akpm, pasha.tatashin, pratyush,
ruirui.yang, m.szyprowski, robin.murphy
In-Reply-To: <20260630074715.4126796-1-chenwandun1@gmail.com>
From: Wandun Chen <chenwandun@lixiang.com>
Reserved memory regions are excluded from vmcore by default unless
marked dumpable. Honor the dumpable flag to filter out device firmware
regions (e.g., GPU, DSP, modem) reserved via device tree, since they
typically contain data not useful for kernel crash analysis and can
significantly increase vmcore size.
Use of_reserved_mem_kdump_exclude() to perform the exclusion, and
pre-size the crash_mem array via of_reserved_mem_kdump_nr_ranges().
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Tested-by: Meijing Zhao <zhaomeijing@lixiang.com>
Acked-by: Will Deacon <will@kernel.org>
---
arch/arm64/kernel/machine_kexec_file.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index e31fabed378a..1d65320c6ba4 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -17,6 +17,7 @@
#include <linux/memblock.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
@@ -51,6 +52,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
nr_ranges = 2; /* for exclusion of crashkernel region */
for_each_mem_range(i, &start, &end)
nr_ranges++;
+ nr_ranges += of_reserved_mem_kdump_nr_ranges();
cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
if (!cmem)
@@ -75,6 +77,10 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
goto out;
}
+ ret = of_reserved_mem_kdump_exclude(cmem);
+ if (ret)
+ goto out;
+
ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
out:
--
2.43.0
^ permalink raw reply related
* [PATCH v3 3/3] phy: rockchip: phy-rockchip-inno-csidphy: add clock lane phase tuning
From: Gerald Loacker @ 2026-06-30 7:48 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree, Gerald Loacker
In-Reply-To: <20260630-feature-mipi-csi-dphy-4k60-v3-0-176792ab71fa@wolfvision.net>
At high data rates like 4K60 (2500 Mbps), such as when using an
LT6911GXD bridge chip on an RK3588 board, fixed default timing parameters
can cause signal integrity issues and clock-data recovery failures.
The driver currently lacks a mechanism to adjust the clock lane sampling
phase to compensate for board-specific trace variations.
Resolve this by parsing and applying the optional 'rockchip,clk-lane-phase'
device tree property. This enables board-specific tuning of the clock
lane sampling phase in ~40 ps steps (range 0-7) to optimize link
stability. If the property is absent, the driver falls back to the
hardware default.
Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
---
drivers/phy/rockchip/phy-rockchip-inno-csidphy.c | 25 ++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
index 5281f8dea0ad3..3a15840e86cad 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
@@ -69,6 +69,10 @@
#define RK1808_CSIDPHY_CLK_CALIB_EN 0x168
#define RK3568_CSIDPHY_CLK_CALIB_EN 0x168
+#define CSIDPHY_LANE_CLK_3_PHASE 0x38
+#define CSIDPHY_CLK_PHASE_MASK GENMASK(6, 4)
+#define CSIDPHY_CLK_PHASE_DEFAULT 3
+
#define RESETS_MAX 2
/*
@@ -151,6 +155,7 @@ struct rockchip_inno_csidphy {
const struct dphy_drv_data *drv_data;
struct phy_configure_opts_mipi_dphy config;
u8 hsfreq;
+ int clk_phase;
};
static inline void write_grf_reg(struct rockchip_inno_csidphy *priv,
@@ -304,6 +309,13 @@ static int rockchip_inno_csidphy_power_on(struct phy *phy)
rockchip_inno_csidphy_ths_settle(priv, priv->hsfreq,
CSIDPHY_LANE_THS_SETTLE(i));
+ if (priv->clk_phase >= 0) {
+ val = readl(priv->phy_base + CSIDPHY_LANE_CLK_3_PHASE);
+ val &= ~CSIDPHY_CLK_PHASE_MASK;
+ val |= FIELD_PREP(CSIDPHY_CLK_PHASE_MASK, priv->clk_phase);
+ writel(val, priv->phy_base + CSIDPHY_LANE_CLK_3_PHASE);
+ }
+
write_grf_reg(priv, GRF_DPHY_CSIPHY_CLKLANE_EN, 0x1);
write_grf_reg(priv, GRF_DPHY_CSIPHY_DATALANE_EN,
GENMASK(priv->config.lanes - 1, 0));
@@ -449,6 +461,7 @@ static int rockchip_inno_csidphy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct phy_provider *phy_provider;
struct phy *phy;
+ u32 phase;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -464,6 +477,18 @@ static int rockchip_inno_csidphy_probe(struct platform_device *pdev)
return -ENODEV;
}
+ priv->clk_phase = -1;
+ if (device_property_read_u32(dev, "rockchip,clk-lane-phase",
+ &phase) == 0) {
+ if (phase >= BIT(3)) {
+ dev_err(dev,
+ "rockchip,clk-lane-phase %u out of range [0,7]\n",
+ phase);
+ return -EINVAL;
+ }
+ priv->clk_phase = phase;
+ }
+
priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf");
if (IS_ERR(priv->grf)) {
--
2.34.1
^ permalink raw reply related
* [PATCH v3 1/3] phy: rockchip: phy-rockchip-inno-csidphy: fix rk1808 hsfreq table
From: Gerald Loacker @ 2026-06-30 7:48 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree, Gerald Loacker
In-Reply-To: <20260630-feature-mipi-csi-dphy-4k60-v3-0-176792ab71fa@wolfvision.net>
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.
Fixes: bd1f775d6027 ("phy/rockchip: add Innosilicon-based CSI dphy")
Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
---
drivers/phy/rockchip/phy-rockchip-inno-csidphy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
index c79fb53d8ee5c..5281f8dea0ad3 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
@@ -170,7 +170,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[] = {
--
2.34.1
^ permalink raw reply related
* [PATCH v3 0/3] phy: rockchip: inno-csidphy: fix 2500 Mbps support and add clock lane phase tuning
From: Gerald Loacker @ 2026-06-30 7:48 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree, Gerald Loacker
This series fixes and extends the Rockchip Innosilicon CSI D-PHY driver
to support data rates up to 2500 Mbps and adds optional board-specific
clock lane phase tuning for signal integrity.
Patch 1 fixes an off-by-one error in the rk1808 hsfreq range table:
the final entry was capped at 2499 Mbps, causing a rejection of the
maximum supported rate of 2500 Mbps.
Patches 2 and 3 add an optional rockchip,clk-lane-phase device tree
property that allows tuning the clock lane sampling phase in ~40 ps
steps to compensate for board-level signal integrity variations.
---
Changes in v3:
- dt-bindings: add default for rockchip,clk-lane-phase
- Link to v2: https://patch.msgid.link/20260619-feature-mipi-csi-dphy-4k60-v2-0-323356c2cc2e@wolfvision.net
Changes in v2:
- dt-bindings: improve rockchip,clk-lane-phase description wording
(Conor Dooley)
- Link to v1: https://patch.msgid.link/20260617-feature-mipi-csi-dphy-4k60-v1-0-4611ff00b0ff@wolfvision.net
To: Vinod Koul <vkoul@kernel.org>
To: Neil Armstrong <neil.armstrong@linaro.org>
To: Heiko Stuebner <heiko@sntech.de>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
Cc: linux-phy@lists.infradead.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-rockchip@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Cc: devicetree@vger.kernel.org
---
Gerald Loacker (3):
phy: rockchip: phy-rockchip-inno-csidphy: fix rk1808 hsfreq table
dt-bindings: phy: rockchip-inno-csi-dphy: add rockchip,clk-lane-phase property
phy: rockchip: phy-rockchip-inno-csidphy: add clock lane phase tuning
.../bindings/phy/rockchip-inno-csi-dphy.yaml | 10 ++++++++
drivers/phy/rockchip/phy-rockchip-inno-csidphy.c | 27 +++++++++++++++++++++-
2 files changed, 36 insertions(+), 1 deletion(-)
---
base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
change-id: 20260617-feature-mipi-csi-dphy-4k60-9879c3d1fe4f
Best regards,
--
Gerald Loacker <gerald.loacker@wolfvision.net>
^ permalink raw reply
* [PATCH net-next 02/14] net: enetc: extract common helpers for MAC hash filter configuration
From: wei.fang @ 2026-06-30 7:20 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260630072036.382761-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
The PSIUMHFR and PSIMMHFR registers in ENETC v4 have the same bit layout
as in ENETC v1. The only difference between the two hardware generations
is the register address offsets.
Since the register functionality is identical, the MAC hash filter
configuration code can be shared between the ENETC v1 and v4 drivers.
Extract two new common helper functions, enetc_set_si_uc_hash_filter()
and enetc_set_si_mc_hash_filter(), into enetc_pf_common.c. These helpers
select the correct register offset based on the hardware revision via
is_enetc_rev1().
Remove v1-specific enetc_clear_mac_ht_flt() and enetc_set_mac_ht_flt()
from enetc_pf.c, and v4-specific enetc4_pf_set_si_uc_hash_filter() and
enetc4_pf_set_si_mc_hash_filter() from enetc4_pf.c, as they are now
superseded by the shared implementations.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_pf.c | 43 +++++++---------
.../net/ethernet/freescale/enetc/enetc_pf.c | 51 +++++--------------
.../freescale/enetc/enetc_pf_common.c | 40 +++++++++++++++
.../freescale/enetc/enetc_pf_common.h | 2 +
4 files changed, 73 insertions(+), 63 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 304ec069654d..48a74db90ed5 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -75,20 +75,6 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
put_unaligned_le16(lower, addr + 4);
}
-static void enetc4_pf_set_si_uc_hash_filter(struct enetc_hw *hw, int si,
- u64 hash)
-{
- enetc_port_wr(hw, ENETC4_PSIUMHFR0(si), lower_32_bits(hash));
- enetc_port_wr(hw, ENETC4_PSIUMHFR1(si), upper_32_bits(hash));
-}
-
-static void enetc4_pf_set_si_mc_hash_filter(struct enetc_hw *hw, int si,
- u64 hash)
-{
- enetc_port_wr(hw, ENETC4_PSIMMHFR0(si), lower_32_bits(hash));
- enetc_port_wr(hw, ENETC4_PSIMMHFR1(si), upper_32_bits(hash));
-}
-
static void enetc4_pf_set_loopback(struct net_device *ndev, bool en)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
@@ -147,11 +133,12 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
int max_num_mfe = pf->caps.mac_filter_num;
struct enetc_mac_filter mac_filter = {};
struct net_device *ndev = pf->si->ndev;
- struct enetc_hw *hw = &pf->si->hw;
struct enetc_mac_addr *mac_tbl;
+ struct enetc_si *si = pf->si;
struct netdev_hw_addr *ha;
int i = 0, err;
int mac_cnt;
+ u64 hash;
netif_addr_lock_bh(ndev);
@@ -159,7 +146,7 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
if (!mac_cnt) {
netif_addr_unlock_bh(ndev);
/* clear both MAC hash and exact filters */
- enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
return 0;
@@ -186,11 +173,13 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
/* Set temporary unicast hash filters in case of Rx loss when
* updating MAC address filter table
*/
- enetc4_pf_set_si_uc_hash_filter(hw, 0, *mac_filter.mac_hash_table);
+ bitmap_to_arr64(&hash, mac_filter.mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_uc_hash_filter(si, 0, hash);
enetc4_pf_clear_maft_entries(pf);
if (!enetc4_pf_add_maft_entries(pf, mac_tbl, i))
- enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
kfree(mac_tbl);
@@ -206,8 +195,9 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
{
struct net_device *ndev = pf->si->ndev;
struct enetc_mac_filter *mac_filter;
- struct enetc_hw *hw = &pf->si->hw;
+ struct enetc_si *si = pf->si;
struct netdev_hw_addr *ha;
+ u64 hash;
netif_addr_lock_bh(ndev);
if (type & ENETC_MAC_FILTER_TYPE_UC) {
@@ -216,8 +206,9 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
netdev_for_each_uc_addr(ha, ndev)
enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
- enetc4_pf_set_si_uc_hash_filter(hw, 0,
- *mac_filter->mac_hash_table);
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_uc_hash_filter(si, 0, hash);
}
if (type & ENETC_MAC_FILTER_TYPE_MC) {
@@ -226,8 +217,9 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
netdev_for_each_mc_addr(ha, ndev)
enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
- enetc4_pf_set_si_mc_hash_filter(hw, 0,
- *mac_filter->mac_hash_table);
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_mc_hash_filter(si, 0, hash);
}
netif_addr_unlock_bh(ndev);
}
@@ -480,7 +472,6 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task);
struct enetc_pf *pf = enetc_si_priv(si);
struct net_device *ndev = si->ndev;
- struct enetc_hw *hw = &si->hw;
bool uc_promisc = false;
bool mc_promisc = false;
int type = 0;
@@ -501,12 +492,12 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
enetc_set_si_mc_promisc(si, 0, mc_promisc);
if (uc_promisc) {
- enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
}
if (mc_promisc)
- enetc4_pf_set_si_mc_hash_filter(hw, 0, 0);
+ enetc_set_si_mc_hash_filter(si, 0, 0);
/* Set new MAC filter */
enetc4_pf_set_mac_filter(pf, type);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index a97d2e2dd07b..db2a800a7aaf 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -80,37 +80,6 @@ static void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter,
filter->mac_addr_cnt++;
}
-static void enetc_clear_mac_ht_flt(struct enetc_si *si, int si_idx, int type)
-{
- bool err = si->errata & ENETC_ERR_UCMCSWP;
-
- if (type == UC) {
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), 0);
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), 0);
- } else { /* MC */
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), 0);
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), 0);
- }
-}
-
-static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
- unsigned long hash)
-{
- bool err = si->errata & ENETC_ERR_UCMCSWP;
-
- if (type == UC) {
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err),
- lower_32_bits(hash));
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx),
- upper_32_bits(hash));
- } else { /* MC */
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err),
- lower_32_bits(hash));
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx),
- upper_32_bits(hash));
- }
-}
-
static void enetc_sync_mac_filters(struct enetc_pf *pf)
{
struct enetc_mac_filter *f = pf->mac_filter;
@@ -122,12 +91,16 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
for (i = 0; i < MADDR_TYPE; i++, f++) {
bool em = (f->mac_addr_cnt == 1) && (i == UC);
bool clear = !f->mac_addr_cnt;
+ u64 hash;
if (clear) {
- if (i == UC)
+ if (i == UC) {
enetc_clear_mac_flt_entry(si, pos);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
+ } else {
+ enetc_set_si_mc_hash_filter(si, 0, 0);
+ }
- enetc_clear_mac_ht_flt(si, 0, i);
continue;
}
@@ -135,7 +108,7 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
if (em) {
int err;
- enetc_clear_mac_ht_flt(si, 0, UC);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
err = enetc_set_mac_flt_entry(si, pos, f->mac_addr,
BIT(0));
@@ -147,11 +120,15 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
err);
}
+ bitmap_to_arr64(&hash, f->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
/* hash table filter, clear EM filter for UC entries */
- if (i == UC)
+ if (i == UC) {
enetc_clear_mac_flt_entry(si, pos);
-
- enetc_set_mac_ht_flt(si, 0, i, *f->mac_hash_table);
+ enetc_set_si_uc_hash_filter(si, 0, hash);
+ } else {
+ enetc_set_si_mc_hash_filter(si, 0, hash);
+ }
}
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index b0c0dc668e34..3597cb81a7cc 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -131,6 +131,46 @@ void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc)
}
EXPORT_SYMBOL_GPL(enetc_set_si_mc_promisc);
+void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash)
+{
+ int psiumhfr0_off, psiumhfr1_off;
+ struct enetc_hw *hw = &si->hw;
+
+ if (is_enetc_rev1(si)) {
+ bool err = si->errata & ENETC_ERR_UCMCSWP;
+
+ psiumhfr0_off = ENETC_PSIUMHFR0(si_id, err);
+ psiumhfr1_off = ENETC_PSIUMHFR1(si_id);
+ } else {
+ psiumhfr0_off = ENETC4_PSIUMHFR0(si_id);
+ psiumhfr1_off = ENETC4_PSIUMHFR1(si_id);
+ }
+
+ enetc_port_wr(hw, psiumhfr0_off, lower_32_bits(hash));
+ enetc_port_wr(hw, psiumhfr1_off, upper_32_bits(hash));
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_uc_hash_filter);
+
+void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash)
+{
+ int psimmhfr0_off, psimmhfr1_off;
+ struct enetc_hw *hw = &si->hw;
+
+ if (is_enetc_rev1(si)) {
+ bool err = si->errata & ENETC_ERR_UCMCSWP;
+
+ psimmhfr0_off = ENETC_PSIMMHFR0(si_id, err);
+ psimmhfr1_off = ENETC_PSIMMHFR1(si_id);
+ } else {
+ psimmhfr0_off = ENETC4_PSIMMHFR0(si_id);
+ psimmhfr1_off = ENETC4_PSIMMHFR1(si_id);
+ }
+
+ enetc_port_wr(hw, psimmhfr0_off, lower_32_bits(hash));
+ enetc_port_wr(hw, psimmhfr1_off, upper_32_bits(hash));
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_mc_hash_filter);
+
void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
const struct net_device_ops *ndev_ops)
{
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index a619fb8fed9c..bf9029b0a017 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -19,6 +19,8 @@ int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_init_sriov_resources(struct enetc_pf *pf);
void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc);
void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc);
+void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash);
+void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash);
static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
{
--
2.34.1
^ permalink raw reply related
* [PATCH v3 2/3] dt-bindings: phy: rockchip-inno-csi-dphy: add rockchip,clk-lane-phase property
From: Gerald Loacker @ 2026-06-30 7:48 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree, Gerald Loacker
In-Reply-To: <20260630-feature-mipi-csi-dphy-4k60-v3-0-176792ab71fa@wolfvision.net>
Add support for the optional rockchip,clk-lane-phase device tree property
to allow board-specific tuning of the clock lane sampling phase for
improved signal integrity across supported data rates.
Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
---
.../devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml b/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml
index 03950b3cad08c..913aa688c0ae9 100644
--- a/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml
+++ b/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml
@@ -56,6 +56,16 @@ properties:
description:
Some additional phy settings are access through GRF regs.
+ rockchip,clk-lane-phase:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+ default: 3
+ description:
+ Clock lane sampling phase selection (hardware tap index 0–7). Each step
+ corresponds to an approximately 40 ps delay as described in the hardware
+ specification.
+
required:
- compatible
- reg
--
2.34.1
^ permalink raw reply related
* [PATCH net-next 01/14] net: enetc: extract common helpers for MAC promiscuous mode setting
From: wei.fang @ 2026-06-30 7:20 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260630072036.382761-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
The PSIPMMR (Port Station Interface Promiscuous MAC Mode Register) in
ENETC v4 has the same bit layout as the PSIPMR register in ENETC v1: bit
n controls unicast promiscuous mode for SI n, and bit (n + 16) controls
multicast promiscuous mode for SI n. The only difference between the two
hardware generations is the register address offset.
Since the register functionality is identical, the MAC promiscuous mode
setting code can be shared between ENETC v1 and v4 drivers.
Rename ENETC_PSIPMR to ENETC_PSIPMMR in enetc_hw.h to match the actual
register name used in the reference manual, and extract two new common
helper functions, enetc_set_si_uc_promisc() and
enetc_set_si_mc_promisc(), into enetc_pf_common.c. These helpers select
the correct register offset based on the hardware revision via
is_enetc_rev1().
Remove the v4-specific enetc4_pf_set_si_mac_promisc() function from
enetc4_pf.c and the duplicate PSIPMMR_SI_MAC_UP/MP macro definitions
from enetc4_hw.h, as they are now superseded by the shared code.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_hw.h | 2 -
.../net/ethernet/freescale/enetc/enetc4_pf.c | 21 +--------
.../ethernet/freescale/enetc/enetc_ethtool.c | 2 +-
.../net/ethernet/freescale/enetc/enetc_hw.h | 7 +--
.../net/ethernet/freescale/enetc/enetc_pf.c | 11 ++---
.../freescale/enetc/enetc_pf_common.c | 44 +++++++++++++++++++
.../freescale/enetc/enetc_pf_common.h | 2 +
7 files changed, 56 insertions(+), 33 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index f18437556a0e..6a8f2ed56017 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -69,8 +69,6 @@
/* Port Station interface promiscuous MAC mode register */
#define ENETC4_PSIPMMR 0x200
-#define PSIPMMR_SI_MAC_UP(a) BIT(a) /* a = SI index */
-#define PSIPMMR_SI_MAC_MP(a) BIT((a) + 16)
/* Port Station interface promiscuous VLAN mode register */
#define ENETC4_PSIPVMR 0x204
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 437a15bbb47b..304ec069654d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -75,24 +75,6 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
put_unaligned_le16(lower, addr + 4);
}
-static void enetc4_pf_set_si_mac_promisc(struct enetc_hw *hw, int si,
- bool uc_promisc, bool mc_promisc)
-{
- u32 val = enetc_port_rd(hw, ENETC4_PSIPMMR);
-
- if (uc_promisc)
- val |= PSIPMMR_SI_MAC_UP(si);
- else
- val &= ~PSIPMMR_SI_MAC_UP(si);
-
- if (mc_promisc)
- val |= PSIPMMR_SI_MAC_MP(si);
- else
- val &= ~PSIPMMR_SI_MAC_MP(si);
-
- enetc_port_wr(hw, ENETC4_PSIPMMR, val);
-}
-
static void enetc4_pf_set_si_uc_hash_filter(struct enetc_hw *hw, int si,
u64 hash)
{
@@ -515,7 +497,8 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
type = ENETC_MAC_FILTER_TYPE_ALL;
}
- enetc4_pf_set_si_mac_promisc(hw, 0, uc_promisc, mc_promisc);
+ enetc_set_si_uc_promisc(si, 0, uc_promisc);
+ enetc_set_si_mc_promisc(si, 0, mc_promisc);
if (uc_promisc) {
enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index 71f376ef1be1..07b7832f2427 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -29,7 +29,7 @@ static const u32 enetc_rxbdr_regs[] = {
};
static const u32 enetc_port_regs[] = {
- ENETC_PMR, ENETC_PSR, ENETC_PSIPMR, ENETC_PSIPMAR0(0),
+ ENETC_PMR, ENETC_PSR, ENETC_PSIPMMR, ENETC_PSIPMAR0(0),
ENETC_PSIPMAR1(0), ENETC_PTXMBAR, ENETC_PCAPR0, ENETC_PCAPR1,
ENETC_PSICFGR0(0), ENETC_PRFSCAPR, ENETC_PTCMSDUR(0),
ENETC_PM0_CMD_CFG, ENETC_PM0_MAXFRM, ENETC_PM0_IF_MODE
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index bf99b65d7598..66bfda60da9c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -180,9 +180,10 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PMR_PSPEED_1000M BIT(9)
#define ENETC_PMR_PSPEED_2500M BIT(10)
#define ENETC_PSR 0x0004 /* RO */
-#define ENETC_PSIPMR 0x0018
-#define ENETC_PSIPMR_SET_UP(n) BIT(n) /* n = SI index */
-#define ENETC_PSIPMR_SET_MP(n) BIT((n) + 16)
+#define ENETC_PSIPMMR 0x0018
+#define PSIPMMR_SI_MAC_UP(n) BIT(n) /* n = SI index */
+#define PSIPMMR_SI_MAC_MP(n) BIT((n) + 16)
+
#define ENETC_PSIPVMR 0x001c
#define ENETC_VLAN_PROMISC_MAP_ALL 0x7
#define ENETC_PSIPVMR_SET_VP(simap) ((simap) & 0x7)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 2d687bb8c3a0..a97d2e2dd07b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -159,21 +159,17 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_pf *pf = enetc_si_priv(priv->si);
- struct enetc_hw *hw = &priv->si->hw;
bool uprom = false, mprom = false;
struct enetc_mac_filter *filter;
struct netdev_hw_addr *ha;
- u32 psipmr = 0;
bool em;
if (ndev->flags & IFF_PROMISC) {
/* enable promisc mode for SI0 (PF) */
- psipmr = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0);
uprom = true;
mprom = true;
} else if (ndev->flags & IFF_ALLMULTI) {
/* enable multi cast promisc mode for SI0 (PF) */
- psipmr = ENETC_PSIPMR_SET_MP(0);
mprom = true;
}
@@ -211,9 +207,8 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
/* update PF entries */
enetc_sync_mac_filters(pf);
- psipmr |= enetc_port_rd(hw, ENETC_PSIPMR) &
- ~(ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0));
- enetc_port_wr(hw, ENETC_PSIPMR, psipmr);
+ enetc_set_si_uc_promisc(priv->si, 0, uprom);
+ enetc_set_si_mc_promisc(priv->si, 0, mprom);
}
static void enetc_set_loopback(struct net_device *ndev, bool en)
@@ -474,7 +469,7 @@ static void enetc_configure_port(struct enetc_pf *pf)
pf->vlan_promisc_simap = ENETC_VLAN_PROMISC_MAP_ALL;
enetc_set_vlan_promisc(hw, pf->vlan_promisc_simap);
- enetc_port_wr(hw, ENETC_PSIPMR, 0);
+ enetc_port_wr(hw, ENETC_PSIPMMR, 0);
/* enable port */
enetc_port_wr(hw, ENETC_PMR, ENETC_PMR_EN);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 6e5d2f869915..b0c0dc668e34 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -87,6 +87,50 @@ int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf)
}
EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses);
+void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc)
+{
+ struct enetc_hw *hw = &si->hw;
+ int psipmmr_off;
+ u32 val;
+
+ if (is_enetc_rev1(si))
+ psipmmr_off = ENETC_PSIPMMR;
+ else
+ psipmmr_off = ENETC4_PSIPMMR;
+
+ val = enetc_port_rd(hw, psipmmr_off);
+
+ if (promisc)
+ val |= PSIPMMR_SI_MAC_UP(si_id);
+ else
+ val &= ~PSIPMMR_SI_MAC_UP(si_id);
+
+ enetc_port_wr(hw, psipmmr_off, val);
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_uc_promisc);
+
+void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc)
+{
+ struct enetc_hw *hw = &si->hw;
+ int psipmmr_off;
+ u32 val;
+
+ if (is_enetc_rev1(si))
+ psipmmr_off = ENETC_PSIPMMR;
+ else
+ psipmmr_off = ENETC4_PSIPMMR;
+
+ val = enetc_port_rd(hw, psipmmr_off);
+
+ if (promisc)
+ val |= PSIPMMR_SI_MAC_MP(si_id);
+ else
+ val &= ~PSIPMMR_SI_MAC_MP(si_id);
+
+ enetc_port_wr(hw, psipmmr_off, val);
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_mc_promisc);
+
void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
const struct net_device_ops *ndev_ops)
{
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index 57d2e0ebd2b0..a619fb8fed9c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -17,6 +17,8 @@ void enetc_set_default_rss_key(struct enetc_pf *pf);
int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_init_sriov_resources(struct enetc_pf *pf);
+void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc);
+void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc);
static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
{
--
2.34.1
^ permalink raw reply related
* [PATCH net-next 00/14] net: enetc: cleanups and improvements
From: wei.fang @ 2026-06-30 7:20 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
From: Wei Fang <wei.fang@nxp.com>
The first group of patches (1, 2, 5-7) eliminates code duplication
between the ENETC v1 and v4 drivers. Since both hardware generations
share identical register layouts for MAC promiscuous mode, MAC hash
filters, and VLAN promiscuous mode - differing only in register address
offsets - common helper functions are extracted into enetc_pf_common.c
and shared by both drivers.
Patch 3 converts ndo_set_rx_mode() to ndo_set_rx_mode_async(), removing
the dedicated workqueue that was previously needed to defer MAC address
list updates to a sleepable context.
Patch 4 replaces counter-based MAFT entry tracking with a bitmap, which
keeps hardware and software state in sync and avoids partial failures
during entry allocation.
Patches 8 and 9 fix phylink-related issues: removing invalid code from
enetc4_pl_mac_link_up() and properly differentiating phylink capabilities
between pseudo-MAC and standalone MAC.
The remaining patches (10-14) are minor cleanups: removing a redundant
VLAN promiscuous mode initialization in probe, using the PCI device name
for the debugfs directory, simplifying port speed configuration, removing
a redundant num_vsi field, using alloc_etherdev_mqs() for the VF driver,
and using kzalloc_flex() for a flexible array allocation.
Claudiu Manoil (1):
net: enetc: differentiate phylink capabilities for pseudo-MAC and
standalone MAC
Wei Fang (13):
net: enetc: extract common helpers for MAC promiscuous mode setting
net: enetc: extract common helpers for MAC hash filter configuration
net: enetc: convert ndo_set_rx_mode() to ndo_set_rx_mode_async()
net: enetc: improve MAFT entry management with bitmap tracking
net: enetc: use PCI device name for debugfs directory
net: enetc: simplify enetc4_set_port_speed()
net: enetc: remove invalid code from enetc4_pl_mac_link_up()
net: enetc: remove enetc4_set_default_si_vlan_promisc()
net: enetc: refactor SI VLAN promiscuous mode configuration
net: enetc: move enetc_set_si_vlan_promisc() to enetc_pf_common.c
net: enetc: remove redundant num_vsi field from enetc_port_caps
net: enetc: use alloc_etherdev_mqs() to create netdev for VF driver
net: enetc: use kzalloc_flex() for enetc_psfp_gate allocation
drivers/net/ethernet/freescale/enetc/enetc.h | 4 +-
.../ethernet/freescale/enetc/enetc4_debugfs.c | 42 +-
.../net/ethernet/freescale/enetc/enetc4_hw.h | 6 +-
.../net/ethernet/freescale/enetc/enetc4_pf.c | 410 +++++++-----------
.../ethernet/freescale/enetc/enetc_ethtool.c | 2 +-
.../net/ethernet/freescale/enetc/enetc_hw.h | 12 +-
.../net/ethernet/freescale/enetc/enetc_pf.c | 93 +---
.../net/ethernet/freescale/enetc/enetc_pf.h | 5 -
.../freescale/enetc/enetc_pf_common.c | 145 ++++++-
.../freescale/enetc/enetc_pf_common.h | 5 +
.../net/ethernet/freescale/enetc/enetc_qos.c | 4 +-
.../net/ethernet/freescale/enetc/enetc_vf.c | 3 +-
include/linux/fsl/ntmp.h | 2 +
13 files changed, 345 insertions(+), 388 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v4 07/10] of: reserved_mem: add kdump helpers to exclude non-dumpable regions
From: Wandun Chen @ 2026-06-30 7:47 UTC (permalink / raw)
To: chenhuacai, kernel, pjw, palmer, aou, robh, saravanak, bhe, rppt,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing
Cc: catalin.marinas, will, alex, akpm, pasha.tatashin, pratyush,
ruirui.yang, m.szyprowski, robin.murphy
In-Reply-To: <20260630074715.4126796-1-chenwandun1@gmail.com>
From: Wandun Chen <chenwandun@lixiang.com>
Add two helpers to exclude non-dumpable regions for arch-specific
code.
- of_reserved_mem_kdump_nr_ranges() returns the count of regions
that are not dumpable. Each excluded region may split an existing
crash_mem range into two, so callers use this to calculate
crash_mem allocation size.
- of_reserved_mem_kdump_exclude() walks reserved_mem[] and calls
crash_exclude_mem_range() for every non-dumpable region.
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Tested-by: Meijing Zhao <zhaomeijing@lixiang.com>
---
drivers/of/of_reserved_mem.c | 34 +++++++++++++++++++++++++++++++++
include/linux/of_reserved_mem.h | 14 ++++++++++++++
2 files changed, 48 insertions(+)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 9db0502989c3..c83ef88dffe2 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/memblock.h>
#include <linux/kmemleak.h>
+#include <linux/crash_core.h>
#include "of_private.h"
@@ -856,6 +857,39 @@ struct reserved_mem *of_reserved_mem_lookup(struct device_node *np)
}
EXPORT_SYMBOL_GPL(of_reserved_mem_lookup);
+/*
+ * Count non-dumpable reserved regions. Excluding each one may split a
+ * crash_mem range in two, callers use this to size the allocation.
+ */
+unsigned int of_reserved_mem_kdump_nr_ranges(void)
+{
+ unsigned int i, n = 0;
+
+ for (i = 0; i < reserved_mem_count; i++)
+ if (reserved_mem[i].size && !reserved_mem[i].dumpable)
+ n++;
+ return n;
+}
+
+/* Exclude non-dumpable reserved regions from @cmem. */
+int of_reserved_mem_kdump_exclude(struct crash_mem *cmem)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < reserved_mem_count; i++) {
+ struct reserved_mem *r = &reserved_mem[i];
+
+ if (!r->size || r->dumpable)
+ continue;
+ ret = crash_exclude_mem_range(cmem, r->base,
+ r->base + r->size - 1);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
/**
* of_reserved_mem_region_to_resource() - Get a reserved memory region as a resource
* @np: node containing 'memory-region' property
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
index 55a67cee41ea..70db99f1fbff 100644
--- a/include/linux/of_reserved_mem.h
+++ b/include/linux/of_reserved_mem.h
@@ -8,6 +8,7 @@
struct of_phandle_args;
struct reserved_mem_ops;
struct resource;
+struct crash_mem;
struct reserved_mem {
const char *name;
@@ -48,6 +49,9 @@ int of_reserved_mem_region_to_resource_byname(const struct device_node *np,
const char *name, struct resource *res);
int of_reserved_mem_region_count(const struct device_node *np);
+unsigned int of_reserved_mem_kdump_nr_ranges(void);
+int of_reserved_mem_kdump_exclude(struct crash_mem *cmem);
+
#else
#define RESERVEDMEM_OF_DECLARE(name, compat, ops) \
@@ -92,6 +96,16 @@ static inline int of_reserved_mem_region_count(const struct device_node *np)
{
return 0;
}
+
+static inline unsigned int of_reserved_mem_kdump_nr_ranges(void)
+{
+ return 0;
+}
+
+static inline int of_reserved_mem_kdump_exclude(struct crash_mem *cmem)
+{
+ return 0;
+}
#endif
/**
--
2.43.0
^ permalink raw reply related
* [PATCH v4 06/10] of: reserved_mem: save /memreserve/ entries into the reserved_mem array
From: Wandun Chen @ 2026-06-30 7:47 UTC (permalink / raw)
To: chenhuacai, kernel, pjw, palmer, aou, robh, saravanak, bhe, rppt,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing
Cc: catalin.marinas, will, alex, akpm, pasha.tatashin, pratyush,
ruirui.yang, m.szyprowski, robin.murphy
In-Reply-To: <20260630074715.4126796-1-chenwandun1@gmail.com>
From: Wandun Chen <chenwandun@lixiang.com>
/memreserve/ is used by firmware or bootloaders, such regions hold no
useful data for crash analysis, they should be excluded from the
kdump vmcore, so save /memreserve/ entries into the reserved_mem array
for later exclusion.
If a /memreserve/ entry overlaps any dumpable reserved region, mark
the whole memreserve entry dumpable as well. This may keep slightly
more memory in vmcore than strictly necessary, but avoids splitting
entries and never drops data that may be useful for crash analysis.
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Tested-by: Meijing Zhao <zhaomeijing@lixiang.com>
---
drivers/of/fdt.c | 4 +++
drivers/of/of_private.h | 2 ++
drivers/of/of_reserved_mem.c | 52 ++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index b97775f6c9d4..3e478d29e247 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -497,6 +497,7 @@ void __init early_init_fdt_scan_reserved_mem(void)
int n;
int res;
u64 base, size;
+ int nr_memreserve = 0;
if (!initial_boot_params)
return;
@@ -514,7 +515,9 @@ void __init early_init_fdt_scan_reserved_mem(void)
if (!size)
break;
memblock_reserve(base, size);
+ nr_memreserve++;
}
+ fdt_reserved_mem_account_memreserve(nr_memreserve);
}
/**
@@ -1286,6 +1289,7 @@ void __init unflatten_device_tree(void)
if (!alloc_reserved_mem_array()) {
/* Save the statically-placed regions in the reserved_mem array */
fdt_scan_reserved_mem_late();
+ fdt_reserved_mem_save_memreserve_entries();
}
/* Populate an empty root node when bootloader doesn't provide one */
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 81c8ec9378b9..a67929c0a6ec 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -188,6 +188,8 @@ static inline struct device_node *__of_get_dma_parent(const struct device_node *
int fdt_scan_reserved_mem(void);
void __init fdt_scan_reserved_mem_late(void);
int __init alloc_reserved_mem_array(void);
+void __init fdt_reserved_mem_account_memreserve(int n);
+void __init fdt_reserved_mem_save_memreserve_entries(void);
bool of_fdt_device_is_available(const void *blob, unsigned long node);
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index f6c02b37deb7..9db0502989c3 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -251,6 +251,43 @@ static void __init __rmem_check_for_overlap(void)
}
}
+static void __init fdt_reserved_mem_add_memreserve(phys_addr_t base,
+ phys_addr_t size)
+{
+ struct reserved_mem *rmem;
+ bool dumpable = false;
+ int i;
+
+ if (reserved_mem_count == total_reserved_mem_cnt) {
+ pr_err("not enough space for memreserve regions.\n");
+ return;
+ }
+
+ for (i = 0; i < reserved_mem_count; i++) {
+ rmem = &reserved_mem[i];
+
+ if (!rmem->dumpable)
+ continue;
+
+ if (base < rmem->base + rmem->size && rmem->base < base + size) {
+ dumpable = true;
+ break;
+ }
+ }
+
+ rmem = &reserved_mem[reserved_mem_count];
+ rmem->base = base;
+ rmem->size = size;
+ rmem->dumpable = dumpable;
+
+ reserved_mem_count++;
+}
+
+void __init fdt_reserved_mem_account_memreserve(int n)
+{
+ total_reserved_mem_cnt += n;
+}
+
/**
* fdt_scan_reserved_mem_late() - Scan FDT and initialize remaining reserved
* memory regions.
@@ -305,6 +342,21 @@ void __init fdt_scan_reserved_mem_late(void)
__rmem_check_for_overlap();
}
+void __init fdt_reserved_mem_save_memreserve_entries(void)
+{
+ const void *fdt = initial_boot_params;
+ u64 base, size;
+ int n;
+
+ for (n = 0; ; n++) {
+ if (fdt_get_mem_rsv(fdt, n, &base, &size))
+ break;
+ if (!size)
+ break;
+ fdt_reserved_mem_add_memreserve(base, size);
+ }
+}
+
static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname);
/*
--
2.43.0
^ permalink raw reply related
* [PATCH v4 05/10] of: reserved_mem: add dumpable flag to opt-in vmcore
From: Wandun Chen @ 2026-06-30 7:47 UTC (permalink / raw)
To: chenhuacai, kernel, pjw, palmer, aou, robh, saravanak, bhe, rppt,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing
Cc: catalin.marinas, will, alex, akpm, pasha.tatashin, pratyush,
ruirui.yang, m.szyprowski, robin.murphy
In-Reply-To: <20260630074715.4126796-1-chenwandun1@gmail.com>
From: Wandun Chen <chenwandun@lixiang.com>
Add a 'dumpable' flag to struct reserved_mem so the kernel can decide
whether a reserved area should be included in the kdump vmcore. Most
reserved regions are owned by devices and do not contain data useful
for kernel crash analysis, so excluding them by default is the right
behaviour.
Reusable CMA regions are different: pages in a CMA region are handed
back to the buddy allocator and may contain key data for crash
analysis, so set dumpable to true in rmem_cma_setup().
Suggested-by: Rob Herring <robh@kernel.org>
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Tested-by: Meijing Zhao <zhaomeijing@lixiang.com>
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Link: https://lore.kernel.org/all/20260506144542.GA2072596-robh@kernel.org/
---
include/linux/of_reserved_mem.h | 1 +
kernel/dma/contiguous.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
index e8b20b29fa68..55a67cee41ea 100644
--- a/include/linux/of_reserved_mem.h
+++ b/include/linux/of_reserved_mem.h
@@ -15,6 +15,7 @@ struct reserved_mem {
phys_addr_t base;
phys_addr_t size;
void *priv;
+ bool dumpable;
};
struct reserved_mem_ops {
diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
index f754079a287d..63ff134dadd4 100644
--- a/kernel/dma/contiguous.c
+++ b/kernel/dma/contiguous.c
@@ -565,6 +565,7 @@ static int __init rmem_cma_setup(unsigned long node, struct reserved_mem *rmem)
dma_contiguous_default_area = cma;
rmem->priv = cma;
+ rmem->dumpable = true;
pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
&rmem->base, (unsigned long)rmem->size / SZ_1M);
--
2.43.0
^ permalink raw reply related
* [PATCH v4 04/10] of: reserved_mem: split alloc_reserved_mem_array() from fdt_scan_reserved_mem_late()
From: Wandun Chen @ 2026-06-30 7:47 UTC (permalink / raw)
To: chenhuacai, kernel, pjw, palmer, aou, robh, saravanak, bhe, rppt,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing
Cc: catalin.marinas, will, alex, akpm, pasha.tatashin, pratyush,
ruirui.yang, m.szyprowski, robin.murphy
In-Reply-To: <20260630074715.4126796-1-chenwandun1@gmail.com>
From: Wandun Chen <chenwandun@lixiang.com>
Prepare for storing /memreserve/ entries in the reserved_mem array.
alloc_reserved_mem_array was skipped if the device tree lacks a
/reserved-memory node, pointer 'reserved_mem' continues to reference
the reserved_mem_array which lives in __initdata, storing
/memreserve/ entries into reserved_mem_array would result in metadata
loss, and an out-of-bounds memory access will occur if the device
tree contains more than MAX_RESERVED_REGIONS /memreserve/ entries.
So split alloc_reserved_mem_array() from fdt_scan_reserved_mem_late(),
and call alloc_reserved_mem_array() whether or not there is a
/reserved-memory node.
No functional change.
The actual /memreserve/ population is added in a follow-up patch.
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
---
drivers/of/fdt.c | 7 +++++--
drivers/of/of_private.h | 1 +
drivers/of/of_reserved_mem.c | 11 ++---------
3 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 26f66046cc32..b97775f6c9d4 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -1282,8 +1282,11 @@ void __init unflatten_device_tree(void)
{
void *fdt = initial_boot_params;
- /* Save the statically-placed regions in the reserved_mem array */
- fdt_scan_reserved_mem_late();
+ /* Attempt dynamic allocation of a new reserved_mem array */
+ if (!alloc_reserved_mem_array()) {
+ /* Save the statically-placed regions in the reserved_mem array */
+ fdt_scan_reserved_mem_late();
+ }
/* Populate an empty root node when bootloader doesn't provide one */
if (!fdt) {
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 0ae16da066e2..81c8ec9378b9 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -187,6 +187,7 @@ static inline struct device_node *__of_get_dma_parent(const struct device_node *
int fdt_scan_reserved_mem(void);
void __init fdt_scan_reserved_mem_late(void);
+int __init alloc_reserved_mem_array(void);
bool of_fdt_device_is_available(const void *blob, unsigned long node);
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index e1bd35115cc1..f6c02b37deb7 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -69,13 +69,13 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
* the initial static array is copied over to this new array and
* the new array is used from this point on.
*/
-static int __init alloc_reserved_mem_array(void)
+int __init alloc_reserved_mem_array(void)
{
struct reserved_mem *new_array;
size_t alloc_size, copy_size, memset_size;
int ret;
- if (!total_reserved_mem_cnt)
+ if (!initial_boot_params || !total_reserved_mem_cnt)
return -ENODEV;
alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array));
@@ -266,17 +266,10 @@ void __init fdt_scan_reserved_mem_late(void)
phys_addr_t base, size;
int node, child;
- if (!fdt)
- return;
-
node = fdt_path_offset(fdt, "/reserved-memory");
if (node < 0)
return;
- /* Attempt dynamic allocation of a new reserved_mem array */
- if (alloc_reserved_mem_array())
- return;
-
if (__reserved_mem_check_root(node))
return;
--
2.43.0
^ permalink raw reply related
* [PATCH v4 03/10] of: reserved_mem: skip late scan when no regions are reserved
From: Wandun Chen @ 2026-06-30 7:47 UTC (permalink / raw)
To: chenhuacai, kernel, pjw, palmer, aou, robh, saravanak, bhe, rppt,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing
Cc: catalin.marinas, will, alex, akpm, pasha.tatashin, pratyush,
ruirui.yang, m.szyprowski, robin.murphy
In-Reply-To: <20260630074715.4126796-1-chenwandun1@gmail.com>
From: Wandun Chen <chenwandun@lixiang.com>
When total_reserved_mem_cnt is 0, there is no /reserved-memory node
so fdt_scan_reserved_mem_late() have nothing to do, so return -ENODEV
directly from alloc_reserved_mem_array() in this case.
No functional change.
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
---
drivers/of/of_reserved_mem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 42649dc3613f..e1bd35115cc1 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -76,7 +76,7 @@ static int __init alloc_reserved_mem_array(void)
int ret;
if (!total_reserved_mem_cnt)
- return 0;
+ return -ENODEV;
alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array));
if (alloc_size == SIZE_MAX) {
--
2.43.0
^ permalink raw reply related
* [PATCH v4 02/10] of: reserved_mem: dedup and relocate reserved-memory messages
From: Wandun Chen @ 2026-06-30 7:47 UTC (permalink / raw)
To: chenhuacai, kernel, pjw, palmer, aou, robh, saravanak, bhe, rppt,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing
Cc: catalin.marinas, will, alex, akpm, pasha.tatashin, pratyush,
ruirui.yang, m.szyprowski, robin.murphy
In-Reply-To: <20260630074715.4126796-1-chenwandun1@gmail.com>
From: Wandun Chen <chenwandun@lixiang.com>
In both fdt_scan_reserved_mem and fdt_scan_reserved_mem_late, there
are identical check-related print messages. Consolidate these messages
by moving them all into the fdt_scan_reserved_mem function.
No functional change.
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
---
drivers/of/of_reserved_mem.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 82222bd45ac6..42649dc3613f 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -270,19 +270,15 @@ void __init fdt_scan_reserved_mem_late(void)
return;
node = fdt_path_offset(fdt, "/reserved-memory");
- if (node < 0) {
- pr_info("Reserved memory: No reserved-memory node in the DT\n");
+ if (node < 0)
return;
- }
/* Attempt dynamic allocation of a new reserved_mem array */
if (alloc_reserved_mem_array())
return;
- if (__reserved_mem_check_root(node)) {
- pr_err("Reserved memory: unsupported node format, ignoring\n");
+ if (__reserved_mem_check_root(node))
return;
- }
fdt_for_each_subnode(child, fdt, node) {
const __be32 *prop;
@@ -337,6 +333,7 @@ int __init fdt_scan_reserved_mem(void)
node = fdt_path_offset(fdt, "/reserved-memory");
if (node < 0) {
+ pr_info("Reserved memory: No reserved-memory node in the DT\n");
total_reserved_mem_cnt = 0;
return -ENODEV;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v4 00/10] kdump: reduce vmcore size and capture time
From: Wandun Chen @ 2026-06-30 7:47 UTC (permalink / raw)
To: chenhuacai, kernel, pjw, palmer, aou, robh, saravanak, bhe, rppt,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing
Cc: catalin.marinas, will, alex, akpm, pasha.tatashin, pratyush,
ruirui.yang, m.szyprowski, robin.murphy
From: Wandun Chen <chenwandun@lixiang.com>
On SoCs that carve out large firmware-owned reserved memory (GPU
firmware, DSP, modem, camera ISP, NPU, ...), kdump currently dumps
those carveouts as part of system RAM even though their contents are
firmware state that is not useful for kernel crash analysis.
This series introduces an opt-in 'dumpable' flag [1] on struct
reserved_mem and uses it to filter the elfcorehdr PT_LOAD ranges on
DT-based architectures (arm64, riscv, loongarch). By default reserved
regions are treated as non-dumpable; CMA regions are explicitly opted
in because their pages are returned to the buddy allocator and may
carry key crash-analysis data.
Since the reserved memory regions are filtered out, the vmcore is
smaller in size and faster to produce. The reserved memory
has already been filtered out in x86; the optimizations in this series
apply to systems that use DTS such as arm64/riscv/loongarch.
The series is organized as follows:
Patches 1-4: Small prepare changes and cleanups.
Patches 5: Add dumpable flag to opt-in vmcore.
Patches 6: Append /memreserve/ entries into reserved_mem[].
Patch 7: Add generic kdump helpers.
Patches 8-10: Wire the helpers into arm64, riscv and loongarch kdump
elfcorehdr preparation.
v3 --> v4:
1. Rebase this series on v7.2-rc1.
2. Add two cleanup patches (patch 02/03).
3. Simplify patch 03 to avoid checking whether initial_boot_params is
NULL multiple times, suggested by Rob.
v2 --> v3:
1. Fix out-of-bounds issue if device tree lacks /reserved-memory node.[2]
2. Fix UAF issue when alloc_reserved_mem_array() fails.
3. Add some prepare patches.
v1 --> v2:
1. v1 added an opt-out DT property ('linux,no-dump'). Per Rob's
feedback [1], v2 drop that property and exclude reserve memory
by default.
2. Split some prepared patches from the original patches.
3. Address coding-style comments on patch 5 from Rob.
[1] https://lore.kernel.org/lkml/20260506144542.GA2072596-robh@kernel.org/
[2] https://sashiko.dev/#/patchset/20260520091844.592753-1-chenwandun%40lixiang.com?part=4
Wandun Chen (10):
kexec/crash: provide crash_exclude_mem_range() stub when
CONFIG_CRASH_DUMP=n
of: reserved_mem: dedup and relocate reserved-memory messages
of: reserved_mem: skip late scan when no regions are reserved
of: reserved_mem: split alloc_reserved_mem_array() from
fdt_scan_reserved_mem_late()
of: reserved_mem: add dumpable flag to opt-in vmcore
of: reserved_mem: save /memreserve/ entries into the reserved_mem
array
of: reserved_mem: add kdump helpers to exclude non-dumpable regions
arm64: kdump: exclude non-dumpable reserved memory regions from vmcore
riscv: kdump: exclude non-dumpable reserved memory regions from vmcore
loongarch: kdump: exclude non-dumpable reserved memory regions from
vmcore
arch/arm64/kernel/machine_kexec_file.c | 6 ++
arch/loongarch/kernel/machine_kexec_file.c | 6 ++
arch/riscv/kernel/machine_kexec_file.c | 4 +
drivers/of/fdt.c | 11 ++-
drivers/of/of_private.h | 3 +
drivers/of/of_reserved_mem.c | 108 ++++++++++++++++++---
include/linux/crash_core.h | 6 ++
include/linux/of_reserved_mem.h | 15 +++
kernel/dma/contiguous.c | 1 +
9 files changed, 142 insertions(+), 18 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH v4 01/10] kexec/crash: provide crash_exclude_mem_range() stub when CONFIG_CRASH_DUMP=n
From: Wandun Chen @ 2026-06-30 7:47 UTC (permalink / raw)
To: chenhuacai, kernel, pjw, palmer, aou, robh, saravanak, bhe, rppt,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing
Cc: catalin.marinas, will, alex, akpm, pasha.tatashin, pratyush,
ruirui.yang, m.szyprowski, robin.murphy
In-Reply-To: <20260630074715.4126796-1-chenwandun1@gmail.com>
From: Wandun Chen <chenwandun@lixiang.com>
Prepare for an upcoming change that excludes non-dumpable reserved
regions from the kdump vmcore and will call crash_exclude_mem_range()
from generic, non-arch code.
No functional change.
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
---
include/linux/crash_core.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index c1dee3f971a9..0033d4777648 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -87,6 +87,12 @@ static inline int kexec_should_crash(struct task_struct *p) { return 0; }
static inline int kexec_crash_loaded(void) { return 0; }
static inline void crash_save_cpu(struct pt_regs *regs, int cpu) {};
static inline int kimage_crash_copy_vmcoreinfo(struct kimage *image) { return 0; };
+static inline int crash_exclude_mem_range(struct crash_mem *mem,
+ unsigned long long mstart,
+ unsigned long long mend)
+{
+ return 0;
+}
#endif /* CONFIG_CRASH_DUMP*/
#ifdef CONFIG_CRASH_DM_CRYPT
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v5 0/5] Add support for AAEON SRG-IMX8P MCU
From: Bartosz Golaszewski @ 2026-06-30 7:47 UTC (permalink / raw)
To: Thomas Perrot
Cc: devicetree, linux-kernel, linux-gpio, imx, linux-arm-kernel,
linux-watchdog, Thomas Petazzoni, Miquel Raynal,
Krzysztof Kozlowski, Conor Dooley, Bartosz Golaszewski,
Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Linus Walleij, Bartosz Golaszewski, Shawn Guo, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
Jérémie Dautheribes, Wim Van Sebroeck, Lee Jones
In-Reply-To: <31477953aace52bb6594461e82ddf99493af2329.camel@bootlin.com>
On Mon, 29 Jun 2026 18:04:59 +0200, Thomas Perrot
<thomas.perrot@bootlin.com> said:
> Hello Guenter,
>
> On Sat, 2026-04-11 at 17:12 -0700, Guenter Roeck wrote:
>> snip
>>
>> Sashiko has some interesting feedback that might be worth looking
>> into.
>>
>> https://sashiko.dev/#/patchset/20260408-dev-b4-aaeon-mcu-driver-v5-0-ad98bd481668%40bootlin.com
>>
>
> Thanks for the pointer. I went through all findings and addressed the
> valid ones in v6:
>
Did I miss anything? I don't see the v6 neither in my inbox nor on lore.
Bart
^ permalink raw reply
* [PATCH v2 9/9] vdso/gettimeofday: Verify COMPAT_32BIT_TIME interactions
From: Thomas Weißschuh @ 2026-06-30 7:38 UTC (permalink / raw)
To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
Will Deacon, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
Andreas Larsson
Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>
If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality.
Add some build-time validations to make sure the architecture-specific
glue satisfies this requirement.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
lib/vdso/gettimeofday.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index b8c1fc85eb74..f7a591aba59f 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -25,6 +25,8 @@
*/
#include <asm/vdso/gettimeofday.h>
+#include <linux/build_bug.h>
+
/* Bring in default accessors */
#include <vdso/vsyscall.h>
@@ -325,6 +327,8 @@ __cvdso_clock_gettime32_data(const struct vdso_time_data *vd, clockid_t clock,
struct __kernel_timespec ts;
bool ok;
+ BUILD_BUG_ON(!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
ok = __cvdso_clock_gettime_common(vd, clock, &ts);
if (unlikely(!ok))
@@ -354,6 +358,8 @@ __cvdso_gettimeofday_data(const struct vdso_time_data *vd,
BUILD_BUG();
#endif
+ BUILD_BUG_ON(sizeof(tv->tv_sec) != 8 && !IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
if (likely(tv != NULL)) {
struct __kernel_timespec ts;
@@ -392,6 +398,8 @@ __cvdso_time_data(const struct vdso_time_data *vd, __kernel_old_time_t *time)
BUILD_BUG();
#endif
+ BUILD_BUG_ON(sizeof(*time) != 8 && !IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
if (vdso_is_timens_clock(vc)) {
vd = vdso_timens_data(vd);
vc = vd->clock_data;
@@ -481,6 +489,8 @@ __cvdso_clock_getres_time32_data(const struct vdso_time_data *vd, clockid_t cloc
struct __kernel_timespec ts;
bool ok;
+ BUILD_BUG_ON(!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
ok = __cvdso_clock_getres_common(vd, clock, &ts);
if (unlikely(!ok))
--
2.55.0
^ permalink raw reply related
* [PATCH v2 7/9] MIPS: VDSO: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30 7:38 UTC (permalink / raw)
To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
Will Deacon, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
Andreas Larsson
Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>
If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.
Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
arch/mips/vdso/vdso.lds.S | 2 ++
arch/mips/vdso/vgettimeofday.c | 3 +++
2 files changed, 5 insertions(+)
diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S
index 278ab6444e98..b11ee493c67f 100644
--- a/arch/mips/vdso/vdso.lds.S
+++ b/arch/mips/vdso/vdso.lds.S
@@ -97,9 +97,11 @@ VERSION
LINUX_2.6 {
#ifdef CONFIG_GENERIC_GETTIMEOFDAY
global:
+#if _MIPS_SIM == _MIPS_SIM_ABI64 || defined(CONFIG_COMPAT_32BIT_TIME)
__vdso_clock_gettime;
__vdso_gettimeofday;
__vdso_clock_getres;
+#endif
#if _MIPS_SIM != _MIPS_SIM_ABI64
__vdso_clock_gettime64;
__vdso_clock_getres_time64;
diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c
index 00f9fcfc327e..a1fb06b8973e 100644
--- a/arch/mips/vdso/vgettimeofday.c
+++ b/arch/mips/vdso/vgettimeofday.c
@@ -12,6 +12,8 @@
#include <vdso/gettime.h>
#if _MIPS_SIM != _MIPS_SIM_ABI64
+
+#ifdef CONFIG_COMPAT_32BIT_TIME
int __vdso_clock_gettime(clockid_t clock,
struct old_timespec32 *ts)
{
@@ -29,6 +31,7 @@ int __vdso_clock_getres(clockid_t clock_id,
{
return __cvdso_clock_getres_time32(clock_id, res);
}
+#endif /* CONFIG_COMPAT_32BIT_TIME */
int __vdso_clock_gettime64(clockid_t clock,
struct __kernel_timespec *ts)
--
2.55.0
^ permalink raw reply related
* [PATCH v2 1/9] time: Respect COMPAT_32BIT_TIME for old time type functions
From: Thomas Weißschuh @ 2026-06-30 7:38 UTC (permalink / raw)
To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
Will Deacon, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
Andreas Larsson
Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>
The "old" time types use 32-bit seconds which are not y2038-safe.
Respect COMPAT_32BIT_TIME for functions using those types.
time(), stime() and gettimeofday() are disabled completely.
settimeofday() is kept as it is required to do the initial timewarping
after boot. However the 'tv' argument will be rejected.
Link: https://lore.kernel.org/lkml/e9487ebe-3730-438a-9c23-e45f75986ecc@app.fastmail.com/
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
kernel/sys_ni.c | 4 ++++
kernel/time/time.c | 24 ++++++++++++++++++++----
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index add3032da16f..c8be0abaa407 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -351,6 +351,10 @@ COND_SYSCALL(ppoll_time32);
COND_SYSCALL_COMPAT(ppoll_time32);
COND_SYSCALL(utimensat_time32);
COND_SYSCALL(clock_adjtime32);
+COND_SYSCALL(gettimeofday);
+COND_SYSCALL_COMPAT(gettimeofday);
+COND_SYSCALL(time);
+COND_SYSCALL(stime);
/*
* The syscalls below are not found in include/uapi/asm-generic/unistd.h
diff --git a/kernel/time/time.c b/kernel/time/time.c
index 0dd63a91e7c5..0b7aa432bc76 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -43,6 +43,12 @@
#include <generated/timeconst.h>
#include "timekeeping.h"
+#if defined(CONFIG_64BIT) || defined(CONFIG_COMPAT_32BIT_TIME)
+#define __WANT_OLD_TIME_TYPE_SYSCALL 1
+#endif
+
+static_assert(sizeof(__kernel_old_time_t) == 8 ? IS_ENABLED(__WANT_OLD_TIME_TYPE_SYSCALL) : true);
+
/*
* The timezone where the local system is located. Used as a default by some
* programs who obtain this value by using gettimeofday.
@@ -51,7 +57,7 @@ struct timezone sys_tz;
EXPORT_SYMBOL(sys_tz);
-#ifdef __ARCH_WANT_SYS_TIME
+#if defined(__ARCH_WANT_SYS_TIME) && defined(__WANT_OLD_TIME_TYPE_SYSCALL)
/*
* sys_time() can be implemented in user-level using
@@ -96,7 +102,7 @@ SYSCALL_DEFINE1(stime, __kernel_old_time_t __user *, tptr)
return 0;
}
-#endif /* __ARCH_WANT_SYS_TIME */
+#endif /* __ARCH_WANT_SYS_TIME && __WANT_OLD_TIME_TYPE_SYSCALL */
#ifdef CONFIG_COMPAT_32BIT_TIME
#ifdef __ARCH_WANT_SYS_TIME32
@@ -137,6 +143,7 @@ SYSCALL_DEFINE1(stime32, old_time32_t __user *, tptr)
#endif /* __ARCH_WANT_SYS_TIME32 */
#endif
+#ifdef __WANT_OLD_TIME_TYPE_SYSCALL
SYSCALL_DEFINE2(gettimeofday, struct __kernel_old_timeval __user *, tv,
struct timezone __user *, tz)
{
@@ -154,6 +161,7 @@ SYSCALL_DEFINE2(gettimeofday, struct __kernel_old_timeval __user *, tv,
}
return 0;
}
+#endif /* __WANT_OLD_TIME_TYPE_SYSCALL */
/*
* In case for some reason the CMOS clock has not already been running
@@ -203,6 +211,9 @@ SYSCALL_DEFINE2(settimeofday, struct __kernel_old_timeval __user *, tv,
struct timezone new_tz;
if (tv) {
+ if (!IS_ENABLED(__WANT_OLD_TIME_TYPE_SYSCALL))
+ return -EINVAL;
+
if (get_user(new_ts.tv_sec, &tv->tv_sec) ||
get_user(new_ts.tv_nsec, &tv->tv_usec))
return -EFAULT;
@@ -220,7 +231,7 @@ SYSCALL_DEFINE2(settimeofday, struct __kernel_old_timeval __user *, tv,
return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_COMPAT_32BIT_TIME
COMPAT_SYSCALL_DEFINE2(gettimeofday, struct old_timeval32 __user *, tv,
struct timezone __user *, tz)
{
@@ -239,7 +250,9 @@ COMPAT_SYSCALL_DEFINE2(gettimeofday, struct old_timeval32 __user *, tv,
return 0;
}
+#endif /* CONFIG_COMPAT_32BIT_TIME */
+#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE2(settimeofday, struct old_timeval32 __user *, tv,
struct timezone __user *, tz)
{
@@ -247,6 +260,9 @@ COMPAT_SYSCALL_DEFINE2(settimeofday, struct old_timeval32 __user *, tv,
struct timezone new_tz;
if (tv) {
+ if (!IS_ENABLED(__WANT_OLD_TIME_TYPE_SYSCALL))
+ return -EINVAL;
+
if (get_user(new_ts.tv_sec, &tv->tv_sec) ||
get_user(new_ts.tv_nsec, &tv->tv_usec))
return -EFAULT;
@@ -263,7 +279,7 @@ COMPAT_SYSCALL_DEFINE2(settimeofday, struct old_timeval32 __user *, tv,
return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
}
-#endif
+#endif /* CONFIG_COMPAT */
#ifdef CONFIG_64BIT
SYSCALL_DEFINE1(adjtimex, struct __kernel_timex __user *, txc_p)
--
2.55.0
^ permalink raw reply related
* [PATCH v2 8/9] sparc: vdso: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30 7:38 UTC (permalink / raw)
To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
Will Deacon, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
Andreas Larsson
Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>
If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.
Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
arch/sparc/vdso/vclock_gettime.c | 4 ++++
arch/sparc/vdso/vdso32/vdso32.lds.S | 6 ++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c
index 1d9859392e4c..221bd4ed19f5 100644
--- a/arch/sparc/vdso/vclock_gettime.c
+++ b/arch/sparc/vdso/vclock_gettime.c
@@ -21,6 +21,7 @@
#include "../../../../lib/vdso/gettimeofday.c"
+#if defined(CONFIG_SPARC64) || defined(CONFIG_COMPAT_32BIT_TIME)
int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
{
return __cvdso_gettimeofday(tv, tz);
@@ -28,6 +29,7 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
int gettimeofday(struct __kernel_old_timeval *, struct timezone *)
__weak __alias(__vdso_gettimeofday);
+#endif
#if defined(CONFIG_SPARC64)
int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts)
@@ -40,6 +42,7 @@ int clock_gettime(clockid_t, struct __kernel_timespec *)
#else
+#if defined(CONFIG_COMPAT_32BIT_TIME)
int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts)
{
return __cvdso_clock_gettime32(clock, ts);
@@ -47,6 +50,7 @@ int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts)
int clock_gettime(clockid_t, struct old_timespec32 *)
__weak __alias(__vdso_clock_gettime);
+#endif
int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts)
{
diff --git a/arch/sparc/vdso/vdso32/vdso32.lds.S b/arch/sparc/vdso/vdso32/vdso32.lds.S
index a14e4f77e6f2..28052168b875 100644
--- a/arch/sparc/vdso/vdso32/vdso32.lds.S
+++ b/arch/sparc/vdso/vdso32/vdso32.lds.S
@@ -15,12 +15,14 @@
VERSION {
LINUX_2.6 {
global:
+#ifdef CONFIG_COMPAT_32BIT_TIME
clock_gettime;
__vdso_clock_gettime;
- clock_gettime64;
- __vdso_clock_gettime64;
gettimeofday;
__vdso_gettimeofday;
+#endif
+ clock_gettime64;
+ __vdso_clock_gettime64;
local: *;
};
}
--
2.55.0
^ permalink raw reply related
* [PATCH v2 6/9] powerpc/vdso: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30 7:38 UTC (permalink / raw)
To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
Will Deacon, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
Andreas Larsson
Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>
If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.
Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
arch/powerpc/kernel/vdso/gettimeofday.S | 8 ++++++++
arch/powerpc/kernel/vdso/vdso32.lds.S | 10 ++++++----
arch/powerpc/kernel/vdso/vgettimeofday.c | 16 ++++++++++------
3 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/kernel/vdso/gettimeofday.S b/arch/powerpc/kernel/vdso/gettimeofday.S
index 1c8e51691bf8..c635cd1e77be 100644
--- a/arch/powerpc/kernel/vdso/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso/gettimeofday.S
@@ -67,9 +67,11 @@
* int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
*
*/
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
V_FUNCTION_BEGIN(__kernel_gettimeofday)
cvdso_call __c_kernel_gettimeofday
V_FUNCTION_END(__kernel_gettimeofday)
+#endif
/*
* Exact prototype of clock_gettime()
@@ -77,9 +79,11 @@ V_FUNCTION_END(__kernel_gettimeofday)
* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp);
*
*/
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
V_FUNCTION_BEGIN(__kernel_clock_gettime)
cvdso_call __c_kernel_clock_gettime
V_FUNCTION_END(__kernel_clock_gettime)
+#endif
/*
* Exact prototype of clock_gettime64()
@@ -99,9 +103,11 @@ V_FUNCTION_END(__kernel_clock_gettime64)
* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res);
*
*/
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
V_FUNCTION_BEGIN(__kernel_clock_getres)
cvdso_call __c_kernel_clock_getres
V_FUNCTION_END(__kernel_clock_getres)
+#endif
/*
* Exact prototype of clock_getres_time64()
@@ -122,6 +128,8 @@ V_FUNCTION_END(__kernel_clock_getres_time64)
* time_t time(time *t);
*
*/
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
V_FUNCTION_BEGIN(__kernel_time)
cvdso_call __c_kernel_time call_time=1
V_FUNCTION_END(__kernel_time)
+#endif
diff --git a/arch/powerpc/kernel/vdso/vdso32.lds.S b/arch/powerpc/kernel/vdso/vdso32.lds.S
index 3f384a2526ae..876c965b827d 100644
--- a/arch/powerpc/kernel/vdso/vdso32.lds.S
+++ b/arch/powerpc/kernel/vdso/vdso32.lds.S
@@ -119,13 +119,15 @@ VERSION
{
VDSO_VERSION_STRING {
global:
- __kernel_get_syscall_map;
- __kernel_gettimeofday;
+#ifdef CONFIG_COMPAT_32BIT_TIME
__kernel_clock_gettime;
- __kernel_clock_gettime64;
__kernel_clock_getres;
- __kernel_clock_getres_time64;
+ __kernel_gettimeofday;
__kernel_time;
+#endif /* CONFIG_COMPAT_32BIT_TIME */
+ __kernel_get_syscall_map;
+ __kernel_clock_gettime64;
+ __kernel_clock_getres_time64;
__kernel_get_tbfreq;
__kernel_sync_dicache;
__kernel_sigtramp32;
diff --git a/arch/powerpc/kernel/vdso/vgettimeofday.c b/arch/powerpc/kernel/vdso/vgettimeofday.c
index 3c194e1ab562..4b712fb01a3f 100644
--- a/arch/powerpc/kernel/vdso/vgettimeofday.c
+++ b/arch/powerpc/kernel/vdso/vgettimeofday.c
@@ -18,23 +18,25 @@ int __c_kernel_clock_getres(clockid_t clock_id, struct __kernel_timespec *res,
return __cvdso_clock_getres_data(vd, clock_id, res);
}
#else
+#ifdef CONFIG_COMPAT_32BIT_TIME
int __c_kernel_clock_gettime(clockid_t clock, struct old_timespec32 *ts,
const struct vdso_time_data *vd)
{
return __cvdso_clock_gettime32_data(vd, clock, ts);
}
-int __c_kernel_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts,
- const struct vdso_time_data *vd)
-{
- return __cvdso_clock_gettime_data(vd, clock, ts);
-}
-
int __c_kernel_clock_getres(clockid_t clock_id, struct old_timespec32 *res,
const struct vdso_time_data *vd)
{
return __cvdso_clock_getres_time32_data(vd, clock_id, res);
}
+#endif /* CONFIG_COMPAT_32BIT_TIME */
+
+int __c_kernel_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts,
+ const struct vdso_time_data *vd)
+{
+ return __cvdso_clock_gettime_data(vd, clock, ts);
+}
int __c_kernel_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res,
const struct vdso_time_data *vd)
@@ -43,6 +45,7 @@ int __c_kernel_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec
}
#endif
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
int __c_kernel_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz,
const struct vdso_time_data *vd)
{
@@ -53,3 +56,4 @@ __kernel_old_time_t __c_kernel_time(__kernel_old_time_t *time, const struct vdso
{
return __cvdso_time_data(vd, time);
}
+#endif
--
2.55.0
^ permalink raw reply related
* [PATCH v2 2/9] vdso/gettimeofday: Validate system call existence for time() and gettimeofday()
From: Thomas Weißschuh @ 2026-06-30 7:38 UTC (permalink / raw)
To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
Will Deacon, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
Andreas Larsson
Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>
Not all architectures have the system calls for time() and
gettimeofday(). When the system call is missing, the vDSO function
should also not be present.
Validate that.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
lib/vdso/gettimeofday.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index e0f289d3d110..b8c1fc85eb74 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -12,6 +12,8 @@
#include <vdso/time32.h>
#include <vdso/time64.h>
+#include <uapi/linux/unistd.h>
+
/*
* The generic vDSO implementation requires that gettimeofday.h
* provides:
@@ -348,6 +350,10 @@ __cvdso_gettimeofday_data(const struct vdso_time_data *vd,
{
const struct vdso_clock *vc = vd->clock_data;
+#ifndef __NR_gettimeofday
+ BUILD_BUG();
+#endif
+
if (likely(tv != NULL)) {
struct __kernel_timespec ts;
@@ -382,6 +388,10 @@ __cvdso_time_data(const struct vdso_time_data *vd, __kernel_old_time_t *time)
const struct vdso_clock *vc = vd->clock_data;
__kernel_old_time_t t;
+#ifndef __NR_time
+ BUILD_BUG();
+#endif
+
if (vdso_is_timens_clock(vc)) {
vd = vdso_timens_data(vd);
vc = vd->clock_data;
--
2.55.0
^ permalink raw reply related
* [PATCH v2 4/9] arm64: vdso32: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30 7:38 UTC (permalink / raw)
To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
Will Deacon, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
Andreas Larsson
Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>
If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.
Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
arch/arm64/kernel/vdso32/vdso.lds.S | 2 ++
arch/arm64/kernel/vdso32/vgettimeofday.c | 14 ++++++++------
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
index c374fb0146f3..12bfc39e8aab 100644
--- a/arch/arm64/kernel/vdso32/vdso.lds.S
+++ b/arch/arm64/kernel/vdso32/vdso.lds.S
@@ -82,9 +82,11 @@ VERSION
{
LINUX_2.6 {
global:
+#ifdef CONFIG_COMPAT_32BIT_TIME
__vdso_clock_gettime;
__vdso_gettimeofday;
__vdso_clock_getres;
+#endif /* CONFIG_COMPAT_32BIT_TIME */
__vdso_clock_gettime64;
__vdso_clock_getres_time64;
local: *;
diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c
index 0c6998ebe491..12d0255cc2cf 100644
--- a/arch/arm64/kernel/vdso32/vgettimeofday.c
+++ b/arch/arm64/kernel/vdso32/vgettimeofday.c
@@ -8,16 +8,17 @@
#define BUILD_VDSO32_64
#include <vdso/gettime.h>
+#ifdef CONFIG_COMPAT_32BIT_TIME
int __vdso_clock_gettime(clockid_t clock,
struct old_timespec32 *ts)
{
return __cvdso_clock_gettime32(clock, ts);
}
-int __vdso_clock_gettime64(clockid_t clock,
- struct __kernel_timespec *ts)
+int __vdso_clock_getres(clockid_t clock_id,
+ struct old_timespec32 *res)
{
- return __cvdso_clock_gettime(clock, ts);
+ return __cvdso_clock_getres_time32(clock_id, res);
}
int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
@@ -25,11 +26,12 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
{
return __cvdso_gettimeofday(tv, tz);
}
+#endif /* CONFIG_COMPAT_32BIT_TIME */
-int __vdso_clock_getres(clockid_t clock_id,
- struct old_timespec32 *res)
+int __vdso_clock_gettime64(clockid_t clock,
+ struct __kernel_timespec *ts)
{
- return __cvdso_clock_getres_time32(clock_id, res);
+ return __cvdso_clock_gettime(clock, ts);
}
int __vdso_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res)
--
2.55.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox