Current release - new code bugs:

- mctp: usblib: fix assertion breaking esoteric builds
 
 Previous releases - regressions:
 
  - eth: ti: am65-cpts: fix support for PTP_EXTTS_REQUEST2 ioctl
 
  - eth: mlx4: always create the eth and ib auxiliary devices
 
  - Revert advertising the TCP MSS from the configured MTU
 
  - eth: tg3: invert restart quirk logic to restrict SNP power-down bypass
 
  - eth: bnxt: recycle agg buffers when Rx head buffer allocation fails
 
 - netlink: check sk_rcvbuf before charging the dump skb
 
 Previous releases - always broken:
 
  - net: fix frag_list leak in skb_segment_list() error path
 
  - sctp: reject forged cookie peer_addr with unknown address family
 
  - vxlan: keep reserved_bits across changelink
 
  - net: limit priority VLAN untag depth
 
  - inet: frags: prevent acceptance of partially authenticated reassembly
 
  - gro: do not GRO GSO packets with inconsistent payload
 
  - tcp: avoid double destroy in tcp_abort() of an unaccepted child
 
 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmrjeuQACgkQMUZtbf5S
 IrsVgRAAv5gGdXhE5FnO5QqM5t8+B8cR2859TV3959TJlVbOSoP7yCtPh5seI8uo
 nMzE6OzKp47aN50ZB/iZ6zLUoZ0sr/dWgmrN979cH9ZSIFhsjwB7xhJD9a54ltoX
 V/ezBxW6WuYFFeEwk+4q8M9rxeNJJ2/ILqeifzormhXyTDPRxtJTJlvLoQ8Tz2R5
 Ke6AP7XEs9fWgwRxpxMa19vDzzMxtOBxfQwhzlypes/5CRIKl57aWrAoFMgXHABT
 ayhnXabctzW92OnOq6gA8VLEaAHN9rX3RHGaphNzHcO5skxIk/Blwb2s6mZKARvC
 PCCTb5lXwzM8jejGZo2vC8+XdcebR1VWZxgw0vnSVkiUZbDoHpeOot0IpAffGzGO
 8tikWJ3Hy81J4WjR+KfsD+xLC26YnlsydRDlyTxnEZnwpeHUueZwE1ONzCIIwtGg
 okRQOdis82s6H76FDBb8/Uumds5ODdDsM7Cc2DUP/EiFOf4YOOTX4M0XrKlcvZS/
 xpaiFkuNemModIhplCzei1ps3DTGpTXYITJD3ykEaZlVF2d7uRj7+v9Tb7Vjl9yK
 cNwz1IOIggx9zlioayZbtCWzs5SOtpUicQ+h02ECb6kbnq9Uc2w3jLwLQrCcAFqy
 UFWtCKKQZ3pilMt+SM4Gi49875BNPgfkIL4JhB15YFJ81ipZKSI=
 =3jq2
 -----END PGP SIGNATURE-----

Merge tag 'net-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Pull networking fixes from Jakub Kicinski:
 "Current release - new code bugs:

   - mctp: usblib: fix assertion breaking esoteric builds

  Previous releases - regressions:

   - Revert advertising the TCP MSS from the configured MTU

  - netlink: check sk_rcvbuf before charging the dump skb

   - eth:
      - ti: am65-cpts: fix support for PTP_EXTTS_REQUEST2 ioctl
      - mlx4: always create the eth and ib auxiliary devices
      - tg3: invert restart quirk logic to restrict SNP power-down bypass
      - bnxt: recycle agg buffers when Rx head buffer allocation fails

  Previous releases - always broken:

   - net: fix frag_list leak in skb_segment_list() error path

   - sctp: reject forged cookie peer_addr with unknown address family

   - vxlan: keep reserved_bits across changelink

   - net: limit priority VLAN untag depth

   - inet: frags: prevent acceptance of partially authenticated reassembly

   - gro: do not GRO GSO packets with inconsistent payload

   - tcp: avoid double destroy in tcp_abort() of an unaccepted child"

* tag 'net-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (137 commits)
  tun: drop batched packets while the device is down
  selftests: net: netlink-dumps: start a dump with a notification queued
  netlink: check sk_rcvbuf before charging the dump skb
  net/sched: act_ife: do not consume the inner header on egress
  openvswitch: use eth_type_trans_careful() in internal_dev_recv()
  net: use eth_type_trans_careful() in __dev_forward_skb2()
  loopback: use eth_type_trans_careful()
  net: add eth_type_trans_careful()
  tcp: initialize mapped children before route lookup
  tcp: fix reordering addition overflow in MTU probing
  tcp: avoid double destroy in tcp_abort() of an unaccepted child
  net: bgmac: fix TX DMA unmapping and slot cleanup
  gro: do not GRO GSO packets with inconsistent payload
  net/packet: check TX_RING fragments before memory accounting
  eth: bnxt: hand XDP frags over to the copybreak skb
  eth: bnxt: free XDP frags when xdp_do_redirect() fails
  eth: bnxt: don't leak buffers when XDP agg buffer allocation fails
  eth: bnxt: resize Rx head buffers when rx-copybreak changes
  eth: bnxt: recycle agg buffers when Rx head buffer allocation fails
  netdev-genl: ignore NETDEV_UNREGISTER rebroadcasts
  ...
This commit is contained in:
Linus Torvalds 2026-10-29 08:17:05 -10:00
commit 4dd16e3113
142 changed files with 1596 additions and 684 deletions

View File

@ -194,3 +194,4 @@ mcast-groups:
list:
-
name: gtp
flags: [uns-admin-perm]

View File

@ -1128,6 +1128,8 @@ tcp_tso_rtt_log - INTEGER
If you want to use the old autosizing, set this sysctl to 0.
Possible values are [0, 31], inclusive.
Default: 9 (2^9 = 512 usec)
tcp_pacing_ss_ratio - INTEGER

View File

@ -71,12 +71,16 @@ During driver initialization device sets the ``NETIF_F_HW_TLS_RX`` and
pointer in the :c:member:`tlsdev_ops` member of the
:c:type:`struct net_device <net_device>`.
When TLS cryptographic connection state is installed on a ``ktls`` socket
(note that it is done twice, once for RX and once for TX direction,
and the two are completely independent), the kernel checks if the underlying
network device is offload-capable and attempts the offload. In case offload
fails the connection is handled entirely in software using the same mechanism
as if the offload was never tried.
TLS cryptographic connection state is installed separately for RX and TX
on a ``ktls`` socket. For each direction, the kernel checks if the underlying
network device is offload-capable and attempts the offload. If offload fails,
that direction is handled in software as if offload had never been tried.
Both hardware directions share one device binding. Once one direction is
offloaded, the other direction must use the same device. If a route change
selects a different device, or ``NETDEV_DOWN`` has cleared the binding,
hardware offload of the other direction is declined and it uses software
instead.
Offload request is performed via the :c:member:`tls_dev_add` callback of
:c:type:`struct tlsdev_ops <tlsdev_ops>`:

View File

@ -27136,6 +27136,8 @@ F: drivers/net/ethernet/synopsys/
SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER
L: netdev@vger.kernel.org
S: Orphan
F: Documentation/devicetree/bindings/net/pcs/snps,dw-xpcs.yaml
F: drivers/net/pcs/pcs-xpcs-plat.c
F: drivers/net/pcs/pcs-xpcs.c
F: drivers/net/pcs/pcs-xpcs.h
F: include/linux/pcs/pcs-xpcs.h

View File

@ -6273,7 +6273,7 @@ static int __init bond_check_params(struct bond_params *params)
}
for (arp_ip_count = 0, i = 0;
(arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) {
(i < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) {
__be32 ip;
/* not a complete check, but good enough to catch mistakes */

View File

@ -679,8 +679,8 @@ yt921x_fdb_flush_port(struct yt921x_priv *priv, int port, bool flush_static)
}
static int
yt921x_fdb_add_index_in12(struct yt921x_priv *priv, u16 index, u16 ctrl1,
u16 ctrl2)
yt921x_fdb_add_index_in12(struct yt921x_priv *priv, u16 index, u32 ctrl1,
u32 ctrl2)
{
u32 ctrl;
u32 val;

View File

@ -3300,10 +3300,13 @@ mt753x_conduit_state_change(struct dsa_switch *ds,
/* Set the CPU port to trap frames to for MT7530. Trapped frames will be
* forwarded to the numerically smallest CPU port whose conduit
* interface is up.
* interface is up. On EN7581, trapped BPDUs do not reach the CPU port
* without this, even with the CPU port bitmap set. AN7583 is set up
* the same way as EN7581.
*/
if (priv->id != ID_MT7530 && priv->id != ID_MT7621 &&
priv->id != ID_EN7528)
priv->id != ID_EN7528 &&
priv->id != ID_EN7581 && priv->id != ID_AN7583)
return;
mask = BIT(cpu_dp->index);

View File

@ -4611,7 +4611,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_get_cmode = mv88e6352_port_get_cmode,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@ -4715,7 +4715,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_get_cmode = mv88e6352_port_get_cmode,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@ -5381,7 +5381,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_get_cmode = mv88e6352_port_get_cmode,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@ -5427,7 +5427,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_get_cmode = mv88e6352_port_get_cmode,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@ -6023,7 +6023,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.g2_irqs = 10,
.stats_type = STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
.stats_type = STATS_TYPE_BANK0 | STATS_TYPE_PORT,
.atu_move_port_mask = 0xf,
.pvt = true,
.multi_chip = true,

View File

@ -342,9 +342,9 @@ static void aq_pci_remove(struct pci_dev *pdev)
struct aq_nic_s *self = pci_get_drvdata(pdev);
if (self->ndev) {
aq_clear_rxnfc_all_rules(self);
if (self->ndev->reg_state == NETREG_REGISTERED)
unregister_netdev(self->ndev);
aq_clear_rxnfc_all_rules(self);
#if IS_ENABLED(CONFIG_MACSEC)
aq_macsec_free(self);

View File

@ -208,19 +208,24 @@ static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac,
return NETDEV_TX_OK;
err_dma:
slot->dma_addr = 0;
while (i-- > 0) {
index = (ring->end + 1 + i) % BGMAC_TX_RING_SLOTS;
slot = &ring->slots[index];
dma_unmap_page(dma_dev, slot->dma_addr,
skb_frag_size(&skb_shinfo(skb)->frags[i]),
DMA_TO_DEVICE);
slot->dma_addr = 0;
}
slot = &ring->slots[ring->end % BGMAC_TX_RING_SLOTS];
dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb),
DMA_TO_DEVICE);
while (i-- > 0) {
int index = (ring->end + i) % BGMAC_TX_RING_SLOTS;
struct bgmac_slot_info *slot = &ring->slots[index];
u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1);
int len = ctl1 & BGMAC_DESC_CTL1_LEN;
dma_unmap_page(dma_dev, slot->dma_addr, len, DMA_TO_DEVICE);
}
err_dma_head:
slot->dma_addr = 0;
netdev_err(bgmac->net_dev, "Mapping error of skb on ring 0x%X\n",
ring->mmio_base);
@ -536,18 +541,26 @@ static void bgmac_dma_tx_ring_free(struct bgmac *bgmac,
u32 ctl1 = le32_to_cpu(dma_desc[i].ctl1);
unsigned int len = ctl1 & BGMAC_DESC_CTL1_LEN;
slot = &ring->slots[i];
if (slot->dma_addr) {
if (le32_to_cpu(dma_desc[i].ctl0) & BGMAC_DESC_CTL0_SOF)
dma_unmap_single(dma_dev, slot->dma_addr,
len, DMA_TO_DEVICE);
else
dma_unmap_page(dma_dev, slot->dma_addr,
len, DMA_TO_DEVICE);
slot->dma_addr = 0;
}
}
/* A packet can wrap around the end of the ring with its skb on the
* last slot, so free the skbs only once every slot is unmapped.
*/
for (i = 0; i < BGMAC_TX_RING_SLOTS; i++) {
slot = &ring->slots[i];
dev_kfree_skb(slot->skb);
if (!slot->dma_addr)
continue;
if (slot->skb)
dma_unmap_single(dma_dev, slot->dma_addr,
len, DMA_TO_DEVICE);
else
dma_unmap_page(dma_dev, slot->dma_addr,
len, DMA_TO_DEVICE);
slot->skb = NULL;
}
}

View File

@ -182,8 +182,9 @@ int bnge_cal_nr_rss_ctxs(u16 rx_rings)
if (!rx_rings)
return 0;
return bnge_adjust_pow_two(rx_rings - 1,
BNGE_RSS_TABLE_ENTRIES);
return min_t(int, bnge_adjust_pow_two(rx_rings - 1,
BNGE_RSS_TABLE_ENTRIES),
BNGE_RSS_TABLE_MAX_TBL);
}
static u16 bnge_rss_ctxs_in_use(struct bnge_dev *bd,
@ -459,6 +460,7 @@ static void _bnge_get_max_rings(struct bnge_dev *bd, u16 *max_rx,
}
*max_rx = min_t(int, *max_rx, max_ring_grps);
*max_rx = min_t(int, *max_rx, BNGE_MAX_RSS_TABLE_ENTRIES);
}
static int bnge_get_max_rings(struct bnge_dev *bd, u16 *max_rx,

View File

@ -81,13 +81,10 @@ bnge_adjust_pow_two(u32 total_ent, u16 ent_per_blk)
{
u32 blks = total_ent / ent_per_blk;
if (blks == 0 || blks == 1)
return ++blks;
if (!blks)
return 1;
if (!is_power_of_2(blks))
blks = roundup_pow_of_two(blks);
return blks;
return roundup_pow_of_two(blks + 1);
}
#define BNGE_MAX_ROCE_MSIX 64

View File

@ -1215,7 +1215,15 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
bp->rx_dir);
skb = napi_build_skb(frag_start, rxr->rx_page_size);
if (!skb) {
page_pool_recycle_direct(rxr->page_pool, page);
struct page *new_page;
new_page = rxr->rx_buf_ring[RING_RX(bp, prod)].data;
/* The caller may still need the XDP frags from shinfo at the
* end of the head page. Release the new buffer instead and
* put the head back on the ring.
*/
page_pool_recycle_direct(rxr->page_pool, new_page);
bnxt_reuse_rx_data(rxr, cons, data);
return NULL;
}
skb_mark_for_recycle(skb);
@ -1419,16 +1427,19 @@ static u32 bnxt_rx_agg_netmems_xdp(struct bnxt *bp,
struct skb_shared_info *shinfo = xdp_get_shared_info_from_buff(xdp);
u32 total_frag_len = 0;
if (!xdp_buff_has_frags(xdp))
if (!xdp_buff_has_frags(xdp)) {
xdp_buff_set_frags_flag(xdp);
shinfo->nr_frags = 0;
}
total_frag_len = __bnxt_rx_agg_netmems(bp, cpr, idx, agg_bufs, tpa,
NULL, xdp);
if (total_frag_len) {
xdp_buff_set_frags_flag(xdp);
shinfo->nr_frags = agg_bufs;
shinfo->xdp_frags_size = total_frag_len;
if (!total_frag_len) {
bnxt_xdp_buff_frags_free(cpr->bnapi->rx_ring, xdp);
return 0;
}
shinfo->nr_frags = agg_bufs;
shinfo->xdp_frags_size = total_frag_len;
return total_frag_len;
}
@ -1500,6 +1511,14 @@ static struct sk_buff *bnxt_copy_xdp(struct bnxt_napi *bnapi,
__skb_pull(skb, metasize);
}
if (unlikely(xdp_buff_has_frags(xdp))) {
struct skb_shared_info *sinfo;
sinfo = xdp_get_shared_info_from_buff(xdp);
memcpy(skb_shinfo(skb)->frags, sinfo->frags,
sinfo->nr_frags * sizeof(skb_frag_t));
}
return skb;
}
@ -2285,8 +2304,10 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
cp_cons,
agg_bufs,
false);
if (!frag_len)
if (!frag_len) {
bnxt_reuse_rx_data(rxr, cons, data);
goto oom_next_rx;
}
}
xdp_active = true;
@ -2313,17 +2334,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
skb = bnxt_copy_xdp(bnapi, &bnxt_xdp.xdp, len,
dma_addr);
bnxt_reuse_rx_data(rxr, cons, data);
if (!skb) {
if (agg_bufs) {
if (!xdp_active)
bnxt_reuse_rx_agg_bufs(cpr, cp_cons, 0,
agg_bufs, false);
else
bnxt_xdp_buff_frags_free(rxr,
&bnxt_xdp.xdp);
}
goto oom_next_rx;
}
if (!skb)
goto oom_next_rx_agg;
} else {
u32 payload;
@ -2334,7 +2346,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
skb = bp->rx_skb_func(bp, rxr, cons, data, data_ptr, dma_addr,
payload | len);
if (!skb)
goto oom_next_rx;
goto oom_next_rx_agg;
}
if (agg_bufs) {
@ -2424,6 +2436,14 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
return rc;
oom_next_rx_agg:
if (agg_bufs) {
if (!xdp_active)
bnxt_reuse_rx_agg_bufs(cpr, cp_cons, 0, agg_bufs,
false);
else
bnxt_xdp_buff_frags_free(rxr, &bnxt_xdp.xdp);
}
oom_next_rx:
cpr->sw_stats->rx.rx_oom_discards += 1;
rc = -ENOMEM;

View File

@ -4601,6 +4601,7 @@ static int bnxt_set_tunable(struct net_device *dev,
if (netif_running(dev))
return -EBUSY;
bp->rx_copybreak = rx_copybreak;
bnxt_set_ring_params(bp);
}
return 0;
case ETHTOOL_PFC_PREVENTION_TOUT:

View File

@ -307,6 +307,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
if (xdp_do_redirect(bp->dev, xdp, xdp_prog)) {
trace_xdp_exception(bp->dev, xdp_prog, act);
bnxt_xdp_buff_frags_free(rxr, xdp);
page_pool_recycle_direct(rxr->page_pool, page);
return true;
}

View File

@ -931,10 +931,13 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
/* Program all TX queues with the same values, as there is no
* ethtool knob to do coalescing on a per-queue basis
*/
for (i = 0; i <= priv->hw_params->tx_queues; i++)
for (i = 0; i <= priv->hw_params->tx_queues; i++) {
priv->tx_rings[i].tx_max_coalesced_frames =
ec->tx_max_coalesced_frames;
bcmgenet_tdma_ring_writel(priv, i,
ec->tx_max_coalesced_frames,
DMA_MBUF_DONE_THRESH);
}
for (i = 0; i <= priv->hw_params->rx_queues; i++)
bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[i], ec);
@ -2753,7 +2756,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
bcmgenet_tdma_ring_writel(priv, index, ring->tx_max_coalesced_frames,
DMA_MBUF_DONE_THRESH);
/* Disable rate control for now */
bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
TDMA_FLOW_PERIOD);
@ -3112,7 +3116,9 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
bcmgenet_free_rx_buffers(priv);
bcmgenet_destroy_rx_page_pools(priv);
kfree(priv->rx_cbs);
priv->rx_cbs = NULL;
kfree(priv->tx_cbs);
priv->tx_cbs = NULL;
}
/* init_edma: Initialize DMA control register */
@ -3170,6 +3176,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv, bool flush_rx)
priv->tx_cbs = kzalloc_objs(struct enet_cb, priv->num_tx_bds);
if (!priv->tx_cbs) {
kfree(priv->rx_cbs);
priv->rx_cbs = NULL;
return -ENOMEM;
}
@ -3189,7 +3196,9 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv, bool flush_rx)
bcmgenet_free_rx_buffers(priv);
bcmgenet_destroy_rx_page_pools(priv);
kfree(priv->rx_cbs);
priv->rx_cbs = NULL;
kfree(priv->tx_cbs);
priv->tx_cbs = NULL;
return ret;
}
@ -3498,7 +3507,9 @@ static int bcmgenet_close(struct net_device *dev)
netif_dbg(priv, ifdown, dev, "bcmgenet_close\n");
bcmgenet_netif_stop(dev, false);
/* A failed resume has torn the datapath down already */
if (priv->tx_cbs)
bcmgenet_netif_stop(dev, false);
/* Really kill the PHY state machine and disconnect from it */
phy_disconnect(dev->phydev);
@ -3506,6 +3517,9 @@ static int bcmgenet_close(struct net_device *dev)
free_irq(priv->irq0, priv);
free_irq(priv->irq1, priv);
/* A failed resume left the device detached, __dev_open() refuses that */
netif_device_attach(dev);
if (priv->internal_phy)
ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
@ -4161,6 +4175,8 @@ static int bcmgenet_probe(struct platform_device *pdev)
priv->rx_rings[i].index = i;
priv->rx_rings[i].rx_max_coalesced_frames = 1;
}
for (i = 0; i <= priv->hw_params->tx_queues; i++)
priv->tx_rings[i].tx_max_coalesced_frames = 1;
/* Initialize u64 stats seq counter for 32bit machines */
for (i = 0; i <= GENET_MAX_MQ_CNT; i++) {
@ -4263,7 +4279,11 @@ static int bcmgenet_resume(struct device *d)
if (device_may_wakeup(d) && priv->wolopts) {
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
if (reg & CMD_RX_EN) {
/* The WoL power down sets CMD_RX_EN itself, so the bit
* alone does not mean the rings survived
*/
if (priv->tx_cbs && (reg & CMD_RX_EN)) {
/* Successfully exited WoL, just resume data flows */
list_for_each_entry(rule, &priv->rxnfc_list, list)
if (rule->state == BCMGENET_RXNFC_STATE_ENABLED)
@ -4293,6 +4313,9 @@ static int bcmgenet_resume(struct device *d)
bcmgenet_rdma_disable(priv);
bcmgenet_intr_disable(priv);
bcmgenet_fini_dma(priv);
if (phy_is_started(dev->phydev) ||
dev->phydev->state == PHY_ERROR)
phy_stop(dev->phydev);
enable_irq(priv->irq1);
}
@ -4315,8 +4338,9 @@ static int bcmgenet_resume(struct device *d)
/* Reinitialize TDMA and RDMA and SW housekeeping */
ret = bcmgenet_init_dma(priv, false);
if (ret) {
/* Leave the block clocked, close and suspend tear it down */
netdev_err(dev, "failed to initialize DMA\n");
goto out_clk_disable;
return ret;
}
if (!device_may_wakeup(d))
@ -4327,24 +4351,57 @@ static int bcmgenet_resume(struct device *d)
netif_device_attach(dev);
return 0;
}
out_clk_disable:
if (priv->internal_phy)
bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
clk_disable_unprepare(priv->clk);
return ret;
/* Arm the configured wake filters and drop the rest, then clear old
* matches so that only a new one wakes the system
*/
static void bcmgenet_wol_arm_filters(struct bcmgenet_priv *priv)
{
struct bcmgenet_rxnfc_rule *rule;
u32 reg, hfb_enable = 0;
if (priv->wolopts & WAKE_FILTER)
list_for_each_entry(rule, &priv->rxnfc_list, list)
if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE &&
rule->state == BCMGENET_RXNFC_STATE_ENABLED)
hfb_enable |= 1 << rule->fs.location;
reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) {
reg &= ~RBUF_HFB_FILTER_EN_MASK;
reg |= hfb_enable << (RBUF_HFB_FILTER_EN_SHIFT + 1);
} else {
bcmgenet_hfb_reg_writel(priv, hfb_enable << 1,
HFB_FLT_ENABLE_V3PLUS + 4);
}
if (!hfb_enable)
reg &= ~RBUF_HFB_EN;
bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
}
static int bcmgenet_suspend(struct device *d)
{
struct net_device *dev = dev_get_drvdata(d);
struct bcmgenet_priv *priv = netdev_priv(dev);
struct bcmgenet_rxnfc_rule *rule;
u32 reg, hfb_enable = 0;
if (!netif_running(dev))
return 0;
/* A failed resume has torn the datapath down already. Resume still
* enables irq1 on the WoL path, so it has to be disabled here.
*/
if (!priv->tx_cbs) {
if (device_may_wakeup(d) && priv->wolopts) {
bcmgenet_wol_arm_filters(priv);
disable_irq(priv->irq1);
}
return 0;
}
netif_device_detach(dev);
if (device_may_wakeup(d) && priv->wolopts) {
@ -4353,26 +4410,7 @@ static int bcmgenet_suspend(struct device *d)
netif_tx_disable(dev);
/* Suspend non-wake Rx data flows */
if (priv->wolopts & WAKE_FILTER)
list_for_each_entry(rule, &priv->rxnfc_list, list)
if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE &&
rule->state == BCMGENET_RXNFC_STATE_ENABLED)
hfb_enable |= 1 << rule->fs.location;
reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) {
reg &= ~RBUF_HFB_FILTER_EN_MASK;
reg |= hfb_enable << (RBUF_HFB_FILTER_EN_SHIFT + 1);
} else {
bcmgenet_hfb_reg_writel(priv, hfb_enable << 1,
HFB_FLT_ENABLE_V3PLUS + 4);
}
if (!hfb_enable)
reg &= ~RBUF_HFB_EN;
bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
/* Clear any old filter matches so only new matches wake */
bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
bcmgenet_wol_arm_filters(priv);
if (-ETIMEDOUT == bcmgenet_tdma_disable(priv))
netdev_warn(priv->dev,

View File

@ -553,6 +553,7 @@ struct bcmgenet_tx_ring {
unsigned int prod_index; /* Tx ring producer index SW copy */
unsigned int cb_ptr; /* Tx ring initial CB ptr */
unsigned int end_ptr; /* Tx ring end CB ptr */
unsigned int tx_max_coalesced_frames;
struct bcmgenet_priv *priv;
};

View File

@ -18256,53 +18256,23 @@ static int tg3_resume(struct device *device)
static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume);
/* Systems where ACPI _PTS (Prepare To Sleep) S5 will result in a fatal
* PCIe AER event on the tg3 device if the tg3 device is not, or cannot
* be, powered down.
/* Systems where powering down a tg3 device on restarts triggers
* NMIs and fatal hangs during reboot if the network adapters were
* initialized under SNP.
*/
static const struct dmi_system_id tg3_restart_aer_quirk_table[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R440"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R540"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R640"),
},
},
static const struct dmi_system_id tg3_restart_snp_quirk_table[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R650"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R740"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R750"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "datto"),
DMI_MATCH(DMI_PRODUCT_NAME, "SIRIS 5 1U Server"),
},
},
{}
};
@ -18320,14 +18290,18 @@ static void tg3_shutdown(struct pci_dev *pdev)
if (netif_running(dev))
dev_close(dev);
if (system_state == SYSTEM_POWER_OFF)
if (!dmi_first_match(tg3_restart_snp_quirk_table) ||
system_state == SYSTEM_POWER_OFF) {
tg3_power_down(tp);
else if (system_state == SYSTEM_RESTART &&
dmi_first_match(tg3_restart_aer_quirk_table) &&
} else if (system_state == SYSTEM_RESTART &&
pdev->current_state != PCI_D3cold &&
pdev->current_state != PCI_UNKNOWN) {
/* Disable PCIe AER on the tg3 to avoid a fatal
* error during this system restart.
* Needed since on restarts for systems in
* tg3_restart_snp_quirk_table skipping on powering down the
* tg3 device causes a fatal AER error during ACPI _PTS
* (Prepare To Sleep).
*/
pcie_capability_clear_word(pdev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_CERE |

View File

@ -206,6 +206,7 @@ int gve_get_flow_rule_entry(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
return -EOPNOTSUPP;
if (!priv->flow_rules_cache.rules_cache_synced ||
!*cache_num ||
fsp->location < be32_to_cpu(rules_cache[0].location) ||
fsp->location > be32_to_cpu(rules_cache[*cache_num - 1].location)) {
err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_RULES, fsp->location);

View File

@ -491,6 +491,7 @@ static int hisi_femac_net_close(struct net_device *dev)
netif_stop_queue(dev);
napi_disable(&priv->napi);
hisi_femac_port_reset(priv);
hisi_femac_free_skb_rings(priv);
return 0;

View File

@ -196,11 +196,10 @@ enum commands {
#define TX_TIMEOUT (HZ/20)
struct i596_reg {
unsigned short porthi;
unsigned short portlo;
unsigned long ca;
};
/* MVME16x: the 82596 PORT and CA registers */
#define MVME_I596_PORT_HI 0x00
#define MVME_I596_PORT_LO 0x02
#define MVME_I596_CA 0x04
#define EOF 0x8000
#define SIZE_MASK 0x3fff
@ -375,7 +374,9 @@ static inline void CA(struct net_device *dev)
{
#ifdef ENABLE_MVME16x_NET
if (MACH_IS_MVME16x) {
((struct i596_reg *) dev->base_addr)->ca = 1;
void __iomem *regs = (void __iomem *)dev->base_addr;
__raw_writel(1, regs + MVME_I596_CA);
}
#endif
#ifdef ENABLE_BVME6000_NET
@ -392,9 +393,15 @@ static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
{
#ifdef ENABLE_MVME16x_NET
if (MACH_IS_MVME16x) {
struct i596_reg *p = (struct i596_reg *) (dev->base_addr);
p->porthi = ((c) | (u32) (x)) & 0xffff;
p->portlo = ((c) | (u32) (x)) >> 16;
void __iomem *regs = (void __iomem *)dev->base_addr;
u32 v = (u32)c | (u32)x;
/*
* The 32bit value is latched on the write of the lo register,
* so the 16bit writes must happen in this order.
*/
__raw_writew(v & 0xffff, regs + MVME_I596_PORT_HI);
__raw_writew(v >> 16, regs + MVME_I596_PORT_LO);
}
#endif
#ifdef ENABLE_BVME6000_NET

View File

@ -6,6 +6,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/srcu.h>
#include <linux/xarray.h>
#include "ice_adapter.h"
#include "ice.h"
@ -54,11 +55,18 @@ static unsigned long ice_adapter_xa_index(struct pci_dev *pdev)
static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev)
{
struct ice_adapter *adapter;
int err;
adapter = kzalloc_obj(*adapter);
if (!adapter)
return NULL;
err = init_srcu_struct(&adapter->ports.srcu);
if (err) {
kfree(adapter);
return NULL;
}
adapter->index = ice_adapter_index(pdev);
spin_lock_init(&adapter->ptp_gltsyn_time_lock);
spin_lock_init(&adapter->txq_ctx_lock);
@ -66,18 +74,19 @@ static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev)
mutex_init(&adapter->cpi_phy_lock[i]);
refcount_set(&adapter->refcount, 1);
mutex_init(&adapter->ports.lock);
INIT_LIST_HEAD(&adapter->ports.ports);
spin_lock_init(&adapter->ports.lock);
INIT_LIST_HEAD(&adapter->ports.list);
return adapter;
}
static void ice_adapter_free(struct ice_adapter *adapter)
{
WARN_ON(!list_empty(&adapter->ports.ports));
WARN_ON(!list_empty(&adapter->ports.list));
for (int i = 0; i < ARRAY_SIZE(adapter->cpi_phy_lock); i++)
mutex_destroy(&adapter->cpi_phy_lock[i]);
mutex_destroy(&adapter->ports.lock);
cleanup_srcu_struct(&adapter->ports.srcu);
kfree(adapter);
}

View File

@ -6,6 +6,7 @@
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/srcu.h>
#include <linux/spinlock_types.h>
#include <linux/refcount_types.h>
@ -17,15 +18,19 @@ struct ice_pf;
/**
* struct ice_port_list - data used to store the list of adapter ports
*
* This structure contains data used to maintain a list of adapter ports
* This structure contains data used to maintain a list of adapter ports.
* Writers modifying the list *must* acquire the lock, and use SRCU safe list
* operations. Readers should use srcu_read_lock() on the provided domain.
*
* @ports: list of ports
* @lock: protect access to the ports list
* @list: list of ports
* @lock: protect write access to the list
* @srcu: Sleepable RCU domain for this adapter
*/
struct ice_port_list {
struct list_head ports;
/* To synchronize the ports list operations */
struct mutex lock;
struct list_head list;
/* To synchronize write operations on the port list */
spinlock_t lock;
struct srcu_struct srcu;
};
/**

View File

@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2021, Intel Corporation. */
#include <linux/rculist.h>
#include <linux/srcu.h>
#include <linux/wait_bit.h>
#include "ice.h"
#include "ice_lib.h"
#include "ice_trace.h"
@ -367,7 +370,7 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx)
{
lockdep_assert_held(&tx->lock);
return tx->init && !tx->calibrating;
return tx->init && !tx->disabled;
}
/**
@ -592,6 +595,12 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
bool drop_ts = !link_up;
struct sk_buff *skb;
/* Paired with smp_mb__before_atomic() in ice_ptp_request_ts()
* to ensure ordering the in_use bitmap and the indexed fields
* in the tstamps array.
*/
smp_rmb();
/* Drop packets which have waited for more than 2 seconds */
if (time_is_before_jiffies(tx->tstamps[idx].start + 2 * HZ)) {
drop_ts = true;
@ -676,20 +685,37 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
pf->ptp.tx_hwtstamp_good += tstamp_good;
}
static void ice_ptp_release_port_srcu(struct kref *ref)
{
/* wake_up_var() requires full ordering but kref_put only provides
* release ordering.
*/
smp_mb__after_atomic();
wake_up_var(ref);
}
static void ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
{
struct ice_port_list *ports = &pf->adapter->ports;
struct ice_ptp_port *port;
int srcu_idx;
mutex_lock(&pf->adapter->ports.lock);
list_for_each_entry(port, &pf->adapter->ports.ports, list_node) {
srcu_idx = srcu_read_lock(&ports->srcu);
list_for_each_entry_srcu(port, &ports->list, list_node,
srcu_read_lock_held(&ports->srcu)) {
struct ice_ptp_tx *tx = &port->tx;
if (!tx || !tx->init)
if (!tx->init)
continue;
if (!kref_get_unless_zero(&port->ref))
continue;
ice_ptp_process_tx_tstamp(tx);
kref_put(&port->ref, ice_ptp_release_port_srcu);
}
mutex_unlock(&pf->adapter->ports.lock);
srcu_read_unlock(&ports->srcu, srcu_idx);
}
/**
@ -809,10 +835,19 @@ ice_ptp_mark_tx_tracker_stale(struct ice_ptp_tx *tx)
static void
ice_ptp_flush_all_tx_tracker(struct ice_pf *pf)
{
struct ice_port_list *ports = &pf->adapter->ports;
struct ice_ptp_port *port;
int srcu_idx;
list_for_each_entry(port, &pf->adapter->ports.ports, list_node)
srcu_idx = srcu_read_lock(&ports->srcu);
list_for_each_entry_srcu(port, &ports->list, list_node,
srcu_read_lock_held(&ports->srcu)) {
if (!kref_get_unless_zero(&port->ref))
continue;
ice_ptp_flush_tx_tracker(ptp_port_to_pf(port), &port->tx);
kref_put(&port->ref, ice_ptp_release_port_srcu);
}
srcu_read_unlock(&ports->srcu, srcu_idx);
}
/**
@ -1136,6 +1171,7 @@ static int ice_ptp_check_tx_fifo(struct ice_ptp_port *port)
static void ice_ptp_wait_for_offsets(struct kthread_work *work)
{
struct ice_ptp_port *port;
unsigned long flags;
struct ice_pf *pf;
struct ice_hw *hw;
int tx_err;
@ -1156,9 +1192,26 @@ static void ice_ptp_wait_for_offsets(struct kthread_work *work)
tx_err = ice_ptp_check_tx_fifo(port);
if (!tx_err)
tx_err = ice_phy_cfg_tx_offset_e82x(hw, port->port_num);
if (!tx_err) {
/* Tx offset has been configured, re-enable Tx timestamps */
spin_lock_irqsave(&port->tx.lock, flags);
if (port->tx.disabled) {
port->tx.disabled = false;
dev_dbg(ice_pf_to_dev(pf), "PTP Tx offset valid for port %u, Tx timestamps enabled\n",
port->port_num);
}
spin_unlock_irqrestore(&port->tx.lock, flags);
}
rx_err = ice_phy_cfg_rx_offset_e82x(hw, port->port_num);
if (tx_err || rx_err) {
/* Tx and/or Rx offset not yet configured, try again later */
/* Tx and/or Rx offset not yet configured, try again later.
* This is expected during normal link-up: the vernier offset
* calibration cannot complete until at least one packet has
* been transmitted, so the first retries routinely land here.
*/
dev_dbg(ice_pf_to_dev(pf), "PTP offset not yet valid for port %u (tx_err=%d rx_err=%d)\n",
port->port_num, tx_err, rx_err);
kthread_queue_delayed_work(pf->ptp.kworker,
&port->ov_work,
msecs_to_jiffies(100));
@ -1236,11 +1289,9 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
/* Start the PHY timer in Vernier mode */
kthread_cancel_delayed_work_sync(&ptp_port->ov_work);
/* temporarily disable Tx timestamps while calibrating
* PHY offset
*/
/* Disable Tx timestamps until PHY calibration completes */
spin_lock_irqsave(&ptp_port->tx.lock, flags);
ptp_port->tx.calibrating = true;
ptp_port->tx.disabled = true;
spin_unlock_irqrestore(&ptp_port->tx.lock, flags);
ptp_port->tx_fifo_busy_cnt = 0;
@ -1249,11 +1300,10 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
if (err)
break;
/* Enable Tx timestamps right away */
spin_lock_irqsave(&ptp_port->tx.lock, flags);
ptp_port->tx.calibrating = false;
spin_unlock_irqrestore(&ptp_port->tx.lock, flags);
/* Do not clear disabled flag here. Tx timestamp requests
* remain disabled until ice_ptp_wait_for_offsets() has
* verified that the Tx offset calibration has completed.
*/
kthread_queue_delayed_work(pf->ptp.kworker, &ptp_port->ov_work,
0);
break;
@ -1427,16 +1477,22 @@ static void ice_ptp_reset_phy_timestamping(struct ice_pf *pf)
*/
static void ice_ptp_restart_all_phy(struct ice_pf *pf)
{
struct list_head *entry;
struct ice_port_list *ports = &pf->adapter->ports;
struct ice_ptp_port *port;
int srcu_idx;
list_for_each(entry, &pf->adapter->ports.ports) {
struct ice_ptp_port *port = list_entry(entry,
struct ice_ptp_port,
list_node);
srcu_idx = srcu_read_lock(&ports->srcu);
list_for_each_entry_srcu(port, &ports->list, list_node,
srcu_read_lock_held(&ports->srcu)) {
if (!kref_get_unless_zero(&port->ref))
continue;
if (port->link_up)
ice_ptp_port_phy_restart(port);
kref_put(&port->ref, ice_ptp_release_port_srcu);
}
srcu_read_unlock(&ports->srcu, srcu_idx);
}
/**
@ -2643,11 +2699,13 @@ s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
* a reference to the skb and the start time to allow discarding old
* requests.
*/
set_bit(idx, tx->in_use);
clear_bit(idx, tx->stale);
tx->tstamps[idx].start = jiffies;
tx->tstamps[idx].skb = skb_get(skb);
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
clear_bit(idx, tx->stale);
/* Ensure index is setup before marking it as used */
smp_mb__before_atomic();
set_bit(idx, tx->in_use);
ice_trace(tx_tstamp_request, skb, idx);
}
@ -2699,19 +2757,28 @@ static bool ice_port_has_timestamps(struct ice_ptp_tx *tx)
static bool ice_any_port_has_timestamps(struct ice_pf *pf)
{
struct ice_port_list *ports = &pf->adapter->ports;
bool have_tstamps = false;
struct ice_ptp_port *port;
int srcu_idx;
scoped_guard(mutex, &pf->adapter->ports.lock) {
list_for_each_entry(port, &pf->adapter->ports.ports,
list_node) {
struct ice_ptp_tx *tx = &port->tx;
srcu_idx = srcu_read_lock(&ports->srcu);
list_for_each_entry_srcu(port, &ports->list, list_node,
srcu_read_lock_held(&ports->srcu)) {
if (!kref_get_unless_zero(&port->ref))
continue;
if (ice_port_has_timestamps(tx))
return true;
}
if (ice_port_has_timestamps(&port->tx))
have_tstamps = true;
kref_put(&port->ref, ice_ptp_release_port_srcu);
if (have_tstamps)
break;
}
srcu_read_unlock(&ports->srcu, srcu_idx);
return false;
return have_tstamps;
}
bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf)
@ -2970,14 +3037,18 @@ void ice_ptp_queue_work(struct ice_pf *pf)
static void ice_ptp_prepare_rebuild_sec(struct ice_pf *pf, bool rebuild,
enum ice_reset_req reset_type)
{
struct list_head *entry;
struct ice_port_list *ports = &pf->adapter->ports;
struct ice_ptp_port *port;
int srcu_idx;
list_for_each(entry, &pf->adapter->ports.ports) {
struct ice_ptp_port *port = list_entry(entry,
struct ice_ptp_port,
list_node);
srcu_idx = srcu_read_lock(&ports->srcu);
list_for_each_entry_srcu(port, &ports->list, list_node,
srcu_read_lock_held(&ports->srcu)) {
struct ice_pf *peer_pf = ptp_port_to_pf(port);
if (!kref_get_unless_zero(&port->ref))
continue;
if (!ice_is_primary(&peer_pf->hw)) {
if (rebuild) {
/* TODO: When implementing rebuild=true:
@ -2989,7 +3060,10 @@ static void ice_ptp_prepare_rebuild_sec(struct ice_pf *pf, bool rebuild,
ice_ptp_prepare_for_reset(peer_pf, reset_type);
}
}
kref_put(&port->ref, ice_ptp_release_port_srcu);
}
srcu_read_unlock(&ports->srcu, srcu_idx);
}
/**
@ -3169,11 +3243,11 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)
return -ENODEV;
INIT_LIST_HEAD(&ptp->port.list_node);
mutex_lock(&pf->adapter->ports.lock);
kref_init(&ptp->port.ref);
list_add(&ptp->port.list_node,
&pf->adapter->ports.ports);
mutex_unlock(&pf->adapter->ports.lock);
spin_lock(&pf->adapter->ports.lock);
list_add_rcu(&ptp->port.list_node, &pf->adapter->ports.list);
spin_unlock(&pf->adapter->ports.lock);
/* Seed the per-PHY Tx reference clock usage map for this port.
* Only meaningful on E825 (other MAC types don't expose tx-clk
@ -3195,13 +3269,23 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)
static void ice_ptp_cleanup_pf(struct ice_pf *pf)
{
struct ice_port_list *ports = &pf->adapter->ports;
struct ice_ptp *ptp = &pf->ptp;
struct kref *ref;
if (pf->hw.mac_type != ICE_MAC_UNKNOWN) {
mutex_lock(&pf->adapter->ports.lock);
list_del(&ptp->port.list_node);
mutex_unlock(&pf->adapter->ports.lock);
}
if (pf->hw.mac_type == ICE_MAC_UNKNOWN)
return;
spin_lock(&ports->lock);
list_del_rcu(&ptp->port.list_node);
spin_unlock(&ports->lock);
ref = &ptp->port.ref;
kref_put(ref, ice_ptp_release_port_srcu);
wait_var_event(ref, !kref_read(ref));
synchronize_srcu(&ports->srcu);
}
/**

View File

@ -5,6 +5,8 @@
#define _ICE_PTP_H_
#include <linux/ptp_clock_kernel.h>
#include <linux/rculist.h>
#include <linux/kref.h>
#include <linux/kthread.h>
#include "ice_ptp_hw.h"
@ -104,8 +106,8 @@ enum ice_tx_tstamp_work {
* @offset: offset into timestamp block to get the real index
* @len: length of the tstamps and in_use fields.
* @init: if true, the tracker is initialized;
* @calibrating: if true, the PHY is calibrating the Tx offset. During this
* window, timestamps are temporarily disabled.
* @disabled: set to true when new Tx timestamp requests are disabled, such as
* while the PHY Tx offset configuration has not yet completed.
* @has_ready_bitmap: if true, the hardware has a valid Tx timestamp ready
* bitmap register. If false, fall back to verifying new
* timestamp values against previously cached copy.
@ -120,7 +122,7 @@ struct ice_ptp_tx {
u8 offset;
u8 len;
u8 init : 1;
u8 calibrating : 1;
u8 disabled : 1;
u8 has_ready_bitmap : 1;
s8 last_ll_ts_idx_read;
};
@ -138,6 +140,7 @@ struct ice_ptp_tx {
* and determine when the port's PHY offset is valid.
*
* @list_node: list member structure
* @ref: reference counter for use with adapter ports list
* @tx: Tx timestamp tracking for this port
* @ov_work: delayed work task for tracking when PHY offset is valid
* @ps_lock: mutex used to protect the overall PTP PHY start procedure
@ -149,6 +152,7 @@ struct ice_ptp_tx {
*/
struct ice_ptp_port {
struct list_head list_node;
struct kref ref;
struct ice_ptp_tx tx;
struct kthread_delayed_work ov_work;
struct mutex ps_lock; /* protects overall PTP PHY start procedure */

View File

@ -9444,23 +9444,6 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
}
protocol = vlan_get_protocol(skb);
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
adapter->ptp_clock) {
if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON &&
!test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS,
&adapter->state)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
/* schedule check for Tx timestamp */
adapter->ptp_tx_skb = skb_get(skb);
adapter->ptp_tx_start = jiffies;
schedule_work(&adapter->ptp_tx_work);
} else {
adapter->tx_hwtstamp_skipped++;
}
}
#ifdef CONFIG_PCI_IOV
/*
* Use the l2switch_enable flag - would be false if the DMA
@ -9525,6 +9508,29 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
#ifdef IXGBE_FCOE
xmit_fcoe:
#endif /* IXGBE_FCOE */
/* Reserve the Tx timestamp only after all skb preparation:
* skb_get() makes the skb shared, and pskb_expand_head()
* (reached from skb_cow_head() or skb_checksum_help())
* refuses shared skbs.
*/
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
adapter->ptp_clock) {
if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON &&
!test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS,
&adapter->state)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
first->tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
/* schedule check for Tx timestamp */
adapter->ptp_tx_skb = skb_get(skb);
adapter->ptp_tx_start = jiffies;
schedule_work(&adapter->ptp_tx_work);
} else {
adapter->tx_hwtstamp_skipped++;
}
}
if (ixgbe_tx_map(tx_ring, first, hdr_len))
goto cleanup_tx_timestamp;

View File

@ -4111,9 +4111,12 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg)
case NIX_FLOW_KEY_TYPE_INNR_IPV4:
field->lid = NPC_LID_LC;
field->ltype_match = NPC_LT_LC_IP;
field->ltype_mask = NPC_LT_LC_IP_MATCH_MSK;
if (key_type == NIX_FLOW_KEY_TYPE_INNR_IPV4) {
field->lid = NPC_LID_LG;
field->ltype_match = NPC_LT_LG_TU_IP;
field->ltype_mask = 0xF;
}
field->hdr_offset = 12; /* SIP offset */
field->bytesm1 = 7; /* SIP + DIP, 8 bytes */
@ -4132,16 +4135,18 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg)
field->bytesm1 = 3; /* DIP, 4 bytes */
}
}
field->ltype_mask = NPC_LT_LC_IP_MATCH_MSK;
keyoff_marker = false;
break;
case NIX_FLOW_KEY_TYPE_IPV6:
case NIX_FLOW_KEY_TYPE_INNR_IPV6:
field->lid = NPC_LID_LC;
field->ltype_match = NPC_LT_LC_IP6;
field->ltype_mask = NPC_LT_LC_IP6_MATCH_MSK;
if (key_type == NIX_FLOW_KEY_TYPE_INNR_IPV6) {
field->lid = NPC_LID_LG;
field->ltype_match = NPC_LT_LG_TU_IP6;
field->ltype_mask = 0xF;
}
field->hdr_offset = 8; /* SIP offset */
field->bytesm1 = 31; /* SIP + DIP, 32 bytes */
@ -4161,7 +4166,6 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg)
field->bytesm1 = 15; /* DIP,16 bytes */
}
}
field->ltype_mask = NPC_LT_LC_IP6_MATCH_MSK;
break;
case NIX_FLOW_KEY_TYPE_TCP:
case NIX_FLOW_KEY_TYPE_UDP:

View File

@ -1037,6 +1037,9 @@ bool cn10k_ipsec_transmit(struct otx2_nic *pf, struct netdev_queue *txq,
cn10k_cpt_inst_flush(pf, &inst, sizeof(struct cpt_inst_s));
return true;
drop:
otx2_dma_unmap_skb_frags(pf, &sq->sg[sq->head], skb);
sq->sg[sq->head].skb = (u64)NULL;
atomic_long_inc(&pf->hw.dev_stats.tx_discards);
dev_kfree_skb_any(skb);
return false;
return true;
}

View File

@ -2115,10 +2115,8 @@ dma_addr_t otx2_dma_map_skb_frag(struct otx2_nic *pfvf,
int offset;
/* Crypto hardware need write permission for ipsec crypto offload */
if (unlikely(xfrm_offload(skb))) {
if (unlikely(xfrm_offload(skb)))
dir = DMA_BIDIRECTIONAL;
skb = skb_unclone_full(skb, GFP_ATOMIC);
}
/* First segment is always skb->data */
if (!seg) {
@ -2134,13 +2132,12 @@ dma_addr_t otx2_dma_map_skb_frag(struct otx2_nic *pfvf,
return otx2_dma_map_page(pfvf, page, offset, *len, dir);
}
void otx2_dma_unmap_skb_frags(struct otx2_nic *pfvf, struct sg_list *sg)
void otx2_dma_unmap_skb_frags(struct otx2_nic *pfvf, struct sg_list *sg,
struct sk_buff *skb)
{
enum dma_data_direction dir = DMA_TO_DEVICE;
struct sk_buff *skb = NULL;
int seg;
skb = (struct sk_buff *)sg->skb;
if (unlikely(xfrm_offload(skb)))
dir = DMA_BIDIRECTIONAL;

View File

@ -1252,7 +1252,8 @@ static inline int mcam_entry_cmp(const void *a, const void *b)
dma_addr_t otx2_dma_map_skb_frag(struct otx2_nic *pfvf,
struct sk_buff *skb, int seg, int *len);
void otx2_dma_unmap_skb_frags(struct otx2_nic *pfvf, struct sg_list *sg);
void otx2_dma_unmap_skb_frags(struct otx2_nic *pfvf, struct sg_list *sg,
struct sk_buff *skb);
int otx2_read_free_sqe(struct otx2_nic *pfvf, u16 qidx);
void otx2_queue_vf_work(struct mbox *mw, struct workqueue_struct *mbox_wq,
int first, int mdevs, u64 intr);

View File

@ -160,7 +160,7 @@ static void otx2_snd_pkt_handler(struct otx2_nic *pfvf,
*tx_bytes += skb->len;
(*tx_pkts)++;
otx2_dma_unmap_skb_frags(pfvf, sg);
otx2_dma_unmap_skb_frags(pfvf, sg, skb);
napi_consume_skb(skb, budget);
sg->skb = (u64)NULL;
}
@ -872,7 +872,7 @@ static int otx2_dma_map_tso_skb(struct otx2_nic *pfvf,
}
return 0;
unmap:
otx2_dma_unmap_skb_frags(pfvf, sg);
otx2_dma_unmap_skb_frags(pfvf, sg, skb);
return -EINVAL;
}
@ -1205,6 +1205,15 @@ bool otx2_sq_append_skb(void *dev, struct netdev_queue *txq,
if (free_desc < otx2_get_sqe_count(pfvf, skb))
return false;
/* Crypto hardware need write permission for ipsec crypto offload */
if (unlikely(xfrm_offload(skb)) &&
(skb_cloned(skb) || skb_is_nonlinear(skb)) &&
skb_ensure_writable(skb, skb->len)) {
atomic_long_inc(&pfvf->hw.dev_stats.tx_discards);
dev_kfree_skb_any(skb);
return true;
}
num_segs = skb_shinfo(skb)->nr_frags + 1;
/* If SKB doesn't fit in a single SQE, linearize it.
@ -1252,7 +1261,7 @@ bool otx2_sq_append_skb(void *dev, struct netdev_queue *txq,
ret = otx2_sqe_add_sg(pfvf, sq, skb, num_segs, &offset);
if (!ret) {
otx2_dma_unmap_skb_frags(pfvf, &sq->sg[sq->head]);
otx2_dma_unmap_skb_frags(pfvf, &sq->sg[sq->head], skb);
return false;
}
@ -1344,7 +1353,7 @@ void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq)
if (skb) {
tx_bytes += skb->len;
tx_pkts++;
otx2_dma_unmap_skb_frags(pfvf, sg);
otx2_dma_unmap_skb_frags(pfvf, sg, skb);
dev_kfree_skb_any(skb);
sg->skb = (u64)NULL;
}
@ -1399,7 +1408,7 @@ void otx2_free_pending_sqe(struct otx2_nic *pfvf)
if (skb) {
tx_bytes += skb->len;
tx_pkts++;
otx2_dma_unmap_skb_frags(pfvf, sg);
otx2_dma_unmap_skb_frags(pfvf, sg, skb);
dev_kfree_skb_any(skb);
sg->skb = (u64)NULL;
}

View File

@ -43,23 +43,12 @@ static DEFINE_IDA(mlx4_adev_ida);
static bool is_eth_supported(struct mlx4_dev *dev)
{
for (int port = 1; port <= dev->caps.num_ports; port++)
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
return true;
return false;
return true;
}
static bool is_ib_supported(struct mlx4_dev *dev)
{
for (int port = 1; port <= dev->caps.num_ports; port++)
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB)
return true;
if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE)
return true;
return false;
return true;
}
static const struct mlx4_adev_device {

View File

@ -542,6 +542,12 @@ static int mlx5_devlink_num_doorbells_validate(struct devlink *devlink, u32 id,
u32 val32 = val->vu32;
u32 max_num_channels;
if (mlx5_dev_is_lightweight(mdev)) {
NL_SET_ERR_MSG_MOD(extack,
"Setting num_doorbells requires full device initialization; reload the device first");
return -EOPNOTSUPP;
}
max_num_channels = mlx5e_get_max_num_channels(mdev);
if (val32 > max_num_channels) {
NL_SET_ERR_MSG_FMT_MOD(extack,

View File

@ -218,6 +218,12 @@ static inline void mlx5e_accel_tx_finish(struct mlx5e_txqsq *sq,
#endif
}
static inline bool
mlx5e_accel_shampo_can_merge(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
{
return mlx5e_psp_shampo_can_merge(rq->hw_gro_data->skb, cqe);
}
static inline int mlx5e_accel_init_rx(struct mlx5e_priv *priv)
{
return mlx5e_ktls_init_rx(priv);

View File

@ -958,6 +958,9 @@ static int mlx5e_ipsec_netevent_event(struct notifier_block *nb,
xa_for_each_marked(&ipsec->sadb, idx, sa_entry, MLX5E_IPSEC_TUNNEL_SA) {
attrs = &sa_entry->attrs;
if (attrs->addrs.family != n->tbl->family)
continue;
if (attrs->addrs.family == AF_INET) {
if (!neigh_key_eq32(n, &attrs->addrs.saddr.a4) &&
!neigh_key_eq32(n, &attrs->addrs.daddr.a4))

View File

@ -85,6 +85,13 @@ static inline bool mlx5e_psp_is_rx_flow(struct mlx5_cqe64 *cqe)
return MLX5_PSP_METADATA_MARKER(be32_to_cpu(cqe->ft_metadata));
}
static inline bool
mlx5e_psp_shampo_can_merge(struct sk_buff *skb, struct mlx5_cqe64 *cqe)
{
/* PSP packets cannot be merged. */
return !skb_ext_exist(skb, SKB_EXT_PSP) && !mlx5e_psp_is_rx_flow(cqe);
}
bool mlx5e_psp_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
struct mlx5_cqe64 *cqe);
#else
@ -110,6 +117,12 @@ static inline bool mlx5e_psp_is_rx_flow(struct mlx5_cqe64 *cqe)
return false;
}
static inline bool
mlx5e_psp_shampo_can_merge(struct sk_buff *skb, struct mlx5_cqe64 *cqe)
{
return true;
}
static inline bool mlx5e_psp_offload_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb,
struct mlx5_cqe64 *cqe)

View File

@ -49,6 +49,7 @@
#include "en_rep.h"
#include "en/rep/tc.h"
#include "ipoib/ipoib.h"
#include "en_accel/en_accel.h"
#include "en_accel/ipsec.h"
#include "en_accel/macsec.h"
#include "en_accel/psp_rxtx.h"
@ -2268,8 +2269,9 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
}
if (*skb &&
!(match && mlx5e_hw_gro_skb_has_enough_space(*skb, data_bcnt,
page_size))) {
!(match &&
mlx5e_hw_gro_skb_has_enough_space(*skb, data_bcnt, page_size) &&
mlx5e_accel_shampo_can_merge(rq, cqe))) {
match = false;
mlx5e_shampo_flush_skb(rq, cqe, match);
}

View File

@ -1025,7 +1025,7 @@ static void fbnic_pkt_prepare(struct fbnic_napi_vector *nv, u64 rcd,
/* Build frame around buffer */
hdr_start = page_address(page) + hdr_pg_start;
net_prefetch(pkt->buff.data);
net_prefetch(hdr_start + headroom);
xdp_prepare_buff(&pkt->buff, hdr_start, headroom,
len - FBNIC_RX_PAD, true);

View File

@ -43,9 +43,19 @@ int __fdma_dcb_add(struct fdma *fdma, int dcb_idx, u64 info, u64 status,
u64 *dataptr))
{
struct fdma_dcb *dcb = fdma_dcb_get(fdma, dcb_idx);
struct fdma_dcb *prev = fdma->last_dcb;
u64 nextptr;
int i, err;
/* Per the FDMA datasheet, adding a DCB to an active channel takes
* three steps:
* 1) Write NEXT_PTR of the current last DCB with the LSB forced to
* FDMA_DCB_INVALID_DATA, and flush that write.
* 2) Clear the LSB to complete the link.
* 3) Reload the channel (FDMA_CH_RELOAD); this is done by the caller
* once the chain has been extended.
*/
for (i = 0; i < fdma->n_dbs; i++) {
err = __fdma_db_add(fdma, dcb_idx, i, status, db_cb);
if (unlikely(err))
@ -56,13 +66,25 @@ int __fdma_dcb_add(struct fdma *fdma, int dcb_idx, u64 info, u64 status,
if (unlikely(err))
return err;
fdma->last_dcb->nextptr = cpu_to_le64(nextptr);
fdma->last_dcb = dcb;
dcb->nextptr = cpu_to_le64(FDMA_DCB_INVALID_DATA);
dcb->info = cpu_to_le64(info);
/* On the first DCB of fdma_dcbs_init() prev is the DCB itself;
* don't link it to itself.
*/
if (prev != dcb) {
/* Write NEXT_PTR of the current last DCB with the LSB forced
* to FDMA_DCB_INVALID_DATA, and flush that write.
*/
prev->nextptr = cpu_to_le64(nextptr | FDMA_DCB_INVALID_DATA);
dma_wmb();
/* Clear the LSB to complete the link. */
prev->nextptr = cpu_to_le64(nextptr);
}
fdma->last_dcb = dcb;
return 0;
}
EXPORT_SYMBOL_GPL(__fdma_dcb_add);

View File

@ -336,14 +336,13 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight)
struct lan966x_tx_dcb_buf *dcb_buf;
struct fdma *fdma = &tx->fdma;
struct xdp_frame_bulk bq;
unsigned long flags;
bool clear = false;
struct fdma_db *db;
int i;
xdp_frame_bulk_init(&bq);
spin_lock_irqsave(&lan966x->tx_lock, flags);
spin_lock(&lan966x->tx_lock);
for (i = 0; i < fdma->n_dcbs; ++i) {
dcb_buf = &tx->dcbs_buf[i];
@ -388,7 +387,7 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight)
if (clear)
lan966x_fdma_wakeup_netdev(lan966x);
spin_unlock_irqrestore(&lan966x->tx_lock, flags);
spin_unlock(&lan966x->tx_lock);
}
static int lan966x_fdma_rx_check_frame(struct lan966x_rx *rx, u64 *src_port)
@ -686,7 +685,8 @@ int lan966x_fdma_xmit_xdpf(struct lan966x_port *port, void *ptr, u32 len)
FDMA_DCB_STATUS_BLOCKO(0) |
FDMA_DCB_STATUS_BLOCKL(next_dcb_buf->len),
&fdma_nextptr_cb,
&lan966x_fdma_xdp_tx_dataptr_cb);
len ? &lan966x_fdma_xdp_tx_dataptr_cb :
&lan966x_fdma_tx_dataptr_cb);
/* Start the transmission */
lan966x_fdma_tx_start(tx);

View File

@ -447,7 +447,7 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
lan966x_mac_process_raw_entry(&raw_entries[column],
mac, &vid, &dest_idx);
if (WARN_ON(dest_idx >= lan966x->num_phys_ports))
if (dest_idx >= lan966x->num_phys_ports)
continue;
/* If the entry in SW is found, then there is nothing
@ -501,7 +501,7 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
lan966x_mac_process_raw_entry(&raw_entries[column],
mac, &vid, &dest_idx);
if (WARN_ON(dest_idx >= lan966x->num_phys_ports))
if (dest_idx >= lan966x->num_phys_ports)
continue;
spin_lock(&lan966x->mac_lock);

View File

@ -263,9 +263,8 @@ static int lan966x_port_ifh_xmit(struct sk_buff *skb,
lan_wr((__force u32)ifh[i], lan966x, QS_INJ_WR(grp));
}
/* Write frame */
count = DIV_ROUND_UP(skb->len, 4);
last = skb->len % 4;
/* Write the whole words of the frame */
count = skb->len / 4;
for (i = 0; i < count; ++i) {
/* Wait until the fifo is ready */
err = lan966x_port_inj_ready(lan966x, grp);
@ -275,6 +274,20 @@ static int lan966x_port_ifh_xmit(struct sk_buff *skb,
lan_wr(((u32 *)skb->data)[i], lan966x, QS_INJ_WR(grp));
}
/* Write the last 1 to 3 bytes, zero padded to a whole word */
last = skb->len % 4;
if (last) {
/* Wait until the fifo is ready */
err = lan966x_port_inj_ready(lan966x, grp);
if (err)
goto err;
val = 0;
memcpy(&val, skb->data + count * 4, last);
lan_wr(val, lan966x, QS_INJ_WR(grp));
++i;
}
/* Add padding */
while (i < (LAN966X_BUFFER_MIN_SZ / 4)) {
/* Wait until the fifo is ready */

View File

@ -376,9 +376,10 @@ static void lan966x_ptp_classify(struct lan966x_port *port, struct sk_buff *skb,
*rew_op = IFH_REW_OP_TWO_STEP_PTP;
}
static void lan966x_ptp_txtstamp_old_release(struct lan966x_port *port)
static unsigned int lan966x_ptp_txtstamp_old_release(struct lan966x_port *port)
{
struct sk_buff *skb, *skb_tmp;
unsigned int purged = 0;
unsigned long flags;
spin_lock_irqsave(&port->tx_skbs.lock, flags);
@ -389,14 +390,18 @@ static void lan966x_ptp_txtstamp_old_release(struct lan966x_port *port)
__skb_unlink(skb, &port->tx_skbs);
dev_kfree_skb_any(skb);
purged++;
}
spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
return purged;
}
int lan966x_ptp_txtstamp_request(struct lan966x_port *port,
struct sk_buff *skb)
{
struct lan966x *lan966x = port->lan966x;
unsigned int purged;
unsigned long flags;
u8 pdu_type;
u8 rew_op;
@ -408,9 +413,10 @@ int lan966x_ptp_txtstamp_request(struct lan966x_port *port,
if (rew_op != IFH_REW_OP_TWO_STEP_PTP)
return 0;
lan966x_ptp_txtstamp_old_release(port);
purged = lan966x_ptp_txtstamp_old_release(port);
spin_lock_irqsave(&lan966x->ptp_ts_id_lock, flags);
lan966x->ptp_skbs -= purged;
if (lan966x->ptp_skbs == LAN966X_MAX_PTP_ID) {
spin_unlock_irqrestore(&lan966x->ptp_ts_id_lock, flags);
return -EBUSY;

View File

@ -217,7 +217,6 @@ int sparx5_fdma_xmit(struct sparx5 *sparx5, u32 *ifh, struct sk_buff *skb,
struct fdma *fdma = &tx->fdma;
void *virt_addr;
fdma_dcb_advance(fdma);
if (!fdma_db_is_done(fdma_db_get(fdma, fdma->dcb_index, 0)))
return -EINVAL;
@ -235,6 +234,8 @@ int sparx5_fdma_xmit(struct sparx5 *sparx5, u32 *ifh, struct sk_buff *skb,
FDMA_DCB_STATUS_BLOCKO(0) |
FDMA_DCB_STATUS_BLOCKL(skb->len + IFH_LEN * 4 + 4));
fdma_dcb_advance(fdma);
sparx5_fdma_reload(sparx5, fdma);
return NETDEV_TX_OK;

View File

@ -169,8 +169,8 @@ static int sparx5_inject(struct sparx5 *sparx5,
struct sk_buff *skb,
struct net_device *ndev)
{
u32 val, w, count, last;
int grp = INJ_QUEUE;
u32 val, w, count;
u8 *buf;
val = spx5_rd(sparx5, QS_INJ_STATUS);
@ -189,14 +189,23 @@ static int sparx5_inject(struct sparx5 *sparx5,
for (w = 0; w < IFH_LEN; w++)
spx5_wr(ifh[w], sparx5, QS_INJ_WR(grp));
/* Write words, round up */
count = DIV_ROUND_UP(skb->len, 4);
/* Write the whole words of the frame */
count = skb->len / 4;
buf = skb->data;
for (w = 0; w < count; w++, buf += 4) {
val = get_unaligned((const u32 *)buf);
spx5_wr(val, sparx5, QS_INJ_WR(grp));
}
/* Write the last 1 to 3 bytes, zero padded to a whole word */
last = skb->len % 4;
if (last) {
val = 0;
memcpy(&val, buf, last);
spx5_wr(val, sparx5, QS_INJ_WR(grp));
w++;
}
/* Add padding */
while (w < (60 / 4)) {
spx5_wr(0, sparx5, QS_INJ_WR(grp));

View File

@ -392,8 +392,11 @@ static void mucse_mbx_fw_req_handler(struct mucse_hw *hw,
u16 speed = le16_to_cpu(req->link_stat.st.speed);
spin_lock_irqsave(&mucse->link_lock, flags);
if (magic != ST_VALID_MAGIC) {
/* Do not change the cached state for an invalid event.
/* Link-down events do not carry valid speed/duplex information
* and may have a zero port_magic. Validate it only for link up.
*/
if (mucse_link_is_up(hw, req) && magic != ST_VALID_MAGIC) {
/* Keep the cached state for an invalid link-up event.
* Use an invalid speed encoding to make firmware report
* again.
*/

View File

@ -94,6 +94,7 @@ struct nfp_fl_stats_id {
* @ipv6_off_lock: Lock for the IPv6 address list
* @mac_off_ids: IDA to manage id assignment for offloaded MACs
* @neigh_nb: Notifier to monitor neighbour state
* @neigh_wq: Workqueue for neighbour updates
*/
struct nfp_fl_tunnel_offloads {
struct rhashtable offloaded_macs;
@ -103,6 +104,7 @@ struct nfp_fl_tunnel_offloads {
struct mutex ipv6_off_lock;
struct ida mac_off_ids;
struct notifier_block neigh_nb;
struct workqueue_struct *neigh_wq;
};
/**

View File

@ -736,7 +736,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
if (!update_work)
return NOTIFY_DONE;
queue_work(system_highpri_wq, &update_work->work);
queue_work(app_priv->tun.neigh_wq, &update_work->work);
return NOTIFY_DONE;
}
@ -1509,6 +1509,13 @@ int nfp_tunnel_config_start(struct nfp_app *app)
if (err)
return err;
priv->tun.neigh_wq = alloc_workqueue("nfp-flower-neigh",
WQ_HIGHPRI | WQ_PERCPU, 0);
if (!priv->tun.neigh_wq) {
err = -ENOMEM;
goto err_free_macs;
}
ida_init(&priv->tun.mac_off_ids);
/* Initialise priv data for IPv4/v6 offloading. */
@ -1521,13 +1528,17 @@ int nfp_tunnel_config_start(struct nfp_app *app)
priv->tun.neigh_nb.notifier_call = nfp_tun_neigh_event_handler;
err = register_netevent_notifier(&priv->tun.neigh_nb);
if (err) {
rhashtable_free_and_destroy(&priv->tun.offloaded_macs,
nfp_check_rhashtable_empty, NULL);
return err;
}
if (err)
goto err_destroy_neigh_wq;
return 0;
err_destroy_neigh_wq:
destroy_workqueue(priv->tun.neigh_wq);
err_free_macs:
rhashtable_free_and_destroy(&priv->tun.offloaded_macs,
nfp_check_rhashtable_empty, NULL);
return err;
}
void nfp_tunnel_config_stop(struct nfp_app *app)
@ -1537,6 +1548,7 @@ void nfp_tunnel_config_stop(struct nfp_app *app)
struct list_head *ptr, *storage;
unregister_netevent_notifier(&priv->tun.neigh_nb);
destroy_workqueue(priv->tun.neigh_wq);
ida_destroy(&priv->tun.mac_off_ids);

View File

@ -116,7 +116,7 @@
#define ETDES1_BUFFER2_SIZE_MASK GENMASK(28, 16)
/* Extended Receive descriptor definitions */
#define ERDES4_IP_PAYLOAD_TYPE_MASK GENMASK(6, 2)
#define ERDES4_IP_PAYLOAD_TYPE_MASK GENMASK(2, 0)
#define ERDES4_IP_HDR_ERR BIT(3)
#define ERDES4_IP_PAYLOAD_ERR BIT(4)
#define ERDES4_IP_CSUM_BYPASSED BIT(5)
@ -147,6 +147,10 @@
#define RDES_PTP_SIGNALING 0xa
#define RDES_PTP_PKT_RESERVED_TYPE 0xf
#define RDES_EXT_PAYLOAD_UDP 0x1
#define RDES_EXT_PAYLOAD_TCP 0x2
#define RDES_EXT_PAYLOAD_ICMP 0x3
/* Basic descriptor structure for normal and alternate descriptors */
struct dma_desc {
__le32 des0;

View File

@ -109,8 +109,25 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
return ret;
}
static void enh_desc_get_ext_status(struct stmmac_extra_stats *x,
struct dma_extended_desc *p)
static int enh_desc_ext_rx_csum(u32 rdes0, u32 rdes4, int status)
{
u32 type = FIELD_GET(ERDES4_IP_PAYLOAD_TYPE_MASK, rdes4);
if (status != csum_none || !(rdes0 & RDES0_FRAME_TYPE))
return status;
if (!(rdes4 & (ERDES4_IPV4_PKT_RCVD | ERDES4_IPV6_PKT_RCVD)) ||
(rdes4 & (ERDES4_IP_HDR_ERR | ERDES4_IP_PAYLOAD_ERR |
ERDES4_IP_CSUM_BYPASSED)))
return status;
if (type != RDES_EXT_PAYLOAD_UDP && type != RDES_EXT_PAYLOAD_TCP &&
type != RDES_EXT_PAYLOAD_ICMP)
return status;
return good_frame;
}
static int enh_desc_get_ext_status(struct stmmac_extra_stats *x,
struct dma_extended_desc *p, int status)
{
u32 rdes0 = le32_to_cpu(p->basic.des0);
u32 rdes4 = le32_to_cpu(p->des4);
@ -170,7 +187,11 @@ static void enh_desc_get_ext_status(struct stmmac_extra_stats *x,
x->l4_filter_match++;
if (rdes4 & ERDES4_L3_L4_FILT_NO_MATCH_MASK)
x->l3_l4_filter_no_match++;
status = enh_desc_ext_rx_csum(rdes0, rdes4, status);
}
return status;
}
static int enh_desc_get_rx_status(struct stmmac_extra_stats *x,

View File

@ -70,8 +70,8 @@ struct stmmac_desc_ops {
/* Return the reception status looking at the RDES1 */
int (*rx_status)(struct stmmac_extra_stats *x,
struct dma_desc *p);
void (*rx_extended_status)(struct stmmac_extra_stats *x,
struct dma_extended_desc *p);
int (*rx_extended_status)(struct stmmac_extra_stats *x,
struct dma_extended_desc *p, int status);
/* Set tx timestamp enable bit */
void (*enable_tx_timestamp) (struct dma_desc *p);
/* get tx timestamp status */
@ -128,7 +128,7 @@ struct stmmac_desc_ops {
#define stmmac_rx_status(__priv, __args...) \
stmmac_do_callback(__priv, desc, rx_status, __args)
#define stmmac_rx_extended_status(__priv, __args...) \
stmmac_do_void_callback(__priv, desc, rx_extended_status, __args)
stmmac_do_callback(__priv, desc, rx_extended_status, __args)
#define stmmac_enable_tx_timestamp(__priv, __args...) \
stmmac_do_void_callback(__priv, desc, enable_tx_timestamp, __args)
#define stmmac_get_tx_timestamp_status(__priv, __args...) \

View File

@ -5700,9 +5700,13 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
if (!buf->xdp)
break;
if (priv->extend_desc)
stmmac_rx_extended_status(priv, &priv->xstats,
rx_q->dma_erx + entry);
if (priv->extend_desc) {
/* Read the extended status after the own bit */
dma_rmb();
status = stmmac_rx_extended_status(priv, &priv->xstats,
&rx_q->dma_erx[entry],
status);
}
if (unlikely(status == discard_frame)) {
xsk_buff_free(buf->xdp);
buf->xdp = NULL;
@ -5883,8 +5887,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
prefetch(np);
if (priv->extend_desc)
stmmac_rx_extended_status(priv, &priv->xstats, rx_q->dma_erx + entry);
if (priv->extend_desc) {
/* Read the extended status after the own bit */
dma_rmb();
status = stmmac_rx_extended_status(priv, &priv->xstats,
&rx_q->dma_erx[entry],
status);
}
if (unlikely(status == discard_frame)) {
page_pool_put_page(rx_q->page_pool, buf->page, 0, true);
buf->page = NULL;

View File

@ -779,6 +779,7 @@ static long am65_cpts_ts_work(struct ptp_clock_info *ptp);
static struct ptp_clock_info am65_ptp_info = {
.owner = THIS_MODULE,
.name = "CTPS timer",
.supported_extts_flags = PTP_RISING_EDGE | PTP_STRICT_FLAGS,
.adjfine = am65_cpts_ptp_adjfine,
.adjtime = am65_cpts_ptp_adjtime,
.gettimex64 = am65_cpts_ptp_gettimex,

View File

@ -118,7 +118,8 @@ enum gtp_multicast_groups {
};
static const struct genl_multicast_group gtp_genl_mcgrps[] = {
[GTP_GENL_MCGRP] = { .name = GTP_GENL_MCGRP_NAME },
[GTP_GENL_MCGRP] = { .name = GTP_GENL_MCGRP_NAME,
.flags = GENL_MCAST_CAP_NET_ADMIN, },
};
static void pdp_context_delete(struct pdp_ctx *pctx);
@ -2355,9 +2356,9 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
struct gtp_dev *gtp;
struct flowi4 fl4;
struct rtable *rt;
int len, ret = 0;
struct sock *sk;
__be16 port;
int len;
if (!info->attrs[GTPA_VERSION] ||
!info->attrs[GTPA_LINK] ||
@ -2369,14 +2370,21 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
dst_ip = nla_get_be32(info->attrs[GTPA_PEER_ADDRESS]);
src_ip = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
rcu_read_lock();
gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
if (!gtp)
return -ENODEV;
if (!gtp) {
ret = -ENODEV;
goto unlock;
}
if (!gtp->sk_created)
return -EOPNOTSUPP;
if (!(gtp->dev->flags & IFF_UP))
return -ENETDOWN;
if (!gtp->sk_created) {
ret = -EOPNOTSUPP;
goto unlock;
}
if (!(gtp->dev->flags & IFF_UP)) {
ret = -ENETDOWN;
goto unlock;
}
if (version == GTP_V0) {
struct gtp0_header *gtp0_h;
@ -2385,8 +2393,10 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
sizeof(struct iphdr) + sizeof(struct udphdr);
skb_to_send = netdev_alloc_skb_ip_align(gtp->dev, len);
if (!skb_to_send)
return -ENOMEM;
if (!skb_to_send) {
ret = -ENOMEM;
goto unlock;
}
sk = gtp->sk0;
port = htons(GTP0_PORT);
@ -2402,8 +2412,10 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
sizeof(struct iphdr) + sizeof(struct udphdr);
skb_to_send = netdev_alloc_skb_ip_align(gtp->dev, len);
if (!skb_to_send)
return -ENOMEM;
if (!skb_to_send) {
ret = -ENOMEM;
goto unlock;
}
sk = gtp->sk1u;
port = htons(GTP1U_PORT);
@ -2413,7 +2425,8 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
memset(gtp1u_h, 0, sizeof(struct gtp1_header_long));
gtp1u_build_echo_msg(gtp1u_h, GTP_ECHO_REQ);
} else {
return -ENODEV;
ret = -ENODEV;
goto unlock;
}
rt = ip4_route_output_gtp(&fl4, sk, dst_ip, src_ip);
@ -2421,7 +2434,8 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
netdev_dbg(gtp->dev, "no route for echo request to %pI4\n",
&dst_ip);
kfree_skb(skb_to_send);
return -ENODEV;
ret = -ENODEV;
goto unlock;
}
local_bh_disable();
@ -2435,7 +2449,10 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
dev_net(gtp->dev)),
false, 0);
local_bh_enable();
return 0;
unlock:
rcu_read_unlock();
return ret;
}
static const struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = {

View File

@ -70,6 +70,7 @@ EXPORT_SYMBOL(blackhole_netdev);
static netdev_tx_t loopback_xmit(struct sk_buff *skb,
struct net_device *dev)
{
enum skb_drop_reason reason;
int len;
skb_tx_timestamp(skb);
@ -84,7 +85,12 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
*/
skb_dst_force(skb);
skb->protocol = eth_type_trans(skb, dev);
reason = eth_type_trans_careful(skb, dev);
if (unlikely(reason)) {
dev_core_stats_tx_dropped_inc(dev);
kfree_skb_reason(skb, reason);
return NETDEV_TX_OK;
}
len = skb->len;
if (likely(__netif_rx(skb) == NET_RX_SUCCESS))

View File

@ -1664,7 +1664,8 @@ static int macvlan_changelink(struct net_device *dev,
if (data && data[IFLA_MACVLAN_FLAGS]) {
__u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC;
if (macvlan_passthru(vlan->port) && promisc) {
if (macvlan_passthru(vlan->port) && promisc &&
netif_running(dev)) {
int err;
if (flags & MACVLAN_FLAG_NOPROMISC)

View File

@ -816,8 +816,8 @@ static void mctp_usblib_test_tx_multi_push(struct kunit *test)
};
int rc;
static_assert(!sends[ARRAY_SIZE(sends) - 1].more,
"The last push must claim there will be no more");
KUNIT_ASSERT_TRUE_MSG(test, !sends[ARRAY_SIZE(sends) - 1].more,
"The last push must claim there will be no more");
max_length = 0;
for (i = 0; i < ARRAY_SIZE(sends); i++) {

View File

@ -275,6 +275,15 @@ static int xpcs_plat_init_res(struct dw_xpcs_plat *pxpcs)
return 0;
}
#ifdef CONFIG_PM
static void xpcs_plat_exit_clk(void *data)
{
struct dw_xpcs_plat *pxpcs = data;
struct device *dev = &pxpcs->pdev->dev;
pm_runtime_force_suspend(dev);
}
static int xpcs_plat_init_clk(struct dw_xpcs_plat *pxpcs)
{
struct device *dev = &pxpcs->pdev->dev;
@ -285,15 +294,50 @@ static int xpcs_plat_init_clk(struct dw_xpcs_plat *pxpcs)
return dev_err_probe(dev, PTR_ERR(pxpcs->cclk),
"Failed to get CSR clock\n");
pm_runtime_set_active(dev);
ret = devm_pm_runtime_enable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_enable(dev);
ret = devm_add_action_or_reset(dev, xpcs_plat_exit_clk, pxpcs);
if (ret) {
dev_err(dev, "Failed to enable runtime-PM\n");
dev_err(dev, "Failed to register devm for xpcs_plat_exit_clk: %d\n", ret);
return ret;
}
return 0;
}
#else
static void xpcs_plat_exit_clk(void *data)
{
struct dw_xpcs_plat *pxpcs = data;
clk_disable_unprepare(pxpcs->cclk);
}
static int xpcs_plat_init_clk(struct dw_xpcs_plat *pxpcs)
{
struct device *dev = &pxpcs->pdev->dev;
int ret;
pxpcs->cclk = devm_clk_get_optional(dev, "csr");
if (IS_ERR(pxpcs->cclk))
return dev_err_probe(dev, PTR_ERR(pxpcs->cclk),
"Failed to get CSR clock\n");
ret = clk_prepare_enable(pxpcs->cclk);
if (ret) {
dev_err(dev, "Failed to enable CSR clock: %d\n", ret);
return ret;
}
ret = devm_add_action_or_reset(dev, xpcs_plat_exit_clk, pxpcs);
if (ret) {
dev_err(dev, "Failed to register devm for xpcs_plat_exit_clk: %d\n", ret);
return ret;
}
return 0;
}
#endif
static int xpcs_plat_init_bus(struct dw_xpcs_plat *pxpcs)
{
@ -398,7 +442,7 @@ static int xpcs_plat_probe(struct platform_device *pdev)
return 0;
}
static int __maybe_unused xpcs_plat_pm_runtime_suspend(struct device *dev)
static int xpcs_plat_pm_runtime_suspend(struct device *dev)
{
struct dw_xpcs_plat *pxpcs = dev_get_drvdata(dev);
@ -407,7 +451,7 @@ static int __maybe_unused xpcs_plat_pm_runtime_suspend(struct device *dev)
return 0;
}
static int __maybe_unused xpcs_plat_pm_runtime_resume(struct device *dev)
static int xpcs_plat_pm_runtime_resume(struct device *dev)
{
struct dw_xpcs_plat *pxpcs = dev_get_drvdata(dev);
@ -415,9 +459,9 @@ static int __maybe_unused xpcs_plat_pm_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops xpcs_plat_pm_ops = {
SET_RUNTIME_PM_OPS(xpcs_plat_pm_runtime_suspend,
xpcs_plat_pm_runtime_resume,
NULL)
RUNTIME_PM_OPS(xpcs_plat_pm_runtime_suspend,
xpcs_plat_pm_runtime_resume,
NULL)
};
DW_XPCS_INFO_DECLARE(xpcs_generic, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_ID_NATIVE);
@ -446,7 +490,7 @@ static struct platform_driver xpcs_plat_driver = {
.probe = xpcs_plat_probe,
.driver = {
.name = "dwxpcs",
.pm = &xpcs_plat_pm_ops,
.pm = pm_ptr(&xpcs_plat_pm_ops),
.of_match_table = xpcs_of_ids,
},
};

View File

@ -365,7 +365,7 @@ static int xpcs_rk_init_clk(struct dw_xpcs_rk *pxpcs)
ret = devm_add_action_or_reset(dev, xpcs_rk_exit_clk, pxpcs);
if (ret) {
dev_err(dev, "Failed to register devm for EEE clock: %d\n", ret);
dev_err(dev, "Failed to register devm for xpcs_rk_exit_clk: %d\n", ret);
return ret;
}

View File

@ -45,6 +45,7 @@
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/unaligned.h>
#include <net/gso.h>
#include <net/netdev_lock.h>
#include <net/slhc_vj.h>
#include <linux/atomic.h>
@ -2278,6 +2279,73 @@ static bool ppp_decompress_proto(struct sk_buff *skb)
return pskb_may_pull(skb, 2);
}
#define PPP_BRIDGE_GSO_TYPES (SKB_GSO_TCPV4 | SKB_GSO_TCPV6 | \
SKB_GSO_TCP_ECN | SKB_GSO_TCP_ACCECN | \
SKB_GSO_TCP_FIXEDID | SKB_GSO_UDP_L4 | \
SKB_GSO_FRAGLIST | SKB_GSO_DODGY)
/* Segment a GSO packet (built by PPPoE GRO, or injected with a
* virtio_net_hdr) before sending it to a bridged channel that does
* not accept GSO packets.
* skb->data points to the PPP protocol field, which is replicated
* in front of each segment.
* Returns a list of segments, or NULL if the packet was dropped.
*/
static struct sk_buff *ppp_bridge_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
struct sk_buff *segs;
/* skb->dev is NULL here (cleared by __sk_receive_skb() for PPPoE),
* and some GSO handlers (tunnels, IPv6 UFO) dereference it.
*/
if (skb->encapsulation ||
(skb_shinfo(skb)->gso_type & ~PPP_BRIDGE_GSO_TYPES))
goto drop;
if (!pskb_may_pull(skb, PPP_PROTO_LEN))
goto drop;
switch (get_unaligned((__be16 *)skb->data)) {
case htons(PPP_IP):
skb->protocol = htons(ETH_P_IP);
break;
case htons(PPP_IPV6):
skb->protocol = htons(ETH_P_IPV6);
break;
default:
goto drop;
}
skb_set_network_header(skb, PPP_PROTO_LEN);
/* No checksum offload: skb_segment() computes the checksums. */
segs = skb_gso_segment(skb, features);
if (IS_ERR_OR_NULL(segs))
goto drop;
consume_skb(skb);
return segs;
drop:
kfree_skb(skb);
return NULL;
}
static void ppp_bridge_xmit(struct ppp_channel *chan, struct sk_buff *skb)
{
if (!chan->direct_xmit && skb_linearize(skb))
goto drop;
if (!chan->xmit_offload && skb->ip_summed == CHECKSUM_PARTIAL &&
skb_csum_hwoffload_help(skb, 0))
goto drop;
if (chan->ops->start_xmit(chan, skb))
return;
drop:
kfree_skb(skb);
}
/* Attempt to handle a frame via. a bridged channel, if one exists.
* If the channel is bridged, the frame is consumed by the bridge.
* If not, the caller must handle the frame by normal recv mechanisms.
@ -2285,6 +2353,8 @@ static bool ppp_decompress_proto(struct sk_buff *skb)
*/
static bool ppp_channel_bridge_input(struct channel *pch, struct sk_buff *skb)
{
struct sk_buff *segs, *next;
struct ppp_channel *chan;
struct channel *pchb;
rcu_read_lock();
@ -2300,8 +2370,29 @@ static bool ppp_channel_bridge_input(struct channel *pch, struct sk_buff *skb)
}
skb_scrub_packet(skb, !net_eq(pch->chan_net, pchb->chan_net));
if (!pchb->chan->ops->start_xmit(pchb->chan, skb))
kfree_skb(skb);
/* Receive paths such as L2TP pull headers without updating
* the checksum state: drop a stale CHECKSUM_PARTIAL state
* pointing before skb->data, as skb_postpull_rcsum() does.
*/
if (skb->ip_summed == CHECKSUM_PARTIAL &&
skb_checksum_start_offset(skb) < 0)
skb->ip_summed = CHECKSUM_NONE;
chan = pchb->chan;
if (!chan->xmit_offload && skb_is_gso(skb)) {
/* Channels needing linear packets get linear segments,
* others keep references to the original pages.
*/
segs = ppp_bridge_gso_segment(skb, chan->direct_xmit ?
NETIF_F_SG : 0);
skb_list_walk_safe(segs, skb, next) {
skb_mark_not_on_list(skb);
ppp_bridge_xmit(chan, skb);
}
} else {
ppp_bridge_xmit(chan, skb);
}
outl:
spin_unlock_bh(&pchb->downl);
@ -3157,6 +3248,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
len = CCP_LENGTH(dp);
if (!pskb_may_pull(skb, len + 2))
return; /* too short */
dp = skb->data + 2;
dp += CCP_HDRLEN;
len -= CCP_HDRLEN;
if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp))

View File

@ -460,6 +460,9 @@ static int pppoe_disc_rcv(struct sk_buff *skb, struct net_device *dev,
if (skb->pkt_type != PACKET_HOST)
goto abort;
if (skb_mac_header_len(skb) < ETH_HLEN)
goto abort;
if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto abort;
@ -618,6 +621,10 @@ static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr
pppox_unbind_sock(sk);
pn = pppoe_pernet(sock_net(sk));
delete_item(pn, po);
/* wait for concurrent readers before clearing the fields */
synchronize_net();
if (po->pppoe_dev) {
dev_put(po->pppoe_dev);
po->pppoe_dev = NULL;
@ -664,6 +671,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr
po->chan.private = sk;
po->chan.ops = &pppoe_chan_ops;
po->chan.direct_xmit = true;
po->chan.xmit_offload = true;
error = ppp_register_net_channel(dev_net(dev), &po->chan);
if (error) {

View File

@ -250,9 +250,9 @@ static int si3474_get_of_channels(struct si3474_priv *priv)
"Failed to read channel reg property\n");
return ret;
}
if (chan_id > SI3474_MAX_CHANS) {
if (chan_id >= SI3474_MAX_CHANS) {
dev_err(&priv->client[0]->dev,
"Incorrect channel number: %d\n", chan_id);
"Incorrect channel number: %u\n", chan_id);
return -EINVAL;
}
@ -267,6 +267,16 @@ static int si3474_get_of_channels(struct si3474_priv *priv)
pi->np);
return -EINVAL;
}
/* The 2P/4P mode bit pairs channels 0+1 and 2+3 of a quad */
if (pairset_found &&
(priv->pi[pi_no].chan[0] ^ 1) != priv->pi[pi_no].chan[1]) {
dev_err(&priv->client[0]->dev,
"PI %pOF: channels %u and %u are not a channel pair\n",
pi->np, priv->pi[pi_no].chan[0],
priv->pi[pi_no].chan[1]);
return -EINVAL;
}
}
return 0;
@ -312,8 +322,13 @@ static int si3474_pi_enable(struct pse_controller_dev *pcdev, int id)
/* DETECT_CLASS_ENABLE must be set when using AUTO mode,
* otherwise PI does not power up - datasheet section 2.10.2
*/
val = CHAN_BIT(chan0) | CHAN_UPPER_BIT(chan0) |
CHAN_BIT(chan1) | CHAN_UPPER_BIT(chan1);
ret = i2c_smbus_read_byte_data(client, DETECT_CLASS_ENABLE_REG);
if (ret < 0)
return ret;
val = (u8)ret;
val |= CHAN_BIT(chan0) | CHAN_UPPER_BIT(chan0) |
CHAN_BIT(chan1) | CHAN_UPPER_BIT(chan1);
ret = i2c_smbus_write_byte_data(client, DETECT_CLASS_ENABLE_REG, val);
if (ret)

View File

@ -688,14 +688,18 @@ static void tun_detach_all(struct net_device *dev)
synchronize_net();
for (i = 0; i < n; i++) {
tfile = rtnl_dereference(tun->tfiles[i]);
mutex_lock(&tfile->napi_mutex);
tun_napi_del(tfile);
mutex_unlock(&tfile->napi_mutex);
/* Drop read queue */
tun_queue_purge(tfile);
xdp_rxq_info_unreg(&tfile->xdp_rxq);
sock_put(&tfile->sk);
}
list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {
mutex_lock(&tfile->napi_mutex);
tun_napi_del(tfile);
mutex_unlock(&tfile->napi_mutex);
tun_enable_queue(tfile);
tun_queue_purge(tfile);
xdp_rxq_info_unreg(&tfile->xdp_rxq);
@ -2551,6 +2555,12 @@ static int tun_xdp_one(struct tun_struct *tun,
return -EINVAL;
}
if (unlikely(!(READ_ONCE(tun->dev->flags) & IFF_UP))) {
put_page(virt_to_head_page(xdp->data));
dev_core_stats_rx_dropped_inc(tun->dev);
return -EIO;
}
xdp_prog = rcu_dereference(tun->xdp_prog);
if (xdp_prog) {
if (gso->gso_type) {

View File

@ -471,8 +471,12 @@ static int aqc111_set_mac_addr(struct net_device *net, void *p)
return ret;
/* Set the MAC address */
return aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN,
ETH_ALEN, net->dev_addr);
ret = aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID,
ETH_ALEN, ETH_ALEN, net->dev_addr);
if (ret < 0)
return ret;
return 0;
}
static int aqc111_vlan_rx_kill_vid(struct net_device *net,

View File

@ -289,9 +289,10 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
}
}
spin_lock_bh(&ctx->mtx);
/* BHs or IRQs are always off here, see cdc_ncm_tx_fixup() */
spin_lock(&ctx->mtx);
skb_out = cdc_ncm_fill_tx_frame(dev, skb, sign);
spin_unlock_bh(&ctx->mtx);
spin_unlock(&ctx->mtx);
return skb_out;
error:

View File

@ -1535,14 +1535,17 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
if (ctx == NULL)
goto error;
spin_lock_bh(&ctx->mtx);
/* BHs or IRQs are always off here. netpoll only disables IRQs, and
* spin_unlock_bh() would then run softirqs with the txq lock held.
*/
spin_lock(&ctx->mtx);
if (ctx->is_ndp16)
skb_out = cdc_ncm_fill_tx_frame(dev, skb, cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN));
else
skb_out = cdc_ncm_fill_tx_frame(dev, skb, cpu_to_le32(USB_CDC_NCM_NDP32_NOCRC_SIGN));
spin_unlock_bh(&ctx->mtx);
spin_unlock(&ctx->mtx);
return skb_out;
error:
@ -2019,6 +2022,12 @@ static const struct usb_device_id cdc_devs[] = {
{ USB_DEVICE_INTERFACE_NUMBER(0x05ac, 0x1902, 2),
.driver_info = (unsigned long)&apple_private_interface_info,
},
{ USB_DEVICE_INTERFACE_NUMBER(0x05ac, 0x1903, 0),
.driver_info = (unsigned long)&apple_private_interface_info,
},
{ USB_DEVICE_INTERFACE_NUMBER(0x05ac, 0x1903, 2),
.driver_info = (unsigned long)&apple_private_interface_info,
},
{ USB_DEVICE_INTERFACE_NUMBER(0x05ac, 0x1905, 0),
.driver_info = (unsigned long)&apple_private_interface_info,
},

View File

@ -1767,6 +1767,12 @@ static void lan78xx_get_wol(struct net_device *netdev,
u32 buf;
struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);
if (!netdev->phydev) {
wol->supported = 0;
wol->wolopts = 0;
return;
}
if (usb_autopm_get_interface(dev->intf) < 0)
return;
@ -1798,6 +1804,9 @@ static int lan78xx_set_wol(struct net_device *netdev,
if (wol->wolopts & ~WAKE_ALL)
return -EINVAL;
if (!netdev->phydev)
return -EOPNOTSUPP;
ret = usb_autopm_get_interface(dev->intf);
if (ret < 0)
return ret;

View File

@ -461,6 +461,7 @@ static void read_bulk_callback(struct urb *urb)
u8 *buf = urb->transfer_buffer;
int rx_status, count = urb->actual_length;
int status = urb->status;
int rx_offset = 0;
__u16 pkt_len;
if (!pegasus)
@ -510,7 +511,7 @@ static void read_bulk_callback(struct urb *urb)
if (pegasus->chip == 0x8513) {
pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer);
pkt_len &= 0x0fff;
pegasus->rx_skb->data += 2;
rx_offset = 2;
} else {
pkt_len = buf[count - 3] << 8;
pkt_len += buf[count - 4];
@ -519,16 +520,23 @@ static void read_bulk_callback(struct urb *urb)
}
/*
* If the packet is unreasonably long, quietly drop it rather than
* kernel panicing by calling skb_put.
* Drop frames shorter than an Ethernet header, because
* eth_type_trans() reads the header whatever the length, and frames
* longer than what was actually received. Passing either up would
* expose stale buffer contents, and skb_put() could panic on the
* latter. count is at most PEGASUS_MTU.
*/
if (pkt_len > PEGASUS_MTU)
if (pkt_len < ETH_HLEN || pkt_len + rx_offset > count) {
net->stats.rx_errors++;
net->stats.rx_length_errors++;
goto goon;
}
/*
* at this point we are sure pegasus->rx_skb != NULL
* so we go ahead and pass up the packet.
*/
skb_reserve(pegasus->rx_skb, rx_offset);
skb_put(pegasus->rx_skb, pkt_len);
pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net);
netif_rx(pegasus->rx_skb);

View File

@ -6958,11 +6958,8 @@ static void set_carrier(struct r8152 *tp)
{
struct net_device *netdev = tp->netdev;
struct napi_struct *napi = &tp->napi;
u16 speed;
speed = rtl8152_get_speed(tp);
if (speed & LINK_STATUS) {
if (r8152_mdio_read(tp, MII_BMSR) & BMSR_LSTATUS) {
if (!netif_carrier_ok(netdev)) {
tp->rtl_ops.enable(tp);
netif_stop_queue(netdev);
@ -6988,6 +6985,11 @@ static void set_carrier(struct r8152 *tp)
tasklet_enable(&tp->tx_tl);
netif_info(tp, link, netdev, "carrier off\n");
}
if (rtl8152_get_speed(tp) & LINK_STATUS) {
set_bit(RTL8152_LINK_CHG, &tp->flags);
schedule_delayed_work(&tp->schedule, 0);
}
}
}

View File

@ -329,9 +329,14 @@ void usbnet_skb_return(struct usbnet *dev, struct sk_buff *skb)
unsigned long flags;
int status;
if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
skb_queue_tail(&dev->rxq_pause, skb);
return;
if (unlikely(test_bit(EVENT_RX_PAUSED, &dev->flags))) {
spin_lock_irqsave(&dev->rxq_pause.lock, flags);
if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
__skb_queue_tail(&dev->rxq_pause, skb);
spin_unlock_irqrestore(&dev->rxq_pause.lock, flags);
return;
}
spin_unlock_irqrestore(&dev->rxq_pause.lock, flags);
}
/* only update if unset to allow minidriver rx_fixup override */
@ -698,13 +703,20 @@ EXPORT_SYMBOL_GPL(usbnet_pause_rx);
void usbnet_resume_rx(struct usbnet *dev)
{
struct sk_buff_head q;
struct sk_buff *skb;
unsigned long flags;
int num = 0;
local_bh_disable();
clear_bit(EVENT_RX_PAUSED, &dev->flags);
__skb_queue_head_init(&q);
while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) {
local_bh_disable();
spin_lock_irqsave(&dev->rxq_pause.lock, flags);
clear_bit(EVENT_RX_PAUSED, &dev->flags);
skb_queue_splice_init(&dev->rxq_pause, &q);
spin_unlock_irqrestore(&dev->rxq_pause.lock, flags);
while ((skb = __skb_dequeue(&q))) {
usbnet_skb_return(dev, skb);
num++;
}

View File

@ -1627,10 +1627,9 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
}
}
if (!old_prog) {
if (!old_prog)
peer->hw_features &= ~NETIF_F_GSO_SOFTWARE;
peer->max_mtu = max_mtu;
}
peer->max_mtu = max_mtu;
xdp_features_set_redirect_target(peer, true);
}

View File

@ -4488,7 +4488,7 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
}
conf->reserved_bits = reserved_bits;
} else {
} else if (!changelink) {
/* For backwards compatibility, only allow reserved fields to be
* used by VXLAN extensions if explicitly requested.
*/

View File

@ -38,6 +38,34 @@ int fwnode_get_mac_address(struct fwnode_handle *fwnode, char *addr);
u32 eth_get_headlen(const struct net_device *dev, const void *data, u32 len);
__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
/**
* eth_type_trans_careful - eth_type_trans() for skbs coming from the stack
* @skb: buffer, possibly with less than ETH_HLEN bytes in its linear area
* @dev: receiving network device
*
* eth_type_trans() expects ETH_HLEN bytes in skb->head, which NIC drivers
* provide. Devices looping skbs from their transmit path back to the
* receive path (loopback, OVS internal ports) get skbs built by the stack,
* whose link-layer header might have been popped by tc or OVS actions.
*
* Sets skb->protocol on success.
*
* Return: SKB_NOT_DROPPED_YET on success, or a drop reason. In the latter
* case, the caller must free @skb.
*/
static inline enum skb_drop_reason
eth_type_trans_careful(struct sk_buff *skb, struct net_device *dev)
{
enum skb_drop_reason reason = pskb_may_pull_reason(skb, ETH_HLEN);
if (unlikely(reason))
return reason;
skb->protocol = eth_type_trans(skb, dev);
return SKB_NOT_DROPPED_YET;
}
extern const struct header_ops eth_header_ops;
int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,

View File

@ -43,6 +43,7 @@ struct ppp_channel {
void *ppp; /* opaque to channel */
int speed; /* transfer rate (bytes/second) */
bool direct_xmit; /* no qdisc, xmit directly */
bool xmit_offload; /* accepts GSO and CHECKSUM_PARTIAL skbs */
};
#ifdef __KERNEL__

View File

@ -171,6 +171,7 @@ extern const u8 ip_frag_ecn_table[16];
#define IPFRAG_OK 0
#define IPFRAG_DUP 1
#define IPFRAG_OVERLAP 2
#define IPFRAG_MIXED_SECPATH 3
int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb,
int offset, int end);
void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb,

View File

@ -513,31 +513,6 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
return res;
}
/* Configured/administrative MTU of a route, for advertising the TCP MSS.
*
* Unlike ip_dst_mtu_maybe_forward(), this deliberately ignores the
* ICMP-learned path MTU (rt->rt_pmtu). The advertised MSS bounds what the
* peer may send to us and must reflect our receive capability (the device or
* route-configured MTU), not a path MTU learned on the reverse (send)
* direction, which may not apply to the peer->us path and outlives the fnhe
* for the whole connection. See RFC 2923 section 2.3 and the comment above
* tcp_advertise_mss().
*/
static inline unsigned int ip_dst_mtu_configured(const struct dst_entry *dst)
{
unsigned int mtu, res;
rcu_read_lock();
mtu = dst_metric_raw(dst, RTAX_MTU);
if (!mtu)
mtu = READ_ONCE(dst_dev_rcu(dst)->mtu);
mtu = min_t(unsigned int, mtu, IP_MAX_MTU);
res = mtu - lwtunnel_headroom(dst->lwtstate, mtu);
rcu_read_unlock();
return res;
}
static inline unsigned int ip_skb_dst_mtu(struct sock *sk,
const struct sk_buff *skb)
{

View File

@ -396,43 +396,6 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dst
return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
}
/* Configured/administrative MTU of a route, for advertising the TCP MSS.
*
* Unlike ip6_dst_mtu_maybe_forward(), this ignores any ICMPv6-learned path
* MTU (which is kept on the RTF_CACHE exception route) and returns the MTU of
* the underlying route (fib6_pmtu) or the egress device. The advertised MSS
* bounds what the peer may send to us and must reflect our receive
* capability, not a path MTU learned on the reverse (send) direction. See
* RFC 2923 section 2.3 and the comment above tcp_advertise_mss().
*/
static inline unsigned int ip6_dst_mtu_configured(const struct dst_entry *dst)
{
const struct rt6_info *rt = dst_rt6_info(dst);
const struct fib6_info *from;
struct inet6_dev *idev;
unsigned int mtu = 0;
rcu_read_lock();
/* IPv6 keeps the learned PMTU and the configured MTU in the same
* RTAX_MTU slot: the learned value sits on this (possibly RTF_CACHE)
* dst, the configured one on the underlying route. Reach the latter
* via ->from (fib6_pmtu), populated by ip6_route_info_create().
*/
from = rcu_dereference(rt->from);
if (from)
mtu = from->fib6_pmtu;
if (!mtu) {
mtu = IPV6_MIN_MTU;
idev = __in6_dev_get(dst_dev_rcu(dst));
if (idev)
mtu = max_t(unsigned int, mtu, READ_ONCE(idev->cnf.mtu6));
}
rcu_read_unlock();
mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
}
u32 ip6_mtu_from_fib6(const struct fib6_result *res,
const struct in6_addr *daddr,
const struct in6_addr *saddr);

View File

@ -1201,6 +1201,23 @@ secpath_reset(struct sk_buff *skb)
#endif
}
static inline bool
secpath_equal(const struct sk_buff *skb1, const struct sk_buff *skb2)
{
const struct sec_path *sp1 = skb_sec_path(skb1);
const struct sec_path *sp2 = skb_sec_path(skb2);
int i;
if (!sp1 || !sp2)
return sp1 == sp2;
if (sp1->len != sp2->len)
return false;
for (i = 0; i < sp1->len; i++)
if (sp1->xvec[i] != sp2->xvec[i])
return false;
return true;
}
static inline int
xfrm_addr_any(const xfrm_address_t *addr, unsigned short family)
{

View File

@ -540,7 +540,7 @@ static int br_fill_ifinfo(struct sk_buff *skb,
else
err = br_fill_ifvlaninfo(skb, vg);
if (port && test_bit(BR_VLAN_TUNNEL_BIT, &port->flags))
if (!err && port && test_bit(BR_VLAN_TUNNEL_BIT, &port->flags))
err = br_fill_vlan_tunnel_info(skb, vg);
rcu_read_unlock();
if (err)

View File

@ -2501,14 +2501,22 @@ EXPORT_SYMBOL_GPL(is_skb_forwardable);
static int __dev_forward_skb2(struct net_device *dev, struct sk_buff *skb,
bool check_mtu)
{
int ret = ____dev_forward_skb(dev, skb, check_mtu);
enum skb_drop_reason reason;
int ret;
if (likely(!ret)) {
skb->protocol = eth_type_trans(skb, dev);
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
ret = ____dev_forward_skb(dev, skb, check_mtu);
if (unlikely(ret))
return ret;
reason = eth_type_trans_careful(skb, dev);
if (unlikely(reason)) {
dev_core_stats_rx_dropped_inc(dev);
kfree_skb_reason(skb, reason);
return NET_RX_DROP;
}
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
return ret;
return 0;
}
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
@ -3041,7 +3049,7 @@ int __netif_set_xps_queue(struct net_device *dev, const unsigned long *mask,
goto out_no_old_maps;
for (j = 0; j < dev_maps->nr_ids; j++) {
for (i = num_tc, tci = j * dev_maps->num_tc; i--; tci++) {
for (i = dev_maps->num_tc, tci = j * dev_maps->num_tc; i--; tci++) {
map = xmap_dereference(dev_maps->attr_map[tci]);
if (!map)
continue;
@ -3478,6 +3486,9 @@ static void __netif_reschedule(struct Qdisc *q)
void __netif_schedule(struct Qdisc *q)
{
if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state)))
return;
/* If q->defer_list is not empty, at least one thread is
* in __dev_xmit_skb() before llist_del_all(&q->defer_list).
* This thread will attempt to run the queue.
@ -4283,7 +4294,7 @@ static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
unsigned int hdr_len, tlen;
u16 gso_segs;
u32 gso_segs;
qdisc_skb_cb(skb)->pkt_len = skb->len;
if (!shinfo->gso_size) {
@ -4334,6 +4345,15 @@ static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb)
if (payload <= 0)
return SKB_DROP_REASON_SKB_BAD_GSO;
gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size);
/* shinfo->gso_segs is a 16bit field.
* Also make sure untrusted gso_size/hdr_len can not inflate
* qdisc_pkt_len() beyond QDISC_PKT_LEN_MAX, or deficit
* schedulers could spin in their refill loops.
*/
if (unlikely(gso_segs > GSO_MAX_SEGS ||
skb->len + (u64)(gso_segs - 1) * hdr_len >
QDISC_PKT_LEN_MAX))
return SKB_DROP_REASON_SKB_BAD_GSO;
shinfo->gso_segs = gso_segs;
qdisc_skb_cb(skb)->pkt_segs = gso_segs;
}
@ -6306,6 +6326,8 @@ static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc,
}
if (unlikely(skb_vlan_tag_present(skb)) && !netdev_uses_dsa(skb->dev)) {
unsigned int priority_tag_depth = 1;
check_vlan_id:
if (skb_vlan_tag_get_id(skb)) {
/* Vlan id is non 0 and vlan_do_receive() above couldn't
@ -6317,6 +6339,12 @@ static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc,
* 802.1Q or 802.1AD and vlan_do_receive() above could
* not find vlan dev for vlan id 0.
*/
if (unlikely(priority_tag_depth >= VLAN_MAX_DEPTH)) {
drop_reason = SKB_DROP_REASON_RECURSION_LIMIT;
goto drop;
}
priority_tag_depth++;
__vlan_hwaccel_clear_tag(skb);
skb = skb_vlan_untag(skb);
if (unlikely(!skb))

View File

@ -513,9 +513,10 @@ static enum gro_result dev_gro_receive(struct gro_node *gro,
NAPI_GRO_CB(skb)->count = 1;
if (unlikely(skb_is_gso(skb))) {
NAPI_GRO_CB(skb)->count = skb_shinfo(skb)->gso_segs;
/* Only support TCP and non DODGY users. */
/* Only support TCP and non DODGY users, with a sane gso_segs. */
if (!skb_is_gso_tcp(skb) ||
(skb_shinfo(skb)->gso_type & SKB_GSO_DODGY))
(skb_shinfo(skb)->gso_type & SKB_GSO_DODGY) ||
!NAPI_GRO_CB(skb)->count)
NAPI_GRO_CB(skb)->flush = 1;
}

View File

@ -1110,6 +1110,13 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue,
while ((mask | (mask >> 1)) != mask)
mask |= (mask >> 1);
/* Require at least two entries. A one-entry table rounds up
* to mask == 0, which encodes log == 0 in the tag.
* get_rps_cpu() then computes hash_32(hash, 0), a shift by 32.
*/
if (!mask)
return -EINVAL;
/* Do not accept too large tables. */
if (mask > (INT_MAX / sizeof(*table) - 1))
return -EINVAL;

View File

@ -1506,6 +1506,12 @@ static int netdev_genl_netdevice_event(struct notifier_block *nb,
netdev_unlock_full_to_ops(netdev);
break;
case NETDEV_UNREGISTER:
/* netdev_wait_allrefs_any() rebroadcasts NETDEV_UNREGISTER
* while waiting for the last references to be dropped; the
* netns may already be torn down by then. Notify only once.
*/
if (READ_ONCE(netdev->reg_state) == NETREG_UNREGISTERED)
break;
netdev_lock(netdev);
netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_DEL_NTF);
netdev_unlock(netdev);

View File

@ -3966,6 +3966,8 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
}
skb_shinfo(to)->nr_frags = j;
skb_shinfo(to)->flags |= skb_shinfo(from)->flags & SKBFL_SHARED_FRAG;
if (i > 0 && from->unreadable)
to->unreadable = 1;
@ -4780,10 +4782,13 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
else
tail->next = nskb;
if (unlikely(err)) {
nskb->next = list_skb;
/* nskb may be a clone with a NULL ->next: keep the remaining
* members linked so that err_linearize frees them.
*/
nskb->next = list_skb;
if (unlikely(err))
goto err_linearize;
}
tail = nskb;

View File

@ -281,6 +281,7 @@ static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh,
if (!getall && !data[i])
continue;
value = 0;
netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
&value);
ret = nla_put_u8(skb, i, value);
@ -1395,6 +1396,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
goto nla_put_failure;
for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
value = 0;
ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value);
if (nla_put_u8(skb, i, value))
goto nla_put_failure;

View File

@ -719,6 +719,11 @@ int devlink_nl_region_new_doit(struct sk_buff *skb, struct genl_info *info)
if (!snapshot_id_attr) {
struct sk_buff *msg;
/* Drop the allocation reference, the snapshot
* now holds its own.
*/
__devlink_snapshot_id_decrement(devlink, snapshot_id);
snapshot = devlink_region_snapshot_get_by_id(region,
snapshot_id);
if (WARN_ON(!snapshot)) {

View File

@ -446,7 +446,8 @@ void inet_csk_update_fastreuse(const struct sock *sk,
{
bool reuse = sk->sk_reuse && sk->sk_state != TCP_LISTEN;
if (hlist_empty(&tb->bhash2)) {
if (hlist_is_singular_node(&tb2->bhash_node, &tb->bhash2) &&
hlist_empty(&tb2->owners)) {
tb->fastreuse = reuse;
if (sk->sk_reuseport) {
tb->fastreuseport = FASTREUSEPORT_ANY;

View File

@ -23,6 +23,7 @@
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/xfrm.h>
/* Use skb->cb to track consecutive/adjacent fragments coming at
* the end of the queue. Nodes in the rb-tree queue will
@ -441,6 +442,10 @@ int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb,
{
struct sk_buff *last = q->fragments_tail;
/* The reassembled skb keeps the first fragment's secpath. */
if (last && !secpath_equal(last, skb))
return IPFRAG_MIXED_SECPATH;
/* An IP fragment is never a GSO packet, but an untrusted source
* (virtio_net_hdr) may have attached GSO metadata to it. Do not let
* that reach the reassembled skb, whose head keeps the first

View File

@ -378,8 +378,9 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb, int *refs)
err = -EINVAL;
goto err;
}
if (err == IPFRAG_OVERLAP)
__IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS);
err = -EINVAL;
__IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS);
discard_qp:
inet_frag_kill(&qp->q, refs);
__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);

View File

@ -539,6 +539,12 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
};
int err;
if (skb->protocol != htons(ETH_P_IP) || !pskb_inet_may_pull(skb)) {
DEV_STATS_INC(dev, tx_errors);
kfree_skb(skb);
return NETDEV_TX_OK;
}
rcu_read_lock();
err = ipmr_fib_lookup(net, &fl4, &mrt);
if (err < 0) {
@ -550,6 +556,11 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
DEV_STATS_ADD(dev, tx_bytes, skb->len);
DEV_STATS_INC(dev, tx_packets);
/* skb->cb[] holds qdisc/tc state at this point, not IPCB.
* ipmr_cache_report() reads it as IPCB to build IP_PKTINFO.
*/
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
/* Pairs with WRITE_ONCE() in vif_add() and vif_delete() */
ipmr_cache_report(mrt, skb, READ_ONCE(mrt->mroute_reg_vif_num),
IGMPMSG_WHOLEPKT);
@ -1063,6 +1074,7 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
static int ipmr_cache_report(const struct mr_table *mrt,
struct sk_buff *pkt, vifi_t vifi, int assert)
{
unsigned char pkt_cb[sizeof(pkt->cb)];
const int ihl = ip_hdrlen(pkt);
struct sock *mroute_sk;
struct igmphdr *igmp;
@ -1118,8 +1130,6 @@ static int ipmr_cache_report(const struct mr_table *mrt,
msg = (struct igmpmsg *)skb_network_header(skb);
msg->im_vif = vifi;
msg->im_vif_hi = vifi >> 8;
ipv4_pktinfo_prepare(mroute_sk, pkt, false);
memcpy(skb->cb, pkt->cb, sizeof(skb->cb));
/* Add our header.
* Note that code, csum and group fields are cleared.
*/
@ -1130,6 +1140,15 @@ static int ipmr_cache_report(const struct mr_table *mrt,
skb->transport_header = skb->network_header;
}
memset(skb->cb, 0, sizeof(skb->cb));
/* Route queries from ipmr_get_route() carry NETLINK_CB, not IPCB. */
if (ip_hdr(pkt)->version) {
memcpy(pkt_cb, pkt->cb, sizeof(pkt_cb));
ipv4_pktinfo_prepare(mroute_sk, pkt, false);
*PKTINFO_SKB_CB(skb) = *PKTINFO_SKB_CB(pkt);
memcpy(pkt->cb, pkt_cb, sizeof(pkt_cb));
}
igmpmsg_netlink_event(mrt, skb);
/* Deliver to mrouted */
@ -2070,7 +2089,8 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
}
/* Wrong interface: drop packet and (maybe) send PIM assert. */
if (rcu_access_pointer(mrt->vif_table[vif].dev) != dev) {
if (true_vifi < 0 ||
rcu_access_pointer(mrt->vif_table[vif].dev) != dev) {
if (rt_is_output_route(skb_rtable(skb))) {
/* It is our own packet, looped back.
* Very complicated situation...
@ -2498,6 +2518,7 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
skb_push(skb2, sizeof(struct iphdr));
skb_reset_network_header(skb2);
iph = ip_hdr(skb2);
memset(iph, 0, sizeof(*iph));
iph->ihl = sizeof(struct iphdr) >> 2;
iph->saddr = saddr;
iph->daddr = daddr;

View File

@ -60,6 +60,11 @@ static int ip_metrics_convert(struct nlattr *fc_mx,
if (ecn_ca)
metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
if ((metrics[RTAX_LOCK - 1] & (1 << RTAX_CWND)) && !metrics[RTAX_CWND - 1]) {
NL_SET_ERR_MSG(extack, "Locked cwnd metric must be non zero");
return -EINVAL;
}
return 0;
}

View File

@ -1365,8 +1365,8 @@ static unsigned int ipv4_default_advmss(const struct dst_entry *dst)
rcu_read_lock();
net = dst_dev_net_rcu(dst);
advmss = max_t(unsigned int, ip_dst_mtu_configured(dst) - header_size,
net->ipv4.ip_rt_min_advmss);
advmss = max_t(unsigned int, ipv4_mtu(dst) - header_size,
net->ipv4.ip_rt_min_advmss);
rcu_read_unlock();
return min(advmss, IPV4_MAX_PMTU - header_size);

View File

@ -26,6 +26,7 @@ static int ip_local_port_range_max[] = { 65535, 65535 };
static int tcp_adv_win_scale_min = -31;
static int tcp_adv_win_scale_max = 31;
static int tcp_app_win_max = 31;
static int tcp_tso_rtt_log_max = 31;
static int tcp_min_snd_mss_min = TCP_MIN_SND_MSS;
static int tcp_min_snd_mss_max = 65535;
static int tcp_rto_max_max = TCP_RTO_MAX_SEC * MSEC_PER_SEC;
@ -1406,6 +1407,7 @@ static const struct ctl_table ipv4_net_table[] = {
.maxlen = sizeof(u8),
.mode = 0644,
.proc_handler = proc_dou8vec_minmax,
.extra2 = &tcp_tso_rtt_log_max,
},
{
.procname = "tcp_min_rtt_wlen",

View File

@ -1172,14 +1172,18 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
zc = MSG_SPLICE_PAGES;
}
if (!sockc_err && sockc.dmabuf_id && (zc != MSG_ZEROCOPY || !binding)) {
err = -EINVAL;
if (sockc.dmabuf_id && (zc != MSG_ZEROCOPY || !binding)) {
err = sockc_err ?: -EINVAL;
goto out_err;
}
if (unlikely(flags & MSG_FASTOPEN ||
inet_test_bit(DEFER_CONNECT, sk)) &&
!tp->repair) {
if (binding) {
err = -EINVAL;
goto out_err;
}
err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size, uarg);
if (err == -EINPROGRESS && copied_syn > 0)
goto out;
@ -1203,6 +1207,10 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
}
if (unlikely(tp->repair)) {
if (binding) {
err = -EINVAL;
goto out_err;
}
if (tp->repair_queue == TCP_RECV_QUEUE) {
copied = tcp_send_rcvq(sk, msg, size);
goto out_nopush;
@ -5114,6 +5122,8 @@ void tcp_done(struct sock *sk)
int tcp_abort(struct sock *sk, int err)
{
int state = inet_sk_state_load(sk);
bool listener = false;
int ret = 0;
if (state == TCP_NEW_SYN_RECV) {
struct request_sock *req = inet_reqsk(sk);
@ -5148,21 +5158,31 @@ int tcp_abort(struct sock *sk, int err)
if (sk->sk_state == TCP_LISTEN) {
tcp_set_state(sk, TCP_CLOSE);
inet_csk_listen_stop(sk);
listener = true;
}
/* Don't race with BH socket closes such as inet_csk_listen_stop. */
local_bh_disable();
bh_lock_sock(sk);
/* An unaccepted child might have been closed by
* inet_csk_listen_stop() while we were not holding its BH lock.
*/
if (!listener && sk->sk_state == TCP_CLOSE) {
ret = -ENOENT;
goto out;
}
if (tcp_need_reset(sk->sk_state))
tcp_send_active_reset(sk, SK_RST_REASON_TCP_STATE);
tcp_done_with_error(sk, err);
out:
bh_unlock_sock(sk);
local_bh_enable();
if (!has_current_bpf_ctx())
release_sock(sk);
return 0;
return ret;
}
EXPORT_SYMBOL_GPL(tcp_abort);

View File

@ -288,12 +288,12 @@ int tcp_set_default_congestion_control(struct net *net, const char *name)
ca = tcp_ca_find_autoload(name);
if (!ca) {
ret = -ENOENT;
} else if (!bpf_try_module_get(ca, ca->owner)) {
ret = -EBUSY;
} else if (!net_eq(net, &init_net) &&
!(ca->flags & TCP_CONG_NON_RESTRICTED)) {
/* Only init netns can set default to a restricted algorithm */
ret = -EPERM;
} else if (!bpf_try_module_get(ca, ca->owner)) {
ret = -EBUSY;
} else {
prev = xchg(&net->ipv4.tcp_congestion_control, ca);
if (prev)

View File

@ -1723,6 +1723,12 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reflect_tos))
newinet->tos = tcp_rsk(req)->syn_tos & ~INET_ECN_MASK;
#if IS_ENABLED(CONFIG_IPV6)
/* Detach IPv6 state before a route lookup can fail. */
if (opt_child_init)
opt_child_init(newsk, sk);
#endif
if (!dst) {
dst = inet_csk_route_child_sock(sk, newsk, req);
if (!dst)
@ -1732,10 +1738,6 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
}
sk_setup_caps(newsk, dst);
#if IS_ENABLED(CONFIG_IPV6)
if (opt_child_init)
opt_child_init(newsk, sk);
#endif
tcp_ca_openreq_child(newsk, dst);
tcp_sync_mss(newsk, dst4_mtu(dst));

View File

@ -315,14 +315,20 @@ struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb,
mss = skb_shinfo(p)->gso_size;
/* If skb is a GRO packet, make sure its gso_size matches prior packet mss.
/* If skb is a GRO packet, make sure its gso_size matches prior packet
* mss, and that its payload is consistent with its gso_segs
* (the last segment can be short).
* If it is a single frame, do not aggregate it if its length
* is bigger than our mss.
*/
if (unlikely(skb_is_gso(skb)))
if (unlikely(skb_is_gso(skb))) {
unsigned int segs = NAPI_GRO_CB(skb)->count;
flush |= (mss != skb_shinfo(skb)->gso_size);
else
flush |= len <= (segs - 1) * mss || len > segs * mss;
} else {
flush |= (len - 1) >= mss;
}
flush |= (ntohl(th2->seq) + skb_gro_len(p)) ^ ntohl(th->seq);
flush |= skb_cmp_decrypted(p, skb);

View File

@ -2776,7 +2776,7 @@ static int tcp_mtu_probe(struct sock *sk)
mss_now = tcp_current_mss(sk);
probe_size = tcp_mtu_to_mss(sk, (icsk->icsk_mtup.search_high +
icsk->icsk_mtup.search_low) >> 1);
size_needed = probe_size + (tp->reordering + 1) * (u64)tp->mss_cache;
size_needed = probe_size + ((u64)tp->reordering + 1) * tp->mss_cache;
interval = icsk->icsk_mtup.search_high - icsk->icsk_mtup.search_low;
/* When misfortune happens, we are reprobing actively,
* and then reprobe timer has expired. We stick with current

View File

@ -1228,9 +1228,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
fib6_nsiblings++;
}
BUG_ON(fib6_nsiblings != rt->fib6_nsiblings);
rcu_read_lock();
rt6_multipath_rebalance(temp_sibling);
rcu_read_unlock();
}
/*
@ -1274,9 +1272,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
sibling->fib6_nsiblings - 1);
WRITE_ONCE(rt->fib6_nsiblings, 0);
list_del_rcu(&rt->fib6_siblings);
rcu_read_lock();
rt6_multipath_rebalance(next_sibling);
rcu_read_unlock();
return err;
}
}

View File

@ -642,7 +642,7 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
.flowi6_mark = skb->mark,
};
if (!pskb_inet_may_pull(skb))
if (skb->protocol != htons(ETH_P_IPV6) || !pskb_inet_may_pull(skb))
goto tx_err;
rcu_read_lock();
@ -2225,7 +2225,8 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
/*
* Wrong interface: drop packet and (maybe) send PIM assert.
*/
if (rcu_access_pointer(mrt->vif_table[vif].dev) != dev) {
if (true_vifi < 0 ||
rcu_access_pointer(mrt->vif_table[vif].dev) != dev) {
atomic_long_inc(&c->_c.mfc_un.res.wrong_if);
if (true_vifi >= 0 && READ_ONCE(mrt->mroute_do_assert) &&

Some files were not shown because too many files have changed in this diff Show More