Lots of fixes, double the count even for the "new normal".

Largely due to my time off followed by a networking conference
 which distracted most maintainers (less so the AI generators).
 
 Including fixes from Bluetooth and WiFi.
 
 Current release - regressions:
 
  - wifi: mt76: fix MAC address for non OF pcie cards
 
 Current release - new code bugs:
 
  - mptcp: fix BUILD_BUG_ON on legacy ARM config
 
  - wifi: cfg80211: guard optional PMSR nominal time
 
 Previous releases - regressions:
 
  - qrtr: ns: raise node count limit to 512, we arbitrarily picked
    256 as a limit, turns out it was too low for real world deployments
 
  - vhost-net: fix TX stall when vhost owns virtio-net header
 
  - eth: amd-xgbe: fix MAC_AUTO_SW handling in CL37 AN
 
  - wifi: ath12k: fix low MLO RX throughput on WCN7850
 
 Previous releases - always broken:
 
  - number of random AI fixes for SCTP, RDS and TIPC protocols
 
  - more AI-looking fixes for WiFi drivers
 
  - number of fixes for missing pointer reloading after skb pull
 
  - reject BPF redirect use from qdisc qevent block
 
  - tcp: initialize standalone TCP-AO response padding
 
  - vsock/virtio: collapse receive queue under memory pressure to avoid
    client OOMing the host with tiny messages
 
  - ipv4: icmp: fill flow parameters in icmp_route_lookup decoy lookup,
    make sure the ICMP response routing follows the routing policy
 
  - gro: fix double aggregation of flush-marked skbs
 
  - ovpn: fix various refcount bugs
 
  - tls: device: push pending open record on splice EOF
 
  - eth: mlx5:
   - use sender devcom for MPV master-up
   - fix MCIA register buffer overflow on 32 dword reads
 
 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmpiX68ACgkQMUZtbf5S
 IrvYsRAAkuMhUpz0Ss9aF7rBY8iTp4SofSvFeVe06ywraUfqPuflGlak07t1Lz/i
 G4MuKXN0q8m+B0EZddfMeYw6rCGd0SCtFAkxUI3dd+pu4hssgioaCPL193drSsfC
 /lYeacjVL45jNrQvAWwKsRaAs3xdwzxWf0ddIXWvVWbdDsVfIf/mYahSS3TvniWw
 MQtEbWPnFwPvOrHzb+1ChLELCtig/yvK+3xS9JrwOkjUF4BczOUgqrYlG5MWerXP
 f/JDLsegPcoZaTycW5F5fshY05umeRQza/zCFqMKQNcQux49fjREnYxBuyTacVCo
 0cxhsNbKOhvBpBFNsHA6TjUbDxuiyL8L/g3e7VOlQFxI4hX3IMsnsP+UrSdE2zyG
 lgFAQ6HIcelgFnzFcwp9YEGsiZ5nDoJKe5aBcgftzTFPx3Plh1UeCrNjYtJawcjk
 1POovopI+G6eszwluVOoucUdDD3wf0jPgDqvdOcI9P9FVTsFmvRESsfen7NbdjG0
 v5mk9+sasWL1dns6mre6nt5is4QWSg7PDjufQUhuPKSSEnld+csEgmyxmUm0/FgL
 krUZLHdx0Yj9yIOAIYAvz8QoW9jHIyK05Mr7CoL4a/9RJ4rtxjb+3CT9qebeyd49
 jK5uzYX6tPHvILFK4CgZwcE/z9S+DoxCAuDEp6LhfstKsJW4KIM=
 =DIF8
 -----END PGP SIGNATURE-----

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

Pull networking fixes from Jakub Kicinski:
 "Lots of fixes, double the count even for the 'new normal'. Largely due
  to my time off followed by a networking conference which distracted
  most maintainers (less so the AI generators).

  Including fixes from Bluetooth and WiFi.

  Current release - regressions:

   - wifi: mt76: fix MAC address for non OF pcie cards

  Current release - new code bugs:

   - mptcp: fix BUILD_BUG_ON on legacy ARM config

   - wifi: cfg80211: guard optional PMSR nominal time

  Previous releases - regressions:

   - qrtr: ns: raise node count limit to 512, we arbitrarily picked
     256 as a limit, turns out it was too low for real world deployments

   - vhost-net: fix TX stall when vhost owns virtio-net header

   - eth: amd-xgbe: fix MAC_AUTO_SW handling in CL37 AN

   - wifi: ath12k: fix low MLO RX throughput on WCN7850

  Previous releases - always broken:

   - number of random AI fixes for SCTP, RDS and TIPC protocols

   - more AI-looking fixes for WiFi drivers

   - number of fixes for missing pointer reloading after skb pull

   - reject BPF redirect use from qdisc qevent block

   - tcp: initialize standalone TCP-AO response padding

   - vsock/virtio: collapse receive queue under memory pressure to avoid
     client OOMing the host with tiny messages

   - ipv4: icmp: fill flow parameters in icmp_route_lookup decoy lookup,
     make sure the ICMP response routing follows the routing policy

   - gro: fix double aggregation of flush-marked skbs

   - ovpn: fix various refcount bugs

   - tls: device: push pending open record on splice EOF

   - eth: mlx5:
      - use sender devcom for MPV master-up
      - fix MCIA register buffer overflow on 32 dword reads"

* tag 'net-7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (234 commits)
  drop_monitor: perform u64_stats updates under IRQ-disabled section
  drop_monitor: fix size calculations for 64-bit attributes
  net: drop_monitor: fix info leak in NET_DM_ATTR_PAYLOAD
  mptcp: fix BUILD_BUG_ON on legacy ARM config
  selftests: mptcp: userspace_pm: fix undefined variable port
  mptcp: fix stale skb->sk reference on subflow close
  mptcp: pm: userspace: fix use-after-free in get_local_id
  mptcp: decrement subflows counter on failed passive join
  mac802154: hold an interface reference across the scan worker
  sctp: don't free the ASCONF's own transport in DEL-IP processing
  phonet: check register_netdevice_notifier() error in phonet_device_init()
  phonet: pep: fix use-after-free in pep_get_sb()
  bnge/bng_re: fix ring ID widths
  tipc: fix integer overflow in tipc_recvmsg() and tipc_recvstream()
  net: airoha: fix ETS channel derivation in airoha_tc_setup_qdisc_ets()
  mctp: check register_netdevice_notifier() error in mctp_device_init()
  ptp: netc: explicitly clear TMR_OFF during initialization
  rds: tcp: unregister sysctl before tearing down listen socket
  ipv6: Change allocation flags to match rcu_read_lock section requirements
  net: slip: serialize receive against buffer reallocation
  ...
This commit is contained in:
Linus Torvalds 2026-07-23 12:58:08 -07:00
commit d326f83e81
264 changed files with 2774 additions and 887 deletions

View File

@ -66,6 +66,11 @@ Alex Hung <alexhung@gmail.com> <alex.hung@canonical.com>
Alex Shi <alexs@kernel.org> <alex.shi@intel.com>
Alex Shi <alexs@kernel.org> <alex.shi@linaro.org>
Alex Shi <alexs@kernel.org> <alex.shi@linux.alibaba.com>
Alice Mikityanska <alice.kernel@fastmail.im> <maxtram95@gmail.com>
Alice Mikityanska <alice.kernel@fastmail.im> <maximmi@mellanox.com>
Alice Mikityanska <alice.kernel@fastmail.im> <maximmi@nvidia.com>
Alice Mikityanska <alice.kernel@fastmail.im> <maxim@isovalent.com>
Alice Mikityanska <alice.kernel@fastmail.im> <alice@isovalent.com>
Aloka Dixit <quic_alokad@quicinc.com> <alokad@codeaurora.org>
Al Viro <viro@ftp.linux.org.uk>
Al Viro <viro@zenIV.linux.org.uk>
@ -585,8 +590,6 @@ Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@osg.samsung.com>
Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@redhat.com>
Mauro Carvalho Chehab <mchehab@kernel.org> <m.chehab@samsung.com>
Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@s-opensource.com>
Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@mellanox.com>
Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@nvidia.com>
Maxime Ripard <mripard@kernel.org> <maxime@cerno.tech>
Maxime Ripard <mripard@kernel.org> <maxime.ripard@bootlin.com>
Maxime Ripard <mripard@kernel.org> <maxime.ripard@free-electrons.com>
@ -595,8 +598,8 @@ Mayuresh Janorkar <mayur@ti.com>
Md Sadre Alam <quic_mdalam@quicinc.com> <mdalam@codeaurora.org>
Miaoqing Pan <quic_miaoqing@quicinc.com> <miaoqing@codeaurora.org>
Michael Buesch <m@bues.ch>
Michal Grzeschik <mgr@kernel.org> <m.grzeschik@pengutronix.de>
Michal Grzeschik <mgr@kernel.org> <mgr@pengutronix.de>
Michael Grzeschik <mgr@kernel.org> <m.grzeschik@pengutronix.de>
Michael Grzeschik <mgr@kernel.org> <mgr@pengutronix.de>
Michael Riesch <michael.riesch@collabora.com> <michael.riesch@wolfvision.net>
Michal Simek <michal.simek@amd.com> <michal.simek@xilinx.com>
Michel Dänzer <michel@tungstengraphics.com>

View File

@ -1585,31 +1585,31 @@ attribute-sets:
type: u32
-
name: mode
type: flag
type: u8
-
name: guard
type: flag
type: u8
-
name: protect
type: flag
type: u8
-
name: fast-leave
type: flag
type: u8
-
name: learning
type: flag
type: u8
-
name: unicast-flood
type: flag
type: u8
-
name: proxyarp
type: flag
type: u8
-
name: learning-sync
type: flag
type: u8
-
name: proxyarp-wifi
type: flag
type: u8
-
name: root-id
type: binary
@ -1656,34 +1656,34 @@ attribute-sets:
type: pad
-
name: mcast-flood
type: flag
type: u8
-
name: mcast-to-ucast
type: flag
type: u8
-
name: vlan-tunnel
type: flag
type: u8
-
name: bcast-flood
type: flag
type: u8
-
name: group-fwd-mask
type: u16
-
name: neigh-suppress
type: flag
type: u8
-
name: isolated
type: flag
type: u8
-
name: backup-port
type: u32
-
name: mrp-ring-open
type: flag
type: u8
-
name: mrp-in-open
type: flag
type: u8
-
name: mcast-eht-hosts-limit
type: u32
@ -1692,10 +1692,10 @@ attribute-sets:
type: u32
-
name: locked
type: flag
type: u8
-
name: mab
type: flag
type: u8
-
name: mcast-n-groups
type: u32
@ -1704,7 +1704,7 @@ attribute-sets:
type: u32
-
name: neigh-vlan-suppress
type: flag
type: u8
-
name: backup-nhid
type: u32

View File

@ -19109,6 +19109,7 @@ F: drivers/nfc/
F: include/net/nfc/
F: include/uapi/linux/nfc.h
F: net/nfc/
F: tools/testing/selftests/nci/
NFC VIRTUAL NCI DEVICE DRIVER
M: Bongsu Jeon <bongsu.jeon@samsung.com>
@ -25973,8 +25974,9 @@ F: Documentation/devicetree/bindings/phy/st,stm32mp25-combophy.yaml
F: drivers/phy/st/phy-stm32-combophy.c
STMMAC ETHERNET DRIVER
M: Maxime Chevallier <maxime.chevallier@bootlin.com>
L: netdev@vger.kernel.org
S: Orphan
S: Maintained
F: Documentation/networking/device_drivers/ethernet/stmicro/
F: drivers/net/ethernet/stmicro/stmmac/
@ -27930,7 +27932,6 @@ F: drivers/usb/isp1760/*
USB LAN78XX ETHERNET DRIVER
M: Thangaraj Samynathan <Thangaraj.S@microchip.com>
M: Rengarajan Sundararajan <Rengarajan.S@microchip.com>
M: UNGLinuxDriver@microchip.com
L: netdev@vger.kernel.org
S: Maintained

View File

@ -65,6 +65,7 @@ ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier);
EXPORT_SYMBOL(s390_epoch_delta_notifier);
unsigned char ptff_function_mask[16];
EXPORT_SYMBOL(ptff_function_mask);
static unsigned long lpar_offset;
static unsigned long initial_leap_seconds;

View File

@ -2782,7 +2782,9 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
{
if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
if (skb->len >= HCI_EVENT_HDR_SIZE + 1 &&
skb->data[0] == HCI_VENDOR_PKT &&
skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
struct rtk_dev_coredump_hdr hdr = {
.code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
};

View File

@ -113,7 +113,7 @@ static void bng_re_fill_fw_msg(struct bnge_fw_msg *fw_msg, void *msg,
}
static int bng_re_net_ring_free(struct bng_re_dev *rdev,
u16 fw_ring_id, int type)
u32 fw_ring_id, int type)
{
struct bnge_auxr_dev *aux_dev = rdev->aux_dev;
struct hwrm_ring_free_input req = {};
@ -123,7 +123,7 @@ static int bng_re_net_ring_free(struct bng_re_dev *rdev,
bng_re_init_hwrm_hdr((void *)&req, HWRM_RING_FREE);
req.ring_type = type;
req.ring_id = cpu_to_le16(fw_ring_id);
req.ring_id = cpu_to_le32(fw_ring_id);
bng_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
sizeof(resp), BNGE_DFLT_HWRM_CMD_TIMEOUT);
rc = bnge_send_msg(aux_dev, &fw_msg);
@ -161,7 +161,7 @@ static int bng_re_net_ring_alloc(struct bng_re_dev *rdev,
sizeof(resp), BNGE_DFLT_HWRM_CMD_TIMEOUT);
rc = bnge_send_msg(aux_dev, &fw_msg);
if (!rc)
*fw_ring_id = le16_to_cpu(resp.ring_id);
*fw_ring_id = (u16)le32_to_cpu(resp.ring_id);
return rc;
}

View File

@ -1211,7 +1211,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
data = true;
}
v6 = false;
group.ip4 = iph->daddr;
group.ip4 = ip_hdr(skb)->daddr;
#if IS_ENABLED(CONFIG_IPV6)
} else if (iph->version == 6) {
ip6h = ipv6_hdr(skb);
@ -1235,7 +1235,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
data = true;
}
v6 = true;
group.ip6 = ip6h->daddr;
group.ip6 = ipv6_hdr(skb)->daddr;
#endif
} else {
dev->stats.tx_errors++;
@ -1278,12 +1278,12 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
hlist_for_each_entry_rcu(gnode, &tunnel->groups[hash],
node) {
if (!v6) {
if (gnode->group_addr.ip4 == iph->daddr)
if (gnode->group_addr.ip4 == group.ip4)
goto found;
#if IS_ENABLED(CONFIG_IPV6)
} else {
if (ipv6_addr_equal(&gnode->group_addr.ip6,
&ip6h->daddr))
&group.ip6))
goto found;
#endif
}
@ -2000,14 +2000,18 @@ static void amt_igmpv3_report_handler(struct amt_dev *amt, struct sk_buff *skb,
struct igmpv3_report *ihrv3 = igmpv3_report_hdr(skb);
int len = skb_transport_offset(skb) + sizeof(*ihrv3);
void *zero_grec = (void *)&igmpv3_zero_grec;
struct iphdr *iph = ip_hdr(skb);
struct amt_group_node *gnode;
union amt_addr group, host;
struct igmpv3_grec *grec;
__be32 saddr;
u16 nsrcs;
u16 ngrec;
int i;
for (i = 0; i < ntohs(ihrv3->ngrec); i++) {
saddr = ip_hdr(skb)->saddr;
ngrec = ntohs(ihrv3->ngrec);
for (i = 0; i < ngrec; i++) {
len += sizeof(*grec);
if (!ip_mc_may_pull(skb, len))
break;
@ -2019,10 +2023,13 @@ static void amt_igmpv3_report_handler(struct amt_dev *amt, struct sk_buff *skb,
if (!ip_mc_may_pull(skb, len))
break;
grec = (void *)(skb->data + len - sizeof(*grec) -
nsrcs * sizeof(__be32));
memset(&group, 0, sizeof(union amt_addr));
group.ip4 = grec->grec_mca;
memset(&host, 0, sizeof(union amt_addr));
host.ip4 = iph->saddr;
host.ip4 = saddr;
gnode = amt_lookup_group(tunnel, &group, &host, false);
if (!gnode) {
gnode = amt_add_group(amt, tunnel, &group, &host,
@ -2162,14 +2169,18 @@ static void amt_mldv2_report_handler(struct amt_dev *amt, struct sk_buff *skb,
struct mld2_report *mld2r = (struct mld2_report *)icmp6_hdr(skb);
int len = skb_transport_offset(skb) + sizeof(*mld2r);
void *zero_grec = (void *)&mldv2_zero_grec;
struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct amt_group_node *gnode;
union amt_addr group, host;
struct mld2_grec *grec;
struct in6_addr saddr;
u16 nsrcs;
u16 ngrec;
int i;
for (i = 0; i < ntohs(mld2r->mld2r_ngrec); i++) {
saddr = ipv6_hdr(skb)->saddr;
ngrec = ntohs(mld2r->mld2r_ngrec);
for (i = 0; i < ngrec; i++) {
len += sizeof(*grec);
if (!ipv6_mc_may_pull(skb, len))
break;
@ -2181,10 +2192,13 @@ static void amt_mldv2_report_handler(struct amt_dev *amt, struct sk_buff *skb,
if (!ipv6_mc_may_pull(skb, len))
break;
grec = (void *)(skb->data + len - sizeof(*grec) -
nsrcs * sizeof(struct in6_addr));
memset(&group, 0, sizeof(union amt_addr));
group.ip6 = grec->grec_mca;
memset(&host, 0, sizeof(union amt_addr));
host.ip6 = ip6h->saddr;
host.ip6 = saddr;
gnode = amt_lookup_group(tunnel, &group, &host, true);
if (!gnode) {
gnode = amt_add_group(amt, tunnel, &group, &host,
@ -2305,7 +2319,9 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
skb_push(skb, sizeof(*eth));
skb_reset_mac_header(skb);
skb_pull(skb, sizeof(*eth));
eth = eth_hdr(skb);
if (skb_cow_head(skb, 0))
return true;
if (!pskb_may_pull(skb, sizeof(*iph)))
return true;
@ -2315,6 +2331,7 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
if (!ipv4_is_multicast(iph->daddr))
return true;
skb->protocol = htons(ETH_P_IP);
eth = eth_hdr(skb);
eth->h_proto = htons(ETH_P_IP);
ip_eth_mc_map(iph->daddr, eth->h_dest);
#if IS_ENABLED(CONFIG_IPV6)
@ -2328,6 +2345,7 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
if (!ipv6_addr_is_multicast(&ip6h->daddr))
return true;
skb->protocol = htons(ETH_P_IPV6);
eth = eth_hdr(skb);
eth->h_proto = htons(ETH_P_IPV6);
ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
#endif
@ -2351,10 +2369,12 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
struct sk_buff *skb)
{
struct amt_header_membership_query *amtmq;
struct igmpv3_query *ihv3;
struct ethhdr *eth, *oeth;
struct igmpv3_query *ihv3;
u8 h_source[ETH_ALEN];
struct iphdr *iph;
int hdr_size, len;
u64 response_mac;
hdr_size = sizeof(*amtmq) + sizeof(struct udphdr);
if (!pskb_may_pull(skb, hdr_size))
@ -2367,6 +2387,8 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
if (amtmq->nonce != amt->nonce)
return true;
response_mac = amtmq->response_mac;
hdr_size -= sizeof(*eth);
if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_TEB), false))
return true;
@ -2376,6 +2398,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
skb_pull(skb, sizeof(*eth));
skb_reset_network_header(skb);
eth = eth_hdr(skb);
ether_addr_copy(h_source, oeth->h_source);
if (skb_cow_head(skb, 0))
return true;
if (!pskb_may_pull(skb, sizeof(*iph)))
return true;
@ -2388,6 +2413,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
sizeof(*ihv3)))
return true;
iph = ip_hdr(skb);
if (!ipv4_is_multicast(iph->daddr))
return true;
@ -2395,10 +2421,11 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
skb_reset_transport_header(skb);
skb_push(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
WRITE_ONCE(amt->ready4, true);
amt->mac = amtmq->response_mac;
amt->mac = response_mac;
amt->req_cnt = 0;
amt->qi = ihv3->qqic;
skb->protocol = htons(ETH_P_IP);
eth = eth_hdr(skb);
eth->h_proto = htons(ETH_P_IP);
ip_eth_mc_map(iph->daddr, eth->h_dest);
#if IS_ENABLED(CONFIG_IPV6)
@ -2421,10 +2448,11 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
skb_reset_transport_header(skb);
skb_push(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
WRITE_ONCE(amt->ready6, true);
amt->mac = amtmq->response_mac;
amt->mac = response_mac;
amt->req_cnt = 0;
amt->qi = mld2q->mld2q_qqic;
skb->protocol = htons(ETH_P_IPV6);
eth = eth_hdr(skb);
eth->h_proto = htons(ETH_P_IPV6);
ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
#endif
@ -2432,7 +2460,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
return true;
}
ether_addr_copy(eth->h_source, oeth->h_source);
ether_addr_copy(eth->h_source, h_source);
skb->pkt_type = PACKET_MULTICAST;
skb->ip_summed = CHECKSUM_NONE;
len = skb->len;
@ -2455,8 +2483,11 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
struct ethhdr *eth;
struct iphdr *iph;
int len, hdr_size;
u64 response_mac;
__be32 saddr;
__be32 nonce;
iph = ip_hdr(skb);
saddr = ip_hdr(skb)->saddr;
hdr_size = sizeof(*amtmu) + sizeof(struct udphdr);
if (!pskb_may_pull(skb, hdr_size))
@ -2466,15 +2497,18 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
if (amtmu->reserved || amtmu->version)
return true;
nonce = amtmu->nonce;
response_mac = amtmu->response_mac;
if (iptunnel_pull_header(skb, hdr_size, skb->protocol, false))
return true;
skb_reset_network_header(skb);
list_for_each_entry_rcu(tunnel, &amt->tunnel_list, list) {
if (tunnel->ip4 == iph->saddr) {
if ((amtmu->nonce == tunnel->nonce &&
amtmu->response_mac == tunnel->mac)) {
if (tunnel->ip4 == saddr) {
if ((nonce == tunnel->nonce &&
response_mac == tunnel->mac)) {
mod_delayed_work(amt_wq, &tunnel->gc_wq,
msecs_to_jiffies(amt_gmi(amt))
* 3);
@ -2492,6 +2526,9 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(*iph)))
return true;
if (skb_cow_head(skb, 0))
return true;
iph = ip_hdr(skb);
if (iph->version == 4) {
if (ip_mc_check_igmp(skb)) {
@ -2508,6 +2545,7 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
eth = eth_hdr(skb);
skb->protocol = htons(ETH_P_IP);
eth->h_proto = htons(ETH_P_IP);
iph = ip_hdr(skb);
ip_eth_mc_map(iph->daddr, eth->h_dest);
#if IS_ENABLED(CONFIG_IPV6)
} else if (iph->version == 6) {
@ -2527,6 +2565,7 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
eth = eth_hdr(skb);
skb->protocol = htons(ETH_P_IPV6);
eth->h_proto = htons(ETH_P_IPV6);
ip6h = ipv6_hdr(skb);
ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
#endif
} else {
@ -2772,7 +2811,7 @@ static void amt_gw_rcv(struct amt_dev *amt, struct sk_buff *skb)
static int amt_rcv(struct sock *sk, struct sk_buff *skb)
{
struct amt_dev *amt;
struct iphdr *iph;
__be32 saddr;
int type;
bool err;
@ -2785,7 +2824,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
}
skb->dev = amt->dev;
iph = ip_hdr(skb);
saddr = ip_hdr(skb)->saddr;
type = amt_parse_type(skb);
if (type == -1) {
err = true;
@ -2795,7 +2834,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
if (amt->mode == AMT_MODE_GATEWAY) {
switch (type) {
case AMT_MSG_ADVERTISEMENT:
if (iph->saddr != amt->discovery_ip) {
if (saddr != amt->discovery_ip) {
netdev_dbg(amt->dev, "Invalid Relay IP\n");
err = true;
goto drop;
@ -2807,7 +2846,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
}
goto out;
case AMT_MSG_MULTICAST_DATA:
if (iph->saddr != amt->remote_ip) {
if (saddr != amt->remote_ip) {
netdev_dbg(amt->dev, "Invalid Relay IP\n");
err = true;
goto drop;
@ -2818,7 +2857,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
else
goto out;
case AMT_MSG_MEMBERSHIP_QUERY:
if (iph->saddr != amt->remote_ip) {
if (saddr != amt->remote_ip) {
netdev_dbg(amt->dev, "Invalid Relay IP\n");
err = true;
goto drop;
@ -2995,9 +3034,15 @@ static int amt_dev_open(struct net_device *dev)
amt->event_idx = 0;
amt->nr_events = 0;
enable_delayed_work(&amt->discovery_wq);
enable_delayed_work(&amt->req_wq);
err = amt_socket_create(amt);
if (err)
if (err) {
disable_delayed_work(&amt->req_wq);
disable_delayed_work(&amt->discovery_wq);
return err;
}
amt->req_cnt = 0;
amt->remote_ip = 0;
@ -3023,8 +3068,8 @@ static int amt_dev_stop(struct net_device *dev)
struct sock *sk;
int i;
cancel_delayed_work_sync(&amt->req_wq);
cancel_delayed_work_sync(&amt->discovery_wq);
disable_delayed_work_sync(&amt->req_wq);
disable_delayed_work_sync(&amt->discovery_wq);
cancel_delayed_work_sync(&amt->secret_wq);
/* shutdown */
@ -3278,6 +3323,8 @@ static int amt_newlink(struct net_device *dev,
INIT_DELAYED_WORK(&amt->req_wq, amt_req_work);
INIT_DELAYED_WORK(&amt->secret_wq, amt_secret_work);
INIT_WORK(&amt->event_wq, amt_event_work);
disable_delayed_work(&amt->req_wq);
disable_delayed_work(&amt->discovery_wq);
INIT_LIST_HEAD(&amt->tunnel_list);
return 0;
err:

View File

@ -3455,7 +3455,8 @@ static void bond_send_validate(struct bonding *bond, struct slave *slave)
{
bond_arp_send_all(bond, slave);
#if IS_ENABLED(CONFIG_IPV6)
bond_ns_send_all(bond, slave);
if (likely(ipv6_mod_enabled()))
bond_ns_send_all(bond, slave);
#endif
}

View File

@ -1686,11 +1686,14 @@ static void airoha_qdma_stop_napi(struct airoha_qdma *qdma)
}
}
static void airoha_dev_get_hw_stats(struct airoha_gdm_dev *dev)
static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
{
struct airoha_gdm_port *port = dev->port;
struct airoha_eth *eth = dev->eth;
u32 val, i = 0;
u64 data;
spin_lock(&port->stats_lock);
/* Read relevant MIB for GDM with multiple port attached */
if (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX)
@ -1701,152 +1704,188 @@ static void airoha_dev_get_hw_stats(struct airoha_gdm_dev *dev)
u64_stats_update_begin(&dev->stats.syncp);
/* TX */
/* TX - 64-bit H+L registers: hw accumulates the total, read directly.
* Use local variable to prevent readers from seeing intermediate values.
* Clamp to prevent regression from torn reads between H and L.
*/
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_PKT_CNT_H(port->id));
dev->stats.tx_ok_pkts += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_PKT_CNT_L(port->id));
dev->stats.tx_ok_pkts += val;
data += val;
dev->stats.tx_ok_pkts = max(data, dev->stats.tx_ok_pkts);
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_BYTE_CNT_H(port->id));
dev->stats.tx_ok_bytes += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_BYTE_CNT_L(port->id));
dev->stats.tx_ok_bytes += val;
data += val;
dev->stats.tx_ok_bytes = max(data, dev->stats.tx_ok_bytes);
/* TX - 32-bit registers: accumulate delta to handle wrap-around. */
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_DROP_CNT(port->id));
dev->stats.tx_drops += val;
dev->stats.tx_drops += (u32)(val - dev->stats.mib_prev.tx_drops);
dev->stats.mib_prev.tx_drops = val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_BC_CNT(port->id));
dev->stats.tx_broadcast += val;
dev->stats.tx_broadcast += (u32)(val - dev->stats.mib_prev.tx_broadcast);
dev->stats.mib_prev.tx_broadcast = val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_MC_CNT(port->id));
dev->stats.tx_multicast += val;
dev->stats.tx_multicast += (u32)(val - dev->stats.mib_prev.tx_multicast);
dev->stats.mib_prev.tx_multicast = val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_RUNT_CNT(port->id));
dev->stats.tx_len[i] += val;
dev->stats.mib_prev.tx_runt64 +=
(u32)(val - dev->stats.mib_prev.tx_runt);
dev->stats.mib_prev.tx_runt = val;
/* tx_len[0]: RUNT (32-bit, delta) + E64 (64-bit, absolute). */
data = dev->stats.mib_prev.tx_runt64;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_E64_CNT_H(port->id));
dev->stats.tx_len[i] += ((u64)val << 32);
data += (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_E64_CNT_L(port->id));
dev->stats.tx_len[i++] += val;
data += val;
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L64_CNT_H(port->id));
dev->stats.tx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L64_CNT_L(port->id));
dev->stats.tx_len[i++] += val;
data += val;
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L127_CNT_H(port->id));
dev->stats.tx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L127_CNT_L(port->id));
dev->stats.tx_len[i++] += val;
data += val;
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L255_CNT_H(port->id));
dev->stats.tx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L255_CNT_L(port->id));
dev->stats.tx_len[i++] += val;
data += val;
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L511_CNT_H(port->id));
dev->stats.tx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L511_CNT_L(port->id));
dev->stats.tx_len[i++] += val;
data += val;
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L1023_CNT_H(port->id));
dev->stats.tx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L1023_CNT_L(port->id));
dev->stats.tx_len[i++] += val;
data += val;
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_LONG_CNT(port->id));
dev->stats.tx_len[i++] += val;
dev->stats.tx_len[i++] += (u32)(val - dev->stats.mib_prev.tx_long);
dev->stats.mib_prev.tx_long = val;
/* RX */
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_PKT_CNT_H(port->id));
dev->stats.rx_ok_pkts += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_PKT_CNT_L(port->id));
dev->stats.rx_ok_pkts += val;
data += val;
dev->stats.rx_ok_pkts = max(data, dev->stats.rx_ok_pkts);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_BYTE_CNT_H(port->id));
dev->stats.rx_ok_bytes += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_BYTE_CNT_L(port->id));
dev->stats.rx_ok_bytes += val;
data += val;
dev->stats.rx_ok_bytes = max(data, dev->stats.rx_ok_bytes);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_DROP_CNT(port->id));
dev->stats.rx_drops += val;
dev->stats.rx_drops += (u32)(val - dev->stats.mib_prev.rx_drops);
dev->stats.mib_prev.rx_drops = val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_BC_CNT(port->id));
dev->stats.rx_broadcast += val;
dev->stats.rx_broadcast += (u32)(val - dev->stats.mib_prev.rx_broadcast);
dev->stats.mib_prev.rx_broadcast = val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_MC_CNT(port->id));
dev->stats.rx_multicast += val;
dev->stats.rx_multicast += (u32)(val - dev->stats.mib_prev.rx_multicast);
dev->stats.mib_prev.rx_multicast = val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ERROR_DROP_CNT(port->id));
dev->stats.rx_errors += val;
dev->stats.rx_errors += (u32)(val - dev->stats.mib_prev.rx_errors);
dev->stats.mib_prev.rx_errors = val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_CRC_ERR_CNT(port->id));
dev->stats.rx_crc_error += val;
dev->stats.rx_crc_error += (u32)(val - dev->stats.mib_prev.rx_crc_error);
dev->stats.mib_prev.rx_crc_error = val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OVERFLOW_DROP_CNT(port->id));
dev->stats.rx_over_errors += val;
dev->stats.rx_over_errors += (u32)(val - dev->stats.mib_prev.rx_over_errors);
dev->stats.mib_prev.rx_over_errors = val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_FRAG_CNT(port->id));
dev->stats.rx_fragment += val;
dev->stats.rx_fragment += (u32)(val - dev->stats.mib_prev.rx_fragment);
dev->stats.mib_prev.rx_fragment = val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_JABBER_CNT(port->id));
dev->stats.rx_jabber += val;
dev->stats.rx_jabber += (u32)(val - dev->stats.mib_prev.rx_jabber);
dev->stats.mib_prev.rx_jabber = val;
i = 0;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_RUNT_CNT(port->id));
dev->stats.rx_len[i] += val;
dev->stats.mib_prev.rx_runt64 +=
(u32)(val - dev->stats.mib_prev.rx_runt);
dev->stats.mib_prev.rx_runt = val;
/* rx_len[0]: RUNT (32-bit, delta) + E64 (64-bit, absolute). */
data = dev->stats.mib_prev.rx_runt64;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_E64_CNT_H(port->id));
dev->stats.rx_len[i] += ((u64)val << 32);
data += (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_E64_CNT_L(port->id));
dev->stats.rx_len[i++] += val;
data += val;
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L64_CNT_H(port->id));
dev->stats.rx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L64_CNT_L(port->id));
dev->stats.rx_len[i++] += val;
data += val;
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L127_CNT_H(port->id));
dev->stats.rx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L127_CNT_L(port->id));
dev->stats.rx_len[i++] += val;
data += val;
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L255_CNT_H(port->id));
dev->stats.rx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L255_CNT_L(port->id));
dev->stats.rx_len[i++] += val;
data += val;
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L511_CNT_H(port->id));
dev->stats.rx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L511_CNT_L(port->id));
dev->stats.rx_len[i++] += val;
data += val;
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L1023_CNT_H(port->id));
dev->stats.rx_len[i] += ((u64)val << 32);
data = (u64)val << 32;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L1023_CNT_L(port->id));
dev->stats.rx_len[i++] += val;
data += val;
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
i++;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_LONG_CNT(port->id));
dev->stats.rx_len[i++] += val;
dev->stats.rx_len[i] += (u32)(val - dev->stats.mib_prev.rx_long);
dev->stats.mib_prev.rx_long = val;
u64_stats_update_end(&dev->stats.syncp);
}
static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
{
struct airoha_gdm_port *port = dev->port;
int i;
spin_lock(&port->stats_lock);
for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
if (port->devs[i])
airoha_dev_get_hw_stats(port->devs[i]);
}
/* Reset MIB counters */
airoha_fe_set(dev->eth, REG_FE_GDM_MIB_CLEAR(port->id),
FE_GDM_MIB_RX_CLEAR_MASK | FE_GDM_MIB_TX_CLEAR_MASK);
spin_unlock(&port->stats_lock);
}
@ -2504,8 +2543,7 @@ static int airoha_tc_setup_qdisc_ets(struct net_device *dev,
if (opt->parent == TC_H_ROOT)
return -EINVAL;
channel = TC_H_MAJ(opt->handle) >> 16;
channel = channel % AIROHA_NUM_QOS_CHANNELS;
channel = TC_H_MIN(opt->parent) % AIROHA_NUM_QOS_CHANNELS;
switch (opt->command) {
case TC_ETS_REPLACE:

View File

@ -245,6 +245,33 @@ struct airoha_hw_stats {
u64 rx_fragment;
u64 rx_jabber;
u64 rx_len[7];
struct {
/* Previous HW register values for 32-bit counter delta
* tracking. Storing the last seen value and accumulating
* (u32)(curr - prev) into the 64-bit software counter
* handles wrap-around transparently via unsigned arithmetic.
* tx_runt64/rx_runt64 hold the running sum of runt deltas.
* These fields are never reported to userspace.
*/
u32 tx_drops;
u32 tx_broadcast;
u32 tx_multicast;
u32 tx_runt;
u32 tx_long;
u64 tx_runt64;
u32 rx_drops;
u32 rx_broadcast;
u32 rx_multicast;
u32 rx_errors;
u32 rx_crc_error;
u32 rx_over_errors;
u32 rx_fragment;
u32 rx_jabber;
u32 rx_runt;
u32 rx_long;
u64 rx_runt64;
} mib_prev;
};
enum {

View File

@ -168,7 +168,7 @@ static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,
dma_addr_t dma_addr;
int ret;
dma_addr = dma_map_single(npu->dev, p, size, DMA_TO_DEVICE);
dma_addr = dma_map_single(npu->dev, p, size, DMA_BIDIRECTIONAL);
ret = dma_mapping_error(npu->dev, dma_addr);
if (ret)
return ret;
@ -191,7 +191,7 @@ static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,
spin_unlock_bh(&npu->cores[core].lock);
dma_unmap_single(npu->dev, dma_addr, size, DMA_TO_DEVICE);
dma_unmap_single(npu->dev, dma_addr, size, DMA_BIDIRECTIONAL);
return ret;
}

View File

@ -1659,6 +1659,7 @@ void airoha_ppe_deinit(struct airoha_eth *eth)
npu = rcu_replace_pointer(eth->npu, NULL,
lockdep_is_held(&flow_offload_mutex));
if (npu) {
synchronize_rcu();
npu->ops.ppe_deinit(npu);
airoha_npu_put(npu);
}

View File

@ -18,7 +18,13 @@ static int pdsc_process_notifyq(struct pdsc_qcq *qcq)
comp = cq_info->comp;
eid = le64_to_cpu(comp->event.eid);
while (eid > pdsc->last_eid) {
u16 ecode = le16_to_cpu(comp->event.ecode);
u16 ecode;
/* Order the payload read after the event id, the field the
* driver uses to detect a new completion.
*/
dma_rmb();
ecode = le16_to_cpu(comp->event.ecode);
switch (ecode) {
case PDS_EVENT_LINK_CHANGE:
@ -101,6 +107,10 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq)
spin_lock_irqsave(&pdsc->adminq_lock, irqflags);
comp = cq->info[cq->tail_idx].comp;
while (pdsc_color_match(comp->color, cq->done_color)) {
/* Order the payload reads after the color bit, the field the
* driver uses to detect a new completion.
*/
dma_rmb();
q_info = &q->info[q->tail_idx];
q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);

View File

@ -177,17 +177,21 @@ void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf,
{
struct pds_auxiliary_dev *padev;
if (!*pd_ptr)
return;
mutex_lock(&pf->config_lock);
/* A concurrent del may have already torn this device down and
* cleared it.
*/
padev = *pd_ptr;
if (!padev)
goto out_unlock;
pds_client_unregister(pf, padev->client_id);
auxiliary_device_delete(&padev->aux_dev);
auxiliary_device_uninit(&padev->aux_dev);
*pd_ptr = NULL;
out_unlock:
mutex_unlock(&pf->config_lock);
}
@ -210,6 +214,13 @@ int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf,
mutex_lock(&pf->config_lock);
/* Nothing to do if the aux device is already present. This also
* guards against a second add overwriting *pd_ptr and leaking the
* first, symmetric with the check in pdsc_auxbus_dev_del().
*/
if (*pd_ptr)
goto out_unlock;
mask = BIT_ULL(PDSC_S_FW_DEAD) |
BIT_ULL(PDSC_S_STOPPING_DRIVER);
if (cf->state & mask) {

View File

@ -110,7 +110,6 @@ static void pdsc_qcq_intr_free(struct pdsc *pdsc, struct pdsc_qcq *qcq)
return;
pdsc_intr_free(pdsc, qcq->intx);
qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED;
}
static int pdsc_qcq_intr_alloc(struct pdsc *pdsc, struct pdsc_qcq *qcq)
@ -145,6 +144,12 @@ void pdsc_qcq_free(struct pdsc *pdsc, struct pdsc_qcq *qcq)
pdsc_qcq_intr_free(pdsc, qcq);
/* Drain any work queued by ISR before it was freed above */
if (qcq->work.func)
cancel_work_sync(&qcq->work);
qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED;
if (qcq->q_base)
dma_free_coherent(dev, qcq->q_size,
qcq->q_base, qcq->q_base_pa);
@ -304,8 +309,11 @@ int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index,
static void pdsc_core_uninit(struct pdsc *pdsc)
{
pdsc_qcq_free(pdsc, &pdsc->notifyqcq);
/* Free adminqcq first: its work accesses notifyqcq, so we must
* disable its IRQ and drain its work before freeing notifyqcq.
*/
pdsc_qcq_free(pdsc, &pdsc->adminqcq);
pdsc_qcq_free(pdsc, &pdsc->notifyqcq);
if (pdsc->kern_dbpage) {
iounmap(pdsc->kern_dbpage);
@ -479,8 +487,6 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing)
{
if (!pdsc->pdev->is_virtfn)
pdsc_devcmd_reset(pdsc);
if (pdsc->adminqcq.work.func)
cancel_work_sync(&pdsc->adminqcq.work);
pci_clear_master(pdsc->pdev);
@ -533,6 +539,7 @@ static void pdsc_adminq_wait_and_dec_once_unused(struct pdsc *pdsc)
dev_dbg_ratelimited(pdsc->dev, "%s: adminq in use\n",
__func__);
cpu_relax();
cond_resched();
}
}
@ -606,9 +613,10 @@ void pdsc_pci_reset_thread(struct work_struct *work)
struct pdsc *pdsc = container_of(work, struct pdsc, pci_reset_work);
struct pci_dev *pdev = pdsc->pdev;
pci_dev_get(pdev);
pci_reset_function(pdev);
pci_dev_put(pdev);
/* Use try variant to avoid deadlock with pdsc_remove().
* If lock is contended, the watchdog timer will retry.
*/
pci_try_reset_function(pdev);
}
static void pdsc_check_pci_health(struct pdsc *pdsc)

View File

@ -90,6 +90,12 @@ int pdsc_dl_flash_update(struct devlink *dl,
{
struct pdsc *pdsc = devlink_priv(dl);
if (params->component) {
NL_SET_ERR_MSG_MOD(extack,
"Component update not supported by this device");
return -EOPNOTSUPP;
}
return pdsc_firmware_update(pdsc, params->fw, extack);
}

View File

@ -238,6 +238,10 @@ static int pdsc_init_pf(struct pdsc *pdsc)
/* General workqueue and timer, but don't start timer yet */
snprintf(wq_name, sizeof(wq_name), "%s.%d", PDS_CORE_DRV_NAME, pdsc->uid);
pdsc->wq = create_singlethread_workqueue(wq_name);
if (!pdsc->wq) {
err = -ENOMEM;
goto err_out_unmap_bars;
}
INIT_WORK(&pdsc->health_work, pdsc_health_thread);
INIT_WORK(&pdsc->pci_reset_work, pdsc_pci_reset_thread);
timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
@ -253,7 +257,7 @@ static int pdsc_init_pf(struct pdsc *pdsc)
err = pdsc_setup(pdsc, PDSC_SETUP_INIT);
if (err) {
mutex_unlock(&pdsc->config_lock);
goto err_out_unmap_bars;
goto err_out_shutdown_timer;
}
err = pdsc_start(pdsc);
@ -305,13 +309,14 @@ static int pdsc_init_pf(struct pdsc *pdsc)
pdsc_stop(pdsc);
err_out_teardown:
pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING);
err_out_unmap_bars:
err_out_shutdown_timer:
timer_shutdown_sync(&pdsc->wdtimer);
if (pdsc->wq)
destroy_workqueue(pdsc->wq);
mutex_destroy(&pdsc->config_lock);
mutex_destroy(&pdsc->devcmd_lock);
pci_free_irq_vectors(pdsc->pdev);
err_out_unmap_bars:
pdsc_unmap_bars(pdsc);
err_out_release_regions:
pci_release_regions(pdsc->pdev);
@ -435,8 +440,6 @@ static void pdsc_remove(struct pci_dev *pdev)
pdsc_auxbus_dev_del(pdsc, pdsc, &pdsc->padev);
timer_shutdown_sync(&pdsc->wdtimer);
if (pdsc->wq)
destroy_workqueue(pdsc->wq);
mutex_lock(&pdsc->config_lock);
set_bit(PDSC_S_STOPPING_DRIVER, &pdsc->state);
@ -444,6 +447,9 @@ static void pdsc_remove(struct pci_dev *pdev)
pdsc_stop(pdsc);
pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING);
mutex_unlock(&pdsc->config_lock);
if (pdsc->wq)
destroy_workqueue(pdsc->wq);
mutex_destroy(&pdsc->config_lock);
mutex_destroy(&pdsc->devcmd_lock);

View File

@ -267,9 +267,14 @@ static void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable,
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL);
reg |= XGBE_VEND2_MAC_AUTO_SW;
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL, reg);
if (pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) {
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL);
if (enable)
reg |= XGBE_VEND2_MAC_AUTO_SW;
else
reg &= ~XGBE_VEND2_MAC_AUTO_SW;
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL, reg);
}
}
static void xgbe_an37_restart(struct xgbe_prv_data *pdata)

View File

@ -36,6 +36,7 @@ struct bnge_pf_info {
};
#define INVALID_HW_RING_ID ((u16)-1)
#define INVALID_HW_RING_ID_32BIT (U32_MAX)
enum {
BNGE_FW_CAP_SHORT_CMD = BIT_ULL(0),

View File

@ -1283,7 +1283,7 @@ int bnge_hwrm_stat_ctx_alloc(struct bnge_net *bn)
int hwrm_ring_free_send_msg(struct bnge_net *bn,
struct bnge_ring_struct *ring,
u32 ring_type, int cmpl_ring_id)
u32 ring_type, u32 cmpl_ring_id)
{
struct hwrm_ring_free_input *req;
struct bnge_dev *bd = bn->bd;
@ -1295,7 +1295,7 @@ int hwrm_ring_free_send_msg(struct bnge_net *bn,
req->cmpl_ring = cpu_to_le16(cmpl_ring_id);
req->ring_type = ring_type;
req->ring_id = cpu_to_le16(ring->fw_ring_id);
req->ring_id = cpu_to_le32(ring->fw_ring_id);
bnge_hwrm_req_hold(bd, req);
rc = bnge_hwrm_req_send(bd, req);
@ -1317,7 +1317,7 @@ int hwrm_ring_alloc_send_msg(struct bnge_net *bn,
struct hwrm_ring_alloc_output *resp;
struct hwrm_ring_alloc_input *req;
struct bnge_dev *bd = bn->bd;
u16 ring_id, flags = 0;
u32 ring_id, flags = 0;
int rc;
rc = bnge_hwrm_req_init(bd, req, HWRM_RING_ALLOC);
@ -1401,7 +1401,7 @@ int hwrm_ring_alloc_send_msg(struct bnge_net *bn,
resp = bnge_hwrm_req_hold(bd, req);
rc = bnge_hwrm_req_send(bd, req);
ring_id = le16_to_cpu(resp->ring_id);
ring_id = le32_to_cpu(resp->ring_id);
bnge_hwrm_req_drop(bd, req);
exit:

View File

@ -50,7 +50,7 @@ int bnge_hwrm_cfa_l2_set_rx_mask(struct bnge_dev *bd,
void bnge_hwrm_stat_ctx_free(struct bnge_net *bn);
int bnge_hwrm_stat_ctx_alloc(struct bnge_net *bn);
int hwrm_ring_free_send_msg(struct bnge_net *bn, struct bnge_ring_struct *ring,
u32 ring_type, int cmpl_ring_id);
u32 ring_type, u32 cmpl_ring_id);
int hwrm_ring_alloc_send_msg(struct bnge_net *bn,
struct bnge_ring_struct *ring,
u32 ring_type, u32 map_index);

View File

@ -1327,12 +1327,12 @@ static int bnge_alloc_core(struct bnge_net *bn)
return rc;
}
u16 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr)
u32 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr)
{
return rxr->rx_cpr->ring_struct.fw_ring_id;
}
u16 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr)
u32 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr)
{
return txr->tx_cpr->ring_struct.fw_ring_id;
}
@ -1375,12 +1375,12 @@ static void bnge_init_nq_tree(struct bnge_net *bn)
struct bnge_nq_ring_info *nqr = &bn->bnapi[i]->nq_ring;
struct bnge_ring_struct *ring = &nqr->ring_struct;
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
for (j = 0; j < nqr->cp_ring_count; j++) {
struct bnge_cp_ring_info *cpr = &nqr->cp_ring_arr[j];
ring = &cpr->ring_struct;
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
}
}
}
@ -1637,7 +1637,7 @@ static void bnge_init_one_rx_ring_rxbd(struct bnge_net *bn,
ring = &rxr->rx_ring_struct;
bnge_init_rxbd_pages(ring, type);
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
}
static void bnge_init_one_agg_ring_rxbd(struct bnge_net *bn,
@ -1647,7 +1647,7 @@ static void bnge_init_one_agg_ring_rxbd(struct bnge_net *bn,
u32 type;
ring = &rxr->rx_agg_ring_struct;
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
if (bnge_is_agg_reqd(bn->bd)) {
type = ((u32)BNGE_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
RX_BD_TYPE_RX_AGG_BD | RX_BD_FLAGS_SOP;
@ -1708,7 +1708,7 @@ static void bnge_init_tx_rings(struct bnge_net *bn)
struct bnge_tx_ring_info *txr = &bn->tx_ring[i];
struct bnge_ring_struct *ring = &txr->tx_ring_struct;
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
netif_queue_set_napi(bn->netdev, i, NETDEV_QUEUE_TYPE_TX,
&txr->bnapi->napi);
@ -1867,7 +1867,7 @@ static int bnge_hwrm_rx_agg_ring_alloc(struct bnge_net *bn,
ring->fw_ring_id);
bnge_db_write(bn->bd, &rxr->rx_agg_db, rxr->rx_agg_prod);
bnge_db_write(bn->bd, &rxr->rx_db, rxr->rx_prod);
bn->grp_info[grp_idx].agg_fw_ring_id = ring->fw_ring_id;
bn->grp_info[grp_idx].agg_fw_ring_id = (u16)ring->fw_ring_id;
return 0;
}
@ -1886,7 +1886,7 @@ static int bnge_hwrm_rx_ring_alloc(struct bnge_net *bn,
return rc;
bnge_set_db(bn, &rxr->rx_db, type, map_idx, ring->fw_ring_id);
bn->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id;
bn->grp_info[map_idx].rx_fw_ring_id = (u16)ring->fw_ring_id;
return 0;
}
@ -1916,7 +1916,7 @@ static int bnge_hwrm_ring_alloc(struct bnge_net *bn)
bnge_set_db(bn, &nqr->nq_db, type, map_idx, ring->fw_ring_id);
bnge_db_nq(bn, &nqr->nq_db, nqr->nq_raw_cons);
enable_irq(vector);
bn->grp_info[i].nq_fw_ring_id = ring->fw_ring_id;
bn->grp_info[i].nq_fw_ring_id = (u16)ring->fw_ring_id;
if (!i) {
rc = bnge_hwrm_set_async_event_cr(bd, ring->fw_ring_id);
@ -1986,15 +1986,13 @@ void bnge_fill_hw_rss_tbl(struct bnge_net *bn, struct bnge_vnic_info *vnic)
tbl_size = bnge_get_rxfh_indir_size(bd);
for (i = 0; i < tbl_size; i++) {
u16 ring_id, j;
u32 j;
j = bd->rss_indir_tbl[i];
rxr = &bn->rx_ring[j];
ring_id = rxr->rx_ring_struct.fw_ring_id;
*ring_tbl++ = cpu_to_le16(ring_id);
ring_id = bnge_cp_ring_for_rx(rxr);
*ring_tbl++ = cpu_to_le16(ring_id);
*ring_tbl++ = cpu_to_le16(rxr->rx_ring_struct.fw_ring_id);
*ring_tbl++ = cpu_to_le16(bnge_cp_ring_for_rx(rxr));
}
}
@ -2285,7 +2283,7 @@ static void bnge_disable_int(struct bnge_net *bn)
nqr = &bnapi->nq_ring;
ring = &nqr->ring_struct;
if (ring->fw_ring_id != INVALID_HW_RING_ID)
if (ring->fw_ring_id != INVALID_HW_RING_ID_32BIT)
bnge_db_nq(bn, &nqr->nq_db, nqr->nq_raw_cons);
}
}
@ -2401,7 +2399,7 @@ static void bnge_hwrm_rx_ring_free(struct bnge_net *bn,
u32 grp_idx = rxr->bnapi->index;
u32 cmpl_ring_id;
if (ring->fw_ring_id == INVALID_HW_RING_ID)
if (ring->fw_ring_id == INVALID_HW_RING_ID_32BIT)
return;
cmpl_ring_id = bnge_cp_ring_for_rx(rxr);
@ -2409,7 +2407,7 @@ static void bnge_hwrm_rx_ring_free(struct bnge_net *bn,
RING_FREE_REQ_RING_TYPE_RX,
close_path ? cmpl_ring_id :
INVALID_HW_RING_ID);
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
bn->grp_info[grp_idx].rx_fw_ring_id = INVALID_HW_RING_ID;
}
@ -2421,14 +2419,14 @@ static void bnge_hwrm_rx_agg_ring_free(struct bnge_net *bn,
u32 grp_idx = rxr->bnapi->index;
u32 cmpl_ring_id;
if (ring->fw_ring_id == INVALID_HW_RING_ID)
if (ring->fw_ring_id == INVALID_HW_RING_ID_32BIT)
return;
cmpl_ring_id = bnge_cp_ring_for_rx(rxr);
hwrm_ring_free_send_msg(bn, ring, RING_FREE_REQ_RING_TYPE_RX_AGG,
close_path ? cmpl_ring_id :
INVALID_HW_RING_ID);
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
bn->grp_info[grp_idx].agg_fw_ring_id = INVALID_HW_RING_ID;
}
@ -2439,14 +2437,14 @@ static void bnge_hwrm_tx_ring_free(struct bnge_net *bn,
struct bnge_ring_struct *ring = &txr->tx_ring_struct;
u32 cmpl_ring_id;
if (ring->fw_ring_id == INVALID_HW_RING_ID)
if (ring->fw_ring_id == INVALID_HW_RING_ID_32BIT)
return;
cmpl_ring_id = close_path ? bnge_cp_ring_for_tx(txr) :
INVALID_HW_RING_ID;
hwrm_ring_free_send_msg(bn, ring, RING_FREE_REQ_RING_TYPE_TX,
cmpl_ring_id);
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
}
static void bnge_hwrm_cp_ring_free(struct bnge_net *bn,
@ -2455,12 +2453,12 @@ static void bnge_hwrm_cp_ring_free(struct bnge_net *bn,
struct bnge_ring_struct *ring;
ring = &cpr->ring_struct;
if (ring->fw_ring_id == INVALID_HW_RING_ID)
if (ring->fw_ring_id == INVALID_HW_RING_ID_32BIT)
return;
hwrm_ring_free_send_msg(bn, ring, RING_FREE_REQ_RING_TYPE_L2_CMPL,
INVALID_HW_RING_ID);
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
}
static void bnge_hwrm_ring_free(struct bnge_net *bn, bool close_path)
@ -2496,11 +2494,11 @@ static void bnge_hwrm_ring_free(struct bnge_net *bn, bool close_path)
bnge_hwrm_cp_ring_free(bn, &nqr->cp_ring_arr[j]);
ring = &nqr->ring_struct;
if (ring->fw_ring_id != INVALID_HW_RING_ID) {
if (ring->fw_ring_id != INVALID_HW_RING_ID_32BIT) {
hwrm_ring_free_send_msg(bn, ring,
RING_FREE_REQ_RING_TYPE_NQ,
INVALID_HW_RING_ID);
ring->fw_ring_id = INVALID_HW_RING_ID;
ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
bn->grp_info[i].nq_fw_ring_id = INVALID_HW_RING_ID;
}
}

View File

@ -630,8 +630,8 @@ struct bnge_l2_filter {
refcount_t refcnt;
};
u16 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr);
u16 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr);
u32 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr);
u32 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr);
void bnge_fill_hw_rss_tbl(struct bnge_net *bn, struct bnge_vnic_info *vnic);
int bnge_alloc_rx_data(struct bnge_net *bn, struct bnge_rx_ring_info *rxr,
u16 prod, gfp_t gfp);

View File

@ -184,7 +184,7 @@ struct bnge_ctx_mem_info {
struct bnge_ring_struct {
struct bnge_ring_mem_info ring_mem;
u16 fw_ring_id;
u32 fw_ring_id;
union {
u16 grp_idx;
u16 map_idx; /* Used by NQs */

View File

@ -4732,6 +4732,7 @@ static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv)
dpaa2_mac_disconnect(mac);
dpaa2_mac_close(mac);
put_device(&mac->mc_dev->dev);
kfree(mac);
}

View File

@ -1560,6 +1560,7 @@ static void dpaa2_switch_port_disconnect_mac(struct ethsw_port_priv *port_priv)
dpaa2_mac_disconnect(mac);
dpaa2_mac_close(mac);
put_device(&mac->mc_dev->dev);
kfree(mac);
}

View File

@ -900,22 +900,28 @@ static void dtsec_mac_config(struct phylink_config *config, unsigned int mode,
{
struct mac_device *mac_dev = fman_config_to_mac(config);
struct dtsec_regs __iomem *regs = mac_dev->fman_mac->regs;
u32 tmp;
u32 ecntrl, maccfg2;
maccfg2 = ioread32be(&regs->maccfg2);
maccfg2 &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE);
switch (state->interface) {
case PHY_INTERFACE_MODE_RMII:
tmp = DTSEC_ECNTRL_RMM;
ecntrl = DTSEC_ECNTRL_RMM;
maccfg2 |= MACCFG2_NIBBLE_MODE;
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
tmp = DTSEC_ECNTRL_GMIIM | DTSEC_ECNTRL_RPM;
ecntrl = DTSEC_ECNTRL_GMIIM | DTSEC_ECNTRL_RPM;
maccfg2 |= MACCFG2_BYTE_MODE;
break;
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
tmp = DTSEC_ECNTRL_TBIM | DTSEC_ECNTRL_SGMIIM;
ecntrl = DTSEC_ECNTRL_TBIM | DTSEC_ECNTRL_SGMIIM;
maccfg2 |= MACCFG2_BYTE_MODE;
break;
default:
dev_warn(mac_dev->dev, "cannot configure dTSEC for %s\n",
@ -923,7 +929,8 @@ static void dtsec_mac_config(struct phylink_config *config, unsigned int mode,
return;
}
iowrite32be(tmp, &regs->ecntrl);
iowrite32be(ecntrl, &regs->ecntrl);
iowrite32be(maccfg2, &regs->maccfg2);
}
static void dtsec_link_up(struct phylink_config *config, struct phy_device *phy,

View File

@ -13,6 +13,7 @@
#include <linux/netdevice.h>
#include <linux/net_tstamp.h>
#include <linux/pci.h>
#include <linux/timer.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/u64_stats_sync.h>
#include <net/page_pool/helpers.h>
@ -41,6 +42,7 @@
/* Interval to schedule a stats report update, 20000ms. */
#define GVE_STATS_REPORT_TIMER_PERIOD 20000
#define GVE_RX_NAPI_RESCHED_MS 20 /* msecs */
/* Numbers of NIC tx/rx stats in stats report. */
#define NIC_TX_STATS_REPORT_NUM 0
@ -341,6 +343,7 @@ struct gve_rx_ring {
struct xdp_rxq_info xdp_rxq;
struct xsk_buff_pool *xsk_pool;
struct page_frag_cache page_cache; /* Page cache to allocate XDP frames */
struct timer_list starvation_timer; /* for queue starvation recovery */
};
/* A TX desc ring entry */

View File

@ -18,6 +18,16 @@
#include <net/tcp.h>
#include <net/xdp_sock_drv.h>
static void gve_rx_starvation_timer(struct timer_list *t)
{
struct gve_rx_ring *rx = timer_container_of(rx, t, starvation_timer);
struct gve_priv *priv = rx->gve;
struct gve_notify_block *block;
block = &priv->ntfy_blocks[rx->ntfy_id];
napi_schedule(&block->napi);
}
static void gve_rx_free_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx)
{
struct device *hdev = &priv->pdev->dev;
@ -120,6 +130,7 @@ void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx)
if (rx->dqo.page_pool)
page_pool_disable_direct_recycling(rx->dqo.page_pool);
timer_shutdown_sync(&rx->starvation_timer);
gve_remove_napi(priv, ntfy_idx);
gve_rx_remove_from_block(priv, idx);
gve_rx_reset_ring_dqo(priv, idx);
@ -208,8 +219,10 @@ static int gve_rx_alloc_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx,
void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx)
{
int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
struct gve_rx_ring *rx = &priv->rx[idx];
gve_rx_add_to_block(priv, idx);
timer_setup(&rx->starvation_timer, gve_rx_starvation_timer, 0);
gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo);
}
@ -365,6 +378,7 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx)
struct gve_rx_compl_queue_dqo *complq = &rx->dqo.complq;
struct gve_rx_buf_queue_dqo *bufq = &rx->dqo.bufq;
struct gve_priv *priv = rx->gve;
u32 num_bufs_avail_to_hw;
u32 num_avail_slots;
u32 num_full_slots;
u32 num_posted = 0;
@ -400,6 +414,26 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx)
}
rx->fill_cnt += num_posted;
/* If the queue has fewer than GVE_RX_BUF_THRESH_DQO descriptors
* visible to the hardware, the hardware is in danger of starving
* and cannot trigger interrupts.
*
* We use a threshold of 32 because a single maximum-sized RSC
* packet can consume up to 19 descriptors in the Rx path. Lower
* thresholds (e.g., 8 or 16) would be unsafe as they could cause
* the device to drop/stall on a maximum-sized RSC packet.
*
* Start the timer to periodically reschedule NAPI and recover.
*/
num_bufs_avail_to_hw =
((bufq->tail & ~(GVE_RX_BUF_THRESH_DQO - 1)) -
bufq->head) & bufq->mask;
if (num_bufs_avail_to_hw < GVE_RX_BUF_THRESH_DQO) {
mod_timer(&rx->starvation_timer,
jiffies + msecs_to_jiffies(GVE_RX_NAPI_RESCHED_MS));
}
}
static void gve_rx_skb_csum(struct sk_buff *skb,

View File

@ -594,7 +594,11 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
skb = build_skb(buf, priv->rx_buf_size);
if (unlikely(!skb)) {
net_dbg_ratelimited("build_skb failed\n");
goto refill;
/* Retain the slot; return budget so NAPI retries this
* buffer. Refill would overwrite rx_buf[]/rx_phys[]
* and leak them.
*/
return budget;
}
dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head],
@ -622,14 +626,15 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
rx++;
}
refill:
buf = netdev_alloc_frag(priv->rx_buf_size);
if (!buf)
goto done;
phys = dma_map_single(priv->dev, buf,
RX_BUF_SIZE, DMA_FROM_DEVICE);
if (dma_mapping_error(priv->dev, phys))
if (dma_mapping_error(priv->dev, phys)) {
skb_free_frag(buf);
goto done;
}
priv->rx_buf[priv->rx_head] = buf;
priv->rx_phys[priv->rx_head] = phys;
hip04_set_recv_desc(priv, phys);

View File

@ -104,8 +104,6 @@ struct hinic_dev {
u16 num_rss;
u16 rss_limit;
struct hinic_rss_type rss_type;
u8 *rss_hkey_user;
s32 *rss_indir_user;
struct hinic_intr_coal_info *rx_intr_coalesce;
struct hinic_intr_coal_info *tx_intr_coalesce;
struct hinic_sriov_info sriov_info;

View File

@ -1064,17 +1064,6 @@ static int __set_rss_rxfh(struct net_device *netdev,
int err;
if (indir) {
if (!nic_dev->rss_indir_user) {
nic_dev->rss_indir_user =
kzalloc(sizeof(u32) * HINIC_RSS_INDIR_SIZE,
GFP_KERNEL);
if (!nic_dev->rss_indir_user)
return -ENOMEM;
}
memcpy(nic_dev->rss_indir_user, indir,
sizeof(u32) * HINIC_RSS_INDIR_SIZE);
err = hinic_rss_set_indir_tbl(nic_dev,
nic_dev->rss_tmpl_idx, indir);
if (err)
@ -1082,16 +1071,6 @@ static int __set_rss_rxfh(struct net_device *netdev,
}
if (key) {
if (!nic_dev->rss_hkey_user) {
nic_dev->rss_hkey_user =
kzalloc(HINIC_RSS_KEY_SIZE * 2, GFP_KERNEL);
if (!nic_dev->rss_hkey_user)
return -ENOMEM;
}
memcpy(nic_dev->rss_hkey_user, key, HINIC_RSS_KEY_SIZE);
err = hinic_rss_set_template_tbl(nic_dev,
nic_dev->rss_tmpl_idx, key);
if (err)

View File

@ -767,6 +767,9 @@ static inline bool ice_is_txtime_ena(const struct ice_tx_ring *ring)
struct ice_vsi *vsi = ring->vsi;
struct ice_pf *pf = vsi->back;
if (vsi->type != ICE_VSI_PF)
return false;
return test_bit(ring->q_index, pf->txtime_txqs);
}

View File

@ -512,9 +512,6 @@ int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf)
struct ice_repr *repr;
int err;
if (!ice_is_eswitch_mode_switchdev(pf))
return 0;
repr = ice_repr_create_vf(vf);
if (IS_ERR(repr))
return PTR_ERR(repr);

View File

@ -2623,7 +2623,7 @@ int ice_init_lag(struct ice_pf *pf)
goto free_lport_res;
/* associate recipes to profiles */
for (n = 0; n < ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER; n++) {
for (n = 0; n < ICE_MAX_NUM_PROFILES; n++) {
err = ice_aq_get_recipe_to_profile(&pf->hw, n,
&recipe_bits, NULL);
if (err)

View File

@ -2368,6 +2368,9 @@ int ice_parser_profile_init(struct ice_parser_result *rslt,
u16 proto_off = 0;
u16 off;
if (rslt->ptype >= ICE_FLOW_PTYPE_MAX)
return -EINVAL;
memset(prof, 0, sizeof(*prof));
set_bit(rslt->ptype, prof->ptypes);
if (blk == ICE_BLK_SW) {

View File

@ -346,7 +346,7 @@ static u64 ice_ptp_extend_40b_ts(struct ice_pf *pf, u64 in_tstamp)
return 0;
}
return ice_ptp_extend_32b_ts(pf->ptp.cached_phc_time,
return ice_ptp_extend_32b_ts(READ_ONCE(pf->ptp.cached_phc_time),
(in_tstamp >> 8) & mask);
}
@ -3037,6 +3037,11 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
struct ice_ptp *ptp = &pf->ptp;
int err;
if (ptp->state == ICE_PTP_UNINIT) {
dev_dbg(ice_pf_to_dev(pf), "PTP was not initialized, skipping rebuild\n");
return;
}
if (ptp->state == ICE_PTP_READY) {
ice_ptp_prepare_for_reset(pf, reset_type);
} else if (ptp->state != ICE_PTP_RESETTING) {

View File

@ -484,12 +484,14 @@ static int ice_start_vfs(struct ice_pf *pf)
goto teardown;
}
retval = ice_eswitch_attach_vf(pf, vf);
if (retval) {
dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
vf->vf_id, retval);
ice_vf_vsi_release(vf);
goto teardown;
if (ice_is_eswitch_mode_switchdev(pf)) {
retval = ice_eswitch_attach_vf(pf, vf);
if (retval) {
dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
vf->vf_id, retval);
ice_vf_vsi_release(vf);
goto teardown;
}
}
set_bit(ICE_VF_STATE_INIT, vf->vf_states);

View File

@ -1654,7 +1654,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
ret = ipv6_skip_exthdr(skb, exthdr - skb->data,
&l4_proto, &frag_off);
if (ret < 0)
return -1;
goto checksum_sw_fb;
}
/* define outer transport */
@ -1673,11 +1673,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
l4.hdr = skb_inner_network_header(skb);
break;
default:
if (first->tx_flags & ICE_TX_FLAGS_TSO)
return -1;
skb_checksum_help(skb);
return 0;
goto checksum_sw_fb;
}
/* compute outer L3 header size */
@ -1736,7 +1732,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_proto,
&frag_off);
} else {
return -1;
goto checksum_sw_fb;
}
/* compute inner L3 header size */
@ -1789,15 +1785,17 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
break;
default:
if (first->tx_flags & ICE_TX_FLAGS_TSO)
return -1;
skb_checksum_help(skb);
return 0;
goto checksum_sw_fb;
}
off->td_cmd |= cmd;
off->td_offset |= offset;
return 1;
checksum_sw_fb:
if (first->tx_flags & ICE_TX_FLAGS_TSO)
return -1;
return skb_checksum_help(skb);
}
/**

View File

@ -812,7 +812,8 @@ void ice_reset_all_vfs(struct ice_pf *pf)
}
ice_vf_post_vsi_rebuild(vf);
ice_eswitch_attach_vf(pf, vf);
if (ice_is_eswitch_mode_switchdev(pf))
ice_eswitch_attach_vf(pf, vf);
mutex_unlock(&vf->cfg_lock);
}

View File

@ -3555,7 +3555,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
pci_sriov_set_totalvfs(adapter->pdev, idpf_get_max_vfs(adapter));
num_max_vports = idpf_get_max_vports(adapter);
adapter->max_vports = num_max_vports;
adapter->vports = kzalloc_objs(*adapter->vports, num_max_vports);
if (!adapter->vports)
return -ENOMEM;
@ -3576,6 +3575,12 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
goto err_netdev_alloc;
}
/* Set max_vports only after vports, netdevs and vport_config buffers
* are allocated to make sure max_vport bound loops don't end up
* crashing, following allocation errors on init.
*/
adapter->max_vports = num_max_vports;
/* Start the mailbox task before requesting vectors. This will ensure
* vector information response from mailbox is handled
*/

View File

@ -272,6 +272,7 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
if (allocated) {
pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
}
if (allocated != count)

View File

@ -30,6 +30,7 @@
#define OTX2_UNSUPP_LSE_DEPTH GENMASK(6, 4)
#define MCAST_INVALID_GRP (-1U)
#define RATE_MANTISSA_BITS 8
static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
u32 *burst_exp, u32 *burst_mantissa)
@ -66,28 +67,30 @@ static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
static void otx2_get_egress_rate_cfg(u64 maxrate, u32 *exp,
u32 *mantissa, u32 *div_exp)
{
u64 tmp;
/* Rate calculation by hardware
*
* PIR_ADD = ((256 + mantissa) << exp) / 256
* rate = (2 * PIR_ADD) / ( 1 << div_exp)
* The resultant rate is in Mbps.
*
* Use div_exp = 0 and compute exp/mantissa for maxrate / 2; the
* leading factor of two yields the full rate. Rates below 2 Mbps
* are floored to the smallest step (exp = 0, mantissa = 0).
*/
/* 2Mbps to 100Gbps can be expressed with div_exp = 0.
* Setting this to '0' will ease the calculation of
* exponent and mantissa.
*/
*div_exp = 0;
if (maxrate) {
*exp = ilog2(maxrate) ? ilog2(maxrate) - 1 : 0;
tmp = maxrate - rounddown_pow_of_two(maxrate);
if (maxrate < MAX_RATE_MANTISSA)
*mantissa = tmp * 2;
else
*mantissa = tmp / (1ULL << (*exp - 7));
maxrate = maxrate / 2;
if (!maxrate) {
/* Rates below 2 Mbps map to the smallest step */
*exp = 0;
*mantissa = 0;
} else {
*exp = ilog2(maxrate);
/* Clear MSB and derive fractional bits */
maxrate &= ~BIT(*exp);
*mantissa = (maxrate << RATE_MANTISSA_BITS) >> *exp;
}
} else {
/* Instead of disabling rate limiting, set all values to max */
*exp = MAX_RATE_EXPONENT;

View File

@ -173,6 +173,13 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev,
}
memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa));
/* Report 0 for non ETS TSA */
for (i = 0; i < ets->ets_cap; i++) {
if (ets->tc_tx_bw[i] == MLX5E_MAX_BW_ALLOC &&
priv->dcbx.tc_tsa[i] != IEEE_8021QAZ_TSA_ETS)
ets->tc_tx_bw[i] = 0;
}
return err;
}
@ -317,6 +324,14 @@ static int mlx5e_dbcnl_validate_ets(struct net_device *netdev,
}
}
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_CB_SHAPER) {
netdev_err(netdev,
"Failed to validate ETS: CB Shaper is not supported\n");
return -EOPNOTSUPP;
}
}
/* Validate Bandwidth Sum */
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) {

View File

@ -211,11 +211,11 @@ static void mlx5e_disable_async_events(struct mlx5e_priv *priv)
static int mlx5e_devcom_event_mpv(int event, void *my_data, void *event_data)
{
struct mlx5e_priv *slave_priv = my_data;
struct mlx5e_priv *master_priv = event_data;
switch (event) {
case MPV_DEVCOM_MASTER_UP:
mlx5_devcom_comp_set_ready(slave_priv->devcom, true);
mlx5_devcom_comp_set_ready(master_priv->devcom, true);
break;
case MPV_DEVCOM_MASTER_DOWN:
/* no need for comp set ready false since we unregister after

View File

@ -71,7 +71,7 @@ int esw_egress_acl_vlan_create(struct mlx5_eswitch *esw,
flow_act.action = flow_action;
vport->egress.allowed_vlan =
mlx5_add_flow_rules(vport->egress.acl, spec,
&flow_act, fwd_dest, 0);
&flow_act, fwd_dest, fwd_dest ? 1 : 0);
if (IS_ERR(vport->egress.allowed_vlan)) {
err = PTR_ERR(vport->egress.allowed_vlan);
esw_warn(esw->dev,

View File

@ -314,7 +314,7 @@ static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num,
return -EIO;
}
ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
ptr = MLX5_ADDR_OF(mcia_reg, out, dwords);
*module_id = ptr[0];
@ -399,7 +399,7 @@ static int mlx5_query_mcia(struct mlx5_core_dev *dev,
return -EIO;
}
ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
ptr = MLX5_ADDR_OF(mcia_reg, out, dwords);
memcpy(data, ptr, size);
return size;

View File

@ -96,6 +96,9 @@ static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
res->mutex =
nfp_cpp_mutex_alloc(cpp,
NFP_RESOURCE_TBL_TARGET, addr, key);
if (!res->mutex)
return -ENOMEM;
res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
entry.region.cpp_action,
entry.region.cpp_token);

View File

@ -192,6 +192,12 @@ enum rtase_sw_flag_content {
RTASE_SWF_MSIX_ENABLED = BIT(2),
};
enum rtase_parse_result {
RTASE_PARSE_OK,
RTASE_PARSE_SKIP,
RTASE_PARSE_DROP,
};
#define RSVD_MASK 0x3FFFC000
struct rtase_tx_desc {
@ -363,4 +369,6 @@ struct rtase_private {
#define RTASE_MSS_MASK GENMASK(28, 18)
#define RTASE_MIN_PAD_LEN 47
#endif /* RTASE_H */

View File

@ -61,6 +61,7 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/prefetch.h>
#include <linux/ptp_classify.h>
#include <linux/rtnetlink.h>
#include <linux/tcp.h>
#include <asm/irq.h>
@ -1252,6 +1253,199 @@ static u32 rtase_tx_csum(struct sk_buff *skb, const struct net_device *dev)
return csum_cmd;
}
static enum rtase_parse_result rtase_get_l3_proto(struct sk_buff *skb,
__be16 *proto,
u32 *network_offset)
{
struct vlan_hdr *vh, _vh;
struct ethhdr *eh, _eh;
u32 offset = ETH_HLEN;
eh = skb_header_pointer(skb, 0, sizeof(_eh), &_eh);
if (!eh)
return RTASE_PARSE_DROP;
*proto = eh->h_proto;
while (eth_type_vlan(*proto)) {
vh = skb_header_pointer(skb, offset, sizeof(_vh), &_vh);
if (!vh)
return RTASE_PARSE_DROP;
*proto = vh->h_vlan_encapsulated_proto;
offset += VLAN_HLEN;
}
*network_offset = offset;
return RTASE_PARSE_OK;
}
static bool rtase_pad_to_transport_len(struct sk_buff *skb,
u32 transport_offset,
u32 pad_to_len)
{
u32 trans_data_len;
u32 pad_len;
trans_data_len = skb->len - transport_offset;
if (trans_data_len >= pad_to_len)
return true;
if (skb_is_nonlinear(skb)) {
if (skb_linearize(skb))
return false;
}
pad_len = pad_to_len - trans_data_len;
if (__skb_put_padto(skb, skb->len + pad_len, false))
return false;
return true;
}
static enum rtase_parse_result rtase_get_transport_offset(struct sk_buff *skb,
u32 *transport_offset,
u8 *transport_proto,
u32 *pad_to_len)
{
enum rtase_parse_result ret;
struct ipv6hdr *i6h, _i6h;
struct iphdr *ih, _ih;
bool non_first_frag;
__be16 proto;
u32 offset;
u32 no;
ret = rtase_get_l3_proto(skb, &proto, &no);
if (ret != RTASE_PARSE_OK)
return ret;
switch (proto) {
case htons(ETH_P_IP):
ih = skb_header_pointer(skb, no, sizeof(_ih), &_ih);
if (!ih)
return RTASE_PARSE_DROP;
if (ih->ihl < 5)
return RTASE_PARSE_DROP;
offset = no + ih->ihl * 4;
if (offset > skb->len)
return RTASE_PARSE_DROP;
non_first_frag = ntohs(ih->frag_off) & IP_OFFSET;
if (ih->protocol == IPPROTO_TCP) {
if (skb->len - offset < sizeof(struct tcphdr)) {
if (non_first_frag) {
*transport_offset = offset;
*transport_proto = IPPROTO_TCP;
*pad_to_len = sizeof(struct tcphdr);
return RTASE_PARSE_OK;
}
return RTASE_PARSE_DROP;
}
return RTASE_PARSE_SKIP;
}
if (ih->protocol != IPPROTO_UDP)
return RTASE_PARSE_SKIP;
*transport_offset = offset;
*transport_proto = IPPROTO_UDP;
if (skb->len - offset < sizeof(struct udphdr)) {
if (non_first_frag) {
*pad_to_len = sizeof(struct udphdr);
return RTASE_PARSE_OK;
}
return RTASE_PARSE_DROP;
}
return RTASE_PARSE_OK;
case htons(ETH_P_IPV6):
i6h = skb_header_pointer(skb, no, sizeof(_i6h), &_i6h);
if (!i6h)
return RTASE_PARSE_DROP;
offset = no + sizeof(*i6h);
if (i6h->nexthdr == IPPROTO_TCP) {
if (skb->len - offset < sizeof(struct tcphdr))
return RTASE_PARSE_DROP;
return RTASE_PARSE_SKIP;
}
if (i6h->nexthdr != IPPROTO_UDP)
return RTASE_PARSE_SKIP;
if (skb->len - offset < sizeof(struct udphdr))
return RTASE_PARSE_DROP;
*transport_offset = offset;
*transport_proto = IPPROTO_UDP;
return RTASE_PARSE_OK;
default:
return RTASE_PARSE_SKIP;
}
}
static bool rtase_skb_pad(struct sk_buff *skb)
{
enum rtase_parse_result ret;
u32 transport_offset;
__be16 *dest, _dest;
u32 trans_data_len;
u32 pad_to_len = 0;
u8 transport_proto;
u16 dest_port;
ret = rtase_get_transport_offset(skb, &transport_offset,
&transport_proto, &pad_to_len);
if (ret == RTASE_PARSE_SKIP) {
return true;
} else if (ret == RTASE_PARSE_DROP) {
netdev_dbg(skb->dev, "drop malformed packet\n");
return false;
}
if (pad_to_len &&
!rtase_pad_to_transport_len(skb, transport_offset, pad_to_len))
return false;
if (transport_proto != IPPROTO_UDP)
return true;
trans_data_len = skb->len - transport_offset;
if (trans_data_len < offsetof(struct udphdr, len) ||
trans_data_len >= RTASE_MIN_PAD_LEN)
return true;
dest = skb_header_pointer(skb,
transport_offset +
offsetof(struct udphdr, dest),
sizeof(_dest), &_dest);
if (!dest)
return true;
dest_port = ntohs(*dest);
if (dest_port != PTP_EV_PORT && dest_port != PTP_GEN_PORT)
return true;
return rtase_pad_to_transport_len(skb, transport_offset,
RTASE_MIN_PAD_LEN);
}
static int rtase_xmit_frags(struct rtase_ring *ring, struct sk_buff *skb,
u32 opts1, u32 opts2)
{
@ -1365,6 +1559,9 @@ static netdev_tx_t rtase_start_xmit(struct sk_buff *skb,
opts2 |= rtase_tx_csum(skb, dev);
}
if (!rtase_skb_pad(skb))
goto err_dma_0;
frags = rtase_xmit_frags(ring, skb, opts1, opts2);
if (unlikely(frags < 0))
goto err_dma_0;

View File

@ -525,6 +525,32 @@ static int intel_set_reg_access(const struct pmc_serdes_regs *regs, int max_regs
return ret;
}
/*
* Return true if the SerDes lane rate must change to serve @interface.
* If the current rate cannot be determined, reconfigure as before.
*/
static bool intel_serdes_needs_reconfig(struct stmmac_priv *priv,
struct intel_priv_data *intel_priv,
phy_interface_t interface)
{
u32 cur_rate, want_rate;
int data;
if (!intel_priv->mdio_adhoc_addr)
return true;
data = mdiobus_read(priv->mii, intel_priv->mdio_adhoc_addr,
SERDES_GCR0);
if (data < 0)
return true;
cur_rate = (data & SERDES_RATE_MASK) >> SERDES_RATE_PCIE_SHIFT;
want_rate = interface == PHY_INTERFACE_MODE_2500BASEX ?
SERDES_RATE_PCIE_GEN2 : SERDES_RATE_PCIE_GEN1;
return cur_rate != want_rate;
}
static int intel_mac_finish(struct net_device *ndev,
void *intel_data,
unsigned int mode,
@ -536,6 +562,11 @@ static int intel_mac_finish(struct net_device *ndev,
int max_regs = 0;
int ret = 0;
if (!intel_serdes_needs_reconfig(priv, intel_priv, interface)) {
priv->plat->phy_interface = interface;
return 0;
}
ret = intel_tsn_lane_is_available(ndev, intel_priv);
if (ret < 0) {
netdev_info(priv->dev, "No TSN lane available to set the registers.\n");

View File

@ -106,6 +106,17 @@ static void dwmac4_dma_init_channel(struct stmmac_priv *priv,
ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
}
static void dwmac4_dma_deinit_channel(struct stmmac_priv *priv,
void __iomem *ioaddr, u32 chan)
{
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
u32 value;
value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
value &= ~DMA_CHAN_INTR_DEFAULT_MASK;
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
}
static void dwmac410_dma_init_channel(struct stmmac_priv *priv,
void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, u32 chan)
@ -125,6 +136,17 @@ static void dwmac410_dma_init_channel(struct stmmac_priv *priv,
ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
}
static void dwmac410_dma_deinit_channel(struct stmmac_priv *priv,
void __iomem *ioaddr, u32 chan)
{
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
u32 value;
value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
value &= ~DMA_CHAN_INTR_DEFAULT_MASK_4_10;
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
}
static void dwmac4_dma_init(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg)
{
@ -548,6 +570,7 @@ const struct stmmac_dma_ops dwmac4_dma_ops = {
.reset = dwmac4_dma_reset,
.init = dwmac4_dma_init,
.init_chan = dwmac4_dma_init_channel,
.deinit_chan = dwmac4_dma_deinit_channel,
.init_rx_chan = dwmac4_dma_init_rx_chan,
.init_tx_chan = dwmac4_dma_init_tx_chan,
.axi = dwmac4_dma_axi,
@ -577,6 +600,7 @@ const struct stmmac_dma_ops dwmac410_dma_ops = {
.reset = dwmac4_dma_reset,
.init = dwmac4_dma_init,
.init_chan = dwmac410_dma_init_channel,
.deinit_chan = dwmac410_dma_deinit_channel,
.init_rx_chan = dwmac4_dma_init_rx_chan,
.init_tx_chan = dwmac4_dma_init_tx_chan,
.axi = dwmac4_dma_axi,

View File

@ -1370,36 +1370,40 @@ static int dwxgmac2_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
value &= ~XGMAC_L4PEN0;
}
value &= ~(XGMAC_L4SPM0 | XGMAC_L4SPIM0);
value &= ~(XGMAC_L4DPM0 | XGMAC_L4DPIM0);
if (sa) {
value |= XGMAC_L4SPM0;
if (inv)
value |= XGMAC_L4SPIM0;
else
value &= ~XGMAC_L4SPIM0;
} else {
value |= XGMAC_L4DPM0;
if (inv)
value |= XGMAC_L4DPIM0;
else
value &= ~XGMAC_L4DPIM0;
}
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, value);
if (ret)
return ret;
ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L4_ADDR, &value);
if (ret)
return ret;
if (sa) {
value = FIELD_PREP(XGMAC_L4SP0, match);
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
if (ret)
return ret;
value &= ~XGMAC_L4SP0;
value |= FIELD_PREP(XGMAC_L4SP0, match);
} else {
value = FIELD_PREP(XGMAC_L4DP0, match);
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
if (ret)
return ret;
value &= ~XGMAC_L4DP0;
value |= FIELD_PREP(XGMAC_L4DP0, match);
}
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
if (ret)
return ret;
if (!en)
return dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, 0);

View File

@ -170,6 +170,8 @@ struct stmmac_dma_ops {
void (*init)(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg);
void (*init_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, u32 chan);
void (*deinit_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
u32 chan);
void (*init_rx_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
dma_addr_t phy, u32 chan);
@ -235,6 +237,8 @@ struct stmmac_dma_ops {
stmmac_do_void_callback(__priv, dma, init, __args)
#define stmmac_init_chan(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, init_chan, __priv, __args)
#define stmmac_deinit_chan(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, deinit_chan, __priv, __args)
#define stmmac_init_rx_chan(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, init_rx_chan, __priv, __args)
#define stmmac_init_tx_chan(__priv, __args...) \

View File

@ -1083,63 +1083,45 @@ static void stmmac_mac_link_up(struct phylink_config *config,
old_ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
ctrl = old_ctrl & ~priv->hw->link.speed_mask;
if (interface == PHY_INTERFACE_MODE_USXGMII) {
switch (speed) {
case SPEED_10000:
ctrl |= priv->hw->link.xgmii.speed10000;
break;
case SPEED_5000:
ctrl |= priv->hw->link.xgmii.speed5000;
break;
case SPEED_2500:
switch (speed) {
case SPEED_100000:
ctrl |= priv->hw->link.xlgmii.speed100000;
break;
case SPEED_50000:
ctrl |= priv->hw->link.xlgmii.speed50000;
break;
case SPEED_40000:
ctrl |= priv->hw->link.xlgmii.speed40000;
break;
case SPEED_25000:
ctrl |= priv->hw->link.xlgmii.speed25000;
break;
case SPEED_10000:
ctrl |= priv->hw->link.xgmii.speed10000;
break;
case SPEED_5000:
ctrl |= priv->hw->link.xgmii.speed5000;
break;
case SPEED_2500:
if (interface == PHY_INTERFACE_MODE_USXGMII)
ctrl |= priv->hw->link.xgmii.speed2500;
break;
default:
return;
}
} else if (interface == PHY_INTERFACE_MODE_XLGMII) {
switch (speed) {
case SPEED_100000:
ctrl |= priv->hw->link.xlgmii.speed100000;
break;
case SPEED_50000:
ctrl |= priv->hw->link.xlgmii.speed50000;
break;
case SPEED_40000:
ctrl |= priv->hw->link.xlgmii.speed40000;
break;
case SPEED_25000:
ctrl |= priv->hw->link.xlgmii.speed25000;
break;
case SPEED_10000:
ctrl |= priv->hw->link.xgmii.speed10000;
break;
case SPEED_2500:
else
ctrl |= priv->hw->link.speed2500;
break;
case SPEED_1000:
ctrl |= priv->hw->link.speed1000;
break;
default:
return;
}
} else {
switch (speed) {
case SPEED_2500:
ctrl |= priv->hw->link.speed2500;
break;
case SPEED_1000:
ctrl |= priv->hw->link.speed1000;
break;
case SPEED_100:
ctrl |= priv->hw->link.speed100;
break;
case SPEED_10:
ctrl |= priv->hw->link.speed10;
break;
default:
return;
}
break;
case SPEED_1000:
ctrl |= priv->hw->link.speed1000;
break;
case SPEED_100:
ctrl |= priv->hw->link.speed100;
break;
case SPEED_10:
ctrl |= priv->hw->link.speed10;
break;
default:
netdev_err(priv->dev,
"unsupported speed %s on %s, leaving the MAC disabled\n",
phy_speed_to_str(speed), phy_modes(interface));
return;
}
if (priv->plat->fix_mac_speed)
@ -2560,6 +2542,7 @@ static void stmmac_stop_all_dma(struct stmmac_priv *priv)
{
u8 rx_channels_count = priv->plat->rx_queues_to_use;
u8 tx_channels_count = priv->plat->tx_queues_to_use;
u8 dma_csr_ch = max(rx_channels_count, tx_channels_count);
u8 chan;
for (chan = 0; chan < rx_channels_count; chan++)
@ -2567,6 +2550,9 @@ static void stmmac_stop_all_dma(struct stmmac_priv *priv)
for (chan = 0; chan < tx_channels_count; chan++)
stmmac_stop_tx_dma(priv, chan);
for (chan = 0; chan < dma_csr_ch; chan++)
stmmac_deinit_chan(priv, priv->ioaddr, chan);
}
/**

View File

@ -446,6 +446,7 @@ static int tc_parse_flow_actions(struct stmmac_priv *priv,
}
#define ETHER_TYPE_FULL_MASK cpu_to_be16(~0)
#define IP_PROTO_FULL_MASK 0xFF
static int tc_add_basic_flow(struct stmmac_priv *priv,
struct flow_cls_offload *cls,
@ -461,6 +462,37 @@ static int tc_add_basic_flow(struct stmmac_priv *priv,
flow_rule_match_basic(rule, &match);
/* Both network proto and transport proto not present in the key */
if (!match.mask || !(match.mask->n_proto || match.mask->ip_proto)) {
NL_SET_ERR_MSG_MOD(cls->common.extack,
"filter must specify network or transport protocol");
return -EOPNOTSUPP;
}
/* If the proto is present in the key and is not full mask */
if ((match.mask->n_proto && match.mask->n_proto != ETHER_TYPE_FULL_MASK) ||
(match.mask->ip_proto && match.mask->ip_proto != IP_PROTO_FULL_MASK)) {
NL_SET_ERR_MSG_MOD(cls->common.extack,
"only full protocol mask is supported");
return -EOPNOTSUPP;
}
/* Network proto is present in the key and is not IPv4 */
if (match.mask->n_proto && match.key->n_proto != cpu_to_be16(ETH_P_IP)) {
NL_SET_ERR_MSG_MOD(cls->common.extack,
"only IPv4 network protocol is supported");
return -EOPNOTSUPP;
}
/* Transport proto is present in the key and is not TCP or UDP */
if (match.mask->ip_proto &&
match.key->ip_proto != IPPROTO_TCP &&
match.key->ip_proto != IPPROTO_UDP) {
NL_SET_ERR_MSG_MOD(cls->common.extack,
"only TCP and UDP transport protocols are supported");
return -EOPNOTSUPP;
}
entry->ip_proto = match.key->ip_proto;
return 0;
}
@ -598,6 +630,8 @@ static int tc_add_flow(struct stmmac_priv *priv,
ret = tc_flow_parsers[i].fn(priv, cls, entry);
if (!ret)
entry->in_use = true;
else if (ret == -EOPNOTSUPP)
return ret;
}
if (!entry->in_use)
@ -627,6 +661,7 @@ static int tc_del_flow(struct stmmac_priv *priv,
entry->in_use = false;
entry->cookie = 0;
entry->is_l4 = false;
entry->action = 0;
return ret;
}

View File

@ -96,11 +96,13 @@ int txgbe_read_eeprom_hostif(struct wx *wx,
dword_len = round_up(length, 4) >> 2;
for (i = 0; i < dword_len; i++) {
u32 copy_len = min_t(u32, 4, length - i * 4);
value = rd32a(wx, WX_FW2SW_MBOX, i + offset);
le32_to_cpus(&value);
memcpy(data, &value, 4);
data += 4;
memcpy(data, &value, copy_len);
data += copy_len;
}
return 0;

View File

@ -945,6 +945,7 @@ static void txgbe_remove(struct pci_dev *pdev)
netdev = wx->netdev;
wx_disable_sriov(wx);
unregister_netdev(netdev);
txgbe_fdir_filter_exit(wx);
timer_shutdown_sync(&wx->service_timer);
cancel_work_sync(&wx->service_task);

View File

@ -43,8 +43,17 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
#define GENEVE_OPT_GRO_HINT_LEN 1
struct geneve_opt_gro_hint {
#if defined(__LITTLE_ENDIAN_BITFIELD)
u8 inner_proto_id:2,
nested_is_v6:1;
nested_is_v6:1,
rsvd:5;
#elif defined(__BIG_ENDIAN_BITFIELD)
u8 rsvd:5,
nested_is_v6:1,
inner_proto_id:2;
#else
#error "Please fix <asm/byteorder.h>"
#endif
u8 nested_nh_offset;
u8 nested_tp_offset;
u8 nested_hdr_len;
@ -577,6 +586,7 @@ static int geneve_post_decap_hint(const struct sock *sk, struct sk_buff *skb,
struct iphdr *iph;
struct udphdr *uh;
__be16 p;
int err;
hint_off = geneve_sk_gro_hint_off(sk, *geneveh, &p, &len);
if (!hint_off)
@ -601,12 +611,20 @@ static int geneve_post_decap_hint(const struct sock *sk, struct sk_buff *skb,
!geneve_opt_gro_hint_validate(skb->data, gro_hint)))
return -EINVAL;
ipv6h = (void *)skb->data + gro_hint->nested_nh_offset;
iph = (struct iphdr *)ipv6h;
total_len = skb->len - gro_hint->nested_nh_offset;
if (total_len >= GRO_LEGACY_MAX_SIZE)
return -E2BIG;
err = skb_ensure_writable(skb, gro_hint->nested_tp_offset + sizeof(*uh));
if (unlikely(err))
return err;
*geneveh = geneve_hdr(skb);
gro_hint = geneve_opt_gro_hint(*geneveh, hint_off);
ipv6h = (void *)skb->data + gro_hint->nested_nh_offset;
iph = (struct iphdr *)ipv6h;
/*
* After stripping the outer encap, the packet still carries a
* tunnel encapsulation: the nested one.
@ -2376,6 +2394,9 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
struct geneve_config cfg;
int err;
if (!rtnl_dev_link_net_capable(dev, geneve->net))
return -EPERM;
/* If the geneve device is configured for metadata (or externally
* controlled, for example, OVS), then nothing can be changed.
*/

View File

@ -669,8 +669,9 @@ static int gtp1u_send_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
return -1;
/* pull GTP and UDP headers */
skb_pull_data(skb,
sizeof(struct gtp1_header_long) + sizeof(struct udphdr));
if (!skb_pull_data(skb, sizeof(struct gtp1_header_long) +
sizeof(struct udphdr)))
return -1;
gtp_pkt = skb_push(skb, sizeof(struct gtp1u_packet));
memset(gtp_pkt, 0, sizeof(struct gtp1u_packet));
@ -826,13 +827,17 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
if (!pskb_may_pull(skb, hdrlen))
return -1;
gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
if (gtp1->flags & GTP1_F_EXTHDR &&
gtp_parse_exthdrs(skb, &hdrlen) < 0)
return -1;
if (gtp_inner_proto(skb, hdrlen, &inner_proto) < 0) {
netdev_dbg(gtp->dev, "GTP packet does not encapsulate an IP packet\n");
return -1;
}
gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid),
gtp_proto_to_family(inner_proto));
if (!pctx) {
@ -840,10 +845,6 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
return 1;
}
if (gtp1->flags & GTP1_F_EXTHDR &&
gtp_parse_exthdrs(skb, &hdrlen) < 0)
return -1;
return gtp_rx(pctx, skb, hdrlen, gtp->role, inner_proto);
}

View File

@ -731,18 +731,21 @@ static __init int mctp_i3c_mod_init(void)
int rc;
rc = i3c_register_notifier(&mctp_i3c_notifier);
if (rc < 0) {
i3c_driver_unregister(&mctp_i3c_driver);
if (rc < 0)
return rc;
}
i3c_for_each_bus_locked(mctp_i3c_bus_add_new, NULL);
rc = i3c_driver_register(&mctp_i3c_driver);
if (rc < 0)
return rc;
goto err_unregister_notifier;
return 0;
err_unregister_notifier:
i3c_unregister_notifier(&mctp_i3c_notifier);
mctp_i3c_bus_remove_all();
return rc;
}
static __exit void mctp_i3c_mod_exit(void)

View File

@ -318,7 +318,7 @@ static void mctp_serial_push_header(struct mctp_serial *dev, u8 c)
} else {
dev->rxlen = c;
dev->rxpos = 0;
dev->rxstate = STATE_DATA;
dev->rxstate = c > 0 ? STATE_DATA : STATE_TRAILER;
dev->rxfcs = crc_ccitt_byte(dev->rxfcs, c);
}
break;

View File

@ -142,7 +142,7 @@ void ovpn_decrypt_post(void *data, int ret)
}
/* keep track of last received authenticated packet for keepalive */
WRITE_ONCE(peer->last_recv, ktime_get_real_seconds());
WRITE_ONCE(peer->last_recv, ktime_get_boottime_seconds());
rcu_read_lock();
sock = rcu_dereference(peer->sock);
@ -294,7 +294,7 @@ void ovpn_encrypt_post(void *data, int ret)
ovpn_peer_stats_increment_tx(&peer->link_stats, orig_len);
/* keep track of last sent packet for keepalive */
WRITE_ONCE(peer->last_sent, ktime_get_real_seconds());
WRITE_ONCE(peer->last_sent, ktime_get_boottime_seconds());
/* skb passed down the stack - don't free it */
skb = NULL;
err_unlock:

View File

@ -26,11 +26,12 @@ static void unlock_ovpn(struct ovpn_priv *ovpn,
struct llist_head *release_list)
__releases(&ovpn->lock)
{
struct ovpn_peer *peer;
struct ovpn_peer *peer, *next;
spin_unlock_bh(&ovpn->lock);
llist_for_each_entry(peer, release_list->first, release_entry) {
llist_for_each_entry_safe(peer, next, release_list->first,
release_entry) {
ovpn_socket_release(peer);
ovpn_peer_put(peer);
}
@ -44,7 +45,7 @@ static void unlock_ovpn(struct ovpn_priv *ovpn,
*/
void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout)
{
time64_t now = ktime_get_real_seconds();
time64_t now = ktime_get_boottime_seconds();
netdev_dbg(peer->ovpn->dev,
"scheduling keepalive for peer %u: interval=%u timeout=%u\n",
@ -1167,7 +1168,6 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk,
ovpn_sock = rcu_access_pointer(peer->sock);
if (!ovpn_sock || ovpn_sock->sk != sk) {
spin_unlock_bh(&ovpn->lock);
ovpn_peer_put(peer);
return;
}
}
@ -1285,8 +1285,10 @@ static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer,
netdev_dbg(peer->ovpn->dev,
"sending keepalive to peer %u\n",
peer->id);
if (schedule_work(&peer->keepalive_work))
ovpn_peer_hold(peer);
if (WARN_ON(!ovpn_peer_hold(peer)))
return 0;
if (!schedule_work(&peer->keepalive_work))
ovpn_peer_put(peer);
}
if (next_run1 < next_run2)
@ -1357,7 +1359,7 @@ void ovpn_peer_keepalive_work(struct work_struct *work)
{
struct ovpn_priv *ovpn = container_of(work, struct ovpn_priv,
keepalive_work.work);
time64_t next_run = 0, now = ktime_get_real_seconds();
time64_t next_run = 0, now = ktime_get_boottime_seconds();
LLIST_HEAD(release_list);
spin_lock_bh(&ovpn->lock);

View File

@ -151,7 +151,8 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
/* take reference for deferred peer deletion. should never fail */
if (WARN_ON(!ovpn_peer_hold(peer)))
goto err_nopeer;
schedule_work(&peer->tcp.defer_del_work);
if (!schedule_work(&peer->tcp.defer_del_work))
ovpn_peer_put(peer);
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
err_nopeer:
kfree_skb(skb);
@ -283,7 +284,8 @@ static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk)
* stream therefore we abort the connection
*/
ovpn_peer_hold(peer);
schedule_work(&peer->tcp.defer_del_work);
if (!schedule_work(&peer->tcp.defer_del_work))
ovpn_peer_put(peer);
/* we bail out immediately and keep tx_in_progress set
* to true. This way we prevent more TX attempts

View File

@ -1058,6 +1058,7 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
/* Reset link_state */
state->link = false;
state->an_complete = false;
state->speed = SPEED_UNKNOWN;
state->duplex = DUPLEX_UNKNOWN;
state->pause = 0;
@ -1069,6 +1070,8 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
if (ret < 0)
return ret;
state->an_complete = ret & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
int speed_value;
@ -1086,35 +1089,14 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
state->duplex = DUPLEX_FULL;
else
state->duplex = DUPLEX_HALF;
} else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
int speed, duplex;
state->link = true;
speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR);
if (speed < 0)
return speed;
speed &= BMCR_SPEED100 | BMCR_SPEED1000;
if (speed == BMCR_SPEED1000)
state->speed = SPEED_1000;
else if (speed == BMCR_SPEED100)
state->speed = SPEED_100;
else if (speed == 0)
state->speed = SPEED_10;
duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
if (duplex < 0)
return duplex;
if (duplex & ADVERTISE_1000XFULL)
state->duplex = DUPLEX_FULL;
else if (duplex & ADVERTISE_1000XHALF)
state->duplex = DUPLEX_HALF;
xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
return 0;
}
/* Clear AN complete status or interrupt */
if (state->an_complete)
xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
return 0;
}

View File

@ -753,7 +753,7 @@ static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes)
err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,
MII_M1111_HWCFG_SERIAL_AN_BYPASS, extsr);
if (err < 0)
return extsr;
return err;
return phy_modify_paged(phydev, MII_MARVELL_FIBER_PAGE, MII_BMCR,
BMCR_ANENABLE, bmcr);

View File

@ -810,7 +810,9 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PPPIOCSMRU:
if (get_user(val, p))
break;
ppp_recv_lock(ppp);
ppp->mru = val;
ppp_recv_unlock(ppp);
err = 0;
break;
@ -831,7 +833,9 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
case PPPIOCGFLAGS:
ppp_lock(ppp);
val = ppp->flags | ppp->xstate | ppp->rstate;
ppp_unlock(ppp);
if (put_user(val, p))
break;
err = 0;
@ -855,7 +859,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PPPIOCSDEBUG:
if (get_user(val, p))
break;
ppp->debug = val;
WRITE_ONCE(ppp->debug, val);
err = 0;
break;
@ -866,16 +870,16 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
case PPPIOCGIDLE32:
idle32.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
idle32.recv_idle = (jiffies - ppp->last_recv) / HZ;
if (copy_to_user(argp, &idle32, sizeof(idle32)))
idle32.xmit_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_xmit))) / HZ;
idle32.recv_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_recv))) / HZ;
if (copy_to_user(argp, &idle32, sizeof(idle32)))
break;
err = 0;
break;
case PPPIOCGIDLE64:
idle64.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
idle64.recv_idle = (jiffies - ppp->last_recv) / HZ;
idle64.xmit_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_xmit))) / HZ;
idle64.recv_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_recv))) / HZ;
if (copy_to_user(argp, &idle64, sizeof(idle64)))
break;
err = 0;
@ -916,7 +920,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (copy_to_user(argp, &npi, sizeof(npi)))
break;
} else {
ppp->npmode[i] = npi.mode;
WRITE_ONCE(ppp->npmode[i], npi.mode);
/* we may be able to transmit more packets now (??) */
netif_wake_queue(ppp->dev);
}
@ -1454,7 +1458,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto outf;
/* Drop, accept or reject the packet */
switch (ppp->npmode[npi]) {
switch (READ_ONCE(ppp->npmode[npi])) {
case NPMODE_PASS:
break;
case NPMODE_QUEUE:
@ -1482,7 +1486,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
outf:
kfree_skb(skb);
++dev->stats.tx_dropped;
DEV_STATS_INC(dev, tx_dropped);
return NETDEV_TX_OK;
}
@ -1532,11 +1536,11 @@ ppp_net_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
static void
ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64)
{
stats64->rx_errors = dev->stats.rx_errors;
stats64->tx_errors = dev->stats.tx_errors;
stats64->rx_dropped = dev->stats.rx_dropped;
stats64->tx_dropped = dev->stats.tx_dropped;
stats64->rx_length_errors = dev->stats.rx_length_errors;
stats64->rx_errors = DEV_STATS_READ(dev, rx_errors);
stats64->tx_errors = DEV_STATS_READ(dev, tx_errors);
stats64->rx_dropped = DEV_STATS_READ(dev, rx_dropped);
stats64->tx_dropped = DEV_STATS_READ(dev, tx_dropped);
stats64->rx_length_errors = DEV_STATS_READ(dev, rx_length_errors);
dev_fetch_sw_netstats(stats64, dev->tstats);
}
@ -1790,7 +1794,7 @@ ppp_prepare_tx_skb(struct ppp *ppp, struct sk_buff **pskb)
*(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_OUTBOUND_TAG);
if (ppp->pass_filter &&
bpf_prog_run(ppp->pass_filter, skb) == 0) {
if (ppp->debug & 1)
if (READ_ONCE(ppp->debug) & 1)
netdev_printk(KERN_DEBUG, ppp->dev,
"PPP: outbound frame "
"not passed\n");
@ -1800,11 +1804,11 @@ ppp_prepare_tx_skb(struct ppp *ppp, struct sk_buff **pskb)
/* if this packet passes the active filter, record the time */
if (!(ppp->active_filter &&
bpf_prog_run(ppp->active_filter, skb) == 0))
ppp->last_xmit = jiffies;
WRITE_ONCE(ppp->last_xmit, jiffies);
skb_pull(skb, 2);
#else
/* for data packets, record the time */
ppp->last_xmit = jiffies;
WRITE_ONCE(ppp->last_xmit, jiffies);
#endif /* CONFIG_PPP_FILTER */
}
@ -1889,7 +1893,7 @@ ppp_prepare_tx_skb(struct ppp *ppp, struct sk_buff **pskb)
drop:
kfree_skb(skb);
++ppp->dev->stats.tx_errors;
DEV_STATS_INC(ppp->dev, tx_errors);
return 1;
}
@ -2154,9 +2158,9 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
noskb:
spin_unlock(&pch->downl);
err_linearize:
if (ppp->debug & 1)
if (READ_ONCE(ppp->debug) & 1)
netdev_err(ppp->dev, "PPP: no memory (fragment)\n");
++ppp->dev->stats.tx_errors;
DEV_STATS_INC(ppp->dev, tx_errors);
++ppp->nxseq;
return 1; /* abandon the frame */
}
@ -2329,7 +2333,7 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
if (!ppp_decompress_proto(skb)) {
kfree_skb(skb);
if (ppp) {
++ppp->dev->stats.rx_length_errors;
DEV_STATS_INC(ppp->dev, rx_length_errors);
ppp_receive_error(ppp);
}
goto done;
@ -2391,7 +2395,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
static void
ppp_receive_error(struct ppp *ppp)
{
++ppp->dev->stats.rx_errors;
DEV_STATS_INC(ppp->dev, rx_errors);
if (ppp->vj)
slhc_toss(ppp->vj);
}
@ -2502,7 +2506,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
*(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_INBOUND_TAG);
if (ppp->pass_filter &&
bpf_prog_run(ppp->pass_filter, skb) == 0) {
if (ppp->debug & 1)
if (READ_ONCE(ppp->debug) & 1)
netdev_printk(KERN_DEBUG, ppp->dev,
"PPP: inbound frame "
"not passed\n");
@ -2511,14 +2515,14 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
}
if (!(ppp->active_filter &&
bpf_prog_run(ppp->active_filter, skb) == 0))
ppp->last_recv = jiffies;
WRITE_ONCE(ppp->last_recv, jiffies);
__skb_pull(skb, 2);
} else
#endif /* CONFIG_PPP_FILTER */
ppp->last_recv = jiffies;
WRITE_ONCE(ppp->last_recv, jiffies);
if ((ppp->dev->flags & IFF_UP) == 0 ||
ppp->npmode[npi] != NPMODE_PASS) {
READ_ONCE(ppp->npmode[npi]) != NPMODE_PASS) {
kfree_skb(skb);
} else {
/* chop off protocol */
@ -2658,7 +2662,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
*/
if (seq_before(seq, ppp->nextseq)) {
kfree_skb(skb);
++ppp->dev->stats.rx_dropped;
DEV_STATS_INC(ppp->dev, rx_dropped);
ppp_receive_error(ppp);
return;
}
@ -2694,7 +2698,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
if (pskb_may_pull(skb, 2))
ppp_receive_nonmp_frame(ppp, skb);
else {
++ppp->dev->stats.rx_length_errors;
DEV_STATS_INC(ppp->dev, rx_length_errors);
kfree_skb(skb);
ppp_receive_error(ppp);
}
@ -2771,7 +2775,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
seq = seq_before(minseq, PPP_MP_CB(p)->sequence)?
minseq + 1: PPP_MP_CB(p)->sequence;
if (ppp->debug & 1)
if (READ_ONCE(ppp->debug) & 1)
netdev_printk(KERN_DEBUG, ppp->dev,
"lost frag %u..%u\n",
oldseq, seq-1);
@ -2800,7 +2804,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
if (lost == 0 && (PPP_MP_CB(p)->BEbits & E) &&
(PPP_MP_CB(head)->BEbits & B)) {
if (len > ppp->mrru + 2) {
++ppp->dev->stats.rx_length_errors;
DEV_STATS_INC(ppp->dev, rx_length_errors);
netdev_printk(KERN_DEBUG, ppp->dev,
"PPP: reconstructed packet"
" is too long (%d)\n", len);
@ -2820,7 +2824,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
struct sk_buff *tmp2;
skb_queue_reverse_walk_from_safe(list, p, tmp2) {
if (ppp->debug & 1)
if (READ_ONCE(ppp->debug) & 1)
netdev_printk(KERN_DEBUG, ppp->dev,
"discarding frag %u\n",
PPP_MP_CB(p)->sequence);
@ -2842,7 +2846,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
skb_queue_walk_safe(list, p, tmp) {
if (p == head)
break;
if (ppp->debug & 1)
if (READ_ONCE(ppp->debug) & 1)
netdev_printk(KERN_DEBUG, ppp->dev,
"discarding frag %u\n",
PPP_MP_CB(p)->sequence);
@ -2850,12 +2854,12 @@ ppp_mp_reconstruct(struct ppp *ppp)
kfree_skb(p);
}
if (ppp->debug & 1)
if (READ_ONCE(ppp->debug) & 1)
netdev_printk(KERN_DEBUG, ppp->dev,
" missed pkts %u..%u\n",
ppp->nextseq,
PPP_MP_CB(head)->sequence-1);
++ppp->dev->stats.rx_dropped;
DEV_STATS_INC(ppp->dev, rx_dropped);
ppp_receive_error(ppp);
}
@ -3161,7 +3165,8 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
if (!ppp->rc_state)
break;
if (ppp->rcomp->decomp_init(ppp->rc_state, dp, len,
ppp->file.index, 0, ppp->mru, ppp->debug)) {
ppp->file.index, 0, ppp->mru,
READ_ONCE(ppp->debug))) {
ppp->rstate |= SC_DECOMP_RUN;
ppp->rstate &= ~(SC_DC_ERROR | SC_DC_FERROR);
}
@ -3170,7 +3175,8 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
if (!ppp->xc_state)
break;
if (ppp->xcomp->comp_init(ppp->xc_state, dp, len,
ppp->file.index, 0, ppp->debug))
ppp->file.index, 0,
READ_ONCE(ppp->debug)))
ppp->xstate |= SC_COMP_RUN;
}
break;
@ -3322,8 +3328,8 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
st->p.ppp_opackets += tx_packets;
st->p.ppp_obytes += tx_bytes;
}
st->p.ppp_ierrors = ppp->dev->stats.rx_errors;
st->p.ppp_oerrors = ppp->dev->stats.tx_errors;
st->p.ppp_ierrors = DEV_STATS_READ(ppp->dev, rx_errors);
st->p.ppp_oerrors = DEV_STATS_READ(ppp->dev, tx_errors);
if (!vj)
return;
st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed;

View File

@ -825,6 +825,7 @@ static int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
dev_hard_header(skb, dev, ETH_P_PPP_SES,
po->pppoe_pa.remote, NULL, total_len);
ph = pppoe_hdr(skb);
memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
ph->length = htons(total_len);

View File

@ -693,6 +693,8 @@ static void slip_receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp,
if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
return;
spin_lock_bh(&sl->lock);
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
@ -708,6 +710,8 @@ static void slip_receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp,
#endif
slip_unesc(sl, *cp++);
}
spin_unlock_bh(&sl->lock);
}
/************************************

View File

@ -1530,7 +1530,11 @@ vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb,
struct ipv6hdr *ipv6;
struct tcphdr *tcp;
} hdr;
BUG_ON(gdesc->rcd.tcp == 0);
/* v4/v6/tcp then describe the inner header, which we can't locate. */
if ((le32_to_cpu(gdesc->dword[0]) & (1UL << VMXNET3_RCD_HDR_INNER_SHIFT)) ||
gdesc->rcd.tcp == 0)
return 0;
maplen = skb_headlen(skb);
if (unlikely(sizeof(struct iphdr) + sizeof(struct tcphdr) > maplen))
@ -1544,15 +1548,21 @@ vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb,
hdr.eth = eth_hdr(skb);
if (gdesc->rcd.v4) {
BUG_ON(hdr.eth->h_proto != htons(ETH_P_IP) &&
hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IP));
if (hdr.eth->h_proto != htons(ETH_P_IP) &&
hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IP))
return 0;
hdr.ptr += hlen;
BUG_ON(hdr.ipv4->protocol != IPPROTO_TCP);
if (hdr.ipv4->protocol != IPPROTO_TCP)
return 0;
hlen = hdr.ipv4->ihl << 2;
hdr.ptr += hdr.ipv4->ihl << 2;
} else if (gdesc->rcd.v6) {
BUG_ON(hdr.eth->h_proto != htons(ETH_P_IPV6) &&
hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IPV6));
if (hdr.eth->h_proto != htons(ETH_P_IPV6) &&
hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IPV6))
return 0;
hdr.ptr += hlen;
/* Use an estimated value, since we also need to handle
* TSO case.

View File

@ -4421,6 +4421,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
struct vxlan_rdst *dst;
int err;
if (!rtnl_dev_link_net_capable(dev, vxlan->net))
return -EPERM;
dst = &vxlan->default_dst;
err = vxlan_nl2conf(tb, data, dev, &conf, true, extack);
if (err)

View File

@ -42,6 +42,7 @@ struct vxlan_mdb_remote {
};
#define VXLAN_SGRP_F_DELETE BIT(0)
#define VXLAN_SGRP_F_NEW BIT(1)
struct vxlan_mdb_src_entry {
struct hlist_node node;
@ -844,6 +845,7 @@ vxlan_mdb_remote_src_add(const struct vxlan_mdb_config *cfg,
ent = vxlan_mdb_remote_src_entry_add(remote, &src->addr);
if (!ent)
return -ENOMEM;
ent->flags |= VXLAN_SGRP_F_NEW;
} else if (!(cfg->nlflags & NLM_F_REPLACE)) {
NL_SET_ERR_MSG_MOD(extack, "Source entry already exists");
return -EEXIST;
@ -853,15 +855,16 @@ vxlan_mdb_remote_src_add(const struct vxlan_mdb_config *cfg,
if (err)
goto err_src_del;
/* Clear flags in case source entry was marked for deletion as part of
* replace flow.
/* Clear the deletion mark so the entry survives the replace sweep.
* The new mark is retained until the whole operation succeeds.
*/
ent->flags = 0;
ent->flags &= ~VXLAN_SGRP_F_DELETE;
return 0;
err_src_del:
vxlan_mdb_remote_src_entry_del(ent);
if (ent->flags & VXLAN_SGRP_F_NEW)
vxlan_mdb_remote_src_entry_del(ent);
return err;
}
@ -889,11 +892,19 @@ static int vxlan_mdb_remote_srcs_add(const struct vxlan_mdb_config *cfg,
goto err_src_del;
}
hlist_for_each_entry(ent, &remote->src_list, node)
ent->flags &= ~VXLAN_SGRP_F_NEW;
return 0;
err_src_del:
hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node)
vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote, ent);
hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) {
if (ent->flags & VXLAN_SGRP_F_NEW)
vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote,
ent);
else
ent->flags &= ~VXLAN_SGRP_F_DELETE;
}
return err;
}
@ -1069,7 +1080,7 @@ vxlan_mdb_remote_srcs_replace(const struct vxlan_mdb_config *cfg,
err = vxlan_mdb_remote_srcs_add(cfg, remote, extack);
if (err)
goto err_clear_delete;
return err;
hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) {
if (ent->flags & VXLAN_SGRP_F_DELETE)
@ -1078,11 +1089,6 @@ vxlan_mdb_remote_srcs_replace(const struct vxlan_mdb_config *cfg,
}
return 0;
err_clear_delete:
hlist_for_each_entry(ent, &remote->src_list, node)
ent->flags &= ~VXLAN_SGRP_F_DELETE;
return err;
}
static int vxlan_mdb_remote_replace(const struct vxlan_mdb_config *cfg,

View File

@ -514,7 +514,8 @@ static void wanxl_pci_remove_one(struct pci_dev *pdev)
if (card->irq)
free_irq(card->irq, card);
wanxl_reset(card);
if (card->plx)
wanxl_reset(card);
for (i = 0; i < RX_QUEUE_LENGTH; i++)
if (card->rx_skbs[i]) {

View File

@ -706,6 +706,7 @@ static int ath10k_htt_rx_pop_paddr32_list(struct ath10k_htt *htt,
if (!(__le32_to_cpu(rxd_attention->flags) &
RX_ATTENTION_FLAGS_MSDU_DONE)) {
ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
__skb_queue_purge(list);
return -EIO;
}
}
@ -770,6 +771,7 @@ static int ath10k_htt_rx_pop_paddr64_list(struct ath10k_htt *htt,
if (!(__le32_to_cpu(rxd_attention->flags) &
RX_ATTENTION_FLAGS_MSDU_DONE)) {
ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
__skb_queue_purge(list);
return -EIO;
}
}

View File

@ -996,6 +996,7 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
ret = ath11k_ahb_setup_msa_resources(ab);
if (ret) {
ath11k_err(ab, "failed to setup msa resources\n");
of_node_put(node);
return ret;
}

View File

@ -4618,6 +4618,9 @@ static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar,
msdu_details = &msdu_link->msdu_link[0];
for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) {
if (!i && FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
msdu_details[i].buf_addr_info.info0) == 0)
break;
if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
msdu_details[i].buf_addr_info.info0) == 0) {
msdu_desc_info = &msdu_details[i - 1].rx_msdu_info;

View File

@ -199,6 +199,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
val |= PCIE_SOC_GLOBAL_RESET_V;
ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
/* Flush the posted write to the device */
ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
/* TODO: exact time to sleep is uncertain */
delay = 10;
@ -208,6 +210,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
val &= ~PCIE_SOC_GLOBAL_RESET_V;
ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
/* Flush the posted write to the device */
ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
mdelay(delay);

View File

@ -3294,9 +3294,14 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
clear_bit(ATH11K_FLAG_CRASH_FLUSH,
&ab->dev_flags);
clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
ath11k_core_qmi_firmware_ready(ab);
set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
if (!test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
ret = ath11k_core_qmi_firmware_ready(ab);
if (ret) {
set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
break;
}
set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
}
break;
case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
break;

View File

@ -274,11 +274,14 @@ int ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp *dp)
void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp)
{
mutex_lock(&dp->link_peer_rhash_tbl_lock);
guard(mutex)(&dp->link_peer_rhash_tbl_lock);
if (!dp->rhead_peer_addr)
return;
rhashtable_destroy(dp->rhead_peer_addr);
kfree(dp->rhead_peer_addr);
dp->rhead_peer_addr = NULL;
mutex_unlock(&dp->link_peer_rhash_tbl_lock);
}
static int ath12k_dp_link_peer_rhash_insert(struct ath12k_dp *dp,
@ -570,6 +573,8 @@ int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], peer);
WRITE_ONCE(dp_peer->link_peers_map,
READ_ONCE(dp_peer->link_peers_map) | BIT(peer->link_id));
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], dp_peer);
@ -632,6 +637,8 @@ void ath12k_dp_link_peer_unassign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
WRITE_ONCE(dp_peer->link_peers_map,
READ_ONCE(dp_peer->link_peers_map) & ~BIT(peer->link_id));
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);

View File

@ -140,6 +140,7 @@ struct ath12k_dp_peer {
/* Info used in MMIC verification of * RX fragments */
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
unsigned long link_peers_map;
struct ath12k_dp_link_peer __rcu *link_peers[ATH12K_NUM_MAX_LINKS];
struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1];
struct ath12k_dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];

View File

@ -1384,10 +1384,9 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc
pubsta = peer ? peer->sta : NULL;
if (pubsta && pubsta->valid_links) {
status->link_valid = 1;
status->link_id = peer->hw_links[rxcb->hw_link_id];
}
status->link_valid = 0;
if (pubsta && pubsta->valid_links)
ath12k_hw_set_rx_link_id(dp->hw_params, peer, rxcb, status);
ath12k_dbg(dp->ab, ATH12K_DBG_DATA,
"rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",

View File

@ -13,6 +13,10 @@
#include "wmi.h"
#include "hal.h"
struct ath12k_dp_peer;
struct ath12k_skb_rxcb;
struct ieee80211_rx_status;
/* Target configuration defines */
/* Num VDEVS per radio */
@ -243,6 +247,9 @@ struct ath12k_hw_ops {
bool (*dp_srng_is_tx_comp_ring)(int ring_num);
bool (*is_frame_link_agnostic)(struct ath12k_link_vif *arvif,
struct ieee80211_mgmt *mgmt);
void (*set_rx_link_id)(struct ath12k_dp_peer *dp_peer,
struct ath12k_skb_rxcb *rxcb,
struct ieee80211_rx_status *status);
};
static inline
@ -273,6 +280,15 @@ static inline int ath12k_hw_mac_id_to_srng_id(const struct ath12k_hw_params *hw,
return 0;
}
static inline void ath12k_hw_set_rx_link_id(const struct ath12k_hw_params *hw,
struct ath12k_dp_peer *dp_peer,
struct ath12k_skb_rxcb *rxcb,
struct ieee80211_rx_status *status)
{
if (hw->hw_ops->set_rx_link_id)
hw->hw_ops->set_rx_link_id(dp_peer, rxcb, status);
}
struct ath12k_fw_ie {
__le32 id;
__le32 len;

View File

@ -1238,9 +1238,13 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar)
/* cleanup dp peer */
spin_lock_bh(&dp_hw->peer_lock);
dp_peer = peer->dp_peer;
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
if (dp_peer) {
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
WRITE_ONCE(dp_peer->link_peers_map,
READ_ONCE(dp_peer->link_peers_map) & ~BIT(peer->link_id));
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
}
spin_unlock_bh(&dp_hw->peer_lock);
ath12k_dp_link_peer_rhash_delete(dp, peer);

View File

@ -188,6 +188,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
val |= PCIE_SOC_GLOBAL_RESET_V;
ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
/* Flush the posted write to the device */
ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
/* TODO: exact time to sleep is uncertain */
delay = 10;
@ -197,6 +199,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
val &= ~PCIE_SOC_GLOBAL_RESET_V;
ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
/* Flush the posted write to the device */
ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
mdelay(delay);

View File

@ -453,6 +453,9 @@ int ath12k_link_sta_rhash_tbl_init(struct ath12k_base *ab)
void ath12k_link_sta_rhash_tbl_destroy(struct ath12k_base *ab)
{
if (!ab->rhead_sta_addr)
return;
rhashtable_destroy(ab->rhead_sta_addr);
kfree(ab->rhead_sta_addr);
ab->rhead_sta_addr = NULL;

View File

@ -5,6 +5,7 @@
*/
#include "dp_rx.h"
#include "../dp_peer.h"
#include "../dp_tx.h"
#include "../peer.h"
#include "hal_qcn9274.h"
@ -2315,3 +2316,35 @@ ath12k_wifi7_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
return tlv_tag == HAL_RX_MPDU_START;
}
void
ath12k_wifi7_dp_rx_set_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
struct ath12k_skb_rxcb *rxcb,
struct ieee80211_rx_status *status)
{
status->link_valid = 1;
status->link_id = dp_peer->hw_links[rxcb->hw_link_id];
}
void
ath12k_wifi7_dp_rx_set_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
struct ath12k_skb_rxcb *rxcb,
struct ieee80211_rx_status *status)
{
struct ath12k_dp_link_peer *link_peer;
unsigned long links_map;
int i;
RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
"ath12k set rx link id called without rcu lock");
links_map = READ_ONCE(dp_peer->link_peers_map);
for_each_set_bit(i, &links_map, ATH12K_NUM_MAX_LINKS) {
link_peer = rcu_dereference(dp_peer->link_peers[i]);
if (link_peer && link_peer->peer_id == rxcb->peer_id) {
status->link_valid = 1;
status->link_id = link_peer->link_id;
return;
}
}
}

View File

@ -57,4 +57,10 @@ ath12k_wifi7_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
struct hal_rx_desc *rx_desc);
int ath12k_wifi7_dp_rx_tid_delete_handler(struct ath12k_base *ab,
struct ath12k_dp_rx_tid_rxq *rx_tid);
void ath12k_wifi7_dp_rx_set_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
struct ath12k_skb_rxcb *rxcb,
struct ieee80211_rx_status *status);
void ath12k_wifi7_dp_rx_set_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
struct ath12k_skb_rxcb *rxcb,
struct ieee80211_rx_status *status);
#endif

View File

@ -158,6 +158,7 @@ static const struct ath12k_hw_ops qcn9274_ops = {
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_qcn9274,
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_qcn9274,
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_qcn9274,
.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_qcn9274,
};
static const struct ath12k_hw_ops wcn7850_ops = {
@ -168,6 +169,7 @@ static const struct ath12k_hw_ops wcn7850_ops = {
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850,
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850,
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850,
.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_wcn7850,
};
static const struct ath12k_hw_ops qcc2072_ops = {
@ -178,6 +180,7 @@ static const struct ath12k_hw_ops qcc2072_ops = {
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850,
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850,
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850,
.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_wcn7850,
};
#define ATH12K_TX_RING_MASK_0 0x1

View File

@ -1723,13 +1723,15 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no,
rxtid = &aggr_conn->rx_tid[tid];
if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX)
ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",
__func__, win_sz, tid);
if (rxtid->aggr)
aggr_delete_tid_state(aggr_conn, tid);
if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) {
ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",
__func__, win_sz, tid);
return;
}
rxtid->seq_next = seq_no;
hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q);
rxtid->hold_q = kzalloc(hold_q_size, GFP_KERNEL);
@ -1828,7 +1830,7 @@ void aggr_reset_state(struct aggr_info_conn *aggr_conn)
return;
if (aggr_conn->timer_scheduled) {
timer_delete(&aggr_conn->timer);
timer_delete_sync(&aggr_conn->timer);
aggr_conn->timer_scheduled = false;
}

View File

@ -484,6 +484,18 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
evt = (struct wmi_tx_complete_event *) datap;
if (len < sizeof(*evt)) {
ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d\n",
len);
return -EINVAL;
}
if (len < sizeof(*evt) + evt->num_msg * sizeof(struct tx_complete_msg_v1)) {
ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d for %u msgs\n",
len, evt->num_msg);
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
evt->num_msg, evt->msg_len, evt->msg_type);
@ -862,6 +874,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
ev = (struct wmi_connect_event *) datap;
if (len < sizeof(*ev) + ev->beacon_ie_len +
ev->assoc_req_len + ev->assoc_resp_len) {
ath6kl_dbg(ATH6KL_DBG_WMI,
"connect event: IE lengths %u+%u+%u exceed buffer %d\n",
ev->beacon_ie_len, ev->assoc_req_len,
ev->assoc_resp_len, len);
return -EINVAL;
}
if (vif->nw_type == AP_NETWORK) {
/* AP mode start/STA connected event */
struct net_device *dev = vif->ndev;

View File

@ -1215,15 +1215,10 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
&hif_dev->udev->dev, GFP_KERNEL,
hif_dev, ath9k_hif_usb_firmware_cb);
if (ret) {
if (ret)
dev_err(&hif_dev->udev->dev,
"ath9k_htc: Async request for firmware %s failed\n",
hif_dev->fw_name);
return ret;
}
dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
hif_dev->fw_name);
return ret;
}

View File

@ -150,7 +150,8 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
spin_lock(&ar->cmd_lock);
if (ar->readbuf) {
if (len >= 4)
memcpy(ar->readbuf, buffer + 4, len - 4);
memcpy(ar->readbuf, buffer + 4,
min_t(u32, len - 4, ar->readlen));
ar->readbuf = NULL;
}
@ -917,7 +918,9 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
}
}
skb_put_data(ar->rx_failover, tbuf, tlen);
skb_put_data(ar->rx_failover, tbuf,
min_t(unsigned int, tlen,
ar->rx_failover_missing));
ar->rx_failover_missing -= tlen;
if (ar->rx_failover_missing <= 0) {

View File

@ -692,7 +692,7 @@ void carl9170_tx_process_status(struct ar9170 *ar,
unsigned int i;
for (i = 0; i < cmd->hdr.ext; i++) {
if (WARN_ON(i > ((cmd->hdr.len / 2) + 1))) {
if (WARN_ON(i >= (cmd->hdr.len / 2))) {
print_hex_dump_bytes("UU:", DUMP_PREFIX_NONE,
(void *) cmd, cmd->hdr.len + 4);
break;

View File

@ -1521,13 +1521,16 @@ static inline int at76_guess_freq(struct at76_priv *priv)
if (ieee80211_is_probe_resp(hdr->frame_control)) {
el_off = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
el = ((struct ieee80211_mgmt *)hdr)->u.probe_resp.variable;
} else if (ieee80211_is_beacon(hdr->frame_control)) {
el_off = offsetof(struct ieee80211_mgmt, u.beacon.variable);
el = ((struct ieee80211_mgmt *)hdr)->u.beacon.variable;
} else {
goto exit;
}
if (len < el_off)
goto exit;
el = priv->rx_skb->data + el_off;
len -= el_off;
el = cfg80211_find_ie(WLAN_EID_DS_PARAMS, el, len);

View File

@ -911,6 +911,7 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
return ret;
}
switch (sdiodev->func2->device) {
case SDIO_DEVICE_ID_BROADCOM_43752:
case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:
f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE;
break;
@ -1069,6 +1070,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
bus_if = kzalloc_obj(*bus_if);
if (!bus_if)
return -ENOMEM;
mutex_init(&bus_if->bus_reset_lock);
sdiodev = kzalloc_obj(*sdiodev);
if (!sdiodev) {
kfree(bus_if);
@ -1130,6 +1132,14 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
if (func->num != 1)
return;
/* Drain bus_reset before the shared brcmf_sdiod_remove()
* teardown, which the SDIO reset callback also reaches. The
* data worker can arm bus_reset via brcmf_fw_crashed(); cancel
* it first.
*/
brcmf_sdio_cancel_datawork(sdiodev->bus);
brcmf_bus_cancel_reset_work(bus_if);
/* only proceed with rest of cleanup if func 1 */
brcmf_sdiod_remove(sdiodev);
@ -1204,6 +1214,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
} else {
/* power will be cut so remove device, probe again in resume */
brcmf_sdiod_intr_unregister(sdiodev);
brcmf_sdio_cancel_datawork(sdiodev->bus);
brcmf_bus_cancel_reset_work(bus_if);
ret = brcmf_sdiod_remove(sdiodev);
if (ret)
brcmf_err("Failed to remove device on suspend\n");
@ -1229,6 +1241,8 @@ static int brcmf_ops_sdio_resume(struct device *dev)
ret = brcmf_sdiod_probe(sdiodev);
if (ret)
brcmf_err("Failed to probe device on resume\n");
else
brcmf_bus_allow_reset_work(bus_if);
} else {
if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported)
disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);

View File

@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/firmware.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include "debug.h"
/* IDs of the 6 default common rings of msgbuf protocol */
@ -179,6 +180,8 @@ struct brcmf_bus {
enum brcmf_fwvendor fwvid;
bool always_use_fws_queue;
bool wowl_supported;
bool removing; /* device removal in progress; quiesce async work */
struct mutex bus_reset_lock;
const struct brcmf_bus_ops *ops;
struct brcmf_bus_msgbuf *msgbuf;
@ -186,6 +189,9 @@ struct brcmf_bus {
struct list_head list;
};
void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if);
void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if);
/*
* callback wrappers
*/

View File

@ -2146,7 +2146,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
sme->crypto.akm_suites[0]);
return -EINVAL;
}
} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_1X_SHA256)) {
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
val = WPA2_AUTH_UNSPECIFIED;

View File

@ -1167,6 +1167,35 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
return 0;
}
/*
* Serialize arming from debugfs reset and brcmf_fw_crashed() against
* teardown. The remove path sets ->removing and drains the work while
* holding bus_reset_lock, so a racing armer is either drained or skips it.
*/
static void brcmf_bus_schedule_reset(struct brcmf_bus *bus_if)
{
mutex_lock(&bus_if->bus_reset_lock);
if (bus_if->drvr && bus_if->drvr->bus_reset.func && !bus_if->removing)
schedule_work(&bus_if->drvr->bus_reset);
mutex_unlock(&bus_if->bus_reset_lock);
}
void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if)
{
mutex_lock(&bus_if->bus_reset_lock);
bus_if->removing = true;
if (bus_if->drvr)
cancel_work_sync(&bus_if->drvr->bus_reset);
mutex_unlock(&bus_if->bus_reset_lock);
}
void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if)
{
mutex_lock(&bus_if->bus_reset_lock);
bus_if->removing = false;
mutex_unlock(&bus_if->bus_reset_lock);
}
static void brcmf_core_bus_reset(struct work_struct *work)
{
struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
@ -1187,7 +1216,7 @@ static ssize_t bus_reset_write(struct file *file, const char __user *user_buf,
if (value != 1)
return -EINVAL;
schedule_work(&drvr->bus_reset);
brcmf_bus_schedule_reset(drvr->bus_if);
return count;
}
@ -1417,14 +1446,23 @@ void brcmf_dev_coredump(struct device *dev)
void brcmf_fw_crashed(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_pub *drvr;
/* May fire before brcmf_attach() wires up drvr, or after removal
* has cleared it; guard the derefs below (and the arming gate in
* brcmf_bus_schedule_reset() already checks drvr/->removing).
*/
if (!bus_if)
return;
drvr = bus_if->drvr;
if (!drvr)
return;
bphy_err(drvr, "Firmware has halted or crashed\n");
brcmf_dev_coredump(dev);
if (drvr->bus_reset.func)
schedule_work(&drvr->bus_reset);
brcmf_bus_schedule_reset(bus_if);
}
void brcmf_detach(struct device *dev)

View File

@ -1383,16 +1383,20 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
static void
brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo)
{
if (devinfo->shared.scratch)
if (devinfo->shared.scratch) {
dma_free_coherent(&devinfo->pdev->dev,
BRCMF_DMA_D2H_SCRATCH_BUF_LEN,
devinfo->shared.scratch,
devinfo->shared.scratch_dmahandle);
if (devinfo->shared.ringupd)
devinfo->shared.scratch = NULL;
}
if (devinfo->shared.ringupd) {
dma_free_coherent(&devinfo->pdev->dev,
BRCMF_DMA_D2H_RINGUPD_BUF_LEN,
devinfo->shared.ringupd,
devinfo->shared.ringupd_dmahandle);
devinfo->shared.ringupd = NULL;
}
}
static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
@ -2499,6 +2503,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = -ENOMEM;
goto fail;
}
mutex_init(&bus->bus_reset_lock);
bus->msgbuf = kzalloc_obj(*bus->msgbuf);
if (!bus->msgbuf) {
ret = -ENOMEM;
@ -2594,6 +2599,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)
if (devinfo->ci)
brcmf_pcie_intr_disable(devinfo);
if (devinfo->irq_allocated)
synchronize_irq(pdev->irq);
brcmf_bus_cancel_reset_work(bus);
brcmf_detach(&pdev->dev);
brcmf_free(&pdev->dev);

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