From 4886e7255c730e4a33edbf84dc6d3a8f4e752af7 Mon Sep 17 00:00:00 2001 From: dao-qiu Date: Mon, 5 Jan 2026 14:37:42 -0600 Subject: [PATCH 08/12] net: ethernet: ti: cpsw_ale: add policer save restore for PM sleep --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 24 ++++++++++++-- drivers/net/ethernet/ti/am65-cpsw-nuss.h | 1 + drivers/net/ethernet/ti/cpsw_ale.c | 41 ++++++++++++++++++++++++ drivers/net/ethernet/ti/cpsw_ale.h | 4 +++ 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index f89c98af5bf958..7c2be5d7f8f372 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -3955,7 +3955,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) struct device_node *node; struct resource *res; struct clk *clk; - int ale_entries; + int tbl_entries; u64 id_temp; int ret, i; @@ -4063,10 +4063,26 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) goto err_of_clear; } - ale_entries = common->ale->params.ale_entries; + tbl_entries = common->ale->params.ale_entries; common->ale_context = devm_kzalloc(dev, - ale_entries * ALE_ENTRY_WORDS * sizeof(u32), + tbl_entries * ALE_ENTRY_WORDS * sizeof(u32), GFP_KERNEL); + + if (!common->ale_context) { + ret = -ENOMEM; + goto err_of_clear; + } + + tbl_entries = common->ale->params.num_policers; + i = CPSW_ALE_POLICER_ENTRY_WORDS + 1; /* 8 CFG + 1 Thread_val */ + i *= tbl_entries; /* for all policers */ + i += 1; /* thread_def register */ + common->policer_context = devm_kzalloc(dev, i * sizeof(u32), + GFP_KERNEL); + if (!common->policer_context) { + ret = -ENOMEM; + goto err_of_clear; + } ret = am65_cpsw_init_cpts(common); if (ret) goto err_of_clear; @@ -4158,6 +4174,7 @@ static int am65_cpsw_nuss_suspend(struct device *dev) int i, ret; cpsw_ale_dump(common->ale, common->ale_context); + cpsw_ale_policer_save(common->ale, common->policer_context); host_p->vid_context = readl(host_p->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET); for (i = 0; i < common->port_num; i++) { port = &common->ports[i]; @@ -4235,6 +4252,7 @@ static int am65_cpsw_nuss_resume(struct device *dev) writel(host_p->vid_context, host_p->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET); cpsw_ale_restore(common->ale, common->ale_context); + cpsw_ale_policer_restore(common->ale, common->policer_context); return 0; } diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h index a615061cf1e7e6..6815196d9b6118 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h @@ -217,6 +217,7 @@ struct am65_cpsw_common { #endif /* only for suspend/resume context restore */ u32 *ale_context; + u32 *policer_context; /* XDP Zero Copy */ unsigned long *xdp_zc_queues; int xsk_port_id[AM65_CPSW_MAX_QUEUES]; diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index fa79161e92f9ec..4c7556c349780c 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -1802,3 +1802,44 @@ int cpsw_ale_policer_set_entry(struct cpsw_ale *ale, u32 policer_idx, return 0; } + +void cpsw_ale_policer_save(struct cpsw_ale *ale, u32 *data) +{ + int i, idx; + + for (idx = 0; idx < ale->params.num_policers; idx++) { + cpsw_ale_policer_read_idx(ale, idx); + for (i = 0; i < CPSW_ALE_POLICER_ENTRY_WORDS; i++) + data[i] = readl_relaxed(ale->params.ale_regs + + ALE_POLICER_PORT_OUI + 4 * i); + + regmap_field_write(ale->fields[ALE_THREAD_CLASS_INDEX], idx); + data[i++] = readl_relaxed(ale->params.ale_regs + + ALE_THREAD_VAL); + data += i; + } + + data[0] = readl_relaxed(ale->params.ale_regs + ALE_THREAD_DEF); +} + +void cpsw_ale_policer_restore(struct cpsw_ale *ale, u32 *data) +{ + int i, idx; + + for (idx = 0; idx < ale->params.num_policers; idx++) { + cpsw_ale_policer_read_idx(ale, idx); + + for (i = 0; i < CPSW_ALE_POLICER_ENTRY_WORDS; i++) + writel_relaxed(data[i], ale->params.ale_regs + + ALE_POLICER_PORT_OUI + 4 * i); + + cpsw_ale_policer_write_idx(ale, idx); + + regmap_field_write(ale->fields[ALE_THREAD_CLASS_INDEX], idx); + writel_relaxed(data[i++], ale->params.ale_regs + + ALE_THREAD_VAL); + data += i; + } + + writel_relaxed(data[0], ale->params.ale_regs + ALE_THREAD_DEF); +} diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index 11d333bf5a5280..dbc095397389d3 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -171,6 +171,8 @@ enum cpsw_ale_port_state { #define CPSW_ALE_POLICER_MATCH_IPSRC BIT(8) #define CPSW_ALE_POLICER_MATCH_IPDST BIT(9) +#define CPSW_ALE_POLICER_ENTRY_WORDS 8 + struct cpsw_ale_policer_cfg { u32 match_flags; u16 ether_type; @@ -227,5 +229,7 @@ int cpsw_ale_policer_set_entry(struct cpsw_ale *ale, u32 policer_idx, struct cpsw_ale_policer_cfg *cfg); void cpsw_ale_policer_clr_entry(struct cpsw_ale *ale, u32 policer_idx, struct cpsw_ale_policer_cfg *cfg); +void cpsw_ale_policer_save(struct cpsw_ale *ale, u32 *data); +void cpsw_ale_policer_restore(struct cpsw_ale *ale, u32 *data); #endif -- 2.34.1