mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
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:
commit
4dd16e3113
|
|
@ -194,3 +194,4 @@ mcast-groups:
|
|||
list:
|
||||
-
|
||||
name: gtp
|
||||
flags: [uns-admin-perm]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>`:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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...) \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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] = {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue
Block a user