summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-06-17 00:57:37 +0300
committerJakub Kicinski <kuba@kernel.org>2026-06-17 00:59:58 +0300
commitd755d45bc08a57a3b845b850f8760de922a499bf (patch)
treeb5da5b113706ef9318f74705d2cd2d265ca7741a
parent8940a8202c83b4bfbf71a859a11a4920b1aa3a77 (diff)
parent406e8a651a7b854c41fecd5117bb282b3a6c2c6b (diff)
downloadlinux-d755d45bc08a57a3b845b850f8760de922a499bf.tar.xz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Merge in late fixes in preparation for the net-next PR. Conflicts: net/tls/tls_sw.c 406e8a651a7b ("net: skmsg: preserve sg.copy across SG transforms") 79511603a65b ("tls: remove dead sockmap (psock) handling from the SW path") drivers/net/ethernet/microsoft/mana/mana_en.c f8fd56977eeea ("net: mana: guard TX wq object destroy with INVALID_MANA_HANDLE check") d07efe5a6e641 ("net: mana: Use per-queue allocation for tx_qp to reduce allocation size") https://lore.kernel.org/ajAPXu-C_PuTgV-a@sirena.org.uk No adjacent changes. Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--.mailmap1
-rw-r--r--Documentation/devicetree/bindings/net/microchip,lan8650.yaml2
-rw-r--r--drivers/net/dsa/qca/qca8k-leds.c3
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.c4
-rw-r--r--drivers/net/ethernet/airoha/airoha_ppe.c6
-rw-r--r--drivers/net/ethernet/airoha/airoha_ppe_debugfs.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c10
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h1
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c23
-rw-r--r--drivers/net/ethernet/intel/idpf/virtchnl2.h12
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/mbox.h31
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c40
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c20
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c22
-rw-r--r--drivers/net/ethernet/mediatek/mtk_wed_debugfs.c6
-rw-r--r--drivers/net/ethernet/mediatek/mtk_wed_mcu.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c12
-rw-r--r--drivers/net/ethernet/microsoft/mana/gdma_main.c2
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c4
-rw-r--r--drivers/net/ethernet/oa_tc6.c140
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_common.c48
-rw-r--r--drivers/net/pfcp.c1
-rw-r--r--drivers/net/virtio_net.c15
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_wwan.c2
-rw-r--r--fs/afs/rxrpc.c6
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/linux/skmsg.h15
-rw-r--r--include/net/fib_rules.h5
-rw-r--r--include/net/ip_fib.h5
-rw-r--r--include/net/tcp.h9
-rw-r--r--net/6lowpan/nhc.c2
-rw-r--r--net/atm/common.c2
-rw-r--r--net/bridge/br_cfm.c6
-rw-r--r--net/bridge/br_cfm_netlink.c4
-rw-r--r--net/core/dev.c3
-rw-r--r--net/core/fib_rules.c6
-rw-r--r--net/core/filter.c27
-rw-r--r--net/core/netdev_rx_queue.c8
-rw-r--r--net/core/skmsg.c2
-rw-r--r--net/ife/ife.c2
-rw-r--r--net/ipv4/fib_trie.c4
-rw-r--r--net/ipv4/inet_connection_sock.c1
-rw-r--r--net/ipv6/route.c6
-rw-r--r--net/kcm/kcmsock.c8
-rw-r--r--net/qrtr/af_qrtr.c2
-rw-r--r--net/rxrpc/call_accept.c25
-rw-r--r--net/rxrpc/recvmsg.c13
-rw-r--r--net/rxrpc/rxgk.c3
-rw-r--r--net/sched/cls_flow.c12
-rw-r--r--net/sched/sch_codel.c48
-rw-r--r--net/sched/sch_dualpi2.c42
-rw-r--r--net/sched/sch_fq_codel.c41
-rw-r--r--net/sched/sch_generic.c44
-rw-r--r--net/sched/sch_hfsc.c2
-rw-r--r--net/sctp/sm_make_chunk.c10
-rw-r--r--net/tipc/bearer.c1
-rw-r--r--net/tipc/name_distr.c13
-rw-r--r--net/tipc/netlink.c12
-rw-r--r--net/tipc/socket.c9
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/ife.json55
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json184
63 files changed, 823 insertions, 238 deletions
diff --git a/.mailmap b/.mailmap
index 0b9298a55d2d..34b9b51e9e8c 100644
--- a/.mailmap
+++ b/.mailmap
@@ -402,6 +402,7 @@ Jesper Dangaard Brouer <hawk@kernel.org> <hawk@comx.dk>
Jesper Dangaard Brouer <hawk@kernel.org> <jbrouer@redhat.com>
Jesper Dangaard Brouer <hawk@kernel.org> <jdb@comx.dk>
Jesper Dangaard Brouer <hawk@kernel.org> <netoptimizer@brouer.com>
+Jesse Brandeburg <jbrandeb@kernel.org> <jesse.brandeburg@intel.com>
Jessica Zhang <jesszhan0024@gmail.com> <jesszhan@codeaurora.org>
Jessica Zhang <jesszhan0024@gmail.com> <quic_jesszhan@quicinc.com>
Jessica Zhang <jesszhan0024@gmail.com> <jessica.zhang@oss.qualcomm.com>
diff --git a/Documentation/devicetree/bindings/net/microchip,lan8650.yaml b/Documentation/devicetree/bindings/net/microchip,lan8650.yaml
index 61e11d4a07c4..766ff58147ae 100644
--- a/Documentation/devicetree/bindings/net/microchip,lan8650.yaml
+++ b/Documentation/devicetree/bindings/net/microchip,lan8650.yaml
@@ -67,7 +67,7 @@ examples:
pinctrl-names = "default";
pinctrl-0 = <&eth0_pins>;
interrupt-parent = <&gpio>;
- interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+ interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
local-mac-address = [04 05 06 01 02 03];
spi-max-frequency = <15000000>;
};
diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c
index 43ac68052baf..ef496e345a4e 100644
--- a/drivers/net/dsa/qca/qca8k-leds.c
+++ b/drivers/net/dsa/qca/qca8k-leds.c
@@ -429,7 +429,8 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p
init_data.fwnode = led;
init_data.devname_mandatory = true;
init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d",
- priv->internal_mdio_bus->id,
+ priv->internal_mdio_bus ?
+ priv->internal_mdio_bus->id : priv->bus->id,
port_num);
if (!init_data.devicename) {
fwnode_handle_put(led);
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 1d1911a4759c..64dde6464f3f 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -361,7 +361,7 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth)
PSE_QUEUE_RSV_PAGES);
/* PPE1 */
for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_PPE1]; q++) {
- if (q < pse_port_num_queues[FE_PSE_PORT_PPE1])
+ if (q < pse_port_num_queues[FE_PSE_PORT_PPE1] / 2)
airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE1, q,
PSE_QUEUE_RSV_PAGES);
else
@@ -1331,7 +1331,7 @@ static void airoha_qdma_init_qos_stats(struct airoha_qdma *qdma)
FIELD_PREP(CNTR_CHAN_MASK, i));
/* Tx-fwd transferred count */
airoha_qdma_wr(qdma, REG_CNTR_VAL((i << 1) + 1), 0);
- airoha_qdma_wr(qdma, REG_CNTR_CFG(i << 1),
+ airoha_qdma_wr(qdma, REG_CNTR_CFG((i << 1) + 1),
CNTR_EN_MASK | CNTR_ALL_QUEUE_EN_MASK |
CNTR_ALL_DSCP_RING_EN_MASK |
FIELD_PREP(CNTR_SRC_MASK, 1) |
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 0d42f82be77a..329e7c2aae89 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -1354,7 +1354,7 @@ static int airoha_ppe_flush_sram_entries(struct airoha_ppe *ppe)
{
u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe);
struct airoha_foe_entry *hwe = ppe->foe;
- int i, err = 0;
+ int i;
for (i = 0; i < sram_num_entries; i++) {
int err;
@@ -1362,10 +1362,10 @@ static int airoha_ppe_flush_sram_entries(struct airoha_ppe *ppe)
memset(&hwe[i], 0, sizeof(*hwe));
err = airoha_ppe_foe_commit_sram_entry(ppe, i);
if (err)
- break;
+ return err;
}
- return err;
+ return 0;
}
static struct airoha_npu *airoha_ppe_npu_get(struct airoha_eth *eth)
diff --git a/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c b/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c
index 0112c41150bb..e46a98514486 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c
@@ -121,8 +121,6 @@ static int airoha_ppe_debugfs_foe_show(struct seq_file *m, void *private,
case PPE_PKT_TYPE_IPV4_DSLITE:
src_port = &hwe->ipv4.new_tuple.src_port;
dest_port = &hwe->ipv4.new_tuple.dest_port;
- fallthrough;
- case PPE_PKT_TYPE_IPV4_ROUTE:
src_addr = &hwe->ipv4.new_tuple.src_ip;
dest_addr = &hwe->ipv4.new_tuple.dest_ip;
seq_puts(m, " new=");
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 2bc27b34475c..055e93a417b6 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -1011,6 +1011,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
mapping += bp->rx_dma_offset;
rx_buf->data = page;
rx_buf->data_ptr = page_address(page) + offset + bp->rx_offset;
+ rx_buf->offset = offset;
} else {
u8 *data = __bnxt_alloc_rx_frag(bp, &mapping, rxr, gfp);
@@ -1019,6 +1020,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
rx_buf->data = data;
rx_buf->data_ptr = data + bp->rx_offset;
+ rx_buf->offset = 0;
}
rx_buf->mapping = mapping;
@@ -1040,6 +1042,7 @@ void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data)
prod_rx_buf->data_ptr = cons_rx_buf->data_ptr;
prod_rx_buf->mapping = cons_rx_buf->mapping;
+ prod_rx_buf->offset = cons_rx_buf->offset;
prod_bd = &rxr->rx_desc_ring[RX_RING(bp, prod)][RX_IDX(prod)];
cons_bd = &rxr->rx_desc_ring[RX_RING(bp, cons)][RX_IDX(cons)];
@@ -1175,8 +1178,11 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
struct page *page = data;
u16 prod = rxr->rx_prod;
struct sk_buff *skb;
+ void *frag_start;
int err;
+ frag_start = page_address(page) + rxr->rx_buf_ring[cons].offset;
+
err = bnxt_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
if (unlikely(err)) {
bnxt_reuse_rx_data(rxr, cons, data);
@@ -1185,13 +1191,13 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
dma_addr -= bp->rx_dma_offset;
dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, rxr->rx_page_size,
bp->rx_dir);
- skb = napi_build_skb(data_ptr - bp->rx_offset, rxr->rx_page_size);
+ skb = napi_build_skb(frag_start, rxr->rx_page_size);
if (!skb) {
page_pool_recycle_direct(rxr->page_pool, page);
return NULL;
}
skb_mark_for_recycle(skb);
- skb_reserve(skb, bp->rx_offset);
+ skb_reserve(skb, data_ptr - (u8 *)frag_start);
__skb_put(skb, len);
return skb;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 29ff5a584d16..6d312259f852 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -911,6 +911,7 @@ struct bnxt_sw_rx_bd {
void *data;
u8 *data_ptr;
dma_addr_t mapping;
+ unsigned int offset;
};
struct bnxt_sw_rx_agg_bd {
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index ca403581357d..a2305e6428d1 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -40,9 +40,8 @@
#include "bcmgenet.h"
-/* Default highest priority queue for multi queue support */
-#define GENET_Q1_PRIORITY 0
-#define GENET_Q0_PRIORITY 1
+#define GENET_Q0_WEIGHT 1
+#define GENET_Q1_WEIGHT 4
#define GENET_Q0_RX_BD_CNT \
(TOTAL_DESC - priv->hw_params->rx_queues * priv->hw_params->rx_bds_per_q)
@@ -2126,13 +2125,6 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
int i;
index = skb_get_queue_mapping(skb);
- /* Mapping strategy:
- * queue_mapping = 0, unclassified, packet xmited through ring 0
- * queue_mapping = 1, goes to ring 1. (highest priority queue)
- * queue_mapping = 2, goes to ring 2.
- * queue_mapping = 3, goes to ring 3.
- * queue_mapping = 4, goes to ring 4.
- */
ring = &priv->tx_rings[index];
txq = netdev_get_tx_queue(dev, index);
@@ -2921,8 +2913,9 @@ static int bcmgenet_rdma_disable(struct bcmgenet_priv *priv)
/* Initialize Tx queues
*
- * Queues 1-4 are priority-based, each one has 32 descriptors,
- * with queue 1 being the highest priority queue.
+ * Queues 1-4 are the priority queues, each one has 32 descriptors.
+ * The weighted round-robin arbiter gives them a larger share of TX
+ * bandwidth than the default queue 0.
*
* Queue 0 is the default Tx queue with
* GENET_Q0_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors.
@@ -2940,8 +2933,8 @@ static void bcmgenet_init_tx_queues(struct net_device *dev)
unsigned int start = 0, end = GENET_Q0_TX_BD_CNT;
u32 i, ring_mask, dma_priority[3] = {0, 0, 0};
- /* Enable strict priority arbiter mode */
- bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL);
+ /* Enable Weighted Round-Robin arbiter mode */
+ bcmgenet_tdma_writel(priv, DMA_ARBITER_WRR, DMA_ARB_CTRL);
/* Initialize Tx priority queues */
for (i = 0; i <= priv->hw_params->tx_queues; i++) {
@@ -2949,7 +2942,7 @@ static void bcmgenet_init_tx_queues(struct net_device *dev)
start = end;
end += priv->hw_params->tx_bds_per_q;
dma_priority[DMA_PRIO_REG_INDEX(i)] |=
- (i ? GENET_Q1_PRIORITY : GENET_Q0_PRIORITY)
+ (i ? GENET_Q1_WEIGHT : GENET_Q0_WEIGHT)
<< DMA_PRIO_REG_SHIFT(i);
}
diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2.h b/drivers/net/ethernet/intel/idpf/virtchnl2.h
index 02ae447cc24a..39fea65c075c 100644
--- a/drivers/net/ethernet/intel/idpf/virtchnl2.h
+++ b/drivers/net/ethernet/intel/idpf/virtchnl2.h
@@ -1572,13 +1572,15 @@ VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_get_vport_tx_tstamp_latches);
* struct virtchnl2_ptp_get_dev_clk_time - Associated with message
* VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME.
* @dev_time_ns: Device clock time value in nanoseconds
+ * @pad: Padding for future extensions
*
* PF/VF sends this message to receive the time from the main timer.
*/
struct virtchnl2_ptp_get_dev_clk_time {
__le64 dev_time_ns;
+ u8 pad[8];
};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_get_dev_clk_time);
+VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_get_dev_clk_time);
/**
* struct virtchnl2_ptp_get_cross_time: Associated with message
@@ -1586,26 +1588,30 @@ VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_get_dev_clk_time);
* @sys_time_ns: System counter value expressed in nanoseconds, read
* synchronously with device time
* @dev_time_ns: Device clock time value expressed in nanoseconds
+ * @pad: Padding for future extensions
*
* PF/VF sends this message to receive the cross time.
*/
struct virtchnl2_ptp_get_cross_time {
__le64 sys_time_ns;
__le64 dev_time_ns;
+ u8 pad[8];
};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_get_cross_time);
+VIRTCHNL2_CHECK_STRUCT_LEN(24, virtchnl2_ptp_get_cross_time);
/**
* struct virtchnl2_ptp_set_dev_clk_time: Associated with message
* VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME.
* @dev_time_ns: Device time value expressed in nanoseconds to set
+ * @pad: Padding for future extensions
*
* PF/VF sends this message to set the time of the main timer.
*/
struct virtchnl2_ptp_set_dev_clk_time {
__le64 dev_time_ns;
+ u8 pad[8];
};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_set_dev_clk_time);
+VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_set_dev_clk_time);
/**
* struct virtchnl2_ptp_adj_dev_clk_fine: Associated with message
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index e0d719c11105..2c9e2dfd8499 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -2649,7 +2649,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
}
if (igc_fpe_is_pmac_enabled(adapter) &&
- igc_fpe_handle_mpacket(adapter, rx_desc, size, pktbuf)) {
+ igc_fpe_handle_mpacket(adapter, rx_desc, size, pktbuf + pkt_offset)) {
/* Advance the ring next-to-clean */
igc_is_non_eop(rx_ring, rx_desc);
cleaned_count++;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index bc16e4c93fd4..8873a8cc4a18 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -3958,7 +3958,8 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
}
/* initialize XPS */
- if (!test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, ring->state)) {
+ if (!ring_is_xdp(ring) &&
+ !test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, ring->state)) {
struct ixgbe_q_vector *q_vector = ring->q_vector;
if (q_vector)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index e07fbf842b94..714e47f68d93 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -283,31 +283,30 @@ M(NPC_GET_FIELD_HASH_INFO, 0x6013, npc_get_field_hash_info,
M(NPC_GET_FIELD_STATUS, 0x6014, npc_get_field_status, \
npc_get_field_status_req, \
npc_get_field_status_rsp) \
-M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6015, npc_cn20k_get_fcnt, \
- msg_req, npc_cn20k_get_fcnt_rsp) \
-M(NPC_CN20K_GET_KEX_CFG, 0x6016, npc_cn20k_get_kex_cfg, \
+M(NPC_MCAM_DEFRAG, 0x6016, npc_defrag, \
+ msg_req, \
+ msg_rsp) \
+M(NPC_CN20K_GET_KEX_CFG, 0x6017, npc_cn20k_get_kex_cfg, \
msg_req, npc_cn20k_get_kex_cfg_rsp) \
-M(NPC_CN20K_MCAM_WRITE_ENTRY, 0x6017, npc_cn20k_mcam_write_entry, \
- npc_cn20k_mcam_write_entry_req, msg_rsp) \
-M(NPC_CN20K_MCAM_ALLOC_AND_WRITE_ENTRY, 0x6018, \
-npc_cn20k_mcam_alloc_and_write_entry, \
+M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6018, npc_cn20k_get_fcnt, \
+ msg_req, npc_cn20k_get_fcnt_rsp) \
+M(NPC_CN20K_MCAM_WRITE_ENTRY, 0x6019, npc_cn20k_mcam_write_entry, \
+ npc_cn20k_mcam_write_entry_req, msg_rsp) \
+M(NPC_CN20K_MCAM_ALLOC_AND_WRITE_ENTRY, 0x601a, npc_cn20k_mcam_alloc_and_write_entry, \
npc_cn20k_mcam_alloc_and_write_entry_req, \
npc_mcam_alloc_and_write_entry_rsp) \
-M(NPC_CN20K_MCAM_READ_ENTRY, 0x6019, npc_cn20k_mcam_read_entry, \
+M(NPC_CN20K_MCAM_READ_ENTRY, 0x601b, npc_cn20k_mcam_read_entry, \
npc_mcam_read_entry_req, \
npc_cn20k_mcam_read_entry_rsp) \
-M(NPC_CN20K_MCAM_READ_BASE_RULE, 0x601a, npc_cn20k_read_base_steer_rule, \
- msg_req, npc_cn20k_mcam_read_base_rule_rsp) \
-M(NPC_MCAM_DEFRAG, 0x601b, npc_defrag, \
- msg_req, \
- msg_rsp) \
-M(NPC_MCAM_GET_NUM_KWS, 0x601c, npc_get_num_kws, \
+M(NPC_CN20K_MCAM_READ_BASE_RULE, 0x601c, npc_cn20k_read_base_steer_rule, \
+ msg_req, npc_cn20k_mcam_read_base_rule_rsp) \
+M(NPC_MCAM_GET_NUM_KWS, 0x601d, npc_get_num_kws, \
npc_get_num_kws_req, \
npc_get_num_kws_rsp) \
-M(NPC_MCAM_GET_DFT_RL_IDXS, 0x601d, npc_get_dft_rl_idxs, \
+M(NPC_MCAM_GET_DFT_RL_IDXS, 0x601e, npc_get_dft_rl_idxs, \
msg_req, \
npc_get_dft_rl_idxs_rsp)\
-M(NPC_MCAM_GET_NPC_PFL_INFO, 0x601e, npc_get_pfl_info, \
+M(NPC_MCAM_GET_NPC_PFL_INFO, 0x601f, npc_get_pfl_info, \
msg_req, \
npc_get_pfl_info_rsp) \
/* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index b4635d78f9d5..c7bc0b3a29b9 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -2476,7 +2476,7 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
/* Alloc memory for MCAM entry to counter mapping and for tracking
* counter's reference count.
*/
- mcam->entry2cntr_map = kcalloc(mcam->bmap_entries, sizeof(u16),
+ mcam->entry2cntr_map = kcalloc(mcam->total_entries, sizeof(u16),
GFP_KERNEL);
if (!mcam->entry2cntr_map)
goto free_cntr_map;
@@ -2492,10 +2492,11 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
if (!mcam->entry2target_pffunc)
goto free_cntr_refcnt;
- for (index = 0; index < mcam->bmap_entries; index++) {
+ for (index = 0; index < mcam->bmap_entries; index++)
mcam->entry2pfvf_map[index] = NPC_MCAM_INVALID_MAP;
+
+ for (index = 0; index < mcam->total_entries; index++)
mcam->entry2cntr_map[index] = NPC_MCAM_INVALID_MAP;
- }
for (cntr = 0; cntr < mcam->counters.max; cntr++)
mcam->cntr2pfvf_map[cntr] = NPC_MCAM_INVALID_MAP;
@@ -3829,7 +3830,7 @@ static int __npc_mcam_free_counter(struct rvu *rvu,
struct msg_rsp *rsp)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
- u16 index, entry = 0;
+ u16 index;
int blkaddr, err;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
@@ -3845,20 +3846,16 @@ static int __npc_mcam_free_counter(struct rvu *rvu,
mcam->cntr2pfvf_map[req->cntr] = NPC_MCAM_INVALID_MAP;
rvu_free_rsrc(&mcam->counters, req->cntr);
- /* Disable all MCAM entry's stats which are using this counter */
- while (entry < mcam->bmap_entries) {
+ /* Disable all MCAM entry's stats which are using this counter.
+ * Scan the full MCAM index range: AF-reserved rules (e.g. CPT pass-2)
+ */
+ for (index = 0; index < mcam->total_entries; index++) {
if (!mcam->cntr_refcnt[req->cntr])
break;
-
- index = find_next_bit(mcam->bmap, mcam->bmap_entries, entry);
- if (index >= mcam->bmap_entries)
- break;
- entry = index + 1;
if (mcam->entry2cntr_map[index] != req->cntr)
continue;
-
- npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr,
- index, req->cntr);
+ npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr, index,
+ req->cntr);
}
return 0;
@@ -3929,7 +3926,7 @@ int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu,
struct npc_mcam_unmap_counter_req *req, struct msg_rsp *rsp)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
- u16 index, entry = 0;
+ u16 index;
int blkaddr, rc;
/* Counter is not supported for CN20K */
@@ -3956,20 +3953,13 @@ int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu,
}
/* Disable all MCAM entry's stats which are using this counter */
- while (entry < mcam->bmap_entries) {
+ for (index = 0; index < mcam->total_entries; index++) {
if (!mcam->cntr_refcnt[req->cntr])
break;
-
- index = find_next_bit(mcam->bmap, mcam->bmap_entries, entry);
- if (index >= mcam->bmap_entries)
- break;
- entry = index + 1;
-
if (mcam->entry2cntr_map[index] != req->cntr)
continue;
-
- npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr,
- index, req->cntr);
+ npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr, index,
+ req->cntr);
}
exit:
mutex_unlock(&mcam->lock);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index b4538edb13f8..41a0ebdf201e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -1118,9 +1118,16 @@ int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af)
{
struct otx2_hw *hw = &pf->hw;
struct msg_req *req;
+ u64 mbox_int_mask;
char *irq_name;
int err;
+ mbox_int_mask = !is_cn20k(pf->pdev) ? BIT_ULL(0) :
+ BIT_ULL(0) | BIT_ULL(1);
+
+ /* Clear stale mailbox interrupt state before installing the handler. */
+ otx2_write64(pf, RVU_PF_INT, mbox_int_mask);
+
/* Register mailbox interrupt handler */
if (!is_cn20k(pf->pdev)) {
irq_name = &hw->irq_name[RVU_PF_INT_VEC_AFPF_MBOX * NAME_SIZE];
@@ -1146,17 +1153,8 @@ int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af)
return err;
}
- /* Enable mailbox interrupt for msgs coming from AF.
- * First clear to avoid spurious interrupts, if any.
- */
- if (!is_cn20k(pf->pdev)) {
- otx2_write64(pf, RVU_PF_INT, BIT_ULL(0));
- otx2_write64(pf, RVU_PF_INT_ENA_W1S, BIT_ULL(0));
- } else {
- otx2_write64(pf, RVU_PF_INT, BIT_ULL(0) | BIT_ULL(1));
- otx2_write64(pf, RVU_PF_INT_ENA_W1S, BIT_ULL(0) |
- BIT_ULL(1));
- }
+ /* Enable mailbox interrupt for msgs coming from AF. */
+ otx2_write64(pf, RVU_PF_INT_ENA_W1S, mbox_int_mask);
if (!probe_af)
return 0;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
index f4fdbfba8667..b022f52c6845 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
@@ -251,9 +251,17 @@ static int otx2vf_register_mbox_intr(struct otx2_nic *vf, bool probe_pf)
{
struct otx2_hw *hw = &vf->hw;
struct msg_req *req;
+ u64 mbox_int_mask;
char *irq_name;
int err;
+ mbox_int_mask = !is_cn20k(vf->pdev) ? BIT_ULL(0) :
+ BIT_ULL(0) | BIT_ULL(1) |
+ BIT_ULL(2) | BIT_ULL(3);
+
+ /* Clear stale mailbox interrupt state before installing the handler. */
+ otx2_write64(vf, RVU_VF_INT, mbox_int_mask);
+
/* Register mailbox interrupt handler */
irq_name = &hw->irq_name[RVU_VF_INT_VEC_MBOX * NAME_SIZE];
snprintf(irq_name, NAME_SIZE, "RVUVF%d AFVF Mbox", ((vf->pcifunc &
@@ -274,18 +282,8 @@ static int otx2vf_register_mbox_intr(struct otx2_nic *vf, bool probe_pf)
return err;
}
- /* Enable mailbox interrupt for msgs coming from PF.
- * First clear to avoid spurious interrupts, if any.
- */
- if (!is_cn20k(vf->pdev)) {
- otx2_write64(vf, RVU_VF_INT, BIT_ULL(0));
- otx2_write64(vf, RVU_VF_INT_ENA_W1S, BIT_ULL(0));
- } else {
- otx2_write64(vf, RVU_VF_INT, BIT_ULL(0) | BIT_ULL(1) |
- BIT_ULL(2) | BIT_ULL(3));
- otx2_write64(vf, RVU_VF_INT_ENA_W1S, BIT_ULL(0) |
- BIT_ULL(1) | BIT_ULL(2) | BIT_ULL(3));
- }
+ /* Enable mailbox interrupt for msgs coming from PF. */
+ otx2_write64(vf, RVU_VF_INT_ENA_W1S, mbox_int_mask);
if (!probe_pf)
return 0;
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
index 781c691473e1..519c364e87d1 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
@@ -310,9 +310,9 @@ wed_amsdu_show(struct seq_file *s, void *data)
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1),
WED_AMSDU_ENG_CUR_ENTRY),
- DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1),
WED_AMSDU_ENG_MAX_BUF_MERGED),
- DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG2 INFO"),
@@ -414,7 +414,7 @@ wed_amsdu_show(struct seq_file *s, void *data)
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7),
WED_AMSDU_ENG_MAX_BUF_MERGED),
- DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG8 INFO"),
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
index fa6b21603416..0d38183c6ba7 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
@@ -367,8 +367,12 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo)
/* wo firmware reset */
wo_w32(MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00);
- val = wo_r32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR) |
- MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK;
+ val = wo_r32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR);
+
+ if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index)
+ val |= MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK;
+ else
+ val |= MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK;
wo_w32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
out:
release_firmware(fw);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index fd285aeb9630..643b4aac2033 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -527,7 +527,6 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)
{
struct mlx5_profile *prof = &dev->profile;
void *set_hca_cap;
- int max_uc_list;
int err;
err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL);
@@ -613,10 +612,13 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)
MLX5_SET(cmd_hca_cap, set_hca_cap, roce,
mlx5_is_roce_on(dev));
- max_uc_list = max_uc_list_get_devlink_param(dev);
- if (max_uc_list > 0)
- MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_current_uc_list,
- ilog2(max_uc_list));
+ if (MLX5_CAP_GEN_MAX(dev, log_max_current_uc_list)) {
+ int max_uc_list = max_uc_list_get_devlink_param(dev);
+
+ if (max_uc_list > 0)
+ MLX5_SET(cmd_hca_cap, set_hca_cap,
+ log_max_current_uc_list, ilog2(max_uc_list));
+ }
/* enable absolute native port num */
if (MLX5_CAP_GEN_MAX(dev, abs_native_port_num))
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index c9ec80a1dd6f..a0fdd052d7f1 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -1267,6 +1267,8 @@ int mana_gd_create_mana_wq_cq(struct gdma_dev *gd,
if (!queue)
return -ENOMEM;
+ queue->id = INVALID_QUEUE_ID;
+
gmi = &queue->mem_info;
err = mana_gd_alloc_memory(gc, spec->queue_size, gmi);
if (err) {
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 26aef21c6c2c..87862b0434c7 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2401,7 +2401,9 @@ static void mana_destroy_txq(struct mana_port_context *apc)
netif_napi_del_locked(napi);
apc->tx_qp[i]->txq.napi_initialized = false;
}
- mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i]->tx_object);
+
+ if (apc->tx_qp[i]->tx_object != INVALID_MANA_HANDLE)
+ mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i]->tx_object);
mana_deinit_cq(apc, &apc->tx_qp[i]->tx_cq);
diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index 91a906a7918a..0727d53345a3 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/iopoll.h>
+#include <linux/interrupt.h>
#include <linux/mdio.h>
#include <linux/phy.h>
#include <linux/oa_tc6.h>
@@ -44,6 +45,8 @@
#define INT_MASK0_LOSS_OF_FRAME_ERR_MASK BIT(4)
#define INT_MASK0_RX_BUFFER_OVERFLOW_ERR_MASK BIT(3)
#define INT_MASK0_TX_PROTOCOL_ERR_MASK BIT(0)
+#define INT_MASK0_ALL_INTERRUPTS (GENMASK(5, 0) | \
+ GENMASK(12, 7))
/* PHY Clause 22 registers base address and mask */
#define OA_TC6_PHY_STD_REG_ADDR_BASE 0xFF00
@@ -107,7 +110,6 @@
/* Internal structure for MAC-PHY drivers */
struct oa_tc6 {
- struct device *dev;
struct net_device *netdev;
struct phy_device *phydev;
struct mii_bus *mdiobus;
@@ -121,14 +123,13 @@ struct oa_tc6 {
struct sk_buff *ongoing_tx_skb;
struct sk_buff *waiting_tx_skb;
struct sk_buff *rx_skb;
- struct task_struct *spi_thread;
- wait_queue_head_t spi_wq;
u16 tx_skb_offset;
u16 spi_data_tx_buf_offset;
u16 tx_credits;
u8 rx_chunks_available;
bool rx_buf_overflow;
bool int_flag;
+ bool disable_traffic;
};
enum oa_tc6_header_type {
@@ -518,7 +519,7 @@ static int oa_tc6_mdiobus_register(struct oa_tc6 *tc6)
tc6->mdiobus->read_c45 = oa_tc6_mdiobus_read_c45;
tc6->mdiobus->write_c45 = oa_tc6_mdiobus_write_c45;
tc6->mdiobus->name = "oa-tc6-mdiobus";
- tc6->mdiobus->parent = tc6->dev;
+ tc6->mdiobus->parent = &tc6->spi->dev;
snprintf(tc6->mdiobus->id, ARRAY_SIZE(tc6->mdiobus->id), "%s",
dev_name(&tc6->spi->dev));
@@ -669,6 +670,38 @@ static void oa_tc6_cleanup_ongoing_tx_skb(struct oa_tc6 *tc6)
}
}
+static void oa_tc6_cleanup_waiting_tx_skb(struct oa_tc6 *tc6)
+{
+ if (tc6->waiting_tx_skb) {
+ tc6->netdev->stats.tx_dropped++;
+ kfree_skb(tc6->waiting_tx_skb);
+ tc6->waiting_tx_skb = NULL;
+ }
+}
+
+static void oa_tc6_free_pending_skbs(struct oa_tc6 *tc6)
+{
+ oa_tc6_cleanup_ongoing_tx_skb(tc6);
+ oa_tc6_cleanup_ongoing_rx_skb(tc6);
+ oa_tc6_cleanup_waiting_tx_skb(tc6);
+}
+
+/* If the failure is at SPI interface level, masking and clearing
+ * the interrupt of the device won't work. Since SPI interrupt is
+ * disabled, it should stop the repeated interrupts.
+ */
+static void oa_tc6_disable_traffic(struct oa_tc6 *tc6)
+{
+ u32 regval = INT_MASK0_ALL_INTERRUPTS;
+
+ tc6->disable_traffic = true;
+ oa_tc6_free_pending_skbs(tc6);
+ oa_tc6_write_register(tc6, OA_TC6_REG_INT_MASK0, regval);
+ oa_tc6_read_register(tc6, OA_TC6_REG_STATUS0, &regval);
+ oa_tc6_write_register(tc6, OA_TC6_REG_STATUS0, regval);
+ dev_err(&tc6->spi->dev, "Device interrupt disabled to avoid interrupt storm");
+}
+
static int oa_tc6_process_extended_status(struct oa_tc6 *tc6)
{
u32 value;
@@ -752,6 +785,17 @@ static int oa_tc6_process_rx_chunk_footer(struct oa_tc6 *tc6, u32 footer)
static void oa_tc6_submit_rx_skb(struct oa_tc6 *tc6)
{
+ /* MAC-PHY delivers each frame with its Ethernet FCS attached.
+ * Strip it before handing over to the stack, unless the user
+ * has asked to keep it via NETIF_F_RXFCS. Keeping the FCS
+ * in the frame is harmless for IP traffic, but is parsed as
+ * a (malformed) suffix TLV by PTP, which makes ptp4l reject
+ * every message with "bad message" error.
+ */
+ if (!(tc6->netdev->features & NETIF_F_RXFCS) &&
+ tc6->rx_skb->len > ETH_FCS_LEN)
+ skb_trim(tc6->rx_skb, tc6->rx_skb->len - ETH_FCS_LEN);
+
tc6->rx_skb->protocol = eth_type_trans(tc6->rx_skb, tc6->netdev);
tc6->netdev->stats.rx_packets++;
tc6->netdev->stats.rx_bytes += tc6->rx_skb->len;
@@ -1105,29 +1149,29 @@ static int oa_tc6_try_spi_transfer(struct oa_tc6 *tc6)
return 0;
}
-static int oa_tc6_spi_thread_handler(void *data)
+static irqreturn_t oa_tc6_macphy_threaded_irq(int irq, void *data)
{
struct oa_tc6 *tc6 = data;
- int ret;
-
- while (likely(!kthread_should_stop())) {
- /* This kthread will be waken up if there is a tx skb or mac-phy
- * interrupt to perform spi transfer with tx chunks.
- */
- wait_event_interruptible(tc6->spi_wq, tc6->int_flag ||
- (tc6->waiting_tx_skb &&
- tc6->tx_credits) ||
- kthread_should_stop());
-
- if (kthread_should_stop())
- break;
+ int ret = 0;
- ret = oa_tc6_try_spi_transfer(tc6);
- if (ret)
- return ret;
+ /* It is possible that interrupt woke the thread before it is
+ * disabled. Until we come up with good recovery mechanism,
+ * no need to attempt spi transfer, once it fails. Pending skbs
+ * are already freed.
+ */
+ if (!tc6->disable_traffic) {
+ while (tc6->int_flag ||
+ (tc6->waiting_tx_skb && tc6->tx_credits)) {
+ ret = oa_tc6_try_spi_transfer(tc6);
+ if (ret) {
+ disable_irq_nosync(tc6->spi->irq);
+ oa_tc6_disable_traffic(tc6);
+ break;
+ }
+ }
}
- return 0;
+ return IRQ_HANDLED;
}
static int oa_tc6_update_buffer_status_from_register(struct oa_tc6 *tc6)
@@ -1161,11 +1205,15 @@ static irqreturn_t oa_tc6_macphy_isr(int irq, void *data)
* the previous rx footer.
* - extended status event not reported in the previous rx footer.
*/
- tc6->int_flag = true;
- /* Wake spi kthread to perform spi transfer */
- wake_up_interruptible(&tc6->spi_wq);
-
- return IRQ_HANDLED;
+ if (tc6->disable_traffic)
+ disable_irq_nosync(tc6->spi->irq);
+ else
+ tc6->int_flag = true;
+ /* Wake IRQ thread to perform spi transfer . In case
+ * disable_traffic is set, threaded irq may run again
+ * one more time.
+ */
+ return IRQ_WAKE_THREAD;
}
/**
@@ -1202,7 +1250,7 @@ EXPORT_SYMBOL_GPL(oa_tc6_zero_align_receive_frame_enable);
*/
netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb)
{
- if (tc6->waiting_tx_skb) {
+ if (tc6->disable_traffic || tc6->waiting_tx_skb) {
netif_stop_queue(tc6->netdev);
return NETDEV_TX_BUSY;
}
@@ -1217,8 +1265,8 @@ netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb)
tc6->waiting_tx_skb = skb;
spin_unlock_bh(&tc6->tx_skb_lock);
- /* Wake spi kthread to perform spi transfer */
- wake_up_interruptible(&tc6->spi_wq);
+ /* Wake the threaded IRQ to perform spi transfer. */
+ irq_wake_thread(tc6->spi->irq, tc6);
return NETDEV_TX_OK;
}
@@ -1311,24 +1359,15 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
goto phy_exit;
}
- init_waitqueue_head(&tc6->spi_wq);
-
- tc6->spi_thread = kthread_run(oa_tc6_spi_thread_handler, tc6,
- "oa-tc6-spi-thread");
- if (IS_ERR(tc6->spi_thread)) {
- dev_err(&tc6->spi->dev, "Failed to create SPI thread\n");
- goto phy_exit;
- }
-
- sched_set_fifo(tc6->spi_thread);
-
- ret = devm_request_irq(&tc6->spi->dev, tc6->spi->irq, oa_tc6_macphy_isr,
- IRQF_TRIGGER_FALLING, dev_name(&tc6->spi->dev),
- tc6);
+ ret = devm_request_threaded_irq(&tc6->spi->dev, tc6->spi->irq,
+ oa_tc6_macphy_isr,
+ oa_tc6_macphy_threaded_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ dev_name(&tc6->spi->dev), tc6);
if (ret) {
dev_err(&tc6->spi->dev, "Failed to request macphy isr %d\n",
ret);
- goto kthread_stop;
+ goto phy_exit;
}
/* oa_tc6_sw_reset_macphy() function resets and clears the MAC-PHY reset
@@ -1338,12 +1377,10 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
* 7.7 and 9.2.8.8 in the OPEN Alliance specification for more details.
*/
tc6->int_flag = true;
- wake_up_interruptible(&tc6->spi_wq);
+ irq_wake_thread(tc6->spi->irq, tc6);
return tc6;
-kthread_stop:
- kthread_stop(tc6->spi_thread);
phy_exit:
oa_tc6_phy_exit(tc6);
return NULL;
@@ -1356,11 +1393,10 @@ EXPORT_SYMBOL_GPL(oa_tc6_init);
*/
void oa_tc6_exit(struct oa_tc6 *tc6)
{
+ tc6->disable_traffic = true;
+ disable_irq(tc6->spi->irq);
oa_tc6_phy_exit(tc6);
- kthread_stop(tc6->spi_thread);
- dev_kfree_skb_any(tc6->ongoing_tx_skb);
- dev_kfree_skb_any(tc6->waiting_tx_skb);
- dev_kfree_skb_any(tc6->rx_skb);
+ oa_tc6_free_pending_skbs(tc6);
}
EXPORT_SYMBOL_GPL(oa_tc6_exit);
diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
index a28a608f9bf4..82ddef9c17d5 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -105,6 +105,7 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac,
struct xdp_desc xdp_desc;
int num_tx = 0, pkt_len;
int descs_avail, ret;
+ u32 dst_tag_id;
u32 *epib;
int i;
@@ -137,9 +138,17 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac,
epib[0] = 0;
epib[1] = 0;
cppi5_hdesc_set_pktlen(host_desc, pkt_len);
- cppi5_desc_set_tags_ids(&host_desc->hdr, 0,
- (emac->port_id | (q_idx << 8)));
+ dst_tag_id = emac->port_id | (q_idx << 8);
+ if (emac->prueth->is_hsr_offload_mode &&
+ (ndev->features & NETIF_F_HW_HSR_DUP))
+ dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG;
+
+ if (emac->prueth->is_hsr_offload_mode &&
+ (ndev->features & NETIF_F_HW_HSR_TAG_INS))
+ epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS;
+
+ cppi5_desc_set_tags_ids(&host_desc->hdr, 0, dst_tag_id);
k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &dma_buf);
cppi5_hdesc_attach_buf(host_desc, dma_buf, pkt_len, dma_buf,
pkt_len);
@@ -696,6 +705,7 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac,
dma_addr_t desc_dma, buf_dma;
struct prueth_swdata *swdata;
struct page *page;
+ u32 dst_tag_id;
u32 *epib;
int ret;
@@ -737,9 +747,25 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac,
/* set dst tag to indicate internal qid at the firmware which is at
* bit8..bit15. bit0..bit7 indicates port num for directed
- * packets in case of switch mode operation
+ * packets in case of switch mode operation and port num 0
+ * for undirected packets in case of HSR offload mode.
+ *
+ * XDP_TX frames arrive on a slave port with the HSR tag already
+ * stripped by the PRU firmware. Like skb TX via hsr0, they must
+ * be sent as undirected so the PRU duplicates them to both ports
+ * and re-inserts the HSR sequence tag.
*/
- cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8)));
+ dst_tag_id = emac->port_id | (q_idx << 8);
+
+ if (emac->prueth->is_hsr_offload_mode &&
+ (ndev->features & NETIF_F_HW_HSR_DUP))
+ dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG;
+
+ if (emac->prueth->is_hsr_offload_mode &&
+ (ndev->features & NETIF_F_HW_HSR_TAG_INS))
+ epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS;
+
+ cppi5_desc_set_tags_ids(&first_desc->hdr, 0, dst_tag_id);
k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
cppi5_hdesc_attach_buf(first_desc, buf_dma, xdpf->len, buf_dma, xdpf->len);
swdata = cppi5_hdesc_get_swdata(first_desc);
@@ -927,6 +953,7 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id,
struct cppi5_host_desc_t *desc_rx;
struct prueth_swdata *swdata;
dma_addr_t desc_dma, buf_dma;
+ int avail_desc, alloc_budget;
struct xdp_buff *xdp;
int xdp_status = 0;
int count = 0;
@@ -993,16 +1020,13 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id,
if (xdp_status & ICSSG_XDP_REDIR)
xdp_do_flush();
- /* Allocate xsk buffers from the pool for the "count" number of
- * packets processed in order to be able to receive more packets.
- */
- ret = prueth_rx_alloc_zc(emac, count);
+ avail_desc = k3_cppi_desc_pool_avail(rx_chn->desc_pool);
+ alloc_budget = min_t(int, budget, avail_desc);
+
+ ret = prueth_rx_alloc_zc(emac, alloc_budget);
if (xsk_uses_need_wakeup(rx_chn->xsk_pool)) {
- /* If the user space doesn't provide enough buffers then it must
- * explicitly wake up the kernel when new buffers are available
- */
- if (ret < count)
+ if (ret < alloc_budget)
xsk_set_rx_need_wakeup(rx_chn->xsk_pool);
else
xsk_clear_rx_need_wakeup(rx_chn->xsk_pool);
diff --git a/drivers/net/pfcp.c b/drivers/net/pfcp.c
index 5f1c9d2c0b49..d8e4d60f5834 100644
--- a/drivers/net/pfcp.c
+++ b/drivers/net/pfcp.c
@@ -148,6 +148,7 @@ static void pfcp_link_setup(struct net_device *dev)
dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
dev->priv_flags |= IFF_NO_QUEUE;
+ dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
netif_keep_dst(dev);
}
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index f4adcfee7a80..7d2eeb9b1226 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -6222,6 +6222,19 @@ static void virtnet_free_irq_moder(struct virtnet_info *vi)
rtnl_unlock();
}
+static netdev_features_t virtnet_features_check(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
+{
+ /* Inner csum offload is only available for GSO packets. */
+ if (skb->encapsulation &&
+ (!skb_is_gso(skb) || netif_needs_gso(skb, features)))
+ return features & ~NETIF_F_CSUM_MASK;
+
+ /* Passthru. */
+ return features;
+}
+
static const struct net_device_ops virtnet_netdev = {
.ndo_open = virtnet_open,
.ndo_stop = virtnet_close,
@@ -6235,7 +6248,7 @@ static const struct net_device_ops virtnet_netdev = {
.ndo_bpf = virtnet_xdp,
.ndo_xdp_xmit = virtnet_xdp_xmit,
.ndo_xsk_wakeup = virtnet_xsk_wakeup,
- .ndo_features_check = passthru_features_check,
+ .ndo_features_check = virtnet_features_check,
.ndo_get_phys_port_name = virtnet_get_phys_port_name,
.ndo_set_features = virtnet_set_features,
.ndo_tx_timeout = virtnet_tx_timeout,
diff --git a/drivers/net/wwan/t7xx/t7xx_port_wwan.c b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
index 7fc569565ff9..d2529df7592a 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
@@ -106,6 +106,8 @@ static int t7xx_port_ctrl_tx(struct t7xx_port *port, struct sk_buff *skb)
while (cur) {
cloned = skb_clone(cur, GFP_KERNEL);
+ if (!cloned)
+ return cnt ? cnt : -ENOMEM;
cloned->len = skb_headlen(cur);
ret = t7xx_port_send_skb(port, cloned, 0, 0);
if (ret) {
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 588f8de51167..d5cfd24e815b 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -127,6 +127,7 @@ void afs_close_socket(struct afs_net *net)
{
_enter("");
+ cancel_work_sync(&net->charge_preallocation_work);
kernel_listen(net->socket, 0);
flush_workqueue(afs_async_calls);
@@ -742,7 +743,7 @@ void afs_charge_preallocation(struct work_struct *work)
container_of(work, struct afs_net, charge_preallocation_work);
struct afs_call *call = net->spare_incoming_call;
- for (;;) {
+ while (READ_ONCE(net->live)) {
if (!call) {
call = afs_alloc_call(net, &afs_RXCMxxxx, GFP_KERNEL);
if (!call)
@@ -792,7 +793,8 @@ static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall,
if (!call->server)
trace_afs_cm_no_server(call, rxrpc_kernel_remote_srx(call->peer));
- queue_work(afs_wq, &net->charge_preallocation_work);
+ if (net->live)
+ queue_work(afs_wq, &net->charge_preallocation_work);
}
/*
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 655564621f28..b67a12541eac 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1993,6 +1993,8 @@ enum netdev_reg_state {
* @qdisc_hash: qdisc hash table
* @watchdog_timeo: Represents the timeout that is used by
* the watchdog (see dev_watchdog())
+ * @watchdog_lock: protect watchdog_ref_held
+ * @watchdog_ref_held: True if the watchdog device ref is taken.
* @watchdog_timer: List of timers
*
* @proto_down_reason: reason a netdev interface is held down
@@ -2404,6 +2406,8 @@ struct net_device {
/* These may be needed for future network-power-down code. */
struct timer_list watchdog_timer;
int watchdog_timeo;
+ spinlock_t watchdog_lock;
+ bool watchdog_ref_held;
u32 proto_down_reason;
diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h
index ca0ec9c8608e..a8553401b1c9 100644
--- a/include/linux/skmsg.h
+++ b/include/linux/skmsg.h
@@ -4,6 +4,7 @@
#ifndef _LINUX_SKMSG_H
#define _LINUX_SKMSG_H
+#include <linux/bitops.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/scatterlist.h>
@@ -199,11 +200,14 @@ static inline void sk_msg_xfer(struct sk_msg *dst, struct sk_msg *src,
int which, u32 size)
{
dst->sg.data[which] = src->sg.data[which];
+ __assign_bit(which, dst->sg.copy, test_bit(which, src->sg.copy));
dst->sg.data[which].length = size;
dst->sg.size += size;
src->sg.size -= size;
src->sg.data[which].length -= size;
src->sg.data[which].offset += size;
+ if (!src->sg.data[which].length)
+ __clear_bit(which, src->sg.copy);
}
static inline void sk_msg_xfer_full(struct sk_msg *dst, struct sk_msg *src)
@@ -273,16 +277,19 @@ static inline void sk_msg_page_add(struct sk_msg *msg, struct page *page,
static inline void sk_msg_sg_copy(struct sk_msg *msg, u32 i, bool copy_state)
{
do {
- if (copy_state)
- __set_bit(i, msg->sg.copy);
- else
- __clear_bit(i, msg->sg.copy);
+ __assign_bit(i, msg->sg.copy, copy_state);
sk_msg_iter_var_next(i);
if (i == msg->sg.end)
break;
} while (1);
}
+static inline void sk_msg_sg_copy_assign(struct sk_msg *dst, u32 dst_i,
+ const struct sk_msg *src, u32 src_i)
+{
+ __assign_bit(dst_i, dst->sg.copy, test_bit(src_i, src->sg.copy));
+}
+
static inline void sk_msg_sg_copy_set(struct sk_msg *msg, u32 start)
{
sk_msg_sg_copy(msg, start, true);
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index 6e68e359ad18..7dee0ae616e3 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -111,6 +111,11 @@ static inline void fib_rule_get(struct fib_rule *rule)
refcount_inc(&rule->refcnt);
}
+static inline bool fib_rule_get_safe(struct fib_rule *rule)
+{
+ return refcount_inc_not_zero(&rule->refcnt);
+}
+
static inline void fib_rule_put(struct fib_rule *rule)
{
if (refcount_dec_and_test(&rule->refcnt))
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 1142ffad7444..a71a98505650 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -628,6 +628,11 @@ static inline void fib_info_hold(struct fib_info *fi)
refcount_inc(&fi->fib_clntref);
}
+static inline bool fib_info_hold_safe(struct fib_info *fi)
+{
+ return refcount_inc_not_zero(&fi->fib_clntref);
+}
+
static inline void fib_info_put(struct fib_info *fi)
{
if (refcount_dec_and_test(&fi->fib_clntref))
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 0632cf39d20a..6d376ea4d1c0 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2925,6 +2925,11 @@ static inline int tcp_call_bpf_3arg(struct sock *sk, int op, u32 arg1, u32 arg2,
return tcp_call_bpf(sk, op, 3, args);
}
+static inline void tcp_clear_sock_ops_cb_flags(struct sock *sk)
+{
+ tcp_sk(sk)->bpf_sock_ops_cb_flags = 0;
+}
+
#else
static inline int tcp_call_bpf(struct sock *sk, int op, u32 nargs, u32 *args)
{
@@ -2942,6 +2947,10 @@ static inline int tcp_call_bpf_3arg(struct sock *sk, int op, u32 arg1, u32 arg2,
return -EPERM;
}
+static inline void tcp_clear_sock_ops_cb_flags(struct sock *sk)
+{
+}
+
#endif
static inline u32 tcp_timeout_init(struct sock *sk)
diff --git a/net/6lowpan/nhc.c b/net/6lowpan/nhc.c
index 7b374595328d..a4dde85664f2 100644
--- a/net/6lowpan/nhc.c
+++ b/net/6lowpan/nhc.c
@@ -117,9 +117,9 @@ int lowpan_nhc_do_uncompression(struct sk_buff *skb,
return ret;
}
} else {
- spin_unlock_bh(&lowpan_nhc_lock);
netdev_warn(dev, "received nhc id for %s which is not implemented.\n",
nhc->name);
+ spin_unlock_bh(&lowpan_nhc_lock);
return -ENOTSUPP;
}
} else {
diff --git a/net/atm/common.c b/net/atm/common.c
index 654cbe3c855e..c7f92405daf0 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -670,6 +670,8 @@ __poll_t vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
static int check_tp(const struct atm_trafprm *tp)
{
/* @@@ Should be merged with adjust_tp */
+ if (tp->traffic_class > ATM_ANYCLASS)
+ return -EINVAL;
if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS)
return 0;
if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr &&
diff --git a/net/bridge/br_cfm.c b/net/bridge/br_cfm.c
index 118c7ea48c35..dea56fffa1c1 100644
--- a/net/bridge/br_cfm.c
+++ b/net/bridge/br_cfm.c
@@ -805,6 +805,12 @@ int br_cfm_cc_ccm_tx(struct net_bridge *br, const u32 instance,
goto save;
}
+ if (!interval_to_us(mep->cc_config.exp_interval)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Invalid CCM interval");
+ return -EINVAL;
+ }
+
/* Start delayed work to transmit CCM frames. It is done with zero delay
* to send first frame immediately
*/
diff --git a/net/bridge/br_cfm_netlink.c b/net/bridge/br_cfm_netlink.c
index 2faab44652e7..91b9922dc3f2 100644
--- a/net/bridge/br_cfm_netlink.c
+++ b/net/bridge/br_cfm_netlink.c
@@ -34,7 +34,9 @@ br_cfm_cc_config_policy[IFLA_BRIDGE_CFM_CC_CONFIG_MAX + 1] = {
[IFLA_BRIDGE_CFM_CC_CONFIG_UNSPEC] = { .type = NLA_REJECT },
[IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE] = { .type = NLA_U32 },
[IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE] = { .type = NLA_U32 },
- [IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL] = { .type = NLA_U32 },
+ [IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL] =
+ NLA_POLICY_RANGE(NLA_U32, BR_CFM_CCM_INTERVAL_3_3_MS,
+ BR_CFM_CCM_INTERVAL_10_MIN),
[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID] = {
.type = NLA_BINARY, .len = CFM_MAID_LENGTH },
};
diff --git a/net/core/dev.c b/net/core/dev.c
index 202e35acb15b..569c10b122f6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -11230,7 +11230,8 @@ static int netif_alloc_netdev_queues(struct net_device *dev)
netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL);
spin_lock_init(&dev->tx_global_lock);
-
+ spin_lock_init(&dev->watchdog_lock);
+ dev->watchdog_ref_held = false;
return 0;
}
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 8ca634964e36..cf374c208732 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -349,7 +349,7 @@ jumped:
if (err != -EAGAIN) {
if ((arg->flags & FIB_LOOKUP_NOREF) ||
- likely(refcount_inc_not_zero(&rule->refcnt))) {
+ likely(fib_rule_get_safe(rule))) {
arg->rule = rule;
goto out;
}
@@ -410,8 +410,12 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,
if (!ops)
return -EAFNOSUPPORT;
list_for_each_entry_rcu(rule, &ops->rules_list, list) {
+ if (!fib_rule_get_safe(rule))
+ continue;
+
err = call_fib_rule_notifier(nb, FIB_EVENT_RULE_ADD,
rule, family, extack);
+ fib_rule_put(rule);
if (err)
break;
}
diff --git a/net/core/filter.c b/net/core/filter.c
index 80439767e0ee..40037413dd4e 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2733,11 +2733,13 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
poffset += len;
sge->length = 0;
put_page(sg_page(sge));
+ __clear_bit(i, msg->sg.copy);
sk_msg_iter_var_next(i);
} while (i != last_sge);
sg_set_page(&msg->sg.data[first_sge], page, copy, 0);
+ __clear_bit(first_sge, msg->sg.copy);
/* To repair sg ring we need to shift entries. If we only
* had a single entry though we can just replace it and
@@ -2763,9 +2765,11 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
break;
msg->sg.data[i] = msg->sg.data[move_from];
+ sk_msg_sg_copy_assign(msg, i, msg, move_from);
msg->sg.data[move_from].length = 0;
msg->sg.data[move_from].page_link = 0;
msg->sg.data[move_from].offset = 0;
+ __clear_bit(move_from, msg->sg.copy);
sk_msg_iter_var_next(i);
} while (1);
@@ -2794,6 +2798,7 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
{
struct scatterlist sge, nsge, nnsge, rsge = {0}, *psge;
u32 new, i = 0, l = 0, space, copy = 0, offset = 0;
+ bool sge_copy, nsge_copy, nnsge_copy, rsge_copy = false;
u8 *raw, *to, *from;
struct page *page;
@@ -2866,6 +2871,7 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
sk_msg_iter_var_prev(i);
psge = sk_msg_elem(msg, i);
rsge = sk_msg_elem_cpy(msg, i);
+ rsge_copy = test_bit(i, msg->sg.copy);
psge->length = start - offset;
rsge.length -= psge->length;
@@ -2890,24 +2896,32 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
/* Shift one or two slots as needed */
sge = sk_msg_elem_cpy(msg, new);
+ sge_copy = test_bit(new, msg->sg.copy);
sg_unmark_end(&sge);
nsge = sk_msg_elem_cpy(msg, i);
+ nsge_copy = test_bit(i, msg->sg.copy);
if (rsge.length) {
sk_msg_iter_var_next(i);
nnsge = sk_msg_elem_cpy(msg, i);
+ nnsge_copy = test_bit(i, msg->sg.copy);
sk_msg_iter_next(msg, end);
}
while (i != msg->sg.end) {
msg->sg.data[i] = sge;
+ __assign_bit(i, msg->sg.copy, sge_copy);
sge = nsge;
+ sge_copy = nsge_copy;
sk_msg_iter_var_next(i);
if (rsge.length) {
nsge = nnsge;
+ nsge_copy = nnsge_copy;
nnsge = sk_msg_elem_cpy(msg, i);
+ nnsge_copy = test_bit(i, msg->sg.copy);
} else {
nsge = sk_msg_elem_cpy(msg, i);
+ nsge_copy = test_bit(i, msg->sg.copy);
}
}
@@ -2921,6 +2935,7 @@ place_new:
get_page(sg_page(&rsge));
sk_msg_iter_var_next(new);
msg->sg.data[new] = rsge;
+ __assign_bit(new, msg->sg.copy, rsge_copy);
}
sk_msg_reset_curr(msg);
@@ -2948,25 +2963,33 @@ static void sk_msg_shift_left(struct sk_msg *msg, int i)
prev = i;
sk_msg_iter_var_next(i);
msg->sg.data[prev] = msg->sg.data[i];
+ sk_msg_sg_copy_assign(msg, prev, msg, i);
} while (i != msg->sg.end);
sk_msg_iter_prev(msg, end);
+ __clear_bit(msg->sg.end, msg->sg.copy);
}
static void sk_msg_shift_right(struct sk_msg *msg, int i)
{
struct scatterlist tmp, sge;
+ bool tmp_copy, sge_copy;
sk_msg_iter_next(msg, end);
sge = sk_msg_elem_cpy(msg, i);
+ sge_copy = test_bit(i, msg->sg.copy);
sk_msg_iter_var_next(i);
tmp = sk_msg_elem_cpy(msg, i);
+ tmp_copy = test_bit(i, msg->sg.copy);
while (i != msg->sg.end) {
msg->sg.data[i] = sge;
+ __assign_bit(i, msg->sg.copy, sge_copy);
sk_msg_iter_var_next(i);
sge = tmp;
+ sge_copy = tmp_copy;
tmp = sk_msg_elem_cpy(msg, i);
+ tmp_copy = test_bit(i, msg->sg.copy);
}
}
@@ -3026,6 +3049,8 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
struct scatterlist *nsge, *sge = sk_msg_elem(msg, i);
int a = start - offset;
int b = sge->length - pop - a;
+ u32 sge_i = i;
+ bool sge_copy = test_bit(i, msg->sg.copy);
sk_msg_iter_var_next(i);
@@ -3038,6 +3063,7 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
sg_set_page(nsge,
sg_page(sge),
b, sge->offset + pop + a);
+ __assign_bit(i, msg->sg.copy, sge_copy);
} else {
struct page *page, *orig;
u8 *to, *from;
@@ -3054,6 +3080,7 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
memcpy(to, from, a);
memcpy(to + a, from + a + pop, b);
sg_set_page(sge, page, a + b, 0);
+ __clear_bit(sge_i, msg->sg.copy);
put_page(orig);
}
pop = 0;
diff --git a/net/core/netdev_rx_queue.c b/net/core/netdev_rx_queue.c
index de4dac4c88b3..00a7011eb4d5 100644
--- a/net/core/netdev_rx_queue.c
+++ b/net/core/netdev_rx_queue.c
@@ -338,12 +338,12 @@ void __netif_mp_uninstall_rxq(struct netdev_rx_queue *rxq,
void netif_rxq_cleanup_unlease(struct netdev_rx_queue *phys_rxq,
struct netdev_rx_queue *virt_rxq)
{
- struct pp_memory_provider_params *p = &phys_rxq->mp_params;
unsigned int rxq_idx = get_netdev_rx_queue_index(phys_rxq);
+ struct pp_memory_provider_params p = phys_rxq->mp_params;
- if (!p->mp_ops)
+ if (!p.mp_ops)
return;
- __netif_mp_uninstall_rxq(virt_rxq, p);
- __netif_mp_close_rxq(phys_rxq->dev, rxq_idx, p);
+ __netif_mp_close_rxq(phys_rxq->dev, rxq_idx, &p);
+ __netif_mp_uninstall_rxq(virt_rxq, &p);
}
diff --git a/net/core/skmsg.c b/net/core/skmsg.c
index 73ae12f25940..2521b643fa05 100644
--- a/net/core/skmsg.c
+++ b/net/core/skmsg.c
@@ -65,6 +65,7 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len,
sge = &msg->sg.data[msg->sg.end];
sg_unmark_end(sge);
sg_set_page(sge, pfrag->page, use, orig_offset);
+ __clear_bit(msg->sg.end, msg->sg.copy);
get_page(pfrag->page);
sk_msg_iter_next(msg, end);
}
@@ -185,6 +186,7 @@ static int sk_msg_free_elem(struct sock *sk, struct sk_msg *msg, u32 i,
sk_mem_uncharge(sk, len);
put_page(sg_page(sge));
}
+ __clear_bit(i, msg->sg.copy);
memset(sge, 0, sizeof(*sge));
return len;
}
diff --git a/net/ife/ife.c b/net/ife/ife.c
index be05b690b9ef..7a75947a31e3 100644
--- a/net/ife/ife.c
+++ b/net/ife/ife.c
@@ -79,7 +79,7 @@ void *ife_decode(struct sk_buff *skb, u16 *metalen)
if (unlikely(ifehdrln < 2))
return NULL;
- if (unlikely(!pskb_may_pull(skb, total_pull)))
+ if (unlikely(!pskb_may_pull(skb, total_pull + ETH_HLEN)))
return NULL;
ifehdr = (struct ifeheadr *)(skb->data + skb->dev->hard_header_len);
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 07068207b888..e11dc86ceda0 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2166,10 +2166,14 @@ static int fib_leaf_notify(struct key_vector *l, struct fib_table *tb,
if (fa->fa_slen == last_slen)
continue;
+ if (!fib_info_hold_safe(fa->fa_info))
+ continue;
+
last_slen = fa->fa_slen;
err = call_fib_entry_notifier(nb, FIB_EVENT_ENTRY_REPLACE,
l->key, KEYLENGTH - fa->fa_slen,
fa, extack);
+ fib_info_put(fa->fa_info);
if (err)
return err;
}
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 18b567288158..56902bba5483 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -1281,6 +1281,7 @@ void inet_csk_destroy_sock(struct sock *sk)
void inet_csk_prepare_for_destroy_sock(struct sock *sk)
{
/* The below has to be done to allow calling inet_csk_destroy_sock */
+ tcp_clear_sock_ops_cb_flags(sk);
sock_set_flag(sk, SOCK_DEAD);
tcp_orphan_count_inc();
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index c14b078b0249..6361ad2fcf77 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3277,11 +3277,11 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst)
/*
* Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
* corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
- * IPV6_MAXPLEN is also valid and means: "any MSS,
- * rely only on pmtu discovery"
+ * Limit the default MSS to GSO_BY_FRAGS - 1 to avoid
+ * collision with the GSO_BY_FRAGS magic value (0xFFFF).
*/
if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
- mtu = IPV6_MAXPLEN;
+ mtu = min_t(unsigned int, IPV6_MAXPLEN, GSO_BY_FRAGS - 1);
return mtu;
}
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index b273213cc68d..d469abcd989b 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -1302,8 +1302,8 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
psock->save_write_space = csk->sk_write_space;
psock->save_state_change = csk->sk_state_change;
csk->sk_user_data = psock;
- csk->sk_data_ready = psock_data_ready;
- csk->sk_write_space = psock_write_space;
+ WRITE_ONCE(csk->sk_data_ready, psock_data_ready);
+ WRITE_ONCE(csk->sk_write_space, psock_write_space);
csk->sk_state_change = psock_state_change;
write_unlock_bh(&csk->sk_callback_lock);
@@ -1379,8 +1379,8 @@ static void kcm_unattach(struct kcm_psock *psock)
*/
write_lock_bh(&csk->sk_callback_lock);
csk->sk_user_data = NULL;
- csk->sk_data_ready = psock->save_data_ready;
- csk->sk_write_space = psock->save_write_space;
+ WRITE_ONCE(csk->sk_data_ready, psock->save_data_ready);
+ WRITE_ONCE(csk->sk_write_space, psock->save_write_space);
csk->sk_state_change = psock->save_state_change;
strp_stop(&psock->strp);
diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
index 663d783e8dc1..d02ef9a74c3c 100644
--- a/net/qrtr/af_qrtr.c
+++ b/net/qrtr/af_qrtr.c
@@ -496,7 +496,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
if (cb->dst_port == QRTR_PORT_CTRL_LEGACY)
cb->dst_port = QRTR_PORT_CTRL;
- if (!size || len != ALIGN(size, 4) + hdrlen)
+ if (!size || size > len || len != ALIGN(size, 4) + hdrlen)
goto err;
if ((cb->type == QRTR_TYPE_NEW_SERVER ||
diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c
index ee2d1319e69a..47824120f1da 100644
--- a/net/rxrpc/call_accept.c
+++ b/net/rxrpc/call_accept.c
@@ -471,13 +471,26 @@ int rxrpc_kernel_charge_accept(struct socket *sock, rxrpc_notify_rx_t notify_rx,
unsigned long user_call_ID, gfp_t gfp,
unsigned int debug_id)
{
- struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
- struct rxrpc_backlog *b = rx->backlog;
+ struct rxrpc_backlog *b;
+ struct rxrpc_sock *rx;
+ struct sock *sk;
+ int ret;
- if (sock->sk->sk_state == RXRPC_CLOSE)
- return -ESHUTDOWN;
+ sk = sock->sk;
+ rx = rxrpc_sk(sk);
+
+ lock_sock(sk);
+ if (sk->sk_state != RXRPC_SERVER_LISTENING || !rx->backlog) {
+ ret = -ESHUTDOWN;
+ goto out;
+ }
+
+ b = rx->backlog;
+ ret = rxrpc_service_prealloc_one(rx, b, notify_rx, user_call_ID,
+ gfp, debug_id);
- return rxrpc_service_prealloc_one(rx, b, notify_rx, user_call_ID,
- gfp, debug_id);
+out:
+ release_sock(sk);
+ return ret;
}
EXPORT_SYMBOL(rxrpc_kernel_charge_accept);
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index c940600117a4..82614cbdb60f 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -161,7 +161,7 @@ static int rxrpc_verify_data(struct rxrpc_call *call, struct sk_buff *skb)
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
int ret;
- if (sp->len > call->rx_dec_bsize) {
+ if (sp->len > call->rx_dec_bsize || !call->rx_dec_buffer) {
/* Make sure we can hold a 1412-byte jumbo subpacket and make
* sure that the buffer size is aligned to a crypto blocksize.
*/
@@ -262,12 +262,13 @@ static int rxrpc_recvmsg_oob(struct socket *sock, struct msghdr *msg,
break;
}
- if (!(flags & MSG_PEEK))
+ if (!(flags & MSG_PEEK)) {
skb_unlink(skb, &rx->recvmsg_oobq);
- if (need_response)
- rxrpc_add_pending_oob(rx, skb);
- else
- rxrpc_free_skb(skb, rxrpc_skb_put_oob);
+ if (need_response)
+ rxrpc_add_pending_oob(rx, skb);
+ else
+ rxrpc_free_skb(skb, rxrpc_skb_put_oob);
+ }
return ret;
}
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index a1ee102abae1..77a67ace1d24 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -687,16 +687,17 @@ static int rxgk_issue_challenge(struct rxrpc_connection *conn)
ret = do_udp_sendmsg(conn->local->socket, &msg, len);
if (ret > 0)
rxrpc_peer_mark_tx(conn->peer);
- __free_page(page);
if (ret < 0) {
trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
rxrpc_tx_point_rxgk_challenge);
+ __free_page(page);
return -EAGAIN;
}
trace_rxrpc_tx_packet(conn->debug_id, whdr,
rxrpc_tx_point_rxgk_challenge);
+ __free_page(page);
_leave(" = 0");
return 0;
}
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index ab364e4e4686..356c68ebc389 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -21,6 +21,7 @@
#include <net/inet_sock.h>
#include <net/pkt_cls.h>
+#include <linux/siphash.h>
#include <net/ip.h>
#include <net/route.h>
#include <net/flow_dissector.h>
@@ -57,11 +58,15 @@ struct flow_filter {
struct rcu_work rwork;
};
+static siphash_aligned_key_t flow_keys_secret __read_mostly;
+
static inline u32 addr_fold(void *addr)
{
- unsigned long a = (unsigned long)addr;
-
- return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0);
+#ifdef CONFIG_64BIT
+ return (u32)siphash_1u64((u64)addr, &flow_keys_secret);
+#else
+ return (u32)siphash_1u32((u32)addr, &flow_keys_secret);
+#endif
}
static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow)
@@ -596,6 +601,7 @@ static int flow_init(struct tcf_proto *tp)
return -ENOBUFS;
INIT_LIST_HEAD(&head->filters);
rcu_assign_pointer(tp->root, head);
+ net_get_random_once(&flow_keys_secret, sizeof(flow_keys_secret));
return 0;
}
diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c
index 91dd2e629af8..cacf5244958e 100644
--- a/net/sched/sch_codel.c
+++ b/net/sched/sch_codel.c
@@ -56,7 +56,7 @@ static void drop_func(struct sk_buff *skb, void *ctx)
qdisc_qstats_drop(sch);
}
-static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
+static struct sk_buff *__codel_qdisc_dequeue(struct Qdisc *sch)
{
struct codel_sched_data *q = qdisc_priv(sch);
struct sk_buff *skb;
@@ -65,13 +65,51 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
&q->stats, qdisc_pkt_len, codel_get_enqueue_time,
drop_func, dequeue_func);
+ if (skb)
+ qdisc_bstats_update(sch, skb);
+ return skb;
+}
+
+static void codel_dequeue_drop(struct Qdisc *sch)
+{
+ struct codel_sched_data *q = qdisc_priv(sch);
+
if (q->stats.drop_count) {
- qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
+ qdisc_tree_reduce_backlog(sch, q->stats.drop_count,
+ q->stats.drop_len);
q->stats.drop_count = 0;
q->stats.drop_len = 0;
}
- if (skb)
- qdisc_bstats_update(sch, skb);
+}
+
+static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
+{
+ struct sk_buff *skb;
+
+ skb = __codel_qdisc_dequeue(sch);
+
+ codel_dequeue_drop(sch);
+
+ return skb;
+}
+
+static struct sk_buff *codel_peek(struct Qdisc *sch)
+{
+ struct sk_buff *skb = skb_peek(&sch->gso_skb);
+
+ if (!skb) {
+ skb = __codel_qdisc_dequeue(sch);
+
+ if (skb) {
+ __skb_queue_head(&sch->gso_skb, skb);
+ /* it's still part of the queue */
+ qdisc_qstats_backlog_inc(sch, skb);
+ sch->q.qlen++;
+ }
+
+ codel_dequeue_drop(sch);
+ }
+
return skb;
}
@@ -257,7 +295,7 @@ static struct Qdisc_ops codel_qdisc_ops __read_mostly = {
.enqueue = codel_qdisc_enqueue,
.dequeue = codel_qdisc_dequeue,
- .peek = qdisc_peek_dequeued,
+ .peek = codel_peek,
.init = codel_init,
.reset = codel_reset,
.change = codel_change,
diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c
index 100ef7e9f9f2..d7c3254ef800 100644
--- a/net/sched/sch_dualpi2.c
+++ b/net/sched/sch_dualpi2.c
@@ -578,7 +578,7 @@ static void drop_and_retry(struct dualpi2_sched_data *q, struct sk_buff *skb,
qdisc_qstats_drop(sch);
}
-static struct sk_buff *dualpi2_qdisc_dequeue(struct Qdisc *sch)
+static struct sk_buff *__dualpi2_qdisc_dequeue(struct Qdisc *sch)
{
struct dualpi2_sched_data *q = qdisc_priv(sch);
struct sk_buff *skb;
@@ -605,12 +605,49 @@ static struct sk_buff *dualpi2_qdisc_dequeue(struct Qdisc *sch)
break;
}
+ return skb;
+}
+
+static void dualpi2_dequeue_drop(struct Qdisc *sch)
+{
+ struct dualpi2_sched_data *q = qdisc_priv(sch);
+
if (q->deferred_drops_cnt) {
qdisc_tree_reduce_backlog(sch, q->deferred_drops_cnt,
q->deferred_drops_len);
q->deferred_drops_cnt = 0;
q->deferred_drops_len = 0;
}
+}
+
+static struct sk_buff *dualpi2_qdisc_dequeue(struct Qdisc *sch)
+{
+ struct sk_buff *skb;
+
+ skb = __dualpi2_qdisc_dequeue(sch);
+
+ dualpi2_dequeue_drop(sch);
+
+ return skb;
+}
+
+static struct sk_buff *dualpi2_peek(struct Qdisc *sch)
+{
+ struct sk_buff *skb = skb_peek(&sch->gso_skb);
+
+ if (!skb) {
+ skb = __dualpi2_qdisc_dequeue(sch);
+
+ if (skb) {
+ __skb_queue_head(&sch->gso_skb, skb);
+ /* it's still part of the queue */
+ qdisc_qstats_backlog_inc(sch, skb);
+ sch->q.qlen++;
+ }
+
+ dualpi2_dequeue_drop(sch);
+ }
+
return skb;
}
@@ -1165,7 +1202,7 @@ static struct Qdisc_ops dualpi2_qdisc_ops __read_mostly = {
.priv_size = sizeof(struct dualpi2_sched_data),
.enqueue = dualpi2_qdisc_enqueue,
.dequeue = dualpi2_qdisc_dequeue,
- .peek = qdisc_peek_dequeued,
+ .peek = dualpi2_peek,
.init = dualpi2_init,
.destroy = dualpi2_destroy,
.reset = dualpi2_reset,
@@ -1174,6 +1211,7 @@ static struct Qdisc_ops dualpi2_qdisc_ops __read_mostly = {
.dump_stats = dualpi2_dump_stats,
.owner = THIS_MODULE,
};
+MODULE_ALIAS_NET_SCH("dualpi2");
static int __init dualpi2_module_init(void)
{
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 71107dc52be7..cafd1f943d99 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -281,7 +281,7 @@ static void drop_func(struct sk_buff *skb, void *ctx)
qdisc_qstats_drop(sch);
}
-static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
+static struct sk_buff *__fq_codel_dequeue(struct Qdisc *sch)
{
struct fq_codel_sched_data *q = qdisc_priv(sch);
struct sk_buff *skb;
@@ -318,12 +318,49 @@ begin:
qdisc_bstats_update(sch, skb);
WRITE_ONCE(flow->deficit, flow->deficit - qdisc_pkt_len(skb));
+ return skb;
+}
+
+static void fq_codel_dequeue_drop(struct Qdisc *sch)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+
if (q->cstats.drop_count) {
qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
q->cstats.drop_len);
q->cstats.drop_count = 0;
q->cstats.drop_len = 0;
}
+}
+
+static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
+{
+ struct sk_buff *skb;
+
+ skb = __fq_codel_dequeue(sch);
+
+ fq_codel_dequeue_drop(sch);
+
+ return skb;
+}
+
+static struct sk_buff *fq_codel_peek(struct Qdisc *sch)
+{
+ struct sk_buff *skb = skb_peek(&sch->gso_skb);
+
+ if (!skb) {
+ skb = __fq_codel_dequeue(sch);
+
+ if (skb) {
+ __skb_queue_head(&sch->gso_skb, skb);
+ /* it's still part of the queue */
+ qdisc_qstats_backlog_inc(sch, skb);
+ sch->q.qlen++;
+ }
+
+ fq_codel_dequeue_drop(sch);
+ }
+
return skb;
}
@@ -726,7 +763,7 @@ static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
.priv_size = sizeof(struct fq_codel_sched_data),
.enqueue = fq_codel_enqueue,
.dequeue = fq_codel_dequeue,
- .peek = qdisc_peek_dequeued,
+ .peek = fq_codel_peek,
.init = fq_codel_init,
.reset = fq_codel_reset,
.destroy = fq_codel_destroy,
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 237ee1cd0136..3f1c510df850 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -568,16 +568,24 @@ static void dev_watchdog(struct timer_list *t)
dev->netdev_ops->ndo_tx_timeout(dev, i);
netif_unfreeze_queues(dev);
}
- if (!mod_timer(&dev->watchdog_timer,
- round_jiffies(oldest_start +
- dev->watchdog_timeo)))
- release = false;
+ spin_lock(&dev->watchdog_lock);
+ mod_timer(&dev->watchdog_timer,
+ round_jiffies(oldest_start +
+ dev->watchdog_timeo));
+ release = false;
+ spin_unlock(&dev->watchdog_lock);
}
}
spin_unlock(&dev->tx_global_lock);
- if (release)
+ spin_lock(&dev->watchdog_lock);
+ if (timer_pending(&dev->watchdog_timer))
+ release = false;
+ if (release && dev->watchdog_ref_held) {
netdev_put(dev, &dev->watchdog_dev_tracker);
+ dev->watchdog_ref_held = false;
+ }
+ spin_unlock(&dev->watchdog_lock);
}
void netdev_watchdog_up(struct net_device *dev)
@@ -586,18 +594,34 @@ void netdev_watchdog_up(struct net_device *dev)
return;
if (dev->watchdog_timeo <= 0)
dev->watchdog_timeo = 5*HZ;
+ spin_lock_bh(&dev->tx_global_lock);
+
+ spin_lock(&dev->watchdog_lock);
if (!mod_timer(&dev->watchdog_timer,
- round_jiffies(jiffies + dev->watchdog_timeo)))
- netdev_hold(dev, &dev->watchdog_dev_tracker,
- GFP_ATOMIC);
+ round_jiffies(jiffies + dev->watchdog_timeo))) {
+ if (!dev->watchdog_ref_held) {
+ netdev_hold(dev, &dev->watchdog_dev_tracker,
+ GFP_ATOMIC);
+ dev->watchdog_ref_held = true;
+ }
+ }
+ spin_unlock(&dev->watchdog_lock);
+
+ spin_unlock_bh(&dev->tx_global_lock);
}
EXPORT_SYMBOL_GPL(netdev_watchdog_up);
static void netdev_watchdog_down(struct net_device *dev)
{
netif_tx_lock_bh(dev);
- if (timer_delete(&dev->watchdog_timer))
+
+ spin_lock(&dev->watchdog_lock);
+ if (timer_delete(&dev->watchdog_timer)) {
netdev_put(dev, &dev->watchdog_dev_tracker);
+ dev->watchdog_ref_held = false;
+ }
+ spin_unlock(&dev->watchdog_lock);
+
netif_tx_unlock_bh(dev);
}
@@ -617,8 +641,6 @@ void netif_carrier_on(struct net_device *dev)
return;
atomic_inc(&dev->carrier_up_count);
linkwatch_fire_event(dev);
- if (netif_running(dev))
- netdev_watchdog_up(dev);
}
}
EXPORT_SYMBOL(netif_carrier_on);
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index c06d2761a1fb..7e537295b8b6 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -753,7 +753,7 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
u64 f; /* , myf_bound, delta; */
int go_passive = 0;
- if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC)
+ if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC && cl->cl_nactive)
go_passive = 1;
for (; cl->cl_parent != NULL; cl = cl->cl_parent) {
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 1741a9f33d8c..41958b8e59fd 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -2641,6 +2641,9 @@ do_addr_param:
goto fall_through;
addr_param = param.v + sizeof(struct sctp_addip_param);
+ if (ntohs(addr_param->p.length) >
+ ntohs(param.p->length) - sizeof(struct sctp_addip_param))
+ break;
af = sctp_get_af_specific(param_type2af(addr_param->p.type));
if (!af)
@@ -3039,13 +3042,16 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
union sctp_addr addr;
struct sctp_af *af;
- addr_param = (void *)asconf_param + sizeof(*asconf_param);
-
if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP &&
asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP &&
asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY)
return SCTP_ERROR_UNKNOWN_PARAM;
+ addr_param = (void *)asconf_param + sizeof(*asconf_param);
+ if (ntohs(addr_param->p.length) >
+ ntohs(asconf_param->param_hdr.length) - sizeof(*asconf_param))
+ return SCTP_ERROR_PROTO_VIOLATION;
+
switch (addr_param->p.type) {
case SCTP_PARAM_IPV6_ADDRESS:
if (!asoc->peer.ipv6_address)
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index a3bd1ef17558..05dcd2f9e887 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -482,6 +482,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b)
dev = (struct net_device *)rtnl_dereference(b->media_ptr);
dev_remove_pack(&b->pt);
RCU_INIT_POINTER(dev->tipc_ptr, NULL);
+ RCU_INIT_POINTER(b->media_ptr, NULL);
synchronize_net();
dev_put(dev);
}
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index 190b49c5cbc3..ba4f4906e13b 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -280,12 +280,21 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
u32 node, u32 dtype)
{
struct publication *p = NULL;
+ u32 lower = ntohl(i->lower);
+ u32 upper = ntohl(i->upper);
struct tipc_socket_addr sk;
- struct tipc_uaddr ua;
u32 key = ntohl(i->key);
+ struct tipc_uaddr ua;
+
+ /* A peer-advertised binding with lower > upper can never be matched
+ * or withdrawn and would leak the publication; the local bind path
+ * rejects such ranges, so reject ranges learned from the network too.
+ */
+ if (lower > upper)
+ return false;
tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
- ntohl(i->type), ntohl(i->lower), ntohl(i->upper));
+ ntohl(i->type), lower, upper);
sk.ref = ntohl(i->port);
sk.node = node;
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 1a9a5bdaccf4..8336a9664703 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -152,11 +152,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
{
.cmd = TIPC_NL_BEARER_DISABLE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_bearer_disable,
},
{
.cmd = TIPC_NL_BEARER_ENABLE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_bearer_enable,
},
{
@@ -168,11 +170,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
{
.cmd = TIPC_NL_BEARER_ADD,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_bearer_add,
},
{
.cmd = TIPC_NL_BEARER_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_bearer_set,
},
{
@@ -197,11 +201,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
{
.cmd = TIPC_NL_LINK_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_set_link,
},
{
.cmd = TIPC_NL_LINK_RESET_STATS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_reset_link_stats,
},
{
@@ -213,6 +219,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
{
.cmd = TIPC_NL_MEDIA_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_media_set,
},
{
@@ -228,6 +235,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
{
.cmd = TIPC_NL_NET_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_net_set,
},
{
@@ -238,6 +246,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
{
.cmd = TIPC_NL_MON_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_set_monitor,
},
{
@@ -255,6 +264,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
{
.cmd = TIPC_NL_PEER_REMOVE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_peer_rm,
},
#ifdef CONFIG_TIPC_MEDIA_UDP
@@ -269,11 +279,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
{
.cmd = TIPC_NL_KEY_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_set_key,
},
{
.cmd = TIPC_NL_KEY_FLUSH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_flush_key,
},
#endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 3a94278a44ac..e564341e0216 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1363,6 +1363,9 @@ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
__skb_queue_tail(xmitq, skb);
return;
} else if (mtyp == CONN_ACK) {
+ if (tsk->snt_unacked < msg_conn_ack(hdr))
+ goto exit;
+
was_cong = tsk_conn_cong(tsk);
tipc_sk_push_backlog(tsk, msg_nagle_ack(hdr));
tsk->snt_unacked -= msg_conn_ack(hdr);
@@ -2453,17 +2456,17 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
atomic_set(dcnt, 0);
lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt);
if (likely(!sk_add_backlog(sk, skb, lim))) {
- trace_tipc_sk_overlimit1(sk, skb, TIPC_DUMP_ALL,
+ trace_tipc_sk_overlimit1(sk, skb, TIPC_DUMP_SK_BKLGQ,
"bklg & rcvq >90% allocated!");
continue;
}
- trace_tipc_sk_dump(sk, skb, TIPC_DUMP_ALL, "err_overload!");
+ trace_tipc_sk_dump(sk, skb, TIPC_DUMP_SK_BKLGQ, "err_overload!");
/* Overload => reject message back to sender */
onode = tipc_own_addr(sock_net(sk));
sk_drops_inc(sk);
if (tipc_msg_reverse(onode, &skb, TIPC_ERR_OVERLOAD)) {
- trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_ALL,
+ trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_SK_BKLGQ,
"@sk_enqueue!");
__skb_queue_tail(xmitq, skb);
}
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json
index 808aef4afe22..ece7ec41bf99 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json
@@ -1378,5 +1378,60 @@
"teardown": [
"$TC actions flush action ife"
]
+ },
+ {
+ "id": "4e6b",
+ "name": "Decode IFE packet with truncated inner Ethernet header",
+ "category": [
+ "actions",
+ "ife"
+ ],
+ "plugins": {
+ "requires": [
+ "nsPlugin",
+ "scapyPlugin"
+ ]
+ },
+ "setup": [
+ [
+ "$TC actions flush action ife",
+ 0,
+ 1,
+ 255
+ ],
+ "$TC qdisc add dev $DEV1 clsact"
+ ],
+ "scapy": [
+ {
+ "iface": "$DEV0",
+ "count": 1,
+ "packet": "Ether(type=0xED3E) / Raw(b'\\x00\\x02\\xaa')"
+ }
+ ],
+ "cmdUnderTest": "$TC filter add dev $DEV1 ingress protocol all matchall action ife decode pipe index 10",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -s -j actions get action ife index 10",
+ "matchJSON": [
+ {
+ "total acts": 0
+ },
+ {
+ "actions": [
+ {
+ "kind": "ife",
+ "mode": "decode",
+ "index": 10,
+ "stats": {
+ "bytes": 3,
+ "packets": 1,
+ "drops": 1
+ }
+ }
+ ]
+ }
+ ],
+ "teardown": [
+ "$TC qdisc del dev $DEV1 clsact"
+ ]
}
]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json b/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json
index 1f4783724e5e..a1f97a4b606e 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json
@@ -1356,5 +1356,189 @@
"teardown": [
"$TC qdisc del dev $DUMMY handle 1: root"
]
+ },
+ {
+ "id": "c797",
+ "name": "Verify fq_codel won't mistakenly deactivate QFQ parent class during peek",
+ "category": [
+ "qdisc",
+ "qfq",
+ "fq_codel"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$IP link set dev $DUMMY up || true",
+ "$IP addr add 10.10.10.10/24 dev $DUMMY || true",
+ "$TC qdisc add dev $DUMMY root handle 1: qfq",
+ "$TC class add dev $DUMMY parent 1: classid 1:1 qfq weight 1 maxpkt 1000",
+ "$TC class add dev $DUMMY parent 1: classid 1:2 qfq weight 1 maxpkt 1000",
+ "$TC qdisc add dev $DUMMY parent 1:1 handle 2:0 plug limit 1024",
+ "$IP l set dev $DUMMY mtu 1500",
+ "$TC qdisc add dev $DUMMY parent 1:2 handle 10: fq_codel target 1 interval 1 flows 1",
+ "$TC filter add dev $DUMMY parent 1: protocol ip prio 1 u32 match ip dst 10.10.10.1/32 flowid 1:1",
+ "$TC filter add dev $DUMMY parent 1: protocol ip prio 2 u32 match ip dst 10.10.10.2/32 flowid 1:2",
+ "$IP l set dev $DUMMY mtu 65336",
+ "ping -c 1 -I $DUMMY 10.10.10.1 -W0.01 > /dev/null || true",
+ "ping -c 3 -s 2000 -I $DUMMY 10.10.10.2 -W0.01 > /dev/null || true",
+ "sleep 0.1"
+ ],
+ "cmdUnderTest": "$TC qdisc change dev $DUMMY handle 2:0 plug release_indefinite",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -s -j qdisc show dev $DUMMY",
+ "matchJSON": [
+ {
+ "kind": "qfq",
+ "handle": "1:",
+ "packets": 3,
+ "drops": 1,
+ "backlog": 0,
+ "qlen": 0
+ },
+ {
+ "kind": "plug",
+ "handle": "2:",
+ "packets": 1,
+ "drops": 0,
+ "backlog": 0,
+ "qlen": 0
+ },
+ {
+ "kind": "fq_codel",
+ "handle": "10:",
+ "packets": 2,
+ "drops": 1,
+ "backlog": 0,
+ "qlen": 0
+ }
+ ],
+ "teardown": [
+ "$TC qdisc del dev $DUMMY root",
+ "$IP addr del 10.10.10.10/24 dev $DUMMY || true"
+ ]
+ },
+ {
+ "id": "82d9",
+ "name": "Verify codel won't mistakenly deactivate QFQ parent class during peek",
+ "category": [
+ "qdisc",
+ "qfq",
+ "codel"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$IP link set dev $DUMMY up || true",
+ "$IP addr add 10.10.10.10/24 dev $DUMMY || true",
+ "$TC qdisc add dev $DUMMY root handle 1: qfq",
+ "$TC class add dev $DUMMY parent 1: classid 1:1 qfq weight 1 maxpkt 1000",
+ "$TC class add dev $DUMMY parent 1: classid 1:2 qfq weight 1 maxpkt 1000",
+ "$TC qdisc add dev $DUMMY parent 1:1 handle 2:0 plug limit 1024",
+ "$IP l set dev $DUMMY mtu 1500",
+ "$TC qdisc add dev $DUMMY parent 1:2 handle 10: codel target 1ms interval 1ms",
+ "$TC filter add dev $DUMMY parent 1: protocol ip prio 1 u32 match ip dst 10.10.10.1/32 flowid 1:1",
+ "$TC filter add dev $DUMMY parent 1: protocol ip prio 2 u32 match ip dst 10.10.10.2/32 flowid 1:2",
+ "$IP l set dev $DUMMY mtu 65336",
+ "ping -c 1 -I $DUMMY 10.10.10.1 -W0.01 > /dev/null || true",
+ "ping -c 3 -s 2000 -I $DUMMY 10.10.10.2 -W0.01 > /dev/null || true",
+ "sleep 0.1"
+ ],
+ "cmdUnderTest": "$TC qdisc change dev $DUMMY handle 2:0 plug release_indefinite",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -s -j qdisc show dev $DUMMY",
+ "matchJSON": [
+ {
+ "kind": "qfq",
+ "handle": "1:",
+ "packets": 3,
+ "drops": 1,
+ "backlog": 0,
+ "qlen": 0
+ },
+ {
+ "kind": "plug",
+ "handle": "2:",
+ "packets": 1,
+ "drops": 0,
+ "backlog": 0,
+ "qlen": 0
+ },
+ {
+ "kind": "codel",
+ "handle": "10:",
+ "packets": 2,
+ "drops": 1,
+ "backlog": 0,
+ "qlen": 0
+ }
+ ],
+ "teardown": [
+ "$TC qdisc del dev $DUMMY root",
+ "$IP addr del 10.10.10.10/24 dev $DUMMY || true"
+ ]
+ },
+ {
+ "id": "d3da",
+ "name": "Verify dualpi2 won't mistakenly deactivate QFQ parent class during peek",
+ "category": [
+ "qdisc",
+ "qfq",
+ "dualpi2"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$IP link set dev $DUMMY up || true",
+ "$IP addr add 10.10.10.10/24 dev $DUMMY || true" ,
+ "$TC qdisc add dev $DUMMY root handle 1: qfq",
+ "$TC class add dev $DUMMY parent 1: classid 1:1 qfq weight 1 maxpkt 1000",
+ "$TC class add dev $DUMMY parent 1: classid 1:2 qfq weight 1 maxpkt 1000",
+ "$TC qdisc add dev $DUMMY parent 1:1 handle 2:0 plug limit 1024",
+ "$TC qdisc add dev $DUMMY parent 1:2 handle 10: dualpi2 step_thresh 500ms",
+ "$TC filter add dev $DUMMY parent 10: protocol ip prio 1 matchall classid 10:1 action ok",
+ "$TC filter add dev $DUMMY parent 1: protocol ip prio 1 u32 match ip dst 10.10.10.1/32 flowid 1:1",
+ "$TC filter add dev $DUMMY parent 1: protocol ip prio 2 u32 match ip dst 10.10.10.2/32 flowid 1:2",
+ "ping -c 1 -I $DUMMY 10.10.10.1 -W0.01 || true",
+ "ping -c 3 -i 0.1 -I $DUMMY 10.10.10.2 -W0.01 || true",
+ "sleep 0.7",
+ "ping -c 1 -I $DUMMY 10.10.10.2 -W0.01 || true",
+ "$TC qdisc change dev $DUMMY handle 2:0 plug release_indefinite"
+ ],
+ "cmdUnderTest": "ping -c 1 -I $DUMMY 10.10.10.1 -W0.01",
+ "expExitCode": "1",
+ "verifyCmd": "$TC -s -j qdisc show dev $DUMMY",
+ "matchJSON": [
+ {
+ "kind": "qfq",
+ "handle": "1:",
+ "packets": 4,
+ "drops": 2,
+ "backlog": 0,
+ "qlen": 0
+ },
+ {
+ "kind": "plug",
+ "handle": "2:",
+ "packets": 2,
+ "drops": 0,
+ "backlog": 0,
+ "qlen": 0
+ },
+ {
+ "kind": "dualpi2",
+ "handle": "10:",
+ "packets": 2,
+ "drops": 2,
+ "backlog": 0,
+ "qlen": 0
+ }
+ ],
+ "teardown": [
+ "$TC qdisc del dev $DUMMY root",
+ "$IP addr del 10.10.10.10/24 dev $DUMMY || true"
+ ]
}
]