+++ /dev/null
-From 1d304174106c93ce05f6088813ad7203b3eb381a Mon Sep 17 00:00:00 2001
-From: Lorenzo Bianconi <lorenzo@kernel.org>
-Date: Sat, 12 Oct 2024 11:01:11 +0200
-Subject: [PATCH] net: airoha: Implement BQL support
-
-Introduce BQL support in the airoha_eth driver reporting to the kernel
-info about tx hw DMA queues in order to avoid bufferbloat and keep the
-latency small.
-
-Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-Link: https://patch.msgid.link/20241012-en7581-bql-v2-1-4deb4efdb60b@kernel.org
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
----
- drivers/net/ethernet/mediatek/airoha_eth.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/airoha_eth.c
-+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
-@@ -1729,9 +1729,11 @@ static int airoha_qdma_tx_napi_poll(stru
- WRITE_ONCE(desc->msg1, 0);
-
- if (skb) {
-+ u16 queue = skb_get_queue_mapping(skb);
- struct netdev_queue *txq;
-
-- txq = netdev_get_tx_queue(skb->dev, qid);
-+ txq = netdev_get_tx_queue(skb->dev, queue);
-+ netdev_tx_completed_queue(txq, 1, skb->len);
- if (netif_tx_queue_stopped(txq) &&
- q->ndesc - q->queued >= q->free_thr)
- netif_tx_wake_queue(txq);
-@@ -2510,7 +2512,9 @@ static netdev_tx_t airoha_dev_xmit(struc
- q->queued += i;
-
- skb_tx_timestamp(skb);
-- if (!netdev_xmit_more())
-+ netdev_tx_sent_queue(txq, skb->len);
-+
-+ if (netif_xmit_stopped(txq) || !netdev_xmit_more())
- airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid),
- TX_RING_CPU_IDX_MASK,
- FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head));
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
-@@ -1685,8 +1685,12 @@ static int airoha_qdma_tx_napi_poll(stru
+@@ -1690,8 +1690,12 @@ static int airoha_qdma_tx_napi_poll(stru
irq_queued = FIELD_GET(IRQ_ENTRY_LEN_MASK, status);
while (irq_queued > 0 && done < budget) {
if (val == 0xff)
break;
-@@ -1696,9 +1700,7 @@ static int airoha_qdma_tx_napi_poll(stru
+@@ -1701,9 +1705,7 @@ static int airoha_qdma_tx_napi_poll(stru
irq_queued--;
done++;
if (qid >= ARRAY_SIZE(qdma->q_tx))
continue;
-@@ -1706,46 +1708,53 @@ static int airoha_qdma_tx_napi_poll(stru
+@@ -1711,46 +1713,53 @@ static int airoha_qdma_tx_napi_poll(stru
if (!q->ndesc)
continue;
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
-@@ -1805,6 +1805,10 @@ static int airoha_qdma_init_tx_queue(str
+@@ -1810,6 +1810,10 @@ static int airoha_qdma_init_tx_queue(str
WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val));
}
#define AIROHA_NUM_TX_RING 32
#define AIROHA_NUM_RX_RING 32
#define AIROHA_FE_MC_MAX_VLAN_TABLE 64
-@@ -2437,21 +2439,44 @@ static void airoha_dev_get_stats64(struc
+@@ -2442,21 +2444,44 @@ static void airoha_dev_get_stats64(struc
} while (u64_stats_fetch_retry(&port->stats.syncp, start));
}
if (skb->ip_summed == CHECKSUM_PARTIAL)
msg0 |= FIELD_PREP(QDMA_ETH_TXMSG_TCO_MASK, 1) |
FIELD_PREP(QDMA_ETH_TXMSG_UCO_MASK, 1) |
-@@ -2625,6 +2650,7 @@ static const struct net_device_ops airoh
+@@ -2630,6 +2655,7 @@ static const struct net_device_ops airoh
.ndo_init = airoha_dev_init,
.ndo_open = airoha_dev_open,
.ndo_stop = airoha_dev_stop,
};
struct airoha_eth {
-@@ -1977,6 +2018,27 @@ static void airoha_qdma_init_qos(struct
+@@ -1982,6 +2023,27 @@ static void airoha_qdma_init_qos(struct
FIELD_PREP(SLA_SLOW_TICK_RATIO_MASK, 40));
}
static int airoha_qdma_hw_init(struct airoha_qdma *qdma)
{
int i;
-@@ -2027,6 +2089,7 @@ static int airoha_qdma_hw_init(struct ai
+@@ -2032,6 +2094,7 @@ static int airoha_qdma_hw_init(struct ai
airoha_qdma_set(qdma, REG_TXQ_CNGST_CFG,
TXQ_CNGST_DROP_EN | TXQ_CNGST_DEI_DROP_EN);
return 0;
}
-@@ -2646,6 +2709,135 @@ airoha_ethtool_get_rmon_stats(struct net
+@@ -2651,6 +2714,135 @@ airoha_ethtool_get_rmon_stats(struct net
} while (u64_stats_fetch_retry(&port->stats.syncp, start));
}
static const struct net_device_ops airoha_netdev_ops = {
.ndo_init = airoha_dev_init,
.ndo_open = airoha_dev_open,
-@@ -2654,6 +2846,7 @@ static const struct net_device_ops airoh
+@@ -2659,6 +2851,7 @@ static const struct net_device_ops airoh
.ndo_start_xmit = airoha_dev_xmit,
.ndo_get_stats64 = airoha_dev_get_stats64,
.ndo_set_mac_address = airoha_dev_set_macaddr,
};
static const struct ethtool_ops airoha_ethtool_ops = {
-@@ -2703,7 +2896,8 @@ static int airoha_alloc_gdm_port(struct
+@@ -2708,7 +2901,8 @@ static int airoha_alloc_gdm_port(struct
dev->watchdog_timeo = 5 * HZ;
dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_TSO6 | NETIF_F_IPV6_CSUM |
/* qos stats counters */
u64 cpu_tx_packets;
u64 fwd_tx_packets;
-@@ -2825,6 +2866,243 @@ static int airoha_tc_setup_qdisc_ets(str
+@@ -2830,6 +2871,243 @@ static int airoha_tc_setup_qdisc_ets(str
}
}
static int airoha_dev_tc_setup(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
-@@ -2833,6 +3111,8 @@ static int airoha_dev_tc_setup(struct ne
+@@ -2838,6 +3116,8 @@ static int airoha_dev_tc_setup(struct ne
switch (type) {
case TC_SETUP_QDISC_ETS:
return airoha_tc_setup_qdisc_ets(port, type_data);
default:
return -EOPNOTSUPP;
}
-@@ -2883,7 +3163,8 @@ static int airoha_alloc_gdm_port(struct
+@@ -2888,7 +3168,8 @@ static int airoha_alloc_gdm_port(struct
}
dev = devm_alloc_etherdev_mqs(eth->dev, sizeof(*port),
if (!dev) {
dev_err(eth->dev, "alloc_etherdev failed\n");
return -ENOMEM;
-@@ -2903,6 +3184,11 @@ static int airoha_alloc_gdm_port(struct
+@@ -2908,6 +3189,11 @@ static int airoha_alloc_gdm_port(struct
dev->irq = qdma->irq;
SET_NETDEV_DEV(dev, eth->dev);
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
-@@ -2801,7 +2801,7 @@ static int airoha_qdma_set_tx_ets_sched(
+@@ -2806,7 +2806,7 @@ static int airoha_qdma_set_tx_ets_sched(
struct tc_ets_qopt_offload_replace_params *p = &opt->replace_params;
enum tx_sched_mode mode = TC_SCH_SP;
u16 w[AIROHA_NUM_QOS_QUEUES] = {};
if (p->bands > AIROHA_NUM_QOS_QUEUES)
return -EINVAL;
-@@ -2815,7 +2815,20 @@ static int airoha_qdma_set_tx_ets_sched(
+@@ -2820,7 +2820,20 @@ static int airoha_qdma_set_tx_ets_sched(
if (nstrict == AIROHA_NUM_QOS_QUEUES - 1)
return -EINVAL;
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
-@@ -2564,11 +2564,10 @@ static u16 airoha_dev_select_queue(struc
+@@ -2569,11 +2569,10 @@ static u16 airoha_dev_select_queue(struc
static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct netdev_queue *txq;
struct airoha_queue *q;
void *data = skb->data;
-@@ -2591,8 +2590,9 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -2596,8 +2595,9 @@ static netdev_tx_t airoha_dev_xmit(struc
if (skb_cow_head(skb, 0))
goto error;
tcp_hdr(skb)->check = (__force __sum16)csum;
msg0 |= FIELD_PREP(QDMA_ETH_TXMSG_TSO_MASK, 1);
-@@ -2621,7 +2621,7 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -2626,7 +2626,7 @@ static netdev_tx_t airoha_dev_xmit(struc
for (i = 0; i < nr_frags; i++) {
struct airoha_qdma_desc *desc = &q->desc[index];
struct airoha_queue_entry *e = &q->entry[index];
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
-@@ -2484,7 +2484,7 @@ static int airoha_dev_stop(struct net_de
+@@ -2489,7 +2489,7 @@ static int airoha_dev_stop(struct net_de
{
struct airoha_gdm_port *port = netdev_priv(dev);
struct airoha_qdma *qdma = port->qdma;
netif_tx_disable(dev);
err = airoha_set_gdm_ports(qdma->eth, false);
-@@ -2495,6 +2495,14 @@ static int airoha_dev_stop(struct net_de
+@@ -2500,6 +2500,14 @@ static int airoha_dev_stop(struct net_de
GLOBAL_CFG_TX_DMA_EN_MASK |
GLOBAL_CFG_RX_DMA_EN_MASK);
-obj-$(CONFIG_NET_AIROHA) += airoha_eth.o
--- /dev/null
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -0,0 +1,3373 @@
+@@ -0,0 +1,3378 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 AIROHA Inc
+ dma_addr_t dma_addr;
+
+ q->buf_size = PAGE_SIZE / 2;
-+ q->ndesc = ndesc;
+ q->qdma = qdma;
+
-+ q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
++ q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry),
+ GFP_KERNEL);
+ if (!q->entry)
+ return -ENOMEM;
+
++ q->desc = dmam_alloc_coherent(eth->dev, ndesc * sizeof(*q->desc),
++ &dma_addr, GFP_KERNEL);
++ if (!q->desc)
++ return -ENOMEM;
++
+ q->page_pool = page_pool_create(&pp_params);
+ if (IS_ERR(q->page_pool)) {
+ int err = PTR_ERR(q->page_pool);
+ return err;
+ }
+
-+ q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc),
-+ &dma_addr, GFP_KERNEL);
-+ if (!q->desc)
-+ return -ENOMEM;
-+
++ q->ndesc = ndesc;
+ netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);
+
+ airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr);
+ }
+
+ q->head = q->tail;
++ /* Set RX_DMA_IDX to RX_CPU_IDX to notify the hw the QDMA RX ring is
++ * empty.
++ */
++ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
++ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head));
+ airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
+ FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail));
+}
+MODULE_DESCRIPTION("Ethernet driver for Airoha SoC");
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ /dev/null
-@@ -1,3373 +0,0 @@
+@@ -1,3378 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2024 AIROHA Inc
- dma_addr_t dma_addr;
-
- q->buf_size = PAGE_SIZE / 2;
-- q->ndesc = ndesc;
- q->qdma = qdma;
-
-- q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
+- q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry),
- GFP_KERNEL);
- if (!q->entry)
- return -ENOMEM;
-
+- q->desc = dmam_alloc_coherent(eth->dev, ndesc * sizeof(*q->desc),
+- &dma_addr, GFP_KERNEL);
+- if (!q->desc)
+- return -ENOMEM;
+-
- q->page_pool = page_pool_create(&pp_params);
- if (IS_ERR(q->page_pool)) {
- int err = PTR_ERR(q->page_pool);
- return err;
- }
-
-- q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc),
-- &dma_addr, GFP_KERNEL);
-- if (!q->desc)
-- return -ENOMEM;
--
+- q->ndesc = ndesc;
- netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);
-
- airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr);
- }
-
- q->head = q->tail;
+- /* Set RX_DMA_IDX to RX_CPU_IDX to notify the hw the QDMA RX ring is
+- * empty.
+- */
+- airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
+- FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head));
- airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
- FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail));
-}
napi_gro_receive(&q->napi, skb);
done++;
-@@ -1652,25 +1671,76 @@ static u16 airoha_dev_select_queue(struc
+@@ -1657,25 +1676,76 @@ static u16 airoha_dev_select_queue(struc
return queue < dev->num_tx_queues ? queue : 0;
}
if (skb->ip_summed == CHECKSUM_PARTIAL)
msg0 |= FIELD_PREP(QDMA_ETH_TXMSG_TCO_MASK, 1) |
FIELD_PREP(QDMA_ETH_TXMSG_UCO_MASK, 1) |
-@@ -1701,6 +1771,8 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -1706,6 +1776,8 @@ static netdev_tx_t airoha_dev_xmit(struc
spin_lock_bh(&q->lock);
txq = netdev_get_tx_queue(dev, qid);
if (q->queued + nr_frags > q->ndesc) {
/* not enough space in the queue */
netif_tx_stop_queue(txq);
-@@ -1708,7 +1780,10 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -1713,7 +1785,10 @@ static netdev_tx_t airoha_dev_xmit(struc
return NETDEV_TX_BUSY;
}
for (i = 0; i < nr_frags; i++) {
struct airoha_qdma_desc *desc = &q->desc[index];
struct airoha_queue_entry *e = &q->entry[index];
-@@ -2239,6 +2314,37 @@ static const struct ethtool_ops airoha_e
+@@ -2244,6 +2319,37 @@ static const struct ethtool_ops airoha_e
.get_rmon_stats = airoha_ethtool_get_rmon_stats,
};
static int airoha_alloc_gdm_port(struct airoha_eth *eth, struct device_node *np)
{
const __be32 *id_ptr = of_get_property(np, "reg", NULL);
-@@ -2311,6 +2417,10 @@ static int airoha_alloc_gdm_port(struct
+@@ -2316,6 +2422,10 @@ static int airoha_alloc_gdm_port(struct
port->id = id;
eth->ports[index] = port;
return register_netdev(dev);
}
-@@ -2403,8 +2513,10 @@ error_hw_cleanup:
+@@ -2408,8 +2518,10 @@ error_hw_cleanup:
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
}
free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
-@@ -2429,6 +2541,7 @@ static void airoha_remove(struct platfor
+@@ -2434,6 +2546,7 @@ static void airoha_remove(struct platfor
continue;
unregister_netdev(port->dev);
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1578,6 +1578,7 @@ static int airoha_dev_open(struct net_de
+@@ -1583,6 +1583,7 @@ static int airoha_dev_open(struct net_de
airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG,
GLOBAL_CFG_TX_DMA_EN_MASK |
GLOBAL_CFG_RX_DMA_EN_MASK);
return 0;
}
-@@ -1593,16 +1594,20 @@ static int airoha_dev_stop(struct net_de
+@@ -1598,16 +1599,20 @@ static int airoha_dev_stop(struct net_de
if (err)
return err;
}
return 0;
-@@ -2345,13 +2350,14 @@ static void airoha_metadata_dst_free(str
+@@ -2350,13 +2355,14 @@ static void airoha_metadata_dst_free(str
}
}
u32 id;
if (!id_ptr) {
-@@ -2360,14 +2366,14 @@ static int airoha_alloc_gdm_port(struct
+@@ -2365,14 +2371,14 @@ static int airoha_alloc_gdm_port(struct
}
id = be32_to_cpup(id_ptr);
dev_err(eth->dev, "duplicate gdm port id: %d\n", id);
return -EINVAL;
}
-@@ -2415,7 +2421,7 @@ static int airoha_alloc_gdm_port(struct
+@@ -2420,7 +2426,7 @@ static int airoha_alloc_gdm_port(struct
port->qdma = qdma;
port->dev = dev;
port->id = id;
err = airoha_metadata_dst_alloc(port);
if (err)
-@@ -2487,6 +2493,7 @@ static int airoha_probe(struct platform_
+@@ -2492,6 +2498,7 @@ static int airoha_probe(struct platform_
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_start_napi(ð->qdma[i]);
for_each_child_of_node(pdev->dev.of_node, np) {
if (!of_device_is_compatible(np, "airoha,eth-mac"))
continue;
-@@ -2494,7 +2501,7 @@ static int airoha_probe(struct platform_
+@@ -2499,7 +2506,7 @@ static int airoha_probe(struct platform_
if (!of_device_is_available(np))
continue;
airoha_fe_rmw(eth, REG_GDM_LEN_CFG(p),
GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
-@@ -1630,8 +1621,11 @@ static int airoha_dev_set_macaddr(struct
+@@ -1635,8 +1626,11 @@ static int airoha_dev_set_macaddr(struct
static int airoha_dev_init(struct net_device *dev)
{
struct airoha_gdm_port *port = netdev_priv(dev);
static void airoha_fe_maccr_init(struct airoha_eth *eth)
{
int p;
-@@ -1555,7 +1528,7 @@ static int airoha_dev_open(struct net_de
+@@ -1560,7 +1533,7 @@ static int airoha_dev_open(struct net_de
int err;
netif_tx_start_all_queues(dev);
if (err)
return err;
-@@ -1581,7 +1554,7 @@ static int airoha_dev_stop(struct net_de
+@@ -1586,7 +1559,7 @@ static int airoha_dev_stop(struct net_de
int i, err;
netif_tx_disable(dev);
napi_gro_receive(&q->napi, skb);
done++;
-@@ -1317,6 +1326,10 @@ static int airoha_hw_init(struct platfor
+@@ -1322,6 +1331,10 @@ static int airoha_hw_init(struct platfor
return err;
}
set_bit(DEV_STATE_INITIALIZED, ð->state);
return 0;
-@@ -2181,6 +2194,47 @@ static int airoha_tc_htb_alloc_leaf_queu
+@@ -2186,6 +2199,47 @@ static int airoha_tc_htb_alloc_leaf_queu
return 0;
}
static void airoha_tc_remove_htb_queue(struct airoha_gdm_port *port, int queue)
{
struct net_device *dev = port->dev;
-@@ -2264,6 +2318,9 @@ static int airoha_dev_tc_setup(struct ne
+@@ -2269,6 +2323,9 @@ static int airoha_dev_tc_setup(struct ne
return airoha_tc_setup_qdisc_ets(port, type_data);
case TC_SETUP_QDISC_HTB:
return airoha_tc_setup_qdisc_htb(port, type_data);
default:
return -EOPNOTSUPP;
}
-@@ -2519,6 +2576,7 @@ static void airoha_remove(struct platfor
+@@ -2524,6 +2581,7 @@ static void airoha_remove(struct platfor
}
free_netdev(eth->napi_dev);
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1604,14 +1604,81 @@ static int airoha_dev_set_macaddr(struct
+@@ -1609,14 +1609,81 @@ static int airoha_dev_set_macaddr(struct
return 0;
}
airoha_fe_rmw(eth, REG_CDM1_VLAN_CTRL, CDM1_VLAN_MASK,
FIELD_PREP(CDM1_VLAN_MASK, 0x8100));
-@@ -1536,9 +1531,9 @@ static void airoha_update_hw_stats(struc
+@@ -1541,9 +1536,9 @@ static void airoha_update_hw_stats(struc
static int airoha_dev_open(struct net_device *dev)
{
netif_tx_start_all_queues(dev);
err = airoha_set_vip_for_gdm_port(port, true);
-@@ -1552,6 +1547,11 @@ static int airoha_dev_open(struct net_de
+@@ -1557,6 +1552,11 @@ static int airoha_dev_open(struct net_de
airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
GDM_STAG_EN_MASK);
airoha_qdma_fill_rx_queue(q);
-@@ -1177,7 +1194,6 @@ static int airoha_qdma_hw_init(struct ai
+@@ -1182,7 +1199,6 @@ static int airoha_qdma_hw_init(struct ai
}
airoha_qdma_wr(qdma, REG_QDMA_GLOBAL_CFG,
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1721,6 +1721,20 @@ static void airoha_dev_get_stats64(struc
+@@ -1726,6 +1726,20 @@ static void airoha_dev_get_stats64(struc
} while (u64_stats_fetch_retry(&port->stats.syncp, start));
}
static u16 airoha_dev_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev)
{
-@@ -2413,6 +2427,7 @@ static const struct net_device_ops airoh
+@@ -2418,6 +2432,7 @@ static const struct net_device_ops airoh
.ndo_init = airoha_dev_init,
.ndo_open = airoha_dev_open,
.ndo_stop = airoha_dev_stop,
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2518,6 +2518,7 @@ static int airoha_alloc_gdm_port(struct
+@@ -2523,6 +2523,7 @@ static int airoha_alloc_gdm_port(struct
NETIF_F_SG | NETIF_F_TSO |
NETIF_F_HW_TC;
dev->features |= dev->hw_features;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1757,18 +1757,13 @@ static u32 airoha_get_dsa_tag(struct sk_
+@@ -1762,18 +1762,13 @@ static u32 airoha_get_dsa_tag(struct sk_
{
#if IS_ENABLED(CONFIG_NET_DSA)
struct ethhdr *ehdr;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2371,7 +2371,7 @@ static int airoha_tc_get_htb_get_leaf_qu
+@@ -2376,7 +2376,7 @@ static int airoha_tc_get_htb_get_leaf_qu
return -EINVAL;
}
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2044,7 +2044,7 @@ static int airoha_qdma_set_tx_ets_sched(
+@@ -2049,7 +2049,7 @@ static int airoha_qdma_set_tx_ets_sched(
struct tc_ets_qopt_offload_replace_params *p = &opt->replace_params;
enum tx_sched_mode mode = TC_SCH_SP;
u16 w[AIROHA_NUM_QOS_QUEUES] = {};
if (p->bands > AIROHA_NUM_QOS_QUEUES)
return -EINVAL;
-@@ -2062,17 +2062,17 @@ static int airoha_qdma_set_tx_ets_sched(
+@@ -2067,17 +2067,17 @@ static int airoha_qdma_set_tx_ets_sched(
* lowest priorities with respect to SP ones.
* e.g: WRR0, WRR1, .., WRRm, SP0, SP1, .., SPn
*/
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2467,6 +2467,19 @@ static void airoha_metadata_dst_free(str
+@@ -2472,6 +2472,19 @@ static void airoha_metadata_dst_free(str
}
}
/* enable 1:N vlan action, init vlan table */
airoha_fe_set(eth, REG_MC_VLAN_EN, MC_VLAN_EN_MASK);
-@@ -1647,7 +1666,6 @@ static void airhoha_set_gdm2_loopback(st
+@@ -1652,7 +1671,6 @@ static void airhoha_set_gdm2_loopback(st
if (port->id == 3) {
/* FIXME: handle XSI_PCE1_PORT */
airoha_fe_rmw(eth, REG_FE_WAN_PORT,
WAN1_EN_MASK | WAN1_MASK | WAN0_MASK,
FIELD_PREP(WAN0_MASK, HSGMII_LAN_PCIE0_SRCPORT));
-@@ -2122,6 +2140,125 @@ static int airoha_tc_setup_qdisc_ets(str
+@@ -2127,6 +2145,125 @@ static int airoha_tc_setup_qdisc_ets(str
}
}
static int airoha_qdma_get_trtcm_param(struct airoha_qdma *qdma, int channel,
u32 addr, enum trtcm_param_type param,
enum trtcm_mode_type mode,
-@@ -2286,10 +2423,142 @@ static int airoha_tc_htb_alloc_leaf_queu
+@@ -2291,10 +2428,142 @@ static int airoha_tc_htb_alloc_leaf_queu
return 0;
}
RX_DONE_INT_MASK);
return done;
-@@ -960,7 +964,7 @@ unlock:
+@@ -965,7 +969,7 @@ unlock:
}
if (done < budget && napi_complete(napi))
TX_DONE_INT_MASK(id));
return done;
-@@ -1191,13 +1195,16 @@ static int airoha_qdma_hw_init(struct ai
+@@ -1196,13 +1200,16 @@ static int airoha_qdma_hw_init(struct ai
int i;
/* clear pending irqs */
/* setup irq binding */
for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
-@@ -1242,13 +1249,14 @@ static int airoha_qdma_hw_init(struct ai
+@@ -1247,13 +1254,14 @@ static int airoha_qdma_hw_init(struct ai
static irqreturn_t airoha_irq_handler(int irq, void *dev_instance)
{
airoha_qdma_wr(qdma, REG_INT_STATUS(i), intr[i]);
}
-@@ -1256,7 +1264,7 @@ static irqreturn_t airoha_irq_handler(in
+@@ -1261,7 +1269,7 @@ static irqreturn_t airoha_irq_handler(in
return IRQ_NONE;
if (intr[1] & RX_DONE_INT_MASK) {
RX_DONE_INT_MASK);
for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
-@@ -1273,7 +1281,7 @@ static irqreturn_t airoha_irq_handler(in
+@@ -1278,7 +1286,7 @@ static irqreturn_t airoha_irq_handler(in
if (!(intr[0] & TX_DONE_INT_MASK(i)))
continue;
TX_DONE_INT_MASK(i));
napi_schedule(&qdma->q_tx_irq[i].napi);
}
-@@ -1282,6 +1290,39 @@ static irqreturn_t airoha_irq_handler(in
+@@ -1287,6 +1295,39 @@ static irqreturn_t airoha_irq_handler(in
return IRQ_HANDLED;
}
static int airoha_qdma_init(struct platform_device *pdev,
struct airoha_eth *eth,
struct airoha_qdma *qdma)
-@@ -1289,9 +1330,7 @@ static int airoha_qdma_init(struct platf
+@@ -1294,9 +1335,7 @@ static int airoha_qdma_init(struct platf
int err, id = qdma - ð->qdma[0];
const char *res;
res = devm_kasprintf(eth->dev, GFP_KERNEL, "qdma%d", id);
if (!res)
return -ENOMEM;
-@@ -1301,12 +1340,7 @@ static int airoha_qdma_init(struct platf
+@@ -1306,12 +1345,7 @@ static int airoha_qdma_init(struct platf
return dev_err_probe(eth->dev, PTR_ERR(qdma->regs),
"failed to iomap qdma%d regs\n", id);
if (err)
return err;
-@@ -2797,7 +2831,7 @@ static int airoha_alloc_gdm_port(struct
+@@ -2802,7 +2836,7 @@ static int airoha_alloc_gdm_port(struct
dev->features |= dev->hw_features;
dev->vlan_features = dev->hw_features;
dev->dev.of_node = np;
return done;
}
-@@ -1194,17 +1204,24 @@ static int airoha_qdma_hw_init(struct ai
+@@ -1199,17 +1209,24 @@ static int airoha_qdma_hw_init(struct ai
{
int i;
/* setup irq binding */
for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
-@@ -1251,6 +1268,7 @@ static irqreturn_t airoha_irq_handler(in
+@@ -1256,6 +1273,7 @@ static irqreturn_t airoha_irq_handler(in
{
struct airoha_irq_bank *irq_bank = dev_instance;
struct airoha_qdma *qdma = irq_bank->qdma;
u32 intr[ARRAY_SIZE(irq_bank->irqmask)];
int i;
-@@ -1263,17 +1281,24 @@ static irqreturn_t airoha_irq_handler(in
+@@ -1268,17 +1286,24 @@ static irqreturn_t airoha_irq_handler(in
if (!test_bit(DEV_STATE_INITIALIZED, &qdma->eth->state))
return IRQ_NONE;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1093,17 +1093,13 @@ static int airoha_qdma_init_hfwd_queues(
+@@ -1098,17 +1098,13 @@ static int airoha_qdma_init_hfwd_queues(
int size;
size = HW_DSCP_NUM * sizeof(struct airoha_qdma_fwd_desc);
#include <linux/platform_device.h>
#include <linux/tcp.h>
#include <linux/u64_stats_sync.h>
-@@ -1088,9 +1089,11 @@ static void airoha_qdma_cleanup_tx_queue
+@@ -1093,9 +1094,11 @@ static void airoha_qdma_cleanup_tx_queue
static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
{
struct airoha_eth *eth = qdma->eth;
size = HW_DSCP_NUM * sizeof(struct airoha_qdma_fwd_desc);
if (!dmam_alloc_coherent(eth->dev, size, &dma_addr, GFP_KERNEL))
-@@ -1098,10 +1101,34 @@ static int airoha_qdma_init_hfwd_queues(
+@@ -1103,10 +1106,34 @@ static int airoha_qdma_init_hfwd_queues(
airoha_qdma_wr(qdma, REG_FWD_DSCP_BASE, dma_addr);
static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
{
struct airoha_eth *eth = port->qdma->eth;
-@@ -1140,7 +1131,7 @@ static int airoha_qdma_init_hfwd_queues(
+@@ -1145,7 +1136,7 @@ static int airoha_qdma_init_hfwd_queues(
LMGR_INIT_START | LMGR_SRAM_MODE_MASK |
HW_FWD_DESC_NUM_MASK,
FIELD_PREP(HW_FWD_DESC_NUM_MASK, HW_DSCP_NUM) |
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2896,7 +2896,15 @@ static int airoha_alloc_gdm_port(struct
+@@ -2901,7 +2901,15 @@ static int airoha_alloc_gdm_port(struct
if (err)
return err;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1081,19 +1081,13 @@ static void airoha_qdma_cleanup_tx_queue
+@@ -1086,19 +1086,13 @@ static void airoha_qdma_cleanup_tx_queue
static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
{
name = devm_kasprintf(eth->dev, GFP_KERNEL, "qdma%d-buf", id);
if (!name)
return -ENOMEM;
-@@ -1115,8 +1109,12 @@ static int airoha_qdma_init_hfwd_queues(
+@@ -1120,8 +1114,12 @@ static int airoha_qdma_init_hfwd_queues(
rmem = of_reserved_mem_lookup(np);
of_node_put(np);
dma_addr = rmem->base;
if (!dmam_alloc_coherent(eth->dev, size, &dma_addr,
GFP_KERNEL))
return -ENOMEM;
-@@ -1124,6 +1122,11 @@ static int airoha_qdma_init_hfwd_queues(
+@@ -1129,6 +1127,11 @@ static int airoha_qdma_init_hfwd_queues(
airoha_qdma_wr(qdma, REG_FWD_BUF_BASE, dma_addr);
airoha_qdma_rmw(qdma, REG_HW_FWD_DSCP_CFG,
HW_FWD_DSCP_PAYLOAD_SIZE_MASK,
FIELD_PREP(HW_FWD_DSCP_PAYLOAD_SIZE_MASK, 0));
-@@ -1132,7 +1135,7 @@ static int airoha_qdma_init_hfwd_queues(
+@@ -1137,7 +1140,7 @@ static int airoha_qdma_init_hfwd_queues(
airoha_qdma_rmw(qdma, REG_LMGR_INIT_CFG,
LMGR_INIT_START | LMGR_SRAM_MODE_MASK |
HW_FWD_DESC_NUM_MASK,
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1084,14 +1084,15 @@ static int airoha_qdma_init_hfwd_queues(
+@@ -1089,14 +1089,15 @@ static int airoha_qdma_init_hfwd_queues(
int size, index, num_desc = HW_DSCP_NUM;
struct airoha_eth *eth = qdma->eth;
int id = qdma - ð->qdma[0];
index = of_property_match_string(eth->dev->of_node,
"memory-region-names", name);
if (index >= 0) {
-@@ -1112,9 +1113,9 @@ static int airoha_qdma_init_hfwd_queues(
+@@ -1117,9 +1118,9 @@ static int airoha_qdma_init_hfwd_queues(
/* Compute the number of hw descriptors according to the
* reserved memory size and the payload buffer size
*/
if (!dmam_alloc_coherent(eth->dev, size, &dma_addr,
GFP_KERNEL))
return -ENOMEM;
-@@ -1127,9 +1128,10 @@ static int airoha_qdma_init_hfwd_queues(
+@@ -1132,9 +1133,10 @@ static int airoha_qdma_init_hfwd_queues(
return -ENOMEM;
airoha_qdma_wr(qdma, REG_FWD_DSCP_BASE, dma_addr);
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2617,13 +2617,15 @@ static int airoha_dev_setup_tc_block_cb(
+@@ -2622,13 +2622,15 @@ static int airoha_dev_setup_tc_block_cb(
void *type_data, void *cb_priv)
{
struct net_device *dev = cb_priv;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2199,11 +2199,14 @@ static int airoha_qdma_get_tx_ets_stats(
+@@ -2204,11 +2204,14 @@ static int airoha_qdma_get_tx_ets_stats(
static int airoha_tc_setup_qdisc_ets(struct airoha_gdm_port *port,
struct tc_ets_qopt_offload *opt)
{
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1731,7 +1731,9 @@ static void airhoha_set_gdm2_loopback(st
+@@ -1736,7 +1736,9 @@ static void airhoha_set_gdm2_loopback(st
airoha_fe_wr(eth, REG_GDM_RXCHN_EN(2), 0xffff);
airoha_fe_rmw(eth, REG_GDM_LPBK_CFG(2),
LPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK,
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2043,8 +2043,12 @@ static void airoha_ethtool_get_mac_stats
+@@ -2048,8 +2048,12 @@ static void airoha_ethtool_get_mac_stats
airoha_update_hw_stats(port);
do {
start = u64_stats_fetch_begin(&port->stats.syncp);
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2791,6 +2791,7 @@ static const struct ethtool_ops airoha_e
+@@ -2796,6 +2796,7 @@ static const struct ethtool_ops airoha_e
.get_drvinfo = airoha_ethtool_get_drvinfo,
.get_eth_mac_stats = airoha_ethtool_get_mac_stats,
.get_rmon_stats = airoha_ethtool_get_rmon_stats,
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1894,6 +1894,20 @@ static u32 airoha_get_dsa_tag(struct sk_
+@@ -1899,6 +1899,20 @@ static u32 airoha_get_dsa_tag(struct sk_
#endif
}
static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct net_device *dev)
{
-@@ -1947,7 +1961,7 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -1952,7 +1966,7 @@ static netdev_tx_t airoha_dev_xmit(struc
txq = netdev_get_tx_queue(dev, qid);
nr_frags = 1 + skb_shinfo(skb)->nr_frags;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1408,8 +1408,7 @@ static int airoha_hw_init(struct platfor
+@@ -1413,8 +1413,7 @@ static int airoha_hw_init(struct platfor
int err, i;
/* disable xsi */
if (err)
return err;
-@@ -2943,6 +2942,7 @@ free_metadata_dst:
+@@ -2948,6 +2947,7 @@ free_metadata_dst:
static int airoha_probe(struct platform_device *pdev)
{
struct device_node *np;
struct airoha_eth *eth;
int i, err;
-@@ -2951,6 +2951,10 @@ static int airoha_probe(struct platform_
+@@ -2956,6 +2956,10 @@ static int airoha_probe(struct platform_
if (!eth)
return -ENOMEM;
eth->dev = &pdev->dev;
err = dma_set_mask_and_coherent(eth->dev, DMA_BIT_MASK(32));
-@@ -2975,13 +2979,18 @@ static int airoha_probe(struct platform_
+@@ -2980,13 +2984,18 @@ static int airoha_probe(struct platform_
return err;
}
eth->xsi_rsts);
if (err) {
dev_err(eth->dev, "failed to get bulk xsi reset lines\n");
-@@ -3067,8 +3076,23 @@ static void airoha_remove(struct platfor
+@@ -3072,8 +3081,23 @@ static void airoha_remove(struct platfor
platform_set_drvdata(pdev, NULL);
}
}
/* GMD4 */
for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_GDM4]; q++)
-@@ -1783,8 +1790,11 @@ static int airoha_dev_init(struct net_de
+@@ -1788,8 +1795,11 @@ static int airoha_dev_init(struct net_de
airhoha_set_gdm2_loopback(port);
fallthrough;
case 2:
/* enable 1:N vlan action, init vlan table */
airoha_fe_set(eth, REG_MC_VLAN_EN, MC_VLAN_EN_MASK);
-@@ -1777,8 +1758,10 @@ static void airhoha_set_gdm2_loopback(st
+@@ -1782,8 +1763,10 @@ static void airhoha_set_gdm2_loopback(st
static int airoha_dev_init(struct net_device *dev)
{
struct airoha_gdm_port *port = netdev_priv(dev);
airoha_set_macaddr(port, dev->dev_addr);
-@@ -1791,16 +1774,27 @@ static int airoha_dev_init(struct net_de
+@@ -1796,16 +1779,27 @@ static int airoha_dev_init(struct net_de
fallthrough;
case 2:
if (airoha_ppe_is_enabled(eth, 1)) {
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1703,13 +1703,17 @@ static int airoha_dev_set_macaddr(struct
+@@ -1708,13 +1708,17 @@ static int airoha_dev_set_macaddr(struct
return 0;
}
airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(2), pse_port);
airoha_fe_clear(eth, REG_GDM_FWD_CFG(2), GDM_STRIP_CRC);
-@@ -1730,29 +1734,25 @@ static void airhoha_set_gdm2_loopback(st
+@@ -1735,29 +1739,25 @@ static void airhoha_set_gdm2_loopback(st
airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(2));
airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(2));
}
static int airoha_dev_init(struct net_device *dev)
-@@ -1769,8 +1769,13 @@ static int airoha_dev_init(struct net_de
+@@ -1774,8 +1774,13 @@ static int airoha_dev_init(struct net_de
case 3:
case 4:
/* If GDM2 is active we can't enable loopback */
fallthrough;
case 2:
if (airoha_ppe_is_enabled(eth, 1)) {
-@@ -3088,11 +3093,38 @@ static const char * const en7581_xsi_rst
+@@ -3093,11 +3098,38 @@ static const char * const en7581_xsi_rst
"xfp-mac",
};
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1705,10 +1705,8 @@ static int airoha_dev_set_macaddr(struct
+@@ -1710,10 +1710,8 @@ static int airoha_dev_set_macaddr(struct
static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port)
{
int src_port;
/* Forward the traffic to the proper GDM port */
-@@ -1720,6 +1718,8 @@ static int airhoha_set_gdm2_loopback(str
+@@ -1725,6 +1723,8 @@ static int airhoha_set_gdm2_loopback(str
/* Enable GDM2 loopback */
airoha_fe_wr(eth, REG_GDM_TXCHN_EN(2), 0xffffffff);
airoha_fe_wr(eth, REG_GDM_RXCHN_EN(2), 0xffff);
airoha_fe_rmw(eth, REG_GDM_LPBK_CFG(2),
LPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK,
FIELD_PREP(LPBK_CHAN_MASK, chan) |
-@@ -1734,6 +1734,8 @@ static int airhoha_set_gdm2_loopback(str
+@@ -1739,6 +1739,8 @@ static int airhoha_set_gdm2_loopback(str
airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(2));
airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(2));
src_port = eth->soc->ops.get_src_port_id(port, nbq);
if (src_port < 0)
return src_port;
-@@ -1747,7 +1749,7 @@ static int airhoha_set_gdm2_loopback(str
+@@ -1752,7 +1754,7 @@ static int airhoha_set_gdm2_loopback(str
SP_CPORT_MASK(val),
FE_PSE_PORT_CDM2 << __ffs(SP_CPORT_MASK(val)));
airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6,
FC_ID_OF_SRC_PORT24_MASK,
FIELD_PREP(FC_ID_OF_SRC_PORT24_MASK, 2));
-@@ -1916,6 +1918,22 @@ static bool airoha_dev_tx_queue_busy(str
+@@ -1921,6 +1923,22 @@ static bool airoha_dev_tx_queue_busy(str
return index >= tail;
}
static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct net_device *dev)
{
-@@ -1956,7 +1974,7 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -1961,7 +1979,7 @@ static netdev_tx_t airoha_dev_xmit(struc
}
}
msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) |
FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f);
-@@ -3117,6 +3135,35 @@ static int airoha_en7581_get_src_port_id
+@@ -3122,6 +3140,35 @@ static int airoha_en7581_get_src_port_id
return -EINVAL;
}
static const struct airoha_eth_soc_data en7581_soc_data = {
.version = 0x7581,
.xsi_rsts_names = en7581_xsi_rsts_names,
-@@ -3127,8 +3174,19 @@ static const struct airoha_eth_soc_data
+@@ -3132,8 +3179,19 @@ static const struct airoha_eth_soc_data
},
};
MBI_RX_AGE_SEL_MASK | MBI_TX_AGE_SEL_MASK,
FIELD_PREP(MBI_RX_AGE_SEL_MASK, 3) |
FIELD_PREP(MBI_TX_AGE_SEL_MASK, 3));
-@@ -1713,7 +1713,7 @@ static int airhoha_set_gdm2_loopback(str
+@@ -1718,7 +1718,7 @@ static int airhoha_set_gdm2_loopback(str
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
: FE_PSE_PORT_GDM4;
airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(2), pse_port);
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -3060,6 +3060,7 @@ static int airoha_probe(struct platform_
+@@ -3065,6 +3065,7 @@ static int airoha_probe(struct platform_
error_napi_stop:
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(ð->qdma[i]);
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -3006,11 +3006,11 @@ static int airoha_probe(struct platform_
+@@ -3011,11 +3011,11 @@ static int airoha_probe(struct platform_
return err;
}
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -908,19 +908,13 @@ static int airoha_qdma_tx_napi_poll(stru
+@@ -913,19 +913,13 @@ static int airoha_qdma_tx_napi_poll(stru
dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
DMA_TO_DEVICE);
if (skb) {
u16 queue = skb_get_queue_mapping(skb);
struct netdev_queue *txq;
-@@ -965,6 +959,7 @@ static int airoha_qdma_init_tx_queue(str
+@@ -970,6 +964,7 @@ static int airoha_qdma_init_tx_queue(str
q->ndesc = size;
q->qdma = qdma;
q->free_thr = 1 + MAX_SKB_FRAGS;
q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
GFP_KERNEL);
-@@ -977,9 +972,9 @@ static int airoha_qdma_init_tx_queue(str
+@@ -982,9 +977,9 @@ static int airoha_qdma_init_tx_queue(str
return -ENOMEM;
for (i = 0; i < q->ndesc; i++) {
WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val));
}
-@@ -989,9 +984,9 @@ static int airoha_qdma_init_tx_queue(str
+@@ -994,9 +989,9 @@ static int airoha_qdma_init_tx_queue(str
airoha_qdma_wr(qdma, REG_TX_RING_BASE(qid), dma_addr);
airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
return 0;
}
-@@ -1047,17 +1042,21 @@ static int airoha_qdma_init_tx(struct ai
+@@ -1052,17 +1047,21 @@ static int airoha_qdma_init_tx(struct ai
static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
{
struct airoha_eth *eth = q->qdma->eth;
q->queued--;
}
spin_unlock_bh(&q->lock);
-@@ -1899,20 +1898,6 @@ static u32 airoha_get_dsa_tag(struct sk_
+@@ -1904,20 +1903,6 @@ static u32 airoha_get_dsa_tag(struct sk_
#endif
}
static int airoha_get_fe_port(struct airoha_gdm_port *port)
{
struct airoha_qdma *qdma = port->qdma;
-@@ -1935,8 +1920,10 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -1940,8 +1925,10 @@ static netdev_tx_t airoha_dev_xmit(struc
struct airoha_gdm_port *port = netdev_priv(dev);
struct airoha_qdma *qdma = port->qdma;
u32 nr_frags, tag, msg0, msg1, len;
void *data;
int i, qid;
u16 index;
-@@ -1982,7 +1969,7 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -1987,7 +1974,7 @@ static netdev_tx_t airoha_dev_xmit(struc
txq = netdev_get_tx_queue(dev, qid);
nr_frags = 1 + skb_shinfo(skb)->nr_frags;
/* not enough space in the queue */
netif_tx_stop_queue(txq);
spin_unlock_bh(&q->lock);
-@@ -1991,11 +1978,13 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -1996,11 +1983,13 @@ static netdev_tx_t airoha_dev_xmit(struc
len = skb_headlen(skb);
data = skb->data;
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
dma_addr_t addr;
u32 val;
-@@ -2005,7 +1994,14 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -2010,7 +1999,14 @@ static netdev_tx_t airoha_dev_xmit(struc
if (unlikely(dma_mapping_error(dev->dev.parent, addr)))
goto error_unmap;
val = FIELD_PREP(QDMA_DESC_LEN_MASK, len);
if (i < nr_frags - 1)
-@@ -2018,15 +2014,9 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -2023,15 +2019,9 @@ static netdev_tx_t airoha_dev_xmit(struc
WRITE_ONCE(desc->msg1, cpu_to_le32(msg1));
WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff));
q->queued += i;
skb_tx_timestamp(skb);
-@@ -2035,7 +2025,7 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -2040,7 +2030,7 @@ static netdev_tx_t airoha_dev_xmit(struc
if (netif_xmit_stopped(txq) || !netdev_xmit_more())
airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid),
TX_RING_CPU_IDX_MASK,
if (q->ndesc - q->queued < q->free_thr)
netif_tx_stop_queue(txq);
-@@ -2045,10 +2035,13 @@ static netdev_tx_t airoha_dev_xmit(struc
+@@ -2050,10 +2040,13 @@ static netdev_tx_t airoha_dev_xmit(struc
return NETDEV_TX_OK;
error_unmap:
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2940,19 +2940,26 @@ static int airoha_alloc_gdm_port(struct
+@@ -2945,19 +2945,26 @@ static int airoha_alloc_gdm_port(struct
port->id = id;
eth->ports[p] = port;
}
static int airoha_probe(struct platform_device *pdev)
-@@ -3043,6 +3050,10 @@ static int airoha_probe(struct platform_
+@@ -3048,6 +3055,10 @@ static int airoha_probe(struct platform_
}
}
return 0;
error_napi_stop:
-@@ -3056,10 +3067,12 @@ error_hw_cleanup:
+@@ -3061,10 +3072,12 @@ error_hw_cleanup:
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
airoha_fe_crsn_qsel_init(eth);
-@@ -1706,27 +1706,29 @@ static int airhoha_set_gdm2_loopback(str
+@@ -1711,27 +1711,29 @@ static int airhoha_set_gdm2_loopback(str
/* Forward the traffic to the proper GDM port */
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
: FE_PSE_PORT_GDM4;
/* XXX: handle XSI_USB_PORT and XSI_PCE1_PORT */
nbq = port->id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0;
-@@ -1762,8 +1764,8 @@ static int airoha_dev_init(struct net_de
+@@ -1767,8 +1769,8 @@ static int airoha_dev_init(struct net_de
airoha_set_macaddr(port, dev->dev_addr);
switch (port->id) {
/* If GDM2 is active we can't enable loopback */
if (!eth->ports[1]) {
int err;
-@@ -1773,7 +1775,7 @@ static int airoha_dev_init(struct net_de
+@@ -1778,7 +1780,7 @@ static int airoha_dev_init(struct net_de
return err;
}
fallthrough;
if (airoha_ppe_is_enabled(eth, 1)) {
/* For PPE2 always use secondary cpu port. */
fe_cpu_port = FE_PSE_PORT_CDM2;
-@@ -3116,14 +3118,14 @@ static const char * const en7581_xsi_rst
+@@ -3121,14 +3123,14 @@ static const char * const en7581_xsi_rst
static int airoha_en7581_get_src_port_id(struct airoha_gdm_port *port, int nbq)
{
switch (port->id) {
/* 7581 SoC supports eth and usb serdes on GDM4 port */
if (!nbq)
return HSGMII_LAN_7581_ETH_SRCPORT;
-@@ -3147,12 +3149,12 @@ static const char * const an7583_xsi_rst
+@@ -3152,12 +3154,12 @@ static const char * const an7583_xsi_rst
static int airoha_an7583_get_src_port_id(struct airoha_gdm_port *port, int nbq)
{
switch (port->id) {
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2821,6 +2821,7 @@ static const struct ethtool_ops airoha_e
+@@ -2826,6 +2826,7 @@ static const struct ethtool_ops airoha_e
.get_drvinfo = airoha_ethtool_get_drvinfo,
.get_eth_mac_stats = airoha_ethtool_get_mac_stats,
.get_rmon_stats = airoha_ethtool_get_rmon_stats,
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1743,7 +1743,7 @@ static int airhoha_set_gdm2_loopback(str
+@@ -1748,7 +1748,7 @@ static int airhoha_set_gdm2_loopback(str
airoha_fe_rmw(eth,
REG_SP_DFT_CPORT(src_port >> fls(SP_CPORT_DFT_MASK)),
SP_CPORT_MASK(val),
if (port->id != AIROHA_GDM3_IDX && airoha_is_7581(eth))
airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6,
-@@ -1797,7 +1797,7 @@ static int airoha_dev_init(struct net_de
+@@ -1802,7 +1802,7 @@ static int airoha_dev_init(struct net_de
ppe_id = pse_port == FE_PSE_PORT_PPE2 ? 1 : 0;
airoha_fe_rmw(eth, REG_PPE_DFT_CPORT0(ppe_id),
DFT_CPORT_MASK(port->id),
return 0;
}
-@@ -2154,7 +2154,7 @@ static int airoha_qdma_set_chan_tx_sched
+@@ -2159,7 +2159,7 @@ static int airoha_qdma_set_chan_tx_sched
airoha_qdma_rmw(port->qdma, REG_CHAN_QOS_MODE(channel >> 3),
CHAN_QOS_MODE_MASK(channel),
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1745,10 +1745,12 @@ static int airhoha_set_gdm2_loopback(str
+@@ -1750,10 +1750,12 @@ static int airhoha_set_gdm2_loopback(str
SP_CPORT_MASK(val),
__field_prep(SP_CPORT_MASK(val), FE_PSE_PORT_CDM2));
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1627,6 +1627,7 @@ static int airoha_dev_open(struct net_de
+@@ -1632,6 +1632,7 @@ static int airoha_dev_open(struct net_de
int err, len = ETH_HLEN + dev->mtu + ETH_FCS_LEN;
struct airoha_gdm_port *port = netdev_priv(dev);
struct airoha_qdma *qdma = port->qdma;
netif_tx_start_all_queues(dev);
err = airoha_set_vip_for_gdm_port(port, true);
-@@ -1650,6 +1651,14 @@ static int airoha_dev_open(struct net_de
+@@ -1655,6 +1656,14 @@ static int airoha_dev_open(struct net_de
GLOBAL_CFG_RX_DMA_EN_MASK);
atomic_inc(&qdma->users);
return 0;
}
-@@ -1667,6 +1676,9 @@ static int airoha_dev_stop(struct net_de
+@@ -1672,6 +1681,9 @@ static int airoha_dev_stop(struct net_de
for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++)
netdev_tx_reset_subqueue(dev, i);
if (atomic_dec_and_test(&qdma->users)) {
airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
GLOBAL_CFG_TX_DMA_EN_MASK |
-@@ -1760,7 +1772,7 @@ static int airoha_dev_init(struct net_de
+@@ -1765,7 +1777,7 @@ static int airoha_dev_init(struct net_de
struct airoha_gdm_port *port = netdev_priv(dev);
struct airoha_qdma *qdma = port->qdma;
struct airoha_eth *eth = qdma->eth;
u8 ppe_id;
airoha_set_macaddr(port, dev->dev_addr);
-@@ -1781,7 +1793,7 @@ static int airoha_dev_init(struct net_de
+@@ -1786,7 +1798,7 @@ static int airoha_dev_init(struct net_de
if (airoha_ppe_is_enabled(eth, 1)) {
/* For PPE2 always use secondary cpu port. */
fe_cpu_port = FE_PSE_PORT_CDM2;
break;
}
fallthrough;
-@@ -1790,13 +1802,11 @@ static int airoha_dev_init(struct net_de
+@@ -1795,13 +1807,11 @@ static int airoha_dev_init(struct net_de
/* For PPE1 select cpu port according to the running QDMA. */
fe_cpu_port = qdma_id ? FE_PSE_PORT_CDM2 : FE_PSE_PORT_CDM1;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1770,11 +1770,13 @@ static int airhoha_set_gdm2_loopback(str
+@@ -1775,11 +1775,13 @@ static int airhoha_set_gdm2_loopback(str
static int airoha_dev_init(struct net_device *dev)
{
struct airoha_gdm_port *port = netdev_priv(dev);
airoha_set_macaddr(port, dev->dev_addr);
switch (port->id) {
-@@ -1798,7 +1800,7 @@ static int airoha_dev_init(struct net_de
+@@ -1803,7 +1805,7 @@ static int airoha_dev_init(struct net_de
}
fallthrough;
default: {
/* For PPE1 select cpu port according to the running QDMA. */
fe_cpu_port = qdma_id ? FE_PSE_PORT_CDM2 : FE_PSE_PORT_CDM1;
-@@ -2882,11 +2884,10 @@ bool airoha_is_valid_gdm_port(struct air
+@@ -2887,11 +2889,10 @@ bool airoha_is_valid_gdm_port(struct air
}
static int airoha_alloc_gdm_port(struct airoha_eth *eth,
struct net_device *dev;
int err, p;
u32 id;
-@@ -2917,7 +2918,6 @@ static int airoha_alloc_gdm_port(struct
+@@ -2922,7 +2923,6 @@ static int airoha_alloc_gdm_port(struct
return -ENOMEM;
}
dev->netdev_ops = &airoha_netdev_ops;
dev->ethtool_ops = &airoha_ethtool_ops;
dev->max_mtu = AIROHA_MAX_MTU;
-@@ -2929,7 +2929,6 @@ static int airoha_alloc_gdm_port(struct
+@@ -2934,7 +2934,6 @@ static int airoha_alloc_gdm_port(struct
dev->features |= dev->hw_features;
dev->vlan_features = dev->hw_features;
dev->dev.of_node = np;
SET_NETDEV_DEV(dev, eth->dev);
/* reserve hw queues for HTB offloading */
-@@ -2950,7 +2949,7 @@ static int airoha_alloc_gdm_port(struct
+@@ -2955,7 +2954,7 @@ static int airoha_alloc_gdm_port(struct
port = netdev_priv(dev);
u64_stats_init(&port->stats.syncp);
spin_lock_init(&port->stats.lock);
port->dev = dev;
port->id = id;
eth->ports[p] = port;
-@@ -3050,7 +3049,6 @@ static int airoha_probe(struct platform_
+@@ -3055,7 +3054,6 @@ static int airoha_probe(struct platform_
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_start_napi(ð->qdma[i]);
for_each_child_of_node(pdev->dev.of_node, np) {
if (!of_device_is_compatible(np, "airoha,eth-mac"))
continue;
-@@ -3058,7 +3056,7 @@ static int airoha_probe(struct platform_
+@@ -3063,7 +3061,7 @@ static int airoha_probe(struct platform_
if (!of_device_is_available(np))
continue;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1771,8 +1771,7 @@ static int airoha_dev_init(struct net_de
+@@ -1776,8 +1776,7 @@ static int airoha_dev_init(struct net_de
{
struct airoha_gdm_port *port = netdev_priv(dev);
struct airoha_eth *eth = port->eth;
/* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */
port->qdma = ð->qdma[!airoha_is_lan_gdm_port(port)];
-@@ -1790,28 +1789,13 @@ static int airoha_dev_init(struct net_de
+@@ -1795,28 +1794,13 @@ static int airoha_dev_init(struct net_de
if (err)
return err;
}
return 0;
}
-@@ -1914,7 +1898,7 @@ static u32 airoha_get_dsa_tag(struct sk_
+@@ -1919,7 +1903,7 @@ static u32 airoha_get_dsa_tag(struct sk_
#endif
}
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1384,6 +1384,33 @@ static int airoha_qdma_init(struct platf
+@@ -1389,6 +1389,33 @@ static int airoha_qdma_init(struct platf
return airoha_qdma_hw_init(qdma);
}
static int airoha_hw_init(struct platform_device *pdev,
struct airoha_eth *eth)
{
-@@ -1411,41 +1438,30 @@ static int airoha_hw_init(struct platfor
+@@ -1416,41 +1443,30 @@ static int airoha_hw_init(struct platfor
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
err = airoha_qdma_init(pdev, eth, ð->qdma[i]);
if (err)
}
static void airoha_qdma_start_napi(struct airoha_qdma *qdma)
-@@ -3028,7 +3044,7 @@ static int airoha_probe(struct platform_
+@@ -3033,7 +3049,7 @@ static int airoha_probe(struct platform_
err = airoha_hw_init(pdev, eth);
if (err)
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_start_napi(ð->qdma[i]);
-@@ -3056,10 +3072,6 @@ static int airoha_probe(struct platform_
+@@ -3061,10 +3077,6 @@ static int airoha_probe(struct platform_
error_napi_stop:
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(ð->qdma[i]);
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
-@@ -3071,6 +3083,8 @@ error_hw_cleanup:
+@@ -3076,6 +3088,8 @@ error_hw_cleanup:
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
-@@ -3082,10 +3096,8 @@ static void airoha_remove(struct platfor
+@@ -3087,10 +3101,8 @@ static void airoha_remove(struct platfor
struct airoha_eth *eth = platform_get_drvdata(pdev);
int i;
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
-@@ -3096,9 +3108,9 @@ static void airoha_remove(struct platfor
+@@ -3101,9 +3113,9 @@ static void airoha_remove(struct platfor
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -2973,6 +2973,8 @@ static int airoha_register_gdm_devices(s
+@@ -2978,6 +2978,8 @@ static int airoha_register_gdm_devices(s
return err;
}
+++ /dev/null
-From 656121b155030086b01cfce9bd31b0c925ee6860 Mon Sep 17 00:00:00 2001
-From: Lorenzo Bianconi <lorenzo@kernel.org>
-Date: Wed, 8 Apr 2026 20:26:56 +0200
-Subject: [PATCH] net: airoha: Add missing RX_CPU_IDX() configuration in
- airoha_qdma_cleanup_rx_queue()
-
-When the descriptor index written in REG_RX_CPU_IDX() is equal to the one
-stored in REG_RX_DMA_IDX(), the hw will stop since the QDMA RX ring is
-empty.
-Add missing REG_RX_CPU_IDX() configuration in airoha_qdma_cleanup_rx_queue
-routine during QDMA RX ring cleanup.
-
-Fixes: 514aac359987 ("net: airoha: Add missing cleanup bits in airoha_qdma_cleanup_rx_queue()")
-Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-Link: https://patch.msgid.link/20260408-airoha-cpu-idx-airoha_qdma_cleanup_rx_queue-v1-1-8efa64844308@kernel.org
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
----
- drivers/net/ethernet/airoha/airoha_eth.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/net/ethernet/airoha/airoha_eth.c
-+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -824,6 +824,11 @@ static void airoha_qdma_cleanup_rx_queue
- }
-
- q->head = q->tail;
-+ /* Set RX_DMA_IDX to RX_CPU_IDX to notify the hw the QDMA RX ring is
-+ * empty.
-+ */
-+ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
-+ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head));
- airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
- FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail));
- }
+++ /dev/null
-From 379050947a1828826ad7ea50c95245a56929b35a Mon Sep 17 00:00:00 2001
-From: Lorenzo Bianconi <lorenzo@kernel.org>
-Date: Mon, 20 Apr 2026 10:07:47 +0200
-Subject: [PATCH] net: airoha: Move ndesc initialization at end of
- airoha_qdma_init_rx_queue()
-
-If queue entry or DMA descriptor list allocation fails in
-airoha_qdma_init_rx_queue routine, airoha_qdma_cleanup() will trigger a
-NULL pointer dereference running netif_napi_del() for RX queue NAPIs
-since netif_napi_add() has never been executed to this particular RX NAPI.
-The issue is due to the early ndesc initialization in
-airoha_qdma_init_rx_queue() since airoha_qdma_cleanup() relies on ndesc
-value to check if the queue is properly initialized. Fix the issue moving
-ndesc initialization at end of airoha_qdma_init_tx routine.
-Move page_pool allocation after descriptor list allocation in order to
-avoid memory leaks if desc allocation fails.
-
-Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
-Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-Link: https://patch.msgid.link/20260420-airoha_qdma_init_rx_queue-fix-v2-1-d99347e5c18d@kernel.org
-Signed-off-by: Paolo Abeni <pabeni@redhat.com>
----
- drivers/net/ethernet/airoha/airoha_eth.c | 14 +++++++-------
- 1 file changed, 7 insertions(+), 7 deletions(-)
-
---- a/drivers/net/ethernet/airoha/airoha_eth.c
-+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -745,14 +745,18 @@ static int airoha_qdma_init_rx_queue(str
- dma_addr_t dma_addr;
-
- q->buf_size = PAGE_SIZE / 2;
-- q->ndesc = ndesc;
- q->qdma = qdma;
-
-- q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
-+ q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry),
- GFP_KERNEL);
- if (!q->entry)
- return -ENOMEM;
-
-+ q->desc = dmam_alloc_coherent(eth->dev, ndesc * sizeof(*q->desc),
-+ &dma_addr, GFP_KERNEL);
-+ if (!q->desc)
-+ return -ENOMEM;
-+
- q->page_pool = page_pool_create(&pp_params);
- if (IS_ERR(q->page_pool)) {
- int err = PTR_ERR(q->page_pool);
-@@ -761,11 +765,7 @@ static int airoha_qdma_init_rx_queue(str
- return err;
- }
-
-- q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc),
-- &dma_addr, GFP_KERNEL);
-- if (!q->desc)
-- return -ENOMEM;
--
-+ q->ndesc = ndesc;
- netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);
-
- airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr);
+ fwnode_handle_put(child);
+ return ERR_PTR(-EINVAL);
+ }
-+ led->rst = __of_reset_control_get(np, NULL, 0, 0, 0, true);
++ led->rst = __of_reset_control_get(np, NULL, 0, RESET_CONTROL_EXCLUSIVE);
+ if (IS_ERR(led->rst))
+ return ERR_PTR(-EINVAL);
+
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
-@@ -31,7 +31,7 @@
+@@ -34,7 +34,7 @@
#define ENET_PAD 8
#define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -2657,7 +2657,7 @@ static void bcmgenet_init_tx_ring(struct
+@@ -2675,7 +2675,7 @@ static void bcmgenet_init_tx_ring(struct
bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
/* Disable rate control for now */
bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
TDMA_FLOW_PERIOD);
-@@ -4132,9 +4132,12 @@ static int bcmgenet_probe(struct platfor
+@@ -4074,8 +4074,10 @@ static int bcmgenet_probe(struct platfor
netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
/* Set default coalescing parameters */
-- for (i = 0; i < priv->hw_params->rx_queues; i++)
-+ for (i = 0; i < priv->hw_params->rx_queues; i++) {
+- for (i = 0; i <= priv->hw_params->rx_queues; i++)
++ for (i = 0; i <= priv->hw_params->rx_queues; i++) {
priv->rx_rings[i].rx_max_coalesced_frames = 1;
+ priv->rx_rings[i].rx_coalesce_usecs = 50;
+ }
- priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1;
-+ priv->rx_rings[DESC_INDEX].rx_coalesce_usecs = 50;
- /* libphy will determine the link state */
- netif_carrier_off(dev);
+ /* Initialize u64 stats seq counter for 32bit machines */
+ for (i = 0; i <= priv->hw_params->rx_queues; i++)
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -333,6 +333,21 @@ static int v3d_platform_drm_probe(struct
+@@ -341,6 +341,21 @@ static int v3d_platform_drm_probe(struct
}
}
if (v3d->ver < 41) {
ret = map_regs(v3d, &v3d->gca_regs, "gca");
if (ret)
-@@ -362,6 +377,8 @@ static int v3d_platform_drm_probe(struct
+@@ -370,6 +385,8 @@ static int v3d_platform_drm_probe(struct
ret = v3d_sysfs_init(dev);
if (ret)
goto drm_unregister;
kref_init(&job->refcount);
return 0;
-@@ -1393,3 +1438,14 @@ fail:
+@@ -1398,3 +1443,14 @@ fail:
return ret;
}
#include <uapi/drm/v3d_drm.h>
#include "v3d_drv.h"
-@@ -263,6 +267,8 @@ map_regs(struct v3d_dev *v3d, void __iom
+@@ -271,6 +275,8 @@ map_regs(struct v3d_dev *v3d, void __iom
static int v3d_platform_drm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct drm_device *drm;
struct v3d_dev *v3d;
int ret;
-@@ -339,7 +345,20 @@ static int v3d_platform_drm_probe(struct
+@@ -347,7 +353,20 @@ static int v3d_platform_drm_probe(struct
dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk));
return PTR_ERR(v3d->clk);
}
/* For downclocking, drop it to the minimum frequency we can get from
* the CPRMAN clock generator dividing off our parent. The divider is
* 4 bits, but ask for just higher than that so that rounding doesn't
-@@ -377,7 +396,7 @@ static int v3d_platform_drm_probe(struct
+@@ -385,7 +404,7 @@ static int v3d_platform_drm_probe(struct
ret = v3d_sysfs_init(dev);
if (ret)
goto drm_unregister;
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -67,6 +67,9 @@
+@@ -65,6 +65,9 @@
/* Forward declarations */
static void bcmgenet_set_rx_mode(struct net_device *dev);
static inline void bcmgenet_writel(u32 value, void __iomem *offset)
{
-@@ -2486,6 +2489,11 @@ static void reset_umac(struct bcmgenet_p
+@@ -2513,6 +2516,11 @@ static void reset_umac(struct bcmgenet_p
bcmgenet_rbuf_ctrl_set(priv, 0);
udelay(10);
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -67,7 +67,7 @@
+@@ -65,7 +65,7 @@
/* Forward declarations */
static void bcmgenet_set_rx_mode(struct net_device *dev);
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -70,6 +70,9 @@ static void bcmgenet_set_rx_mode(struct
+@@ -68,6 +68,9 @@ static void bcmgenet_set_rx_mode(struct
static bool skip_umac_reset = false;
module_param(skip_umac_reset, bool, 0444);
MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step");
static inline void bcmgenet_writel(u32 value, void __iomem *offset)
{
-@@ -3423,6 +3426,17 @@ static int bcmgenet_open(struct net_devi
+@@ -3360,6 +3363,17 @@ static int bcmgenet_open(struct net_devi
bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause);
return;
}
-@@ -673,18 +748,25 @@ static int dw_axi_dma_set_hw_desc(struct
+@@ -671,18 +746,25 @@ static int dw_axi_dma_set_hw_desc(struct
switch (chan->direction) {
case DMA_MEM_TO_DEV:
reg_width = __ffs(chan->config.dst_addr_width);
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS;
block_ts = len >> reg_width;
-@@ -720,9 +802,6 @@ static int dw_axi_dma_set_hw_desc(struct
+@@ -718,9 +800,6 @@ static int dw_axi_dma_set_hw_desc(struct
}
hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1);
hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
set_desc_src_master(hw_desc);
-@@ -817,6 +896,8 @@ dw_axi_dma_chan_prep_cyclic(struct dma_c
+@@ -815,6 +894,8 @@ dw_axi_dma_chan_prep_cyclic(struct dma_c
src_addr += segment_len;
}
llp = desc->hw_desc[0].llp;
/* Managed transfer list */
-@@ -896,6 +977,8 @@ dw_axi_dma_chan_prep_slave_sg(struct dma
+@@ -894,6 +975,8 @@ dw_axi_dma_chan_prep_slave_sg(struct dma
} while (len >= segment_len);
}
/* Set end-of-link to the last link descriptor of list */
set_desc_last(&desc->hw_desc[num_sgs - 1]);
-@@ -1003,6 +1086,8 @@ dma_chan_prep_dma_memcpy(struct dma_chan
+@@ -1001,6 +1084,8 @@ dma_chan_prep_dma_memcpy(struct dma_chan
num++;
}
/* Set end-of-link to the last link descriptor of list */
set_desc_last(&desc->hw_desc[num - 1]);
/* Managed transfer list */
-@@ -1051,7 +1136,7 @@ static void axi_chan_dump_lli(struct axi
+@@ -1049,7 +1134,7 @@ static void axi_chan_dump_lli(struct axi
static void axi_chan_list_dump_lli(struct axi_dma_chan *chan,
struct axi_dma_desc *desc_head)
{
int i;
for (i = 0; i < count; i++)
-@@ -1094,11 +1179,11 @@ out:
+@@ -1092,11 +1177,11 @@ out:
static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)
{
u64 llp;
int i;
-@@ -1120,6 +1205,7 @@ static void axi_chan_block_xfer_complete
+@@ -1118,6 +1203,7 @@ static void axi_chan_block_xfer_complete
if (chan->cyclic) {
desc = vd_to_axi_desc(vd);
if (desc) {
llp = lo_hi_readq(chan->chan_regs + CH_LLP);
for (i = 0; i < count; i++) {
hw_desc = &desc->hw_desc[i];
-@@ -1140,6 +1226,9 @@ static void axi_chan_block_xfer_complete
+@@ -1138,6 +1224,9 @@ static void axi_chan_block_xfer_complete
/* Remove the completed descriptor from issued list before completing */
list_del(&vd->node);
vchan_cookie_complete(vd);
}
out:
-@@ -1397,6 +1486,10 @@ static int parse_device_properties(struc
+@@ -1395,6 +1484,10 @@ static int parse_device_properties(struc
chip->dw->hdata->nr_masters = tmp;
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -249,6 +249,7 @@ static const struct drm_driver v3d_drm_d
+@@ -257,6 +257,7 @@ static const struct drm_driver v3d_drm_d
};
static const struct of_device_id v3d_of_match[] = {
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-@@ -963,6 +963,9 @@ dw_axi_dma_chan_prep_slave_sg(struct dma
+@@ -961,6 +961,9 @@ dw_axi_dma_chan_prep_slave_sg(struct dma
mem = sg_dma_address(sg);
len = sg_dma_len(sg);
num_segments = DIV_ROUND_UP(sg_dma_len(sg), axi_block_len);
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-@@ -1563,6 +1563,7 @@ static int dw_probe(struct platform_devi
+@@ -1561,6 +1561,7 @@ static int dw_probe(struct platform_devi
struct dw_axi_dma *dw;
struct dw_axi_dma_hcfg *hdata;
struct reset_control *resets;
unsigned int flags;
u32 i;
int ret;
-@@ -1673,9 +1674,21 @@ static int dw_probe(struct platform_devi
+@@ -1671,9 +1672,21 @@ static int dw_probe(struct platform_devi
* Synopsis DesignWare AxiDMA datasheet mentioned Maximum
* supported blocks is 1024. Device register width is 4 bytes.
* Therefore, set constraint to 1024 * 4.
static inline const char *axi_chan_name(struct axi_dma_chan *chan)
{
return dma_chan_name(&chan->vc.chan);
-@@ -732,41 +741,41 @@ static int dw_axi_dma_set_hw_desc(struct
+@@ -730,41 +739,41 @@ static int dw_axi_dma_set_hw_desc(struct
size_t axi_block_ts;
size_t block_ts;
u32 ctllo, ctlhi;
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS;
block_ts = len >> reg_width;
-@@ -807,6 +816,12 @@ static int dw_axi_dma_set_hw_desc(struct
+@@ -805,6 +814,12 @@ static int dw_axi_dma_set_hw_desc(struct
set_desc_src_master(hw_desc);
hw_desc->len = len;
return 0;
}
-@@ -823,9 +838,6 @@ static size_t calculate_block_len(struct
+@@ -821,9 +836,6 @@ static size_t calculate_block_len(struct
case DMA_MEM_TO_DEV:
data_width = BIT(chan->chip->dw->hdata->m_data_width);
mem_width = __ffs(data_width | dma_addr | buf_len);
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-@@ -771,6 +771,18 @@ static int dw_axi_dma_set_hw_desc(struct
+@@ -769,6 +769,18 @@ static int dw_axi_dma_set_hw_desc(struct
case DMA_DEV_TO_MEM:
reg_burst_msize = axi_dma_encode_msize(chan->config.src_maxburst);
reg_width = __ffs(chan->config.src_addr_width);
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
-@@ -2112,6 +2112,7 @@ static void nvme_free_host_mem(struct nv
+@@ -2113,6 +2113,7 @@ static void nvme_free_host_mem(struct nv
dev->nr_host_mem_descs = 0;
}
static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,
u32 chunk_size)
{
-@@ -2180,9 +2181,11 @@ out:
+@@ -2181,9 +2182,11 @@ out:
dev->host_mem_descs = NULL;
return -ENOMEM;
}
u64 min_chunk = min_t(u64, preferred, PAGE_SIZE * MAX_ORDER_NR_PAGES);
u64 hmminds = max_t(u32, dev->ctrl.hmminds * 4096, PAGE_SIZE * 2);
u64 chunk_size;
-@@ -2195,6 +2198,7 @@ static int nvme_alloc_host_mem(struct nv
+@@ -2196,6 +2199,7 @@ static int nvme_alloc_host_mem(struct nv
nvme_free_host_mem(dev);
}
}
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
-@@ -6933,6 +6933,39 @@ static int __init cgroup_disable(char *s
+@@ -6935,6 +6935,39 @@ static int __init cgroup_disable(char *s
}
__setup("cgroup_disable=", cgroup_disable);
kref_init(&job->refcount);
return 0;
-@@ -1350,7 +1368,7 @@ v3d_submit_cpu_ioctl(struct drm_device *
+@@ -1355,7 +1373,7 @@ v3d_submit_cpu_ioctl(struct drm_device *
trace_v3d_submit_cpu_ioctl(&v3d->drm, cpu_job->job_type);
ret = v3d_job_init(v3d, file_priv, &cpu_job->base,
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -228,6 +228,7 @@ static const struct drm_ioctl_desc v3d_d
+@@ -236,6 +236,7 @@ static const struct drm_ioctl_desc v3d_d
DRM_IOCTL_DEF_DRV(V3D_PERFMON_GET_VALUES, v3d_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CPU, v3d_submit_cpu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
DRM_IOCTL_DEF_DRV(V3D_PERFMON_GET_COUNTER, v3d_perfmon_get_counter_ioctl, DRM_RENDER_ALLOW),
static void
--- a/drivers/gpu/drm/v3d/v3d_submit.c
+++ b/drivers/gpu/drm/v3d/v3d_submit.c
-@@ -1044,6 +1044,11 @@ v3d_submit_cl_ioctl(struct drm_device *d
+@@ -1049,6 +1049,11 @@ v3d_submit_cl_ioctl(struct drm_device *d
goto fail;
if (args->perfmon_id) {
render->base.perfmon = v3d_perfmon_find(v3d_priv,
args->perfmon_id);
-@@ -1259,6 +1264,11 @@ v3d_submit_csd_ioctl(struct drm_device *
+@@ -1264,6 +1269,11 @@ v3d_submit_csd_ioctl(struct drm_device *
goto fail;
if (args->perfmon_id) {
return 0;
case DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT:
args->value = 1;
-@@ -260,15 +260,44 @@ static const struct drm_driver v3d_drm_d
+@@ -268,15 +268,44 @@ static const struct drm_driver v3d_drm_d
};
static const struct of_device_id v3d_of_match[] = {
static int
map_regs(struct v3d_dev *v3d, void __iomem **regs, const char *name)
{
-@@ -283,6 +312,7 @@ static int v3d_platform_drm_probe(struct
+@@ -291,6 +320,7 @@ static int v3d_platform_drm_probe(struct
struct device_node *node;
struct drm_device *drm;
struct v3d_dev *v3d;
int ret;
u32 mmu_debug;
u32 ident1, ident3;
-@@ -296,6 +326,9 @@ static int v3d_platform_drm_probe(struct
+@@ -304,6 +334,9 @@ static int v3d_platform_drm_probe(struct
platform_set_drvdata(pdev, drm);
ret = map_regs(v3d, &v3d->hub_regs, "hub");
if (ret)
return ret;
-@@ -304,6 +337,12 @@ static int v3d_platform_drm_probe(struct
+@@ -312,6 +345,12 @@ static int v3d_platform_drm_probe(struct
if (ret)
return ret;
v3d->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(v3d->clk))
return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n");
-@@ -314,6 +353,8 @@ static int v3d_platform_drm_probe(struct
+@@ -322,6 +361,8 @@ static int v3d_platform_drm_probe(struct
return ret;
}
mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO);
mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH));
ret = dma_set_mask_and_coherent(dev, mask);
-@@ -327,6 +368,11 @@ static int v3d_platform_drm_probe(struct
+@@ -335,6 +376,11 @@ static int v3d_platform_drm_probe(struct
ident1 = V3D_READ(V3D_HUB_IDENT1);
v3d->ver = (V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER) * 10 +
V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_REV));
v3d->cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES);
WARN_ON(v3d->cores > 1); /* multicore not yet implemented */
-@@ -379,7 +425,7 @@ static int v3d_platform_drm_probe(struct
+@@ -387,7 +433,7 @@ static int v3d_platform_drm_probe(struct
v3d->clk_down_rate =
(clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -487,6 +487,8 @@ static void v3d_platform_drm_remove(stru
+@@ -495,6 +495,8 @@ static void v3d_platform_drm_remove(stru
dma_free_wc(v3d->drm.dev, 4096, v3d->mmu_scratch,
v3d->mmu_scratch_paddr);
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-@@ -750,11 +750,6 @@ static int dw_axi_dma_set_hw_desc(struct
+@@ -748,11 +748,6 @@ static int dw_axi_dma_set_hw_desc(struct
mem_width = __ffs(data_width | mem_addr | len);
/* Use a reasonable upper limit otherwise residue reporting granularity grows large */
mem_burst_msize = axi_dma_encode_msize(16);
-@@ -799,6 +794,11 @@ static int dw_axi_dma_set_hw_desc(struct
+@@ -797,6 +792,11 @@ static int dw_axi_dma_set_hw_desc(struct
return -EINVAL;
}
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -397,21 +397,18 @@ static int v3d_platform_drm_probe(struct
+@@ -405,21 +405,18 @@ static int v3d_platform_drm_probe(struct
}
}
--- /dev/null
+From 5c9ceee75a90cd5db0d38d9dbfde6659194a9b5b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 10:29:50 -0400
+Subject: Revert "perf cgroup: Update metric leader in evlist__expand_cgroup"
+
+This reverts commit d26e31446c0fa96feca0b7701243b42447225d33.
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/perf/util/cgroup.c | 30 +++++++-----------------------
+ 1 file changed, 7 insertions(+), 23 deletions(-)
+
+--- a/tools/perf/util/cgroup.c
++++ b/tools/perf/util/cgroup.c
+@@ -417,6 +417,7 @@ int evlist__expand_cgroup(struct evlist
+ struct rblist *metric_events, bool open_cgroup)
+ {
+ struct evlist *orig_list, *tmp_list;
++ struct evsel *pos, *evsel, *leader;
+ struct rblist orig_metric_events;
+ struct cgroup *cgrp = NULL;
+ struct cgroup_name *cn;
+@@ -455,7 +456,6 @@ int evlist__expand_cgroup(struct evlist
+ goto out_err;
+
+ list_for_each_entry(cn, &cgroup_list, list) {
+- struct evsel *pos;
+ char *name;
+
+ if (!cn->used)
+@@ -471,37 +471,21 @@ int evlist__expand_cgroup(struct evlist
+ if (cgrp == NULL)
+ continue;
+
+- /* copy the list and set to the new cgroup. */
++ leader = NULL;
+ evlist__for_each_entry(orig_list, pos) {
+- struct evsel *evsel = evsel__clone(/*dest=*/NULL, pos);
+-
++ evsel = evsel__clone(/*dest=*/NULL, pos);
+ if (evsel == NULL)
+ goto out_err;
+
+- /* stash the copy during the copying. */
+- pos->priv = evsel;
+ cgroup__put(evsel->cgrp);
+ evsel->cgrp = cgroup__get(cgrp);
+
+- evlist__add(tmp_list, evsel);
+- }
+- /* update leader information using stashed pointer to copy. */
+- evlist__for_each_entry(orig_list, pos) {
+- struct evsel *evsel = pos->priv;
+-
+- if (evsel__leader(pos))
+- evsel__set_leader(evsel, evsel__leader(pos)->priv);
+-
+- if (pos->metric_leader)
+- evsel->metric_leader = pos->metric_leader->priv;
++ if (evsel__is_group_leader(pos))
++ leader = evsel;
++ evsel__set_leader(evsel, leader);
+
+- if (pos->first_wildcard_match)
+- evsel->first_wildcard_match = pos->first_wildcard_match->priv;
++ evlist__add(tmp_list, evsel);
+ }
+- /* the stashed copy is no longer used. */
+- evlist__for_each_entry(orig_list, pos)
+- pos->priv = NULL;
+-
+ /* cgroup__new() has a refcount, release it here */
+ cgroup__put(cgrp);
+ nr_cgroups++;
--- /dev/null
+From f126428e706b7c6eb9aa1c79ced284b195d4e392 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 10:36:48 -0400
+Subject: Revert "perf tool_pmu: Fix aggregation on duration_time"
+
+This reverts commit 310be445ab1028315627b326516f193511cb1c97.
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/perf/util/tool_pmu.c | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+--- a/tools/perf/util/tool_pmu.c
++++ b/tools/perf/util/tool_pmu.c
+@@ -392,14 +392,8 @@ int evsel__read_tool(struct evsel *evsel
+ delta_start *= 1000000000 / ticks_per_sec;
+ }
+ count->val = delta_start;
++ count->ena = count->run = delta_start;
+ count->lost = 0;
+- /*
+- * The values of enabled and running must make a ratio of 100%. The
+- * exact values don't matter as long as they are non-zero to avoid
+- * issues with evsel__count_has_error.
+- */
+- count->ena++;
+- count->run++;
+ return 0;
+ }
+
--- /dev/null
+From 8a11c59a5aab9423777ee1ead5e66174896c7adb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 10:36:48 -0400
+Subject: Revert "perf python: Add parse_events function"
+
+This reverts commit 9cd264079fab9867dbc9fbc8a1e521996e3d7212.
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/perf/util/cgroup.c | 2 +-
+ tools/perf/util/evsel.c | 19 +++++--------
+ tools/perf/util/evsel.h | 2 +-
+ tools/perf/util/python.c | 61 ----------------------------------------
+ 4 files changed, 9 insertions(+), 75 deletions(-)
+
+--- a/tools/perf/util/cgroup.c
++++ b/tools/perf/util/cgroup.c
+@@ -473,7 +473,7 @@ int evlist__expand_cgroup(struct evlist
+
+ leader = NULL;
+ evlist__for_each_entry(orig_list, pos) {
+- evsel = evsel__clone(/*dest=*/NULL, pos);
++ evsel = evsel__clone(pos);
+ if (evsel == NULL)
+ goto out_err;
+
+--- a/tools/perf/util/evsel.c
++++ b/tools/perf/util/evsel.c
+@@ -332,7 +332,7 @@ static int evsel__copy_config_terms(stru
+ * The assumption is that @orig is not configured nor opened yet.
+ * So we only care about the attributes that can be set while it's parsed.
+ */
+-struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig)
++struct evsel *evsel__clone(struct evsel *orig)
+ {
+ struct evsel *evsel;
+
+@@ -345,11 +345,7 @@ struct evsel *evsel__clone(struct evsel
+ if (orig->bpf_obj)
+ return NULL;
+
+- if (dest)
+- evsel = dest;
+- else
+- evsel = evsel__new(&orig->core.attr);
+-
++ evsel = evsel__new(&orig->core.attr);
+ if (evsel == NULL)
+ return NULL;
+
+@@ -399,12 +395,11 @@ struct evsel *evsel__clone(struct evsel
+ evsel->core.leader = orig->core.leader;
+
+ evsel->max_events = orig->max_events;
+- zfree(&evsel->unit);
+- if (orig->unit) {
+- evsel->unit = strdup(orig->unit);
+- if (evsel->unit == NULL)
+- goto out_err;
+- }
++ free((char *)evsel->unit);
++ evsel->unit = strdup(orig->unit);
++ if (evsel->unit == NULL)
++ goto out_err;
++
+ evsel->scale = orig->scale;
+ evsel->snapshot = orig->snapshot;
+ evsel->per_pkg = orig->per_pkg;
+--- a/tools/perf/util/evsel.h
++++ b/tools/perf/util/evsel.h
+@@ -241,7 +241,7 @@ static inline struct evsel *evsel__new(s
+ return evsel__new_idx(attr, 0);
+ }
+
+-struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig);
++struct evsel *evsel__clone(struct evsel *orig);
+
+ int copy_config_terms(struct list_head *dst, struct list_head *src);
+ void free_config_terms(struct list_head *config_terms);
+--- a/tools/perf/util/python.c
++++ b/tools/perf/util/python.c
+@@ -13,7 +13,6 @@
+ #include "evsel.h"
+ #include "event.h"
+ #include "print_binary.h"
+-#include "strbuf.h"
+ #include "thread_map.h"
+ #include "trace-event.h"
+ #include "mmap.h"
+@@ -1248,60 +1247,6 @@ static PyObject *pyrf__tracepoint(struct
+ #endif // HAVE_LIBTRACEEVENT
+ }
+
+-static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
+-{
+- struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
+-
+- if (!pevsel)
+- return NULL;
+-
+- memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
+- evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
+-
+- evsel__clone(&pevsel->evsel, evsel);
+- return (PyObject *)pevsel;
+-}
+-
+-static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist)
+-{
+- struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type);
+- struct evsel *pos;
+-
+- if (!pevlist)
+- return NULL;
+-
+- memset(&pevlist->evlist, 0, sizeof(pevlist->evlist));
+- evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads);
+- evlist__for_each_entry(evlist, pos) {
+- struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos);
+-
+- evlist__add(&pevlist->evlist, &pevsel->evsel);
+- }
+- return (PyObject *)pevlist;
+-}
+-
+-static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
+-{
+- const char *input;
+- struct evlist evlist = {};
+- struct parse_events_error err;
+- PyObject *result;
+-
+- if (!PyArg_ParseTuple(args, "s", &input))
+- return NULL;
+-
+- parse_events_error__init(&err);
+- evlist__init(&evlist, NULL, NULL);
+- if (parse_events(&evlist, input, &err)) {
+- parse_events_error__print(&err, input);
+- PyErr_SetFromErrno(PyExc_OSError);
+- return NULL;
+- }
+- result = pyrf_evlist__from_evlist(&evlist);
+- evlist__exit(&evlist);
+- return result;
+-}
+-
+ static PyMethodDef perf__methods[] = {
+ {
+ .ml_name = "tracepoint",
+@@ -1309,12 +1254,6 @@ static PyMethodDef perf__methods[] = {
+ .ml_flags = METH_VARARGS | METH_KEYWORDS,
+ .ml_doc = PyDoc_STR("Get tracepoint config.")
+ },
+- {
+- .ml_name = "parse_events",
+- .ml_meth = (PyCFunction) pyrf__parse_events,
+- .ml_flags = METH_VARARGS,
+- .ml_doc = PyDoc_STR("Parse a string of events and return an evlist.")
+- },
+ { .ml_name = NULL, }
+ };
+
--- /dev/null
+From 0a56a56da306fbc202f01e7373295d6239716451 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 10:36:48 -0400
+Subject: Revert "perf tool_pmu: Factor tool events into their own PMU"
+
+This reverts commit 7cfcd01f33fc3400c60f923d2896a8cdc60cecc4.
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/perf/builtin-list.c | 13 +-
+ tools/perf/builtin-stat.c | 1 -
+ tools/perf/util/Build | 1 -
+ tools/perf/util/evsel.c | 272 ++++++++++++++++++++--
+ tools/perf/util/evsel.h | 28 ++-
+ tools/perf/util/metricgroup.c | 1 -
+ tools/perf/util/parse-events.c | 39 ++++
+ tools/perf/util/parse-events.h | 3 +
+ tools/perf/util/parse-events.l | 11 +
+ tools/perf/util/parse-events.y | 16 ++
+ tools/perf/util/pmu.c | 20 +-
+ tools/perf/util/pmu.h | 2 -
+ tools/perf/util/pmus.c | 9 -
+ tools/perf/util/print-events.c | 36 ++-
+ tools/perf/util/print-events.h | 1 +
+ tools/perf/util/stat-display.c | 6 +-
+ tools/perf/util/stat-shadow.c | 1 -
+ tools/perf/util/tool_pmu.c | 411 ---------------------------------
+ tools/perf/util/tool_pmu.h | 51 ----
+ 19 files changed, 392 insertions(+), 530 deletions(-)
+ delete mode 100644 tools/perf/util/tool_pmu.c
+ delete mode 100644 tools/perf/util/tool_pmu.h
+
+--- a/tools/perf/builtin-list.c
++++ b/tools/perf/builtin-list.c
+@@ -19,7 +19,6 @@
+ #include "util/string2.h"
+ #include "util/strlist.h"
+ #include "util/strbuf.h"
+-#include "util/tool_pmu.h"
+ #include <subcmd/pager.h>
+ #include <subcmd/parse-options.h>
+ #include <linux/zalloc.h>
+@@ -615,18 +614,9 @@ int cmd_list(int argc, const char **argv
+ event_symbols_hw, PERF_COUNT_HW_MAX);
+ else if (strcmp(argv[i], "sw") == 0 ||
+ strcmp(argv[i], "software") == 0) {
+- char *old_pmu_glob = default_ps.pmu_glob;
+-
+ print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE,
+ event_symbols_sw, PERF_COUNT_SW_MAX);
+- default_ps.pmu_glob = strdup("tool");
+- if (!default_ps.pmu_glob) {
+- ret = -1;
+- goto out;
+- }
+- perf_pmus__print_pmu_events(&print_cb, ps);
+- zfree(&default_ps.pmu_glob);
+- default_ps.pmu_glob = old_pmu_glob;
++ print_tool_events(&print_cb, ps);
+ } else if (strcmp(argv[i], "cache") == 0 ||
+ strcmp(argv[i], "hwcache") == 0)
+ print_hwcache_events(&print_cb, ps);
+@@ -674,6 +664,7 @@ int cmd_list(int argc, const char **argv
+ event_symbols_hw, PERF_COUNT_HW_MAX);
+ print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE,
+ event_symbols_sw, PERF_COUNT_SW_MAX);
++ print_tool_events(&print_cb, ps);
+ print_hwcache_events(&print_cb, ps);
+ perf_pmus__print_pmu_events(&print_cb, ps);
+ print_tracepoint_events(&print_cb, ps);
+--- a/tools/perf/builtin-stat.c
++++ b/tools/perf/builtin-stat.c
+@@ -46,7 +46,6 @@
+ #include "util/parse-events.h"
+ #include "util/pmus.h"
+ #include "util/pmu.h"
+-#include "util/tool_pmu.h"
+ #include "util/event.h"
+ #include "util/evlist.h"
+ #include "util/evsel.h"
+--- a/tools/perf/util/Build
++++ b/tools/perf/util/Build
+@@ -83,7 +83,6 @@ perf-util-y += pmu.o
+ perf-util-y += pmus.o
+ perf-util-y += pmu-flex.o
+ perf-util-y += pmu-bison.o
+-perf-util-y += tool_pmu.o
+ perf-util-y += svghelper.o
+ perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-info.o
+ perf-util-y += trace-event-scripting.o
+--- a/tools/perf/util/evsel.c
++++ b/tools/perf/util/evsel.c
+@@ -10,6 +10,7 @@
+ #include <errno.h>
+ #include <inttypes.h>
+ #include <linux/bitops.h>
++#include <api/io.h>
+ #include <api/fs/fs.h>
+ #include <api/fs/tracing_path.h>
+ #include <linux/hw_breakpoint.h>
+@@ -50,7 +51,6 @@
+ #include "off_cpu.h"
+ #include "pmu.h"
+ #include "pmus.h"
+-#include "tool_pmu.h"
+ #include "rlimit.h"
+ #include "../perf-sys.h"
+ #include "util/parse-branch-options.h"
+@@ -71,6 +71,33 @@ struct perf_missing_features perf_missin
+
+ static clockid_t clockid;
+
++static const char *const perf_tool_event__tool_names[PERF_TOOL_MAX] = {
++ NULL,
++ "duration_time",
++ "user_time",
++ "system_time",
++};
++
++const char *perf_tool_event__to_str(enum perf_tool_event ev)
++{
++ if (ev > PERF_TOOL_NONE && ev < PERF_TOOL_MAX)
++ return perf_tool_event__tool_names[ev];
++
++ return NULL;
++}
++
++enum perf_tool_event perf_tool_event__from_str(const char *str)
++{
++ int i;
++
++ perf_tool_event__for_each_event(i) {
++ if (!strcmp(str, perf_tool_event__tool_names[i]))
++ return i;
++ }
++ return PERF_TOOL_NONE;
++}
++
++
+ static int evsel__no_extra_init(struct evsel *evsel __maybe_unused)
+ {
+ return 0;
+@@ -395,6 +422,7 @@ struct evsel *evsel__clone(struct evsel
+ evsel->core.leader = orig->core.leader;
+
+ evsel->max_events = orig->max_events;
++ evsel->tool_event = orig->tool_event;
+ free((char *)evsel->unit);
+ evsel->unit = strdup(orig->unit);
+ if (evsel->unit == NULL)
+@@ -592,6 +620,11 @@ static int evsel__sw_name(struct evsel *
+ return r + evsel__add_modifiers(evsel, bf + r, size - r);
+ }
+
++static int evsel__tool_name(enum perf_tool_event ev, char *bf, size_t size)
++{
++ return scnprintf(bf, size, "%s", perf_tool_event__to_str(ev));
++}
++
+ static int __evsel__bp_name(char *bf, size_t size, u64 addr, u64 type)
+ {
+ int r;
+@@ -742,7 +775,10 @@ const char *evsel__name(struct evsel *ev
+ break;
+
+ case PERF_TYPE_SOFTWARE:
+- evsel__sw_name(evsel, bf, sizeof(bf));
++ if (evsel__is_tool(evsel))
++ evsel__tool_name(evsel__tool_event(evsel), bf, sizeof(bf));
++ else
++ evsel__sw_name(evsel, bf, sizeof(bf));
+ break;
+
+ case PERF_TYPE_TRACEPOINT:
+@@ -753,10 +789,6 @@ const char *evsel__name(struct evsel *ev
+ evsel__bp_name(evsel, bf, sizeof(bf));
+ break;
+
+- case PERF_PMU_TYPE_TOOL:
+- scnprintf(bf, sizeof(bf), "%s", evsel__tool_pmu_event_name(evsel));
+- break;
+-
+ default:
+ scnprintf(bf, sizeof(bf), "unknown attr type: %d",
+ evsel->core.attr.type);
+@@ -782,7 +814,7 @@ const char *evsel__metric_id(const struc
+ return evsel->metric_id;
+
+ if (evsel__is_tool(evsel))
+- return evsel__tool_pmu_event_name(evsel);
++ return perf_tool_event__to_str(evsel__tool_event(evsel));
+
+ return "unknown";
+ }
+@@ -1666,6 +1698,167 @@ static int evsel__read_group(struct evse
+ return evsel__process_group_data(leader, cpu_map_idx, thread, data);
+ }
+
++static bool read_until_char(struct io *io, char e)
++{
++ int c;
++
++ do {
++ c = io__get_char(io);
++ if (c == -1)
++ return false;
++ } while (c != e);
++ return true;
++}
++
++static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val)
++{
++ char buf[256];
++ struct io io;
++ int i;
++
++ io__init(&io, fd, buf, sizeof(buf));
++
++ /* Skip lines to relevant CPU. */
++ for (i = -1; i < cpu.cpu; i++) {
++ if (!read_until_char(&io, '\n'))
++ return -EINVAL;
++ }
++ /* Skip to "cpu". */
++ if (io__get_char(&io) != 'c') return -EINVAL;
++ if (io__get_char(&io) != 'p') return -EINVAL;
++ if (io__get_char(&io) != 'u') return -EINVAL;
++
++ /* Skip N of cpuN. */
++ if (!read_until_char(&io, ' '))
++ return -EINVAL;
++
++ i = 1;
++ while (true) {
++ if (io__get_dec(&io, val) != ' ')
++ break;
++ if (field == i)
++ return 0;
++ i++;
++ }
++ return -EINVAL;
++}
++
++static int read_pid_stat_field(int fd, int field, __u64 *val)
++{
++ char buf[256];
++ struct io io;
++ int c, i;
++
++ io__init(&io, fd, buf, sizeof(buf));
++ if (io__get_dec(&io, val) != ' ')
++ return -EINVAL;
++ if (field == 1)
++ return 0;
++
++ /* Skip comm. */
++ if (io__get_char(&io) != '(' || !read_until_char(&io, ')'))
++ return -EINVAL;
++ if (field == 2)
++ return -EINVAL; /* String can't be returned. */
++
++ /* Skip state */
++ if (io__get_char(&io) != ' ' || io__get_char(&io) == -1)
++ return -EINVAL;
++ if (field == 3)
++ return -EINVAL; /* String can't be returned. */
++
++ /* Loop over numeric fields*/
++ if (io__get_char(&io) != ' ')
++ return -EINVAL;
++
++ i = 4;
++ while (true) {
++ c = io__get_dec(&io, val);
++ if (c == -1)
++ return -EINVAL;
++ if (c == -2) {
++ /* Assume a -ve was read */
++ c = io__get_dec(&io, val);
++ *val *= -1;
++ }
++ if (c != ' ')
++ return -EINVAL;
++ if (field == i)
++ return 0;
++ i++;
++ }
++ return -EINVAL;
++}
++
++static int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread)
++{
++ __u64 *start_time, cur_time, delta_start;
++ int fd, err = 0;
++ struct perf_counts_values *count;
++ bool adjust = false;
++
++ count = perf_counts(evsel->counts, cpu_map_idx, thread);
++
++ switch (evsel__tool_event(evsel)) {
++ case PERF_TOOL_DURATION_TIME:
++ /*
++ * Pretend duration_time is only on the first CPU and thread, or
++ * else aggregation will scale duration_time by the number of
++ * CPUs/threads.
++ */
++ start_time = &evsel->start_time;
++ if (cpu_map_idx == 0 && thread == 0)
++ cur_time = rdclock();
++ else
++ cur_time = *start_time;
++ break;
++ case PERF_TOOL_USER_TIME:
++ case PERF_TOOL_SYSTEM_TIME: {
++ bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME;
++
++ start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread);
++ fd = FD(evsel, cpu_map_idx, thread);
++ lseek(fd, SEEK_SET, 0);
++ if (evsel->pid_stat) {
++ /* The event exists solely on 1 CPU. */
++ if (cpu_map_idx == 0)
++ err = read_pid_stat_field(fd, system ? 15 : 14, &cur_time);
++ else
++ cur_time = 0;
++ } else {
++ /* The event is for all threads. */
++ if (thread == 0) {
++ struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus,
++ cpu_map_idx);
++
++ err = read_stat_field(fd, cpu, system ? 3 : 1, &cur_time);
++ } else {
++ cur_time = 0;
++ }
++ }
++ adjust = true;
++ break;
++ }
++ case PERF_TOOL_NONE:
++ case PERF_TOOL_MAX:
++ default:
++ err = -EINVAL;
++ }
++ if (err)
++ return err;
++
++ delta_start = cur_time - *start_time;
++ if (adjust) {
++ __u64 ticks_per_sec = sysconf(_SC_CLK_TCK);
++
++ delta_start *= 1000000000 / ticks_per_sec;
++ }
++ count->val = delta_start;
++ count->ena = count->run = delta_start;
++ count->lost = 0;
++ return 0;
++}
++
+ bool __evsel__match(const struct evsel *evsel, u32 type, u64 config)
+ {
+
+@@ -1881,7 +2074,6 @@ static struct perf_thread_map *empty_thr
+ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus,
+ struct perf_thread_map *threads)
+ {
+- int ret = 0;
+ int nthreads = perf_thread_map__nr(threads);
+
+ if ((perf_missing_features.write_backward && evsel->core.attr.write_backward) ||
+@@ -1912,14 +2104,19 @@ static int __evsel__prepare_open(struct
+ perf_evsel__alloc_fd(&evsel->core, perf_cpu_map__nr(cpus), nthreads) < 0)
+ return -ENOMEM;
+
+- if (evsel__is_tool(evsel))
+- ret = evsel__tool_pmu_prepare_open(evsel, cpus, nthreads);
++ if ((evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME ||
++ evsel__tool_event(evsel) == PERF_TOOL_USER_TIME) &&
++ !evsel->start_times) {
++ evsel->start_times = xyarray__new(perf_cpu_map__nr(cpus), nthreads, sizeof(__u64));
++ if (!evsel->start_times)
++ return -ENOMEM;
++ }
+
+ evsel->open_flags = PERF_FLAG_FD_CLOEXEC;
+ if (evsel->cgrp)
+ evsel->open_flags |= PERF_FLAG_PID_CGROUP;
+
+- return ret;
++ return 0;
+ }
+
+ static void evsel__disable_missing_features(struct evsel *evsel)
+@@ -2097,6 +2294,13 @@ static int evsel__open_cpu(struct evsel
+ int pid = -1, err, old_errno;
+ enum rlimit_action set_rlimit = NO_CHANGE;
+
++ if (evsel__tool_event(evsel) == PERF_TOOL_DURATION_TIME) {
++ if (evsel->core.attr.sample_period) /* no sampling */
++ return -EINVAL;
++ evsel->start_time = rdclock();
++ return 0;
++ }
++
+ if (evsel__is_retire_lat(evsel))
+ return tpebs_start(evsel->evlist);
+
+@@ -2121,12 +2325,6 @@ fallback_missing_features:
+ pr_debug3("Opening: %s\n", evsel__name(evsel));
+ display_attr(&evsel->core.attr);
+
+- if (evsel__is_tool(evsel)) {
+- return evsel__tool_pmu_open(evsel, threads,
+- start_cpu_map_idx,
+- end_cpu_map_idx);
+- }
+-
+ for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) {
+
+ for (thread = 0; thread < nthreads; thread++) {
+@@ -2138,6 +2336,46 @@ retry_open:
+ if (!evsel->cgrp && !evsel->core.system_wide)
+ pid = perf_thread_map__pid(threads, thread);
+
++ if (evsel__tool_event(evsel) == PERF_TOOL_USER_TIME ||
++ evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME) {
++ bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME;
++ __u64 *start_time = NULL;
++
++ if (evsel->core.attr.sample_period) {
++ /* no sampling */
++ err = -EINVAL;
++ goto out_close;
++ }
++ if (pid > -1) {
++ char buf[64];
++
++ snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
++ fd = open(buf, O_RDONLY);
++ evsel->pid_stat = true;
++ } else {
++ fd = open("/proc/stat", O_RDONLY);
++ }
++ FD(evsel, idx, thread) = fd;
++ if (fd < 0) {
++ err = -errno;
++ goto out_close;
++ }
++ start_time = xyarray__entry(evsel->start_times, idx, thread);
++ if (pid > -1) {
++ err = read_pid_stat_field(fd, system ? 15 : 14,
++ start_time);
++ } else {
++ struct perf_cpu cpu;
++
++ cpu = perf_cpu_map__cpu(evsel->core.cpus, idx);
++ err = read_stat_field(fd, cpu, system ? 3 : 1,
++ start_time);
++ }
++ if (err)
++ goto out_close;
++ continue;
++ }
++
+ group_fd = get_group_fd(evsel, idx, thread);
+
+ if (group_fd == -2) {
+--- a/tools/perf/util/evsel.h
++++ b/tools/perf/util/evsel.h
+@@ -11,7 +11,6 @@
+ #include <perf/evsel.h>
+ #include "symbol_conf.h"
+ #include "pmus.h"
+-#include "pmu.h"
+
+ struct bpf_object;
+ struct cgroup;
+@@ -23,9 +22,25 @@ struct target;
+ struct hashmap;
+ struct bperf_leader_bpf;
+ struct bperf_follower_bpf;
++struct perf_pmu;
+
+ typedef int (evsel__sb_cb_t)(union perf_event *event, void *data);
+
++enum perf_tool_event {
++ PERF_TOOL_NONE = 0,
++ PERF_TOOL_DURATION_TIME = 1,
++ PERF_TOOL_USER_TIME = 2,
++ PERF_TOOL_SYSTEM_TIME = 3,
++
++ PERF_TOOL_MAX,
++};
++
++const char *perf_tool_event__to_str(enum perf_tool_event ev);
++enum perf_tool_event perf_tool_event__from_str(const char *str);
++
++#define perf_tool_event__for_each_event(ev) \
++ for ((ev) = PERF_TOOL_DURATION_TIME; (ev) < PERF_TOOL_MAX; ev++)
++
+ /** struct evsel - event selector
+ *
+ * @evlist - evlist this evsel is in, if it is in one.
+@@ -68,6 +83,7 @@ struct evsel {
+ const char *unit;
+ struct cgroup *cgrp;
+ const char *metric_id;
++ enum perf_tool_event tool_event;
+ /* parse modifier helper */
+ int exclude_GH;
+ int sample_read;
+@@ -307,11 +323,21 @@ const char *evsel__name(struct evsel *ev
+ bool evsel__name_is(struct evsel *evsel, const char *name);
+ const char *evsel__metric_id(const struct evsel *evsel);
+
++static inline bool evsel__is_tool(const struct evsel *evsel)
++{
++ return evsel->tool_event != PERF_TOOL_NONE;
++}
++
+ static inline bool evsel__is_retire_lat(const struct evsel *evsel)
+ {
+ return evsel->retire_lat;
+ }
+
++static inline enum perf_tool_event evsel__tool_event(const struct evsel *evsel)
++{
++ return evsel->tool_event;
++}
++
+ const char *evsel__group_name(struct evsel *evsel);
+ int evsel__group_desc(struct evsel *evsel, char *buf, size_t size);
+
+--- a/tools/perf/util/metricgroup.c
++++ b/tools/perf/util/metricgroup.c
+@@ -14,7 +14,6 @@
+ #include "pmus.h"
+ #include "print-events.h"
+ #include "smt.h"
+-#include "tool_pmu.h"
+ #include "expr.h"
+ #include "rblist.h"
+ #include <string.h>
+--- a/tools/perf/util/parse-events.c
++++ b/tools/perf/util/parse-events.c
+@@ -302,6 +302,38 @@ static int add_event(struct list_head *l
+ alternate_hw_config) ? 0 : -ENOMEM;
+ }
+
++static int add_event_tool(struct list_head *list, int *idx,
++ enum perf_tool_event tool_event)
++{
++ struct evsel *evsel;
++ struct perf_event_attr attr = {
++ .type = PERF_TYPE_SOFTWARE,
++ .config = PERF_COUNT_SW_DUMMY,
++ };
++ struct perf_cpu_map *cpu_list = NULL;
++
++ if (tool_event == PERF_TOOL_DURATION_TIME) {
++ /* Duration time is gathered globally, pretend it is only on CPU0. */
++ cpu_list = perf_cpu_map__new("0");
++ }
++ evsel = __add_event(list, idx, &attr, /*init_attr=*/true, /*name=*/NULL,
++ /*metric_id=*/NULL, /*pmu=*/NULL,
++ /*config_terms=*/NULL, /*auto_merge_stats=*/false,
++ cpu_list,
++ /*alternate_hw_config=*/PERF_COUNT_HW_MAX);
++ perf_cpu_map__put(cpu_list);
++ if (!evsel)
++ return -ENOMEM;
++ evsel->tool_event = tool_event;
++ if (tool_event == PERF_TOOL_DURATION_TIME
++ || tool_event == PERF_TOOL_USER_TIME
++ || tool_event == PERF_TOOL_SYSTEM_TIME) {
++ free((char *)evsel->unit);
++ evsel->unit = strdup("ns");
++ }
++ return 0;
++}
++
+ /**
+ * parse_aliases - search names for entries beginning or equalling str ignoring
+ * case. If mutliple entries in names match str then the longest
+@@ -1398,6 +1430,13 @@ int parse_events_add_numeric(struct pars
+ type, /*extended_type=*/0, config, head_config);
+ }
+
++int parse_events_add_tool(struct parse_events_state *parse_state,
++ struct list_head *list,
++ int tool_event)
++{
++ return add_event_tool(list, &parse_state->idx, tool_event);
++}
++
+ static bool config_term_percore(struct list_head *config_terms)
+ {
+ struct evsel_config_term *term;
+--- a/tools/perf/util/parse-events.h
++++ b/tools/perf/util/parse-events.h
+@@ -227,6 +227,9 @@ int parse_events_add_numeric(struct pars
+ u32 type, u64 config,
+ const struct parse_events_terms *head_config,
+ bool wildcard);
++int parse_events_add_tool(struct parse_events_state *parse_state,
++ struct list_head *list,
++ int tool_event);
+ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
+ struct parse_events_state *parse_state,
+ struct parse_events_terms *parsed_terms);
+--- a/tools/perf/util/parse-events.l
++++ b/tools/perf/util/parse-events.l
+@@ -121,6 +121,14 @@ static int sym(yyscan_t scanner, int typ
+ return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW;
+ }
+
++static int tool(yyscan_t scanner, enum perf_tool_event event)
++{
++ YYSTYPE *yylval = parse_events_get_lval(scanner);
++
++ yylval->num = event;
++ return PE_VALUE_SYM_TOOL;
++}
++
+ static int term(yyscan_t scanner, enum parse_events__term_type type)
+ {
+ YYSTYPE *yylval = parse_events_get_lval(scanner);
+@@ -396,6 +404,9 @@ cpu-migrations|migrations { return sym
+ alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+ emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+ dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
++duration_time { return tool(yyscanner, PERF_TOOL_DURATION_TIME); }
++user_time { return tool(yyscanner, PERF_TOOL_USER_TIME); }
++system_time { return tool(yyscanner, PERF_TOOL_SYSTEM_TIME); }
+ bpf-output { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); }
+ cgroup-switches { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CGROUP_SWITCHES); }
+
+--- a/tools/perf/util/parse-events.y
++++ b/tools/perf/util/parse-events.y
+@@ -56,6 +56,7 @@ static void free_list_evsel(struct list_
+
+ %token PE_START_EVENTS PE_START_TERMS
+ %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM
++%token PE_VALUE_SYM_TOOL
+ %token PE_EVENT_NAME
+ %token PE_RAW PE_NAME
+ %token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH
+@@ -67,6 +68,7 @@ static void free_list_evsel(struct list_
+ %type <num> PE_VALUE
+ %type <num> PE_VALUE_SYM_HW
+ %type <num> PE_VALUE_SYM_SW
++%type <num> PE_VALUE_SYM_TOOL
+ %type <mod> PE_MODIFIER_EVENT
+ %type <term_type> PE_TERM
+ %type <num> value_sym
+@@ -348,6 +350,20 @@ value_sym sep_slash_slash_dc
+ PE_ABORT(err);
+ $$ = list;
+ }
++|
++PE_VALUE_SYM_TOOL sep_slash_slash_dc
++{
++ struct list_head *list;
++ int err;
++
++ list = alloc_list();
++ if (!list)
++ YYNOMEM;
++ err = parse_events_add_tool(_parse_state, list, $1);
++ if (err)
++ YYNOMEM;
++ $$ = list;
++}
+
+ event_legacy_cache:
+ PE_LEGACY_CACHE opt_event_config
+--- a/tools/perf/util/pmu.c
++++ b/tools/perf/util/pmu.c
+@@ -19,7 +19,6 @@
+ #include "evsel.h"
+ #include "pmu.h"
+ #include "pmus.h"
+-#include "tool_pmu.h"
+ #include <util/pmu-bison.h>
+ #include <util/pmu-flex.h>
+ #include "parse-events.h"
+@@ -1512,9 +1511,6 @@ int perf_pmu__config(struct perf_pmu *pm
+ {
+ bool zero = !!pmu->perf_event_attr_init_default;
+
+- if (perf_pmu__is_tool(pmu))
+- return tool_pmu__config_terms(attr, head_terms, err);
+-
+ /* Fake PMU doesn't have proper terms so nothing to configure in attr. */
+ if (perf_pmu__is_fake(pmu))
+ return 0;
+@@ -1627,8 +1623,8 @@ int perf_pmu__check_alias(struct perf_pm
+ info->scale = 0.0;
+ info->snapshot = false;
+
+- /* Tool/fake PMU doesn't rewrite terms. */
+- if (perf_pmu__is_tool(pmu) || perf_pmu__is_fake(pmu))
++ /* Fake PMU doesn't rewrite terms. */
++ if (perf_pmu__is_fake(pmu))
+ goto out;
+
+ list_for_each_entry_safe(term, h, &head_terms->terms, list) {
+@@ -1798,8 +1794,6 @@ bool perf_pmu__have_event(struct perf_pm
+ {
+ if (!name)
+ return false;
+- if (perf_pmu__is_tool(pmu))
+- return perf_tool_event__from_str(name) != PERF_TOOL_NONE;
+ if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)
+ return true;
+ if (pmu->cpu_aliases_added || !pmu->events_table)
+@@ -1811,9 +1805,6 @@ size_t perf_pmu__num_events(struct perf_
+ {
+ size_t nr;
+
+- if (perf_pmu__is_tool(pmu))
+- return tool_pmu__num_events();
+-
+ pmu_aliases_parse(pmu);
+ nr = pmu->sysfs_aliases + pmu->sys_json_aliases;
+
+@@ -1875,9 +1866,6 @@ int perf_pmu__for_each_event(struct perf
+ int ret = 0;
+ struct strbuf sb;
+
+- if (perf_pmu__is_tool(pmu))
+- return tool_pmu__for_each_event_cb(pmu, state, cb);
+-
+ strbuf_init(&sb, /*hint=*/ 0);
+ pmu_aliases_parse(pmu);
+ pmu_add_cpu_aliases(pmu);
+@@ -1966,7 +1954,6 @@ bool perf_pmu__is_software(const struct
+ case PERF_TYPE_HW_CACHE: return false;
+ case PERF_TYPE_RAW: return false;
+ case PERF_TYPE_BREAKPOINT: return true;
+- case PERF_PMU_TYPE_TOOL: return true;
+ default: break;
+ }
+ for (size_t i = 0; i < ARRAY_SIZE(known_sw_pmus); i++) {
+@@ -2294,9 +2281,6 @@ const char *perf_pmu__name_from_config(s
+ if (!pmu)
+ return NULL;
+
+- if (perf_pmu__is_tool(pmu))
+- return perf_tool_event__to_str(config);
+-
+ pmu_aliases_parse(pmu);
+ pmu_add_cpu_aliases(pmu);
+ list_for_each_entry(event, &pmu->aliases, list) {
+--- a/tools/perf/util/pmu.h
++++ b/tools/perf/util/pmu.h
+@@ -37,7 +37,6 @@ struct perf_pmu_caps {
+ };
+
+ enum {
+- PERF_PMU_TYPE_TOOL = 0xFFFFFFFE,
+ PERF_PMU_TYPE_FAKE = 0xFFFFFFFF,
+ };
+
+@@ -286,7 +285,6 @@ struct perf_pmu *perf_pmu__lookup(struct
+ struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus);
+ void perf_pmu__delete(struct perf_pmu *pmu);
+ struct perf_pmu *perf_pmus__find_core_pmu(void);
+-
+ const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config);
+
+ #endif /* __PMU_H */
+--- a/tools/perf/util/pmus.c
++++ b/tools/perf/util/pmus.c
+@@ -15,7 +15,6 @@
+ #include "evsel.h"
+ #include "pmus.h"
+ #include "pmu.h"
+-#include "tool_pmu.h"
+ #include "print-events.h"
+ #include "strbuf.h"
+
+@@ -201,7 +200,6 @@ static void pmu_read_sysfs(bool core_onl
+ int fd;
+ DIR *dir;
+ struct dirent *dent;
+- struct perf_pmu *tool_pmu;
+
+ if (read_sysfs_all_pmus || (core_only && read_sysfs_core_pmus))
+ return;
+@@ -231,10 +229,6 @@ static void pmu_read_sysfs(bool core_onl
+ pr_err("Failure to set up any core PMUs\n");
+ }
+ list_sort(NULL, &core_pmus, pmus_cmp);
+- if (!core_only) {
+- tool_pmu = perf_pmus__tool_pmu();
+- list_add_tail(&tool_pmu->list, &other_pmus);
+- }
+ list_sort(NULL, &other_pmus, pmus_cmp);
+ if (!list_empty(&core_pmus)) {
+ read_sysfs_core_pmus = true;
+@@ -590,9 +584,6 @@ void perf_pmus__print_raw_pmu_events(con
+ int len = pmu_name_len_no_suffix(pmu->name);
+ const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)";
+
+- if (perf_pmu__is_tool(pmu))
+- continue;
+-
+ if (!pmu->is_core)
+ desc = NULL;
+
+--- a/tools/perf/util/print-events.c
++++ b/tools/perf/util/print-events.c
+@@ -29,7 +29,6 @@
+ #include "tracepoint.h"
+ #include "pfm.h"
+ #include "thread_map.h"
+-#include "tool_pmu.h"
+ #include "util.h"
+
+ #define MAX_NAME_LEN 100
+@@ -44,6 +43,21 @@ static const char * const event_type_des
+ "Hardware breakpoint",
+ };
+
++static const struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = {
++ [PERF_TOOL_DURATION_TIME] = {
++ .symbol = "duration_time",
++ .alias = "",
++ },
++ [PERF_TOOL_USER_TIME] = {
++ .symbol = "user_time",
++ .alias = "",
++ },
++ [PERF_TOOL_SYSTEM_TIME] = {
++ .symbol = "system_time",
++ .alias = "",
++ },
++};
++
+ /*
+ * Print the events from <debugfs_mount_point>/tracing/events
+ */
+@@ -328,6 +342,24 @@ int print_hwcache_events(const struct pr
+ return 0;
+ }
+
++void print_tool_events(const struct print_callbacks *print_cb, void *print_state)
++{
++ // Start at 1 because the first enum entry means no tool event.
++ for (int i = 1; i < PERF_TOOL_MAX; ++i) {
++ print_cb->print_event(print_state,
++ "tool",
++ /*pmu_name=*/NULL,
++ event_symbols_tool[i].symbol,
++ event_symbols_tool[i].alias,
++ /*scale_unit=*/NULL,
++ /*deprecated=*/false,
++ "Tool event",
++ /*desc=*/NULL,
++ /*long_desc=*/NULL,
++ /*encoding_desc=*/NULL);
++ }
++}
++
+ void print_symbol_events(const struct print_callbacks *print_cb, void *print_state,
+ unsigned int type, const struct event_symbol *syms,
+ unsigned int max)
+@@ -391,6 +423,8 @@ void print_events(const struct print_cal
+ print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE,
+ event_symbols_sw, PERF_COUNT_SW_MAX);
+
++ print_tool_events(print_cb, print_state);
++
+ print_hwcache_events(print_cb, print_state);
+
+ perf_pmus__print_pmu_events(print_cb, print_state);
+--- a/tools/perf/util/print-events.h
++++ b/tools/perf/util/print-events.h
+@@ -36,6 +36,7 @@ void print_sdt_events(const struct print
+ void print_symbol_events(const struct print_callbacks *print_cb, void *print_state,
+ unsigned int type, const struct event_symbol *syms,
+ unsigned int max);
++void print_tool_events(const struct print_callbacks *print_cb, void *print_state);
+ void print_tracepoint_events(const struct print_callbacks *print_cb, void *print_state);
+ bool is_event_supported(u8 type, u64 config);
+
+--- a/tools/perf/util/stat-display.c
++++ b/tools/perf/util/stat-display.c
+@@ -21,7 +21,6 @@
+ #include "iostat.h"
+ #include "pmu.h"
+ #include "pmus.h"
+-#include "tool_pmu.h"
+
+ #define CNTR_NOT_SUPPORTED "<not supported>"
+ #define CNTR_NOT_COUNTED "<not counted>"
+@@ -947,10 +946,7 @@ static bool should_skip_zero_counter(str
+ if (config->aggr_mode == AGGR_THREAD && config->system_wide)
+ return true;
+
+- /*
+- * Many tool events are only gathered on the first index, skip other
+- * zero values.
+- */
++ /* Tool events have the software PMU but are only gathered on 1. */
+ if (evsel__is_tool(counter))
+ return true;
+
+--- a/tools/perf/util/stat-shadow.c
++++ b/tools/perf/util/stat-shadow.c
+@@ -15,7 +15,6 @@
+ #include <linux/zalloc.h>
+ #include "iostat.h"
+ #include "util/hashmap.h"
+-#include "tool_pmu.h"
+
+ struct stats walltime_nsecs_stats;
+ struct rusage_stats ru_stats;
+--- a/tools/perf/util/tool_pmu.c
++++ /dev/null
+@@ -1,411 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+-#include "cgroup.h"
+-#include "counts.h"
+-#include "evsel.h"
+-#include "pmu.h"
+-#include "print-events.h"
+-#include "time-utils.h"
+-#include "tool_pmu.h"
+-#include <api/io.h>
+-#include <internal/threadmap.h>
+-#include <perf/threadmap.h>
+-#include <fcntl.h>
+-#include <strings.h>
+-
+-static const char *const tool_pmu__event_names[PERF_TOOL_MAX] = {
+- NULL,
+- "duration_time",
+- "user_time",
+- "system_time",
+-};
+-
+-
+-const char *perf_tool_event__to_str(enum perf_tool_event ev)
+-{
+- if (ev > PERF_TOOL_NONE && ev < PERF_TOOL_MAX)
+- return tool_pmu__event_names[ev];
+-
+- return NULL;
+-}
+-
+-enum perf_tool_event perf_tool_event__from_str(const char *str)
+-{
+- int i;
+-
+- perf_tool_event__for_each_event(i) {
+- if (!strcasecmp(str, tool_pmu__event_names[i]))
+- return i;
+- }
+- return PERF_TOOL_NONE;
+-}
+-
+-static int tool_pmu__config_term(struct perf_event_attr *attr,
+- struct parse_events_term *term,
+- struct parse_events_error *err)
+-{
+- if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {
+- enum perf_tool_event ev = perf_tool_event__from_str(term->config);
+-
+- if (ev == PERF_TOOL_NONE)
+- goto err_out;
+-
+- attr->config = ev;
+- return 0;
+- }
+-err_out:
+- if (err) {
+- char *err_str;
+-
+- parse_events_error__handle(err, term->err_val,
+- asprintf(&err_str,
+- "unexpected tool event term (%s) %s",
+- parse_events__term_type_str(term->type_term),
+- term->config) < 0
+- ? strdup("unexpected tool event term")
+- : err_str,
+- NULL);
+- }
+- return -EINVAL;
+-}
+-
+-int tool_pmu__config_terms(struct perf_event_attr *attr,
+- struct parse_events_terms *terms,
+- struct parse_events_error *err)
+-{
+- struct parse_events_term *term;
+-
+- list_for_each_entry(term, &terms->terms, list) {
+- if (tool_pmu__config_term(attr, term, err))
+- return -EINVAL;
+- }
+-
+- return 0;
+-
+-}
+-
+-int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb)
+-{
+- struct pmu_event_info info = {
+- .pmu = pmu,
+- .event_type_desc = "Tool event",
+- };
+- int i;
+-
+- perf_tool_event__for_each_event(i) {
+- int ret;
+-
+- info.name = perf_tool_event__to_str(i);
+- info.alias = NULL;
+- info.scale_unit = NULL;
+- info.desc = NULL;
+- info.long_desc = NULL;
+- info.encoding_desc = NULL;
+- info.topic = NULL;
+- info.pmu_name = pmu->name;
+- info.deprecated = false;
+- ret = cb(state, &info);
+- if (ret)
+- return ret;
+- }
+- return 0;
+-}
+-
+-bool perf_pmu__is_tool(const struct perf_pmu *pmu)
+-{
+- return pmu && pmu->type == PERF_PMU_TYPE_TOOL;
+-}
+-
+-bool evsel__is_tool(const struct evsel *evsel)
+-{
+- return perf_pmu__is_tool(evsel->pmu);
+-}
+-
+-enum perf_tool_event evsel__tool_event(const struct evsel *evsel)
+-{
+- if (!evsel__is_tool(evsel))
+- return PERF_TOOL_NONE;
+-
+- return (enum perf_tool_event)evsel->core.attr.config;
+-}
+-
+-const char *evsel__tool_pmu_event_name(const struct evsel *evsel)
+-{
+- return perf_tool_event__to_str(evsel->core.attr.config);
+-}
+-
+-static bool read_until_char(struct io *io, char e)
+-{
+- int c;
+-
+- do {
+- c = io__get_char(io);
+- if (c == -1)
+- return false;
+- } while (c != e);
+- return true;
+-}
+-
+-static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val)
+-{
+- char buf[256];
+- struct io io;
+- int i;
+-
+- io__init(&io, fd, buf, sizeof(buf));
+-
+- /* Skip lines to relevant CPU. */
+- for (i = -1; i < cpu.cpu; i++) {
+- if (!read_until_char(&io, '\n'))
+- return -EINVAL;
+- }
+- /* Skip to "cpu". */
+- if (io__get_char(&io) != 'c') return -EINVAL;
+- if (io__get_char(&io) != 'p') return -EINVAL;
+- if (io__get_char(&io) != 'u') return -EINVAL;
+-
+- /* Skip N of cpuN. */
+- if (!read_until_char(&io, ' '))
+- return -EINVAL;
+-
+- i = 1;
+- while (true) {
+- if (io__get_dec(&io, val) != ' ')
+- break;
+- if (field == i)
+- return 0;
+- i++;
+- }
+- return -EINVAL;
+-}
+-
+-static int read_pid_stat_field(int fd, int field, __u64 *val)
+-{
+- char buf[256];
+- struct io io;
+- int c, i;
+-
+- io__init(&io, fd, buf, sizeof(buf));
+- if (io__get_dec(&io, val) != ' ')
+- return -EINVAL;
+- if (field == 1)
+- return 0;
+-
+- /* Skip comm. */
+- if (io__get_char(&io) != '(' || !read_until_char(&io, ')'))
+- return -EINVAL;
+- if (field == 2)
+- return -EINVAL; /* String can't be returned. */
+-
+- /* Skip state */
+- if (io__get_char(&io) != ' ' || io__get_char(&io) == -1)
+- return -EINVAL;
+- if (field == 3)
+- return -EINVAL; /* String can't be returned. */
+-
+- /* Loop over numeric fields*/
+- if (io__get_char(&io) != ' ')
+- return -EINVAL;
+-
+- i = 4;
+- while (true) {
+- c = io__get_dec(&io, val);
+- if (c == -1)
+- return -EINVAL;
+- if (c == -2) {
+- /* Assume a -ve was read */
+- c = io__get_dec(&io, val);
+- *val *= -1;
+- }
+- if (c != ' ')
+- return -EINVAL;
+- if (field == i)
+- return 0;
+- i++;
+- }
+- return -EINVAL;
+-}
+-
+-int evsel__tool_pmu_prepare_open(struct evsel *evsel,
+- struct perf_cpu_map *cpus,
+- int nthreads)
+-{
+- if ((evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME ||
+- evsel__tool_event(evsel) == PERF_TOOL_USER_TIME) &&
+- !evsel->start_times) {
+- evsel->start_times = xyarray__new(perf_cpu_map__nr(cpus),
+- nthreads,
+- sizeof(__u64));
+- if (!evsel->start_times)
+- return -ENOMEM;
+- }
+- return 0;
+-}
+-
+-#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
+-
+-int evsel__tool_pmu_open(struct evsel *evsel,
+- struct perf_thread_map *threads,
+- int start_cpu_map_idx, int end_cpu_map_idx)
+-{
+- enum perf_tool_event ev = evsel__tool_event(evsel);
+- int pid = -1, idx = 0, thread = 0, nthreads, err = 0, old_errno;
+-
+- if (ev == PERF_TOOL_DURATION_TIME) {
+- if (evsel->core.attr.sample_period) /* no sampling */
+- return -EINVAL;
+- evsel->start_time = rdclock();
+- return 0;
+- }
+-
+- if (evsel->cgrp)
+- pid = evsel->cgrp->fd;
+-
+- nthreads = perf_thread_map__nr(threads);
+- for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) {
+- for (thread = 0; thread < nthreads; thread++) {
+- if (thread >= nthreads)
+- break;
+-
+- if (!evsel->cgrp && !evsel->core.system_wide)
+- pid = perf_thread_map__pid(threads, thread);
+-
+- if (ev == PERF_TOOL_USER_TIME || ev == PERF_TOOL_SYSTEM_TIME) {
+- bool system = ev == PERF_TOOL_SYSTEM_TIME;
+- __u64 *start_time = NULL;
+- int fd;
+-
+- if (evsel->core.attr.sample_period) {
+- /* no sampling */
+- err = -EINVAL;
+- goto out_close;
+- }
+- if (pid > -1) {
+- char buf[64];
+-
+- snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
+- fd = open(buf, O_RDONLY);
+- evsel->pid_stat = true;
+- } else {
+- fd = open("/proc/stat", O_RDONLY);
+- }
+- FD(evsel, idx, thread) = fd;
+- if (fd < 0) {
+- err = -errno;
+- goto out_close;
+- }
+- start_time = xyarray__entry(evsel->start_times, idx, thread);
+- if (pid > -1) {
+- err = read_pid_stat_field(fd, system ? 15 : 14,
+- start_time);
+- } else {
+- struct perf_cpu cpu;
+-
+- cpu = perf_cpu_map__cpu(evsel->core.cpus, idx);
+- err = read_stat_field(fd, cpu, system ? 3 : 1,
+- start_time);
+- }
+- if (err)
+- goto out_close;
+- }
+-
+- }
+- }
+- return 0;
+-out_close:
+- if (err)
+- threads->err_thread = thread;
+-
+- old_errno = errno;
+- do {
+- while (--thread >= 0) {
+- if (FD(evsel, idx, thread) >= 0)
+- close(FD(evsel, idx, thread));
+- FD(evsel, idx, thread) = -1;
+- }
+- thread = nthreads;
+- } while (--idx >= 0);
+- errno = old_errno;
+- return err;
+-}
+-
+-int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread)
+-{
+- __u64 *start_time, cur_time, delta_start;
+- int fd, err = 0;
+- struct perf_counts_values *count;
+- bool adjust = false;
+-
+- count = perf_counts(evsel->counts, cpu_map_idx, thread);
+-
+- switch (evsel__tool_event(evsel)) {
+- case PERF_TOOL_DURATION_TIME:
+- /*
+- * Pretend duration_time is only on the first CPU and thread, or
+- * else aggregation will scale duration_time by the number of
+- * CPUs/threads.
+- */
+- start_time = &evsel->start_time;
+- if (cpu_map_idx == 0 && thread == 0)
+- cur_time = rdclock();
+- else
+- cur_time = *start_time;
+- break;
+- case PERF_TOOL_USER_TIME:
+- case PERF_TOOL_SYSTEM_TIME: {
+- bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME;
+-
+- start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread);
+- fd = FD(evsel, cpu_map_idx, thread);
+- lseek(fd, SEEK_SET, 0);
+- if (evsel->pid_stat) {
+- /* The event exists solely on 1 CPU. */
+- if (cpu_map_idx == 0)
+- err = read_pid_stat_field(fd, system ? 15 : 14, &cur_time);
+- else
+- cur_time = 0;
+- } else {
+- /* The event is for all threads. */
+- if (thread == 0) {
+- struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus,
+- cpu_map_idx);
+-
+- err = read_stat_field(fd, cpu, system ? 3 : 1, &cur_time);
+- } else {
+- cur_time = 0;
+- }
+- }
+- adjust = true;
+- break;
+- }
+- case PERF_TOOL_NONE:
+- case PERF_TOOL_MAX:
+- default:
+- err = -EINVAL;
+- }
+- if (err)
+- return err;
+-
+- delta_start = cur_time - *start_time;
+- if (adjust) {
+- __u64 ticks_per_sec = sysconf(_SC_CLK_TCK);
+-
+- delta_start *= 1000000000 / ticks_per_sec;
+- }
+- count->val = delta_start;
+- count->ena = count->run = delta_start;
+- count->lost = 0;
+- return 0;
+-}
+-
+-struct perf_pmu *perf_pmus__tool_pmu(void)
+-{
+- static struct perf_pmu tool = {
+- .name = "tool",
+- .type = PERF_PMU_TYPE_TOOL,
+- .aliases = LIST_HEAD_INIT(tool.aliases),
+- .caps = LIST_HEAD_INIT(tool.caps),
+- .format = LIST_HEAD_INIT(tool.format),
+- };
+-
+- return &tool;
+-}
+--- a/tools/perf/util/tool_pmu.h
++++ /dev/null
+@@ -1,51 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-#ifndef __TOOL_PMU_H
+-#define __TOOL_PMU_H
+-
+-#include "pmu.h"
+-
+-struct evsel;
+-struct perf_thread_map;
+-struct print_callbacks;
+-
+-enum perf_tool_event {
+- PERF_TOOL_NONE = 0,
+- PERF_TOOL_DURATION_TIME = 1,
+- PERF_TOOL_USER_TIME = 2,
+- PERF_TOOL_SYSTEM_TIME = 3,
+-
+- PERF_TOOL_MAX,
+-};
+-
+-#define perf_tool_event__for_each_event(ev) \
+- for ((ev) = PERF_TOOL_DURATION_TIME; (ev) < PERF_TOOL_MAX; ev++)
+-
+-static inline size_t tool_pmu__num_events(void)
+-{
+- return PERF_TOOL_MAX - 1;
+-}
+-
+-const char *perf_tool_event__to_str(enum perf_tool_event ev);
+-enum perf_tool_event perf_tool_event__from_str(const char *str);
+-int tool_pmu__config_terms(struct perf_event_attr *attr,
+- struct parse_events_terms *terms,
+- struct parse_events_error *err);
+-int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb);
+-
+-bool perf_pmu__is_tool(const struct perf_pmu *pmu);
+-
+-
+-bool evsel__is_tool(const struct evsel *evsel);
+-enum perf_tool_event evsel__tool_event(const struct evsel *evsel);
+-const char *evsel__tool_pmu_event_name(const struct evsel *evsel);
+-int evsel__tool_pmu_prepare_open(struct evsel *evsel,
+- struct perf_cpu_map *cpus,
+- int nthreads);
+-int evsel__tool_pmu_open(struct evsel *evsel,
+- struct perf_thread_map *threads,
+- int start_cpu_map_idx, int end_cpu_map_idx);
+-int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread);
+-
+-struct perf_pmu *perf_pmus__tool_pmu(void);
+-
+-#endif /* __TOOL_PMU_H */
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
-@@ -3504,6 +3504,10 @@ ppp_connect_channel(struct channel *pch,
+@@ -3507,6 +3507,10 @@ ppp_connect_channel(struct channel *pch,
ret = -ENOTCONN;
goto outl;
}
ppp->file.hdrlen = pch->file.hdrlen;
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
-@@ -693,6 +693,7 @@ static int pppoe_connect(struct socket *
+@@ -699,6 +699,7 @@ static int pppoe_connect(struct socket *
po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
po->chan.private = sk;
po->chan.ops = &pppoe_chan_ops;
};
/*
-@@ -1541,23 +1528,12 @@ ppp_net_siocdevprivate(struct net_device
+@@ -1544,23 +1531,12 @@ ppp_net_siocdevprivate(struct net_device
static void
ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64)
{
}
static int ppp_dev_init(struct net_device *dev)
-@@ -1655,6 +1631,7 @@ static void ppp_setup(struct net_device
+@@ -1658,6 +1634,7 @@ static void ppp_setup(struct net_device
dev->type = ARPHRD_PPP;
dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
dev->priv_destructor = ppp_dev_priv_destructor;
netif_keep_dst(dev);
}
-@@ -1800,8 +1777,7 @@ ppp_send_frame(struct ppp *ppp, struct s
+@@ -1803,8 +1780,7 @@ ppp_send_frame(struct ppp *ppp, struct s
#endif /* CONFIG_PPP_FILTER */
}
switch (proto) {
case PPP_IP:
-@@ -2479,8 +2455,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp,
+@@ -2482,8 +2458,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp,
break;
}
npi = proto_to_npindex(proto);
if (npi < 0) {
-@@ -3308,14 +3283,25 @@ static void
+@@ -3311,14 +3286,25 @@ static void
ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
{
struct slcompress *vj = ppp->vj;
synchronize_rcu();
-@@ -2144,10 +2144,9 @@ static int ppp_mp_explode(struct ppp *pp
+@@ -2147,10 +2147,9 @@ static int ppp_mp_explode(struct ppp *pp
#endif /* CONFIG_PPP_MULTILINK */
/* Try to send data out on a channel */
spin_lock(&pch->downl);
if (pch->chan) {
-@@ -2166,7 +2165,6 @@ static void __ppp_channel_push(struct ch
+@@ -2169,7 +2168,6 @@ static void __ppp_channel_push(struct ch
spin_unlock(&pch->downl);
/* see if there is anything from the attached unit to be sent */
if (skb_queue_empty(&pch->file.xq)) {
if (ppp)
__ppp_xmit_process(ppp, NULL);
}
-@@ -2174,15 +2172,18 @@ static void __ppp_channel_push(struct ch
+@@ -2177,15 +2175,18 @@ static void __ppp_channel_push(struct ch
static void ppp_channel_push(struct channel *pch)
{
}
/*
-@@ -2284,6 +2285,7 @@ void
+@@ -2287,6 +2288,7 @@ void
ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
{
struct channel *pch = chan->ppp;
int proto;
if (!pch) {
-@@ -2295,18 +2297,19 @@ ppp_input(struct ppp_channel *chan, stru
+@@ -2298,18 +2300,19 @@ ppp_input(struct ppp_channel *chan, stru
if (ppp_channel_bridge_input(pch, skb))
return;
/* put it on the channel queue */
skb_queue_tail(&pch->file.rq, skb);
/* drop old frames if queue too long */
-@@ -2315,11 +2318,11 @@ ppp_input(struct ppp_channel *chan, stru
+@@ -2318,11 +2321,11 @@ ppp_input(struct ppp_channel *chan, stru
kfree_skb(skb);
wake_up_interruptible(&pch->file.rwait);
} else {
}
/* Put a 0-length skb in the receive queue as an error indication */
-@@ -2328,20 +2331,22 @@ ppp_input_error(struct ppp_channel *chan
+@@ -2331,20 +2334,22 @@ ppp_input_error(struct ppp_channel *chan
{
struct channel *pch = chan->ppp;
struct sk_buff *skb;
}
/*
-@@ -2889,7 +2894,6 @@ int ppp_register_net_channel(struct net
+@@ -2892,7 +2897,6 @@ int ppp_register_net_channel(struct net
pn = ppp_pernet(net);
pch->chan = chan;
pch->chan_net = get_net_track(net, &pch->ns_tracker, GFP_KERNEL);
chan->ppp = pch;
-@@ -2900,7 +2904,7 @@ int ppp_register_net_channel(struct net
+@@ -2903,7 +2907,7 @@ int ppp_register_net_channel(struct net
#endif /* CONFIG_PPP_MULTILINK */
init_rwsem(&pch->chan_sem);
spin_lock_init(&pch->downl);
spin_lock_bh(&pn->all_channels_lock);
pch->file.index = ++pn->last_channel_index;
-@@ -2929,13 +2933,15 @@ int ppp_channel_index(struct ppp_channel
+@@ -2932,13 +2936,15 @@ int ppp_channel_index(struct ppp_channel
int ppp_unit_number(struct ppp_channel *chan)
{
struct channel *pch = chan->ppp;
}
return unit;
}
-@@ -2947,12 +2953,14 @@ char *ppp_dev_name(struct ppp_channel *c
+@@ -2950,12 +2956,14 @@ char *ppp_dev_name(struct ppp_channel *c
{
struct channel *pch = chan->ppp;
char *name = NULL;
}
return name;
}
-@@ -3475,9 +3483,9 @@ ppp_connect_channel(struct channel *pch,
+@@ -3478,9 +3486,9 @@ ppp_connect_channel(struct channel *pch,
ppp = ppp_find_unit(pn, unit);
if (!ppp)
goto out;
rcu_dereference_protected(pch->bridge, lockdep_is_held(&pch->upl)))
goto outl;
-@@ -3502,13 +3510,13 @@ ppp_connect_channel(struct channel *pch,
+@@ -3505,13 +3513,13 @@ ppp_connect_channel(struct channel *pch,
ppp->dev->hard_header_len = hdrlen;
list_add_tail_rcu(&pch->clist, &ppp->channels);
++ppp->n_channels;
out:
mutex_unlock(&pn->all_ppp_mutex);
return ret;
-@@ -3523,10 +3531,9 @@ ppp_disconnect_channel(struct channel *p
+@@ -3526,10 +3534,9 @@ ppp_disconnect_channel(struct channel *p
struct ppp *ppp;
int err = -EINVAL;
}
static int pppoe_device_event(struct notifier_block *this,
-@@ -528,6 +534,11 @@ static struct proto pppoe_sk_proto __rea
+@@ -534,6 +540,11 @@ static struct proto pppoe_sk_proto __rea
.obj_size = sizeof(struct pppox_sock),
};
/***********************************************************************
*
* Initialize a new struct sock.
-@@ -542,11 +553,13 @@ static int pppoe_create(struct net *net,
+@@ -548,11 +559,13 @@ static int pppoe_create(struct net *net,
return -ENOMEM;
sock_init_data(sock, sk);
sk->sk_state = PPPOX_NONE;
sk->sk_type = SOCK_STREAM;
sk->sk_family = PF_PPPOX;
-@@ -599,7 +612,6 @@ static int pppoe_release(struct socket *
+@@ -605,7 +618,6 @@ static int pppoe_release(struct socket *
sock_orphan(sk);
sock->sk = NULL;
release_sock(sk);
sock_put(sk);
-@@ -681,9 +693,9 @@ static int pppoe_connect(struct socket *
+@@ -687,9 +699,9 @@ static int pppoe_connect(struct socket *
&sp->sa_addr.pppoe,
sizeof(struct pppoe_addr));
if (error < 0)
goto err_put;
-@@ -1052,11 +1064,11 @@ static inline struct pppox_sock *pppoe_g
+@@ -1058,11 +1070,11 @@ static inline struct pppox_sock *pppoe_g
int i;
for (i = 0; i < PPPOE_HASH_SIZE; i++) {
}
}
-@@ -1065,19 +1077,19 @@ out:
+@@ -1071,19 +1083,19 @@ out:
}
static void *pppoe_seq_start(struct seq_file *seq, loff_t *pos)
++*pos;
if (v == SEQ_START_TOKEN) {
-@@ -1085,14 +1097,15 @@ static void *pppoe_seq_next(struct seq_f
+@@ -1091,14 +1103,15 @@ static void *pppoe_seq_next(struct seq_f
goto out;
}
po = v;
if (po)
break;
}
-@@ -1103,10 +1116,9 @@ out:
+@@ -1109,10 +1122,9 @@ out:
}
static void pppoe_seq_stop(struct seq_file *seq, void *v)
}
static const struct seq_operations pppoe_seq_ops = {
-@@ -1149,7 +1161,7 @@ static __net_init int pppoe_init_net(str
+@@ -1155,7 +1167,7 @@ static __net_init int pppoe_init_net(str
struct pppoe_net *pn = pppoe_pernet(net);
struct proc_dir_entry *pde;
abort_kfree:
kfree_skb(skb);
return NET_RX_DROP;
-@@ -447,14 +440,11 @@ static int pppoe_rcv(struct sk_buff *skb
+@@ -453,14 +446,11 @@ static int pppoe_rcv(struct sk_buff *skb
ph = pppoe_hdr(skb);
pn = pppoe_pernet(dev_net(dev));
drop:
kfree_skb(skb);
-@@ -820,11 +810,12 @@ static int pppoe_ioctl(struct socket *so
+@@ -826,11 +816,12 @@ static int pppoe_ioctl(struct socket *so
/* Check that the socket referenced by the address
actually exists. */
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
-@@ -1632,6 +1632,8 @@ static void ppp_setup(struct net_device
+@@ -1635,6 +1635,8 @@ static void ppp_setup(struct net_device
dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
dev->priv_destructor = ppp_dev_priv_destructor;
dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
netif_keep_dst(dev);
}
-@@ -1696,6 +1698,10 @@ pad_compress_skb(struct ppp *ppp, struct
+@@ -1699,6 +1701,10 @@ pad_compress_skb(struct ppp *ppp, struct
ppp->xcomp->comp_extra + ppp->dev->hard_header_len;
int compressor_skb_size = ppp->dev->mtu +
ppp->xcomp->comp_extra + PPP_HDRLEN;
new_skb = alloc_skb(new_skb_size, GFP_ATOMIC);
if (!new_skb) {
if (net_ratelimit())
-@@ -1783,6 +1789,10 @@ ppp_send_frame(struct ppp *ppp, struct s
+@@ -1786,6 +1792,10 @@ ppp_send_frame(struct ppp *ppp, struct s
case PPP_IP:
if (!ppp->vj || (ppp->flags & SC_COMP_TCP) == 0)
break;
/* try to do VJ TCP header compression */
new_skb = alloc_skb(skb->len + ppp->dev->hard_header_len - 2,
GFP_ATOMIC);
-@@ -1880,19 +1890,26 @@ ppp_push(struct ppp *ppp)
+@@ -1883,19 +1893,26 @@ ppp_push(struct ppp *ppp)
}
if ((ppp->flags & SC_MULTILINK) == 0) {
spin_unlock(&pch->downl);
return;
}
-@@ -1977,6 +1994,8 @@ static int ppp_mp_explode(struct ppp *pp
+@@ -1980,6 +1997,8 @@ static int ppp_mp_explode(struct ppp *pp
return 0; /* can't take now, leave it in xmit_pending */
/* Do protocol field compression */
p = skb->data;
len = skb->len;
if (*p == 0 && mp_protocol_compress) {
-@@ -2135,6 +2154,7 @@ static int ppp_mp_explode(struct ppp *pp
+@@ -2138,6 +2157,7 @@ static int ppp_mp_explode(struct ppp *pp
noskb:
spin_unlock(&pch->downl);
#include <linux/uaccess.h>
-@@ -434,7 +435,7 @@ static int pppoe_rcv(struct sk_buff *skb
- if (skb->len < len)
+@@ -440,7 +441,7 @@ static int pppoe_rcv(struct sk_buff *skb
+ if (ppp_skb_is_compressed_proto(skb))
goto drop;
- if (pskb_trim_rcsum(skb, len))
goto drop;
ph = pppoe_hdr(skb);
-@@ -1176,6 +1177,160 @@ static struct pernet_operations pppoe_ne
+@@ -1182,6 +1183,160 @@ static struct pernet_operations pppoe_ne
.size = sizeof(struct pppoe_net),
};
static int __init pppoe_init(void)
{
int err;
-@@ -1192,6 +1347,8 @@ static int __init pppoe_init(void)
+@@ -1198,6 +1353,8 @@ static int __init pppoe_init(void)
if (err)
goto out_unregister_pppoe_proto;
dev_add_pack(&pppoes_ptype);
dev_add_pack(&pppoed_ptype);
register_netdevice_notifier(&pppoe_notifier);
-@@ -1211,6 +1368,8 @@ static void __exit pppoe_exit(void)
+@@ -1217,6 +1374,8 @@ static void __exit pppoe_exit(void)
unregister_netdevice_notifier(&pppoe_notifier);
dev_remove_pack(&pppoed_ptype);
dev_remove_pack(&pppoes_ptype);
goto retry;
}
-@@ -2311,7 +2316,7 @@ static int cake_config_besteffort(struct
+@@ -2312,7 +2317,7 @@ static int cake_config_besteffort(struct
struct cake_sched_data *q = qdisc_priv(sch);
struct cake_tin_data *b = &q->tins[0];
u32 mtu = psched_mtu(qdisc_dev(sch));
q->tin_cnt = 1;
-@@ -2319,7 +2324,7 @@ static int cake_config_besteffort(struct
+@@ -2320,7 +2325,7 @@ static int cake_config_besteffort(struct
q->tin_order = normal_order;
cake_set_rate(b, rate, mtu,
b->tin_quantum = 65535;
return 0;
-@@ -2330,7 +2335,7 @@ static int cake_config_precedence(struct
+@@ -2331,7 +2336,7 @@ static int cake_config_precedence(struct
/* convert high-level (user visible) parameters into internal format */
struct cake_sched_data *q = qdisc_priv(sch);
u32 mtu = psched_mtu(qdisc_dev(sch));
u32 quantum = 256;
u32 i;
-@@ -2341,8 +2346,8 @@ static int cake_config_precedence(struct
+@@ -2342,8 +2347,8 @@ static int cake_config_precedence(struct
for (i = 0; i < q->tin_cnt; i++) {
struct cake_tin_data *b = &q->tins[i];
b->tin_quantum = max_t(u16, 1U, quantum);
-@@ -2419,7 +2424,7 @@ static int cake_config_diffserv8(struct
+@@ -2420,7 +2425,7 @@ static int cake_config_diffserv8(struct
struct cake_sched_data *q = qdisc_priv(sch);
u32 mtu = psched_mtu(qdisc_dev(sch));
u32 quantum = 256;
u32 i;
-@@ -2433,8 +2438,8 @@ static int cake_config_diffserv8(struct
+@@ -2434,8 +2439,8 @@ static int cake_config_diffserv8(struct
for (i = 0; i < q->tin_cnt; i++) {
struct cake_tin_data *b = &q->tins[i];
b->tin_quantum = max_t(u16, 1U, quantum);
-@@ -2463,7 +2468,7 @@ static int cake_config_diffserv4(struct
+@@ -2464,7 +2469,7 @@ static int cake_config_diffserv4(struct
struct cake_sched_data *q = qdisc_priv(sch);
u32 mtu = psched_mtu(qdisc_dev(sch));
u32 quantum = 1024;
q->tin_cnt = 4;
-@@ -2474,13 +2479,13 @@ static int cake_config_diffserv4(struct
+@@ -2475,13 +2480,13 @@ static int cake_config_diffserv4(struct
/* class characteristics */
cake_set_rate(&q->tins[0], rate, mtu,
/* bandwidth-sharing weights */
q->tins[0].tin_quantum = quantum;
-@@ -2500,7 +2505,7 @@ static int cake_config_diffserv3(struct
+@@ -2501,7 +2506,7 @@ static int cake_config_diffserv3(struct
*/
struct cake_sched_data *q = qdisc_priv(sch);
u32 mtu = psched_mtu(qdisc_dev(sch));
u32 quantum = 1024;
q->tin_cnt = 3;
-@@ -2511,11 +2516,11 @@ static int cake_config_diffserv3(struct
+@@ -2512,11 +2517,11 @@ static int cake_config_diffserv3(struct
/* class characteristics */
cake_set_rate(&q->tins[0], rate, mtu,
/* bandwidth-sharing weights */
q->tins[0].tin_quantum = quantum;
-@@ -2527,7 +2532,8 @@ static int cake_config_diffserv3(struct
+@@ -2528,7 +2533,8 @@ static int cake_config_diffserv3(struct
static void cake_reconfigure(struct Qdisc *sch)
{
int c, ft;
switch (q->tin_mode) {
-@@ -2553,36 +2559,37 @@ static void cake_reconfigure(struct Qdis
+@@ -2554,36 +2560,37 @@ static void cake_reconfigure(struct Qdis
break;
}
struct nlattr *tb[TCA_CAKE_MAX + 1];
u16 rate_flags;
u8 flow_mode;
-@@ -2636,19 +2643,19 @@ static int cake_change(struct Qdisc *sch
+@@ -2637,19 +2644,19 @@ static int cake_change(struct Qdisc *sch
nla_get_s32(tb[TCA_CAKE_OVERHEAD]));
rate_flags |= CAKE_FLAG_OVERHEAD;
}
if (tb[TCA_CAKE_MPU])
-@@ -2704,7 +2711,7 @@ static int cake_change(struct Qdisc *sch
+@@ -2705,7 +2712,7 @@ static int cake_change(struct Qdisc *sch
WRITE_ONCE(q->rate_flags, rate_flags);
WRITE_ONCE(q->flow_mode, flow_mode);
sch_tree_lock(sch);
cake_reconfigure(sch);
sch_tree_unlock(sch);
-@@ -2720,14 +2727,20 @@ static void cake_destroy(struct Qdisc *s
+@@ -2721,14 +2728,20 @@ static void cake_destroy(struct Qdisc *s
qdisc_watchdog_cancel(&q->watchdog);
tcf_block_put(q->block);
kvfree(q->tins);
sch->limit = 10240;
q->tin_mode = CAKE_DIFFSERV_DIFFSERV3;
q->flow_mode = CAKE_FLOW_TRIPLE;
-@@ -2739,33 +2752,36 @@ static int cake_init(struct Qdisc *sch,
+@@ -2740,33 +2753,36 @@ static int cake_init(struct Qdisc *sch,
* for 5 to 10% of interval
*/
q->rate_flags |= CAKE_FLAG_SPLIT_GSO;
INIT_LIST_HEAD(&b->new_flows);
INIT_LIST_HEAD(&b->old_flows);
-@@ -2781,22 +2797,27 @@ static int cake_init(struct Qdisc *sch,
+@@ -2782,22 +2798,27 @@ static int cake_init(struct Qdisc *sch,
INIT_LIST_HEAD(&flow->flowchain);
cobalt_vars_init(&flow->cvars);
#include <net/pkt_cls.h>
#include <net/tcp.h>
#include <net/flow_dissector.h>
-@@ -3154,14 +3155,89 @@ static struct Qdisc_ops cake_qdisc_ops _
+@@ -3155,14 +3156,89 @@ static struct Qdisc_ops cake_qdisc_ops _
};
MODULE_ALIAS_NET_SCH("cake");
}
module_init(cake_module_init)
-@@ -3169,3 +3245,4 @@ module_exit(cake_module_exit)
+@@ -3170,3 +3246,4 @@ module_exit(cake_module_exit)
MODULE_AUTHOR("Jonathan Morton");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("The CAKE shaper.");
};
struct cake_sched_data {
-@@ -2586,14 +2587,12 @@ static void cake_reconfigure(struct Qdis
+@@ -2587,14 +2588,12 @@ static void cake_reconfigure(struct Qdis
q->buffer_config_limit));
}
int err;
err = nla_parse_nested_deprecated(tb, TCA_CAKE_MAX, opt, cake_policy,
-@@ -2601,7 +2600,6 @@ static int cake_change(struct Qdisc *sch
+@@ -2602,7 +2601,6 @@ static int cake_change(struct Qdisc *sch
if (err < 0)
return err;
if (tb[TCA_CAKE_NAT]) {
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
flow_mode &= ~CAKE_FLOW_NAT_FLAG;
-@@ -2614,6 +2612,19 @@ static int cake_change(struct Qdisc *sch
+@@ -2615,6 +2613,19 @@ static int cake_change(struct Qdisc *sch
#endif
}
if (tb[TCA_CAKE_BASE_RATE64])
WRITE_ONCE(q->rate_bps,
nla_get_u64(tb[TCA_CAKE_BASE_RATE64]));
-@@ -2622,7 +2633,6 @@ static int cake_change(struct Qdisc *sch
+@@ -2623,7 +2634,6 @@ static int cake_change(struct Qdisc *sch
WRITE_ONCE(q->tin_mode,
nla_get_u32(tb[TCA_CAKE_DIFFSERV_MODE]));
if (tb[TCA_CAKE_WASH]) {
if (!!nla_get_u32(tb[TCA_CAKE_WASH]))
rate_flags |= CAKE_FLAG_WASH;
-@@ -2643,20 +2653,12 @@ static int cake_change(struct Qdisc *sch
+@@ -2644,20 +2654,12 @@ static int cake_change(struct Qdisc *sch
WRITE_ONCE(q->rate_overhead,
nla_get_s32(tb[TCA_CAKE_OVERHEAD]));
rate_flags |= CAKE_FLAG_OVERHEAD;
}
if (tb[TCA_CAKE_MPU])
-@@ -2675,13 +2677,6 @@ static int cake_change(struct Qdisc *sch
+@@ -2676,13 +2678,6 @@ static int cake_change(struct Qdisc *sch
WRITE_ONCE(q->target, max(target, 1U));
}
if (tb[TCA_CAKE_INGRESS]) {
if (!!nla_get_u32(tb[TCA_CAKE_INGRESS]))
rate_flags |= CAKE_FLAG_INGRESS;
-@@ -2712,6 +2707,34 @@ static int cake_change(struct Qdisc *sch
+@@ -2713,6 +2708,34 @@ static int cake_change(struct Qdisc *sch
WRITE_ONCE(q->rate_flags, rate_flags);
WRITE_ONCE(q->flow_mode, flow_mode);
if (qd->tins) {
sch_tree_lock(sch);
cake_reconfigure(sch);
-@@ -2728,7 +2751,23 @@ static void cake_destroy(struct Qdisc *s
+@@ -2729,7 +2752,23 @@ static void cake_destroy(struct Qdisc *s
qdisc_watchdog_cancel(&q->watchdog);
tcf_block_put(q->block);
kvfree(q->tins);
}
static int cake_init(struct Qdisc *sch, struct nlattr *opt,
-@@ -2742,17 +2781,9 @@ static int cake_init(struct Qdisc *sch,
+@@ -2743,17 +2782,9 @@ static int cake_init(struct Qdisc *sch,
if (!q)
return -ENOMEM;
qd->cur_tin = 0;
qd->cur_flow = 0;
qd->config = q;
-@@ -2815,10 +2846,21 @@ err:
+@@ -2816,10 +2847,21 @@ err:
return err;
}
struct nlattr *opts;
u16 rate_flags;
u8 flow_mode;
-@@ -2894,6 +2936,13 @@ nla_put_failure:
+@@ -2895,6 +2937,13 @@ nla_put_failure:
return -1;
}
static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
{
struct nlattr *stats = nla_nest_start_noflag(d->skb, TCA_STATS_APP);
-@@ -3157,6 +3206,7 @@ MODULE_ALIAS_NET_SCH("cake");
+@@ -3158,6 +3207,7 @@ MODULE_ALIAS_NET_SCH("cake");
struct cake_mq_sched {
struct mq_sched mq_priv; /* must be first */
};
static void cake_mq_destroy(struct Qdisc *sch)
-@@ -3167,25 +3217,68 @@ static void cake_mq_destroy(struct Qdisc
+@@ -3168,25 +3218,68 @@ static void cake_mq_destroy(struct Qdisc
static int cake_mq_init(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
+
byte_target_ns = (byte_target * rate_ns) >> rate_shft;
- b->cparams.target = max((byte_target_ns * 3) / 2, target_ns);
-@@ -2768,6 +2814,7 @@ static void cake_config_init(struct cake
+ WRITE_ONCE(b->cparams.target,
+@@ -2769,6 +2815,7 @@ static void cake_config_init(struct cake
*/
q->rate_flags |= CAKE_FLAG_SPLIT_GSO;
q->is_shared = is_shared;
}
static int cake_init(struct Qdisc *sch, struct nlattr *opt,
-@@ -2839,6 +2886,9 @@ static int cake_init(struct Qdisc *sch,
+@@ -2840,6 +2887,9 @@ static int cake_init(struct Qdisc *sch,
qd->avg_peak_bandwidth = q->rate_bps;
qd->min_netlen = ~0;
qd->min_adjlen = ~0;
return 0;
err:
kvfree(qd->config);
-@@ -2971,6 +3021,7 @@ static int cake_dump_stats(struct Qdisc
+@@ -2972,6 +3022,7 @@ static int cake_dump_stats(struct Qdisc
PUT_STAT_U32(MAX_ADJLEN, q->max_adjlen);
PUT_STAT_U32(MIN_NETLEN, q->min_netlen);
PUT_STAT_U32(MIN_ADJLEN, q->min_adjlen);
struct cake_heap_entry overflow_heap[CAKE_QUEUES * CAKE_MAX_TINS];
-@@ -2797,8 +2798,6 @@ static void cake_destroy(struct Qdisc *s
+@@ -2798,8 +2799,6 @@ static void cake_destroy(struct Qdisc *s
qdisc_watchdog_cancel(&q->watchdog);
tcf_block_put(q->block);
kvfree(q->tins);
}
static void cake_config_init(struct cake_sched_config *q, bool is_shared)
-@@ -2821,13 +2820,9 @@ static int cake_init(struct Qdisc *sch,
+@@ -2822,13 +2821,9 @@ static int cake_init(struct Qdisc *sch,
struct netlink_ext_ack *extack)
{
struct cake_sched_data *qd = qdisc_priv(sch);
cake_config_init(q, false);
sch->limit = 10240;
-@@ -2839,14 +2834,13 @@ static int cake_init(struct Qdisc *sch,
+@@ -2840,14 +2835,13 @@ static int cake_init(struct Qdisc *sch,
if (opt) {
err = cake_change(sch, opt, extack);
quantum_div[0] = ~0;
for (i = 1; i <= CAKE_QUEUES; i++)
-@@ -2854,10 +2848,8 @@ static int cake_init(struct Qdisc *sch,
+@@ -2855,10 +2849,8 @@ static int cake_init(struct Qdisc *sch,
qd->tins = kvcalloc(CAKE_MAX_TINS, sizeof(struct cake_tin_data),
GFP_KERNEL);
for (i = 0; i < CAKE_MAX_TINS; i++) {
struct cake_tin_data *b = qd->tins + i;
-@@ -2890,22 +2882,13 @@ static int cake_init(struct Qdisc *sch,
+@@ -2891,22 +2883,13 @@ static int cake_init(struct Qdisc *sch,
qd->last_checked_active = 0;
return 0;
}
begin:
-@@ -2361,12 +2358,10 @@ static void cake_set_rate(struct cake_ti
+@@ -2362,12 +2359,10 @@ static void cake_set_rate(struct cake_ti
b->cparams.p_dec = 1 << 20; /* 1/4096 */
}
q->tin_cnt = 1;
-@@ -2380,12 +2375,10 @@ static int cake_config_besteffort(struct
+@@ -2381,12 +2376,10 @@ static int cake_config_besteffort(struct
return 0;
}
u32 quantum = 256;
u32 i;
-@@ -2456,7 +2449,7 @@ static int cake_config_precedence(struct
+@@ -2457,7 +2450,7 @@ static int cake_config_precedence(struct
* Total 12 traffic classes.
*/
{
/* Pruned list of traffic classes for typical applications:
*
-@@ -2473,8 +2466,6 @@ static int cake_config_diffserv8(struct
+@@ -2474,8 +2467,6 @@ static int cake_config_diffserv8(struct
*/
struct cake_sched_data *q = qdisc_priv(sch);
u32 quantum = 256;
u32 i;
-@@ -2504,7 +2495,7 @@ static int cake_config_diffserv8(struct
+@@ -2505,7 +2496,7 @@ static int cake_config_diffserv8(struct
return 0;
}
{
/* Further pruned list of traffic classes for four-class system:
*
-@@ -2517,8 +2508,6 @@ static int cake_config_diffserv4(struct
+@@ -2518,8 +2509,6 @@ static int cake_config_diffserv4(struct
*/
struct cake_sched_data *q = qdisc_priv(sch);
u32 quantum = 1024;
q->tin_cnt = 4;
-@@ -2546,7 +2535,7 @@ static int cake_config_diffserv4(struct
+@@ -2547,7 +2536,7 @@ static int cake_config_diffserv4(struct
return 0;
}
{
/* Simplified Diffserv structure with 3 tins.
* Latency Sensitive (CS7, CS6, EF, VA, TOS4)
-@@ -2554,8 +2543,6 @@ static int cake_config_diffserv3(struct
+@@ -2555,8 +2544,6 @@ static int cake_config_diffserv3(struct
* Low Priority (LE, CS1)
*/
struct cake_sched_data *q = qdisc_priv(sch);
u32 quantum = 1024;
q->tin_cnt = 3;
-@@ -2580,32 +2567,33 @@ static int cake_config_diffserv3(struct
+@@ -2581,32 +2568,33 @@ static int cake_config_diffserv3(struct
return 0;
}
break;
}
-@@ -2616,6 +2604,14 @@ static void cake_reconfigure(struct Qdis
+@@ -2617,6 +2605,14 @@ static void cake_reconfigure(struct Qdis
qd->rate_ns = qd->tins[ft].tin_rate_ns;
qd->rate_shft = qd->tins[ft].tin_rate_shft;
};
--- a/drivers/net/phy/dp83869.c
+++ b/drivers/net/phy/dp83869.c
-@@ -928,7 +928,7 @@ static struct phy_driver dp83869_driver[
+@@ -939,7 +939,7 @@ static struct phy_driver dp83869_driver[
};
module_phy_driver(dp83869_driver);
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
-@@ -498,9 +498,6 @@ void dw_pcie_iatu_detect(struct dw_pcie
+@@ -500,9 +500,6 @@ void dw_pcie_iatu_detect(struct dw_pcie
int dw_pcie_edma_detect(struct dw_pcie *pci);
void dw_pcie_edma_remove(struct dw_pcie *pci);
static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
{
dw_pcie_write_dbi(pci, reg, 0x4, val);
-@@ -678,6 +675,8 @@ static inline enum dw_pcie_ltssm dw_pcie
+@@ -680,6 +677,8 @@ static inline enum dw_pcie_ltssm dw_pcie
}
#ifdef CONFIG_PCIE_DW_HOST
irqreturn_t dw_handle_msi_irq(struct dw_pcie_rp *pp);
int dw_pcie_setup_rc(struct dw_pcie_rp *pp);
int dw_pcie_host_init(struct dw_pcie_rp *pp);
-@@ -686,6 +685,16 @@ int dw_pcie_allocate_domains(struct dw_p
+@@ -688,6 +687,16 @@ int dw_pcie_allocate_domains(struct dw_p
void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn,
int where);
#else
/* Setup RC BARs */
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
-@@ -678,6 +678,9 @@ static inline enum dw_pcie_ltssm dw_pcie
+@@ -680,6 +680,9 @@ static inline enum dw_pcie_ltssm dw_pcie
int dw_pcie_suspend_noirq(struct dw_pcie *pci);
int dw_pcie_resume_noirq(struct dw_pcie *pci);
irqreturn_t dw_handle_msi_irq(struct dw_pcie_rp *pp);
int dw_pcie_setup_rc(struct dw_pcie_rp *pp);
int dw_pcie_host_init(struct dw_pcie_rp *pp);
void dw_pcie_host_deinit(struct dw_pcie_rp *pp);
-@@ -700,6 +703,17 @@ static inline irqreturn_t dw_handle_msi_
+@@ -702,6 +705,17 @@ static inline irqreturn_t dw_handle_msi_
return IRQ_NONE;
}
EXPORT_SYMBOL_GPL(dw_pcie_free_msi);
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
-@@ -368,7 +368,6 @@ struct dw_pcie_rp {
+@@ -370,7 +370,6 @@ struct dw_pcie_rp {
const struct dw_pcie_host_ops *ops;
int msi_irq[MAX_MSI_CTRLS];
struct irq_domain *irq_domain;
irq_domain_remove(pp->irq_domain);
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
-@@ -676,7 +676,7 @@ static inline enum dw_pcie_ltssm dw_pcie
+@@ -678,7 +678,7 @@ static inline enum dw_pcie_ltssm dw_pcie
#ifdef CONFIG_PCIE_DW_HOST
int dw_pcie_suspend_noirq(struct dw_pcie *pci);
int dw_pcie_resume_noirq(struct dw_pcie *pci);
void dw_pcie_msi_init(struct dw_pcie_rp *pp);
int dw_pcie_msi_host_init(struct dw_pcie_rp *pp);
void dw_pcie_free_msi(struct dw_pcie_rp *pp);
-@@ -697,10 +697,7 @@ static inline int dw_pcie_resume_noirq(s
+@@ -699,10 +699,7 @@ static inline int dw_pcie_resume_noirq(s
return 0;
}
+++ /dev/null
-From 0c078021d3861966614d5e594ee03587f0c9e74d Mon Sep 17 00:00:00 2001
-From: Mieczyslaw Nalewaj <namiltd@yahoo.com>
-Date: Sun, 19 Apr 2026 21:37:07 +0200
-Subject: net: dsa: realtek: rtl8365mb: fix mode mask calculation
-
-The RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK macro was shifting
-the 4-bit mask (0xF) by only (_extint % 2) bits instead of
-(_extint % 2) * 4. This caused the mask to overlap with the adjacent
-nibble when configuring odd-numbered external interfaces, selecting
-the wrong bits entirely.
-
-Align the shift calculation with the existing ...MODE_OFFSET macro.
-
-Fixes: 4af2950c50c8 ("net: dsa: realtek-smi: add rtl8365mb subdriver for RTL8365MB-VC")
-Signed-off-by: Abdulkader Alrezej <alrazj.abdulkader@gmail.com>
-Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
-Reviewed-by: Luiz Angelo Daros de Luca <luizluca@gmail.com>
-Link: https://patch.msgid.link/400a6387-a444-4576-af6d-26be5410bce3@yahoo.com
-Signed-off-by: Paolo Abeni <pabeni@redhat.com>
----
- drivers/net/dsa/realtek/rtl8365mb.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/dsa/realtek/rtl8365mb.c
-+++ b/drivers/net/dsa/realtek/rtl8365mb.c
-@@ -216,7 +216,7 @@
- (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \
- 0x0)
- #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \
-- (0xF << (((_extint) % 2)))
-+ (0xF << (((_extint) % 2) * 4))
- #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \
- (((_extint) % 2) * 4)
-
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
-@@ -1155,8 +1155,9 @@ static void page_pool_release_retry(stru
+@@ -1167,8 +1167,9 @@ static void page_pool_release_retry(stru
{
struct delayed_work *dwq = to_delayed_work(wq);
struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw);
inflight = page_pool_release(pool);
/* In rare cases, a driver bug may cause inflight to go negative.
-@@ -1168,6 +1169,21 @@ static void page_pool_release_retry(stru
+@@ -1180,6 +1181,21 @@ static void page_pool_release_retry(stru
if (inflight <= 0)
return;
struct net_device *dev = qdisc_dev(sch);
struct cake_sched_data *other_priv;
u64 new_rate = q->config->rate_bps;
-@@ -3352,8 +3355,13 @@ static int __init cake_module_init(void)
+@@ -3353,8 +3356,13 @@ static int __init cake_module_init(void)
return ret;
ret = register_qdisc(&cake_mq_qdisc_ops);
return ret;
}
-@@ -3362,6 +3370,7 @@ static void __exit cake_module_exit(void
+@@ -3363,6 +3371,7 @@ static void __exit cake_module_exit(void
{
unregister_qdisc(&cake_qdisc_ops);
unregister_qdisc(&cake_mq_qdisc_ops);
-LINUX_VERSION-6.12 = .90
-LINUX_KERNEL_HASH-6.12.90 = 1f1a1ff057468b8a6284d3ce1d181278259beb5670ea16724c46dbf8820fa2a8
+LINUX_VERSION-6.12 = .91
+LINUX_KERNEL_HASH-6.12.91 = 0ff2ab9e169f9f1948557471fbb450d3018f8c5b77caf288e1a3982582597969
static const struct flash_info spi_nor_generic_flash = {
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
-@@ -593,6 +593,7 @@ extern const struct spi_nor_manufacturer
+@@ -599,6 +599,7 @@ extern const struct spi_nor_manufacturer
extern const struct spi_nor_manufacturer spi_nor_sst;
extern const struct spi_nor_manufacturer spi_nor_winbond;
extern const struct spi_nor_manufacturer spi_nor_xmc;
| NETIF_F_HW_CSUM
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
-@@ -903,7 +903,7 @@ static int macvlan_hwtstamp_set(struct n
+@@ -904,7 +904,7 @@ static int macvlan_hwtstamp_set(struct n
static struct lock_class_key macvlan_netdev_addr_lock_key;
#define ALWAYS_ON_OFFLOADS \
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
-@@ -8722,7 +8722,7 @@ static int nft_register_flowtable_net_ho
+@@ -8724,7 +8724,7 @@ static int nft_register_flowtable_net_ho
err = flowtable->data.type->setup(&flowtable->data,
hook->ops.dev,
FLOW_BLOCK_BIND);
/* show configuration fields */
#define pci_config_attr(field, format_string) \
-@@ -1551,12 +1553,32 @@ static const struct attribute_group pci_
+@@ -1523,12 +1525,32 @@ static const struct attribute_group pci_
.is_visible = resource_resize_is_visible,
};
}
/**
-@@ -1577,21 +1599,23 @@ static int __init pci_sysfs_init(void)
+@@ -1549,21 +1571,23 @@ static int __init pci_sysfs_init(void)
{
struct pci_dev *pdev = NULL;
struct pci_bus *pbus = NULL;
#include <net/dst.h>
#include <net/sock.h>
#include <net/checksum.h>
-@@ -5067,6 +5071,9 @@ static const u8 skb_ext_type_len[] = {
+@@ -5074,6 +5078,9 @@ static const u8 skb_ext_type_len[] = {
#if IS_ENABLED(CONFIG_MCTP_FLOWS)
[SKB_EXT_MCTP] = SKB_EXT_CHUNKSIZEOF(struct mctp_flow),
#endif
};
#define QCOM_PCIE_2_7_0_MAX_SUPPLIES 2
-@@ -710,12 +723,65 @@ static int qcom_pcie_post_init_2_3_2(str
+@@ -715,12 +728,65 @@ static int qcom_pcie_post_init_2_3_2(str
return 0;
}
int ret;
res->num_clks = devm_clk_bulk_get_all(dev, &res->clks);
-@@ -754,6 +820,17 @@ static void qcom_pcie_deinit_2_4_0(struc
+@@ -759,6 +825,17 @@ static void qcom_pcie_deinit_2_4_0(struc
clk_bulk_disable_unprepare(res->num_clks, res->clks);
}
static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
{
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
-@@ -1336,6 +1413,16 @@ static const struct qcom_pcie_ops ops_2_
+@@ -1341,6 +1418,16 @@ static const struct qcom_pcie_ops ops_2_
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
};
/* Qcom IP rev.: 2.3.3 Synopsys IP rev.: 4.30a */
static const struct qcom_pcie_ops ops_2_3_3 = {
.get_resources = qcom_pcie_get_resources_2_3_3,
-@@ -1404,6 +1491,10 @@ static const struct qcom_pcie_cfg cfg_2_
+@@ -1409,6 +1496,10 @@ static const struct qcom_pcie_cfg cfg_2_
.ops = &ops_2_4_0,
};
static const struct qcom_pcie_cfg cfg_2_7_0 = {
.ops = &ops_2_7_0,
};
-@@ -1827,6 +1918,7 @@ static const struct of_device_id qcom_pc
+@@ -1832,6 +1923,7 @@ static const struct of_device_id qcom_pc
{ .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 },
{ .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 },
{ .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 },
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
-@@ -2985,6 +2985,24 @@ char *ppp_dev_name(struct ppp_channel *c
+@@ -2988,6 +2988,24 @@ char *ppp_dev_name(struct ppp_channel *c
return name;
}
/*
* Disconnect a channel from the generic layer.
-@@ -3646,6 +3664,7 @@ EXPORT_SYMBOL(ppp_unregister_channel);
+@@ -3649,6 +3667,7 @@ EXPORT_SYMBOL(ppp_unregister_channel);
EXPORT_SYMBOL(ppp_channel_index);
EXPORT_SYMBOL(ppp_unit_number);
EXPORT_SYMBOL(ppp_dev_name);
(transaction layer end-to-end CRC checking).
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
-@@ -1658,6 +1658,8 @@ void pci_walk_bus_locked(struct pci_bus
+@@ -1652,6 +1652,8 @@ void pci_walk_bus_locked(struct pci_bus
void *userdata);
int pci_cfg_space_size(struct pci_dev *dev);
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
return nr_parts;
@@ -197,6 +249,7 @@ ofpart_none:
+ if (dedicated)
of_node_put(ofpart_node);
- of_node_put(pp);
kfree(parts);
+ kfree(part_nodes);
return ret;
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
-@@ -1827,6 +1827,7 @@ static const struct of_device_id qcom_pc
+@@ -1832,6 +1832,7 @@ static const struct of_device_id qcom_pc
{ .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 },
{ .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 },
{ .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 },