mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
Including fixes from Bluetooth, wireless and netfilter.
Current release - fix to a fix:
- Bluetooth: btmtk: accept too short WMT FUNC_CTRL events
- vsock/virtio: relax the recently added memory limit a little
Current release - regressions:
- IB/IPoIB: make sure IB drivers always use async set_rx_mode since
some (mlx5) are now required to use it due to locking changes
Previous releases - regressions:
- udp: fix UDP length on last GSO_PARTIAL segment
- af_unix: fix UAF read of tail->len in unix_stream_data_wait()
- tcp: fix stale per-CPU tcp_tw_isn leak enabling ISN prediction
- mlx5e: fix unlocked writing to ICOSQ, breaking AF_XDP
Previous releases - always broken:
- tap: fix stack info leak in tap_ioctl() SIOCGIFHWADDR
- ipv4: raw: reject IP_HDRINCL packets with ihl < 5
- Bluetooth: a lot of locking and concurrency fixes (as always)
- batman-adv (mesh wireless networking): a lot of random fixes
for issues reported by security researchers and Sashiko
- netfilter: same thing, a lot of small security-ish fixes
all over the place, nothing really stands out
Misc:
- bring back the old 3c509 driver, Maciej wants to maintain it
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmoPULUACgkQMUZtbf5S
IrtAvA//bfjxxazZKkGqL8mp6uMYS5Su81Oh/pBcyEWC7q2xv3ftNp5pt8oCTWYP
eryKi7XrxfNHrkFcmnH+aWQ431UekZLfAjrSd+5V0YvE1nQDnKrgbat5qx2SYSsr
ZA7EYnJjvAtPMb0KqUJlYPMSfVdFA0H3gEOdnawkGRnizkKNO5NsNRkC4rHzpCil
hzW5SCTZWQ0r1Cm3IxcTnSCJEOYRqH0BUBbiSRFCWNMZZpq0xKi3UiJFOdgRvqgc
VoPz6sMRPxZyL8gW8i2jJVz6vj2yuWifJwbl8y3ZkqJJy4HvNXfcPIBH5+vBIWlB
hWMuYlUv5F0w+h4+UKeDr789Tdpv12edUIDX+prbsJ8c4bXmBflt069HlFjG9Pto
/k2e5owR0NYSaLt4WvAM6Tr5j1ralzQjHKVDg8JbPaAD+0dtb+e3dXE8J3MBPrw6
EWtdg9jX+vqsbVoHwMQO9Xp2waNY9+97L07w+I0nVf7NLJvrvz0lkSjMKfNPNyV1
C5W7McAbSOx3nJ+XzYwMoVK0wP9OunKA73EhAoEdvQSyOGLqQT+iZzDoTMnwKJFs
2L3fbc8LQ10WBG2B2rCPB/gaGQ1ZZD8uSlZoS9N31dvUPFDaCnCYgKIze/pdcE/R
KOQskME2xd61KzpYlJszkrjJIbnppkNt/mBvvfNUP+zJZPFRyuA=
=ei7U
-----END PGP SIGNATURE-----
Merge tag 'net-7.1-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Pull networking fixes from Jakub Kicinski:
"Including fixes from Bluetooth, wireless and netfilter.
Craziness continues with no end in sight. Even discounting the driver
revert this is a pretty huge PR for standards of the previous era. I'd
speculate - we haven't seen the worst of it, yet. Good news, I guess,
is that so far we haven't seen many (any?) cases of "AI reported a
bug, we fixed it and a real user regressed".
Current release - fix to a fix:
- Bluetooth: btmtk: accept too short WMT FUNC_CTRL events
- vsock/virtio: relax the recently added memory limit a little
Current release - regressions:
- IB/IPoIB: make sure IB drivers always use async set_rx_mode since
some (mlx5) are now required to use it due to locking changes
Previous releases - regressions:
- udp: fix UDP length on last GSO_PARTIAL segment
- af_unix: fix UAF read of tail->len in unix_stream_data_wait()
- tcp: fix stale per-CPU tcp_tw_isn leak enabling ISN prediction
- mlx5e: fix unlocked writing to ICOSQ, breaking AF_XDP
Previous releases - always broken:
- tap: fix stack info leak in tap_ioctl() SIOCGIFHWADDR
- ipv4: raw: reject IP_HDRINCL packets with ihl < 5
- Bluetooth: a lot of locking and concurrency fixes (as always)
- batman-adv (mesh wireless networking): a lot of random fixes for
issues reported by security researchers and Sashiko
- netfilter: same thing, a lot of small security-ish fixes all over
the place, nothing really stands out
Misc:
- bring back the old 3c509 driver, Maciej wants to maintain it"
* tag 'net-7.1-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (187 commits)
net: enetc: avoid VF->PF mailbox timeout during SR-IOV teardown
net: enetc: fix init and teardown order to prevent use of unsafe resources
net: enetc: fix unbounded loop and interrupt handling in VF-to-PF messaging
net: enetc: fix DMA write to freed memory in enetc_msg_free_mbx()
net: enetc: fix race condition in VF MAC address configuration
net: enetc: fix TOCTOU race and validate VF MAC address
net: enetc: add ratelimiting to VF mailbox error messages
net: enetc: fix missing error code when pf->vf_state allocation fails
net: enetc: fix incorrect mailbox message status returned to VFs
net: bridge: prevent too big nested attributes in br_fill_linkxstats()
l2tp: use list_del_rcu in l2tp_session_unhash
net: bcmgenet: keep RBUF EEE/PM disabled
ethernet: 3c509: Fix most coding style issues
ethernet: 3c509: Update documentation to match MAINTAINERS
ethernet: 3c509: Add GPL 2.0 SPDX license identifier
ethernet: 3c509: Fix AUI transceiver type selection
Revert "drivers: net: 3com: 3c509: Remove this driver"
tools: ynl: support listening on all nsids
net: gro: don't merge zcopy skbs
pds_core: ensure null-termination for firmware version strings
...
This commit is contained in:
commit
68993ced0f
2
.mailmap
2
.mailmap
|
|
@ -584,6 +584,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 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>
|
||||
|
|
|
|||
|
|
@ -786,6 +786,7 @@ networking/altera_tse networking/device_drivers/ethernet/altera/altera_tse
|
|||
networking/bpf_flow_dissector bpf/prog_flow_dissector
|
||||
networking/cxacru networking/device_drivers/atm/cxacru
|
||||
networking/defza networking/device_drivers/fddi/defza
|
||||
networking/device_drivers/3com/3c509 networking/device_drivers/ethernet/3com/3c509
|
||||
networking/device_drivers/3com/vortex networking/device_drivers/ethernet/3com/vortex
|
||||
networking/device_drivers/amazon/ena networking/device_drivers/ethernet/amazon/ena
|
||||
networking/device_drivers/aquantia/atlantic networking/device_drivers/ethernet/aquantia/atlantic
|
||||
|
|
|
|||
|
|
@ -158,13 +158,22 @@ returned.
|
|||
When a message has been received, the location and size of the data with the
|
||||
message can be determined by calling::
|
||||
|
||||
void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_offset, size_t *_len);
|
||||
int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_offset, size_t *_len);
|
||||
|
||||
The caller provides the offset and length of the message to the function, which
|
||||
then alters those values to indicate the region containing the data (plus any
|
||||
padding). It is up to the caller to determine how much padding there is.
|
||||
padding). It is up to the caller to determine how much padding there is. The
|
||||
function returns an error if the length is too small or if the mode is
|
||||
unsupported. An additional function::
|
||||
|
||||
int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t len, size_t min_content);
|
||||
|
||||
is provided to just do a basic check that the decrypted/verified message would
|
||||
have a sufficient minimum payload.
|
||||
|
||||
Preparation Functions
|
||||
---------------------
|
||||
|
|
|
|||
|
|
@ -73,6 +73,15 @@ properties:
|
|||
HSP CSR is to control and get status of different high-speed peripherals
|
||||
(such as Ethernet, USB, SATA, etc.) via register, which can tune
|
||||
board-level's parameters of PHY, etc.
|
||||
|
||||
Additional background information about the High-Speed Subsystem
|
||||
and the HSP CSR block is available in Chapter 10 ("High-Speed Interface")
|
||||
of the EIC7700X SoC Technical Reference Manual, Part 4
|
||||
(EIC7700X_SoC_Technical_Reference_Manual_Part4.pdf). The manual is
|
||||
publicly available at
|
||||
https://github.com/eswincomputing/EIC7700X-SoC-Technical-Reference-Manual/releases
|
||||
|
||||
This reference is provided for background information only.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- items:
|
||||
|
|
@ -82,6 +91,8 @@ properties:
|
|||
- description: Offset of AXI clock controller Low-Power request
|
||||
register
|
||||
- description: Offset of register controlling TX/RX clock delay
|
||||
- description: Optional offset of register controlling TXD delay
|
||||
- description: Optional offset of register controlling RXD delay
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
|
@ -116,7 +127,7 @@ examples:
|
|||
reset-names = "stmmaceth";
|
||||
rx-internal-delay-ps = <200>;
|
||||
tx-internal-delay-ps = <200>;
|
||||
eswin,hsp-sp-csr = <&hsp_sp_csr 0x100 0x108 0x118>;
|
||||
eswin,hsp-sp-csr = <&hsp_sp_csr 0x100 0x108 0x118 0x114 0x11c>;
|
||||
snps,axi-config = <&stmmac_axi_setup>;
|
||||
snps,aal;
|
||||
snps,fixed-burst;
|
||||
|
|
|
|||
249
Documentation/networking/device_drivers/ethernet/3com/3c509.rst
Normal file
249
Documentation/networking/device_drivers/ethernet/3com/3c509.rst
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=============================================================================
|
||||
Linux and the 3Com EtherLink III Series Ethercards (driver v1.18c and higher)
|
||||
=============================================================================
|
||||
|
||||
This file contains the instructions and caveats for v1.18c and higher versions
|
||||
of the 3c509 driver. You should not use the driver without reading this file.
|
||||
|
||||
release 1.0
|
||||
|
||||
28 February 2002
|
||||
|
||||
Current maintainer (corrections to):
|
||||
Maciej W. Rozycki <macro@orcam.me.uk>
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The following are notes and information on using the 3Com EtherLink III series
|
||||
ethercards in Linux. These cards are commonly known by the most widely-used
|
||||
card's 3Com model number, 3c509. They are all 10mb/s ISA-bus cards and shouldn't
|
||||
be (but sometimes are) confused with the similarly-numbered PCI-bus "3c905"
|
||||
(aka "Vortex" or "Boomerang") series. Kernel support for the 3c509 family is
|
||||
provided by the module 3c509.c, which has code to support all of the following
|
||||
models:
|
||||
|
||||
- 3c509 (original ISA card)
|
||||
- 3c509B (later revision of the ISA card; supports full-duplex)
|
||||
- 3c589 (PCMCIA)
|
||||
- 3c589B (later revision of the 3c589; supports full-duplex)
|
||||
- 3c579 (EISA)
|
||||
|
||||
Large portions of this documentation were heavily borrowed from the guide
|
||||
written the original author of the 3c509 driver, Donald Becker. The master
|
||||
copy of that document, which contains notes on older versions of the driver,
|
||||
currently resides on Scyld web server: http://www.scyld.com/.
|
||||
|
||||
|
||||
Special Driver Features
|
||||
=======================
|
||||
|
||||
Overriding card settings
|
||||
|
||||
The driver allows boot- or load-time overriding of the card's detected IOADDR,
|
||||
IRQ, and transceiver settings, although this capability shouldn't generally be
|
||||
needed except to enable full-duplex mode (see below). An example of the syntax
|
||||
for LILO parameters for doing this::
|
||||
|
||||
ether=10,0x310,3,0x3c509,eth0
|
||||
|
||||
This configures the first found 3c509 card for IRQ 10, base I/O 0x310, and
|
||||
transceiver type 3 (10base2). The flag "0x3c509" must be set to avoid conflicts
|
||||
with other card types when overriding the I/O address. When the driver is
|
||||
loaded as a module, only the IRQ may be overridden. For example,
|
||||
setting two cards to IRQ10 and IRQ11 is done by using the irq module
|
||||
option::
|
||||
|
||||
options 3c509 irq=10,11
|
||||
|
||||
|
||||
Full-duplex mode
|
||||
================
|
||||
|
||||
The v1.18c driver added support for the 3c509B's full-duplex capabilities.
|
||||
In order to enable and successfully use full-duplex mode, three conditions
|
||||
must be met:
|
||||
|
||||
(a) You must have a Etherlink III card model whose hardware supports full-
|
||||
duplex operations. Currently, the only members of the 3c509 family that are
|
||||
positively known to support full-duplex are the 3c509B (ISA bus) and 3c589B
|
||||
(PCMCIA) cards. Cards without the "B" model designation do *not* support
|
||||
full-duplex mode; these include the original 3c509 (no "B"), the original
|
||||
3c589, the 3c529 (MCA bus), and the 3c579 (EISA bus).
|
||||
|
||||
(b) You must be using your card's 10baseT transceiver (i.e., the RJ-45
|
||||
connector), not its AUI (thick-net) or 10base2 (thin-net/coax) interfaces.
|
||||
AUI and 10base2 network cabling is physically incapable of full-duplex
|
||||
operation.
|
||||
|
||||
(c) Most importantly, your 3c509B must be connected to a link partner that is
|
||||
itself full-duplex capable. This is almost certainly one of two things: a full-
|
||||
duplex-capable Ethernet switch (*not* a hub), or a full-duplex-capable NIC on
|
||||
another system that's connected directly to the 3c509B via a crossover cable.
|
||||
|
||||
Full-duplex mode can be enabled using 'ethtool'.
|
||||
|
||||
.. warning::
|
||||
|
||||
Extremely important caution concerning full-duplex mode
|
||||
|
||||
Understand that the 3c509B's hardware's full-duplex support is much more
|
||||
limited than that provide by more modern network interface cards. Although
|
||||
at the physical layer of the network it fully supports full-duplex operation,
|
||||
the card was designed before the current Ethernet auto-negotiation (N-way)
|
||||
spec was written. This means that the 3c509B family ***cannot and will not
|
||||
auto-negotiate a full-duplex connection with its link partner under any
|
||||
circumstances, no matter how it is initialized***. If the full-duplex mode
|
||||
of the 3c509B is enabled, its link partner will very likely need to be
|
||||
independently _forced_ into full-duplex mode as well; otherwise various nasty
|
||||
failures will occur - at the very least, you'll see massive numbers of packet
|
||||
collisions. This is one of very rare circumstances where disabling auto-
|
||||
negotiation and forcing the duplex mode of a network interface card or switch
|
||||
would ever be necessary or desirable.
|
||||
|
||||
|
||||
Available Transceiver Types
|
||||
===========================
|
||||
|
||||
For versions of the driver v1.18c and above, the available transceiver types are:
|
||||
|
||||
== =========================================================================
|
||||
0 transceiver type from EEPROM config (normally 10baseT); force half-duplex
|
||||
1 AUI (thick-net / DB15 connector)
|
||||
2 (undefined)
|
||||
3 10base2 (thin-net == coax / BNC connector)
|
||||
4 10baseT (RJ-45 connector); force half-duplex mode
|
||||
8 transceiver type and duplex mode taken from card's EEPROM config settings
|
||||
12 10baseT (RJ-45 connector); force full-duplex mode
|
||||
== =========================================================================
|
||||
|
||||
Prior to driver version 1.18c, only transceiver codes 0-4 were supported. Note
|
||||
that the new transceiver codes 8 and 12 are the *only* ones that will enable
|
||||
full-duplex mode, no matter what the card's detected EEPROM settings might be.
|
||||
This insured that merely upgrading the driver from an earlier version would
|
||||
never automatically enable full-duplex mode in an existing installation;
|
||||
it must always be explicitly enabled via one of these code in order to be
|
||||
activated.
|
||||
|
||||
The transceiver type can be changed using 'ethtool'.
|
||||
|
||||
|
||||
Interpretation of error messages and common problems
|
||||
----------------------------------------------------
|
||||
|
||||
Error Messages
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
eth0: Infinite loop in interrupt, status 2011.
|
||||
These are "mostly harmless" message indicating that the driver had too much
|
||||
work during that interrupt cycle. With a status of 0x2011 you are receiving
|
||||
packets faster than they can be removed from the card. This should be rare
|
||||
or impossible in normal operation. Possible causes of this error report are:
|
||||
|
||||
- a "green" mode enabled that slows the processor down when there is no
|
||||
keyboard activity.
|
||||
|
||||
- some other device or device driver hogging the bus or disabling interrupts.
|
||||
Check /proc/interrupts for excessive interrupt counts. The timer tick
|
||||
interrupt should always be incrementing faster than the others.
|
||||
|
||||
No received packets
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If a 3c509, 3c562 or 3c589 can successfully transmit packets, but never
|
||||
receives packets (as reported by /proc/net/dev or 'ifconfig') you likely
|
||||
have an interrupt line problem. Check /proc/interrupts to verify that the
|
||||
card is actually generating interrupts. If the interrupt count is not
|
||||
increasing you likely have a physical conflict with two devices trying to
|
||||
use the same ISA IRQ line. The common conflict is with a sound card on IRQ10
|
||||
or IRQ5, and the easiest solution is to move the 3c509 to a different
|
||||
interrupt line. If the device is receiving packets but 'ping' doesn't work,
|
||||
you have a routing problem.
|
||||
|
||||
Tx Carrier Errors Reported in /proc/net/dev
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
If an EtherLink III appears to transmit packets, but the "Tx carrier errors"
|
||||
field in /proc/net/dev increments as quickly as the Tx packet count, you
|
||||
likely have an unterminated network or the incorrect media transceiver selected.
|
||||
|
||||
3c509B card is not detected on machines with an ISA PnP BIOS.
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
While the updated driver works with most PnP BIOS programs, it does not work
|
||||
with all. This can be fixed by disabling PnP support using the 3Com-supplied
|
||||
setup program.
|
||||
|
||||
3c509 card is not detected on overclocked machines
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Increase the delay time in id_read_eeprom() from the current value, 500,
|
||||
to an absurdly high value, such as 5000.
|
||||
|
||||
|
||||
Decoding Status and Error Messages
|
||||
----------------------------------
|
||||
|
||||
|
||||
The bits in the main status register are:
|
||||
|
||||
===== ======================================
|
||||
value description
|
||||
===== ======================================
|
||||
0x01 Interrupt latch
|
||||
0x02 Tx overrun, or Rx underrun
|
||||
0x04 Tx complete
|
||||
0x08 Tx FIFO room available
|
||||
0x10 A complete Rx packet has arrived
|
||||
0x20 A Rx packet has started to arrive
|
||||
0x40 The driver has requested an interrupt
|
||||
0x80 Statistics counter nearly full
|
||||
===== ======================================
|
||||
|
||||
The bits in the transmit (Tx) status word are:
|
||||
|
||||
===== ============================================
|
||||
value description
|
||||
===== ============================================
|
||||
0x02 Out-of-window collision.
|
||||
0x04 Status stack overflow (normally impossible).
|
||||
0x08 16 collisions.
|
||||
0x10 Tx underrun (not enough PCI bus bandwidth).
|
||||
0x20 Tx jabber.
|
||||
0x40 Tx interrupt requested.
|
||||
0x80 Status is valid (this should always be set).
|
||||
===== ============================================
|
||||
|
||||
|
||||
When a transmit error occurs the driver produces a status message such as::
|
||||
|
||||
eth0: Transmit error, Tx status register 82
|
||||
|
||||
The two values typically seen here are:
|
||||
|
||||
0x82
|
||||
^^^^
|
||||
|
||||
Out of window collision. This typically occurs when some other Ethernet
|
||||
host is incorrectly set to full duplex on a half duplex network.
|
||||
|
||||
0x88
|
||||
^^^^
|
||||
|
||||
16 collisions. This typically occurs when the network is exceptionally busy
|
||||
or when another host doesn't correctly back off after a collision. If this
|
||||
error is mixed with 0x82 errors it is the result of a host incorrectly set
|
||||
to full duplex (see above).
|
||||
|
||||
Both of these errors are the result of network problems that should be
|
||||
corrected. They do not represent driver malfunction.
|
||||
|
||||
|
||||
Revision history (this file)
|
||||
============================
|
||||
|
||||
28Feb02 v1.0 DR New; major portions based on Becker original 3c509 docs
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ Contents:
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
3com/3c509
|
||||
3com/vortex
|
||||
amazon/ena
|
||||
altera/altera_tse
|
||||
|
|
|
|||
|
|
@ -2064,7 +2064,7 @@ F: Documentation/devicetree/bindings/display/snps,arcpgu.txt
|
|||
F: drivers/gpu/drm/tiny/arcpgu.c
|
||||
|
||||
ARCNET NETWORK LAYER
|
||||
M: Michael Grzeschik <m.grzeschik@pengutronix.de>
|
||||
M: Michael Grzeschik <mgr@kernel.org>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/arcnet/
|
||||
|
|
@ -18638,6 +18638,7 @@ F: tools/testing/selftests/net/
|
|||
X: Documentation/networking/mac80211-injection.rst
|
||||
X: Documentation/networking/mac80211_hwsim/
|
||||
X: Documentation/networking/regulatory.rst
|
||||
X: include/net/bluetooth/
|
||||
X: include/net/cfg80211.h
|
||||
X: include/net/ieee80211_radiotap.h
|
||||
X: include/net/iw_handler.h
|
||||
|
|
|
|||
|
|
@ -393,6 +393,7 @@ CONFIG_NETCONSOLE=m
|
|||
CONFIG_TUN=m
|
||||
CONFIG_VETH=m
|
||||
CONFIG_VIRTIO_NET=m
|
||||
CONFIG_EL3=m
|
||||
CONFIG_VORTEX=m
|
||||
CONFIG_TYPHOON=m
|
||||
CONFIG_ADAPTEC_STARFIRE=m
|
||||
|
|
|
|||
|
|
@ -134,27 +134,69 @@ EXPORT_SYMBOL(crypto_krb5_how_much_data);
|
|||
* Find the offset and size of the data in a secure message so that this
|
||||
* information can be used in the metadata buffer which will get added to the
|
||||
* digest by crypto_krb5_verify_mic().
|
||||
*
|
||||
* Return: 0 if successful, -EBADMSG if the message is too short or -EINVAL if
|
||||
* the mode is unsupported.
|
||||
*/
|
||||
void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_offset, size_t *_len)
|
||||
int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_offset, size_t *_len)
|
||||
{
|
||||
switch (mode) {
|
||||
case KRB5_CHECKSUM_MODE:
|
||||
if (*_len < krb5->cksum_len)
|
||||
return -EBADMSG;
|
||||
*_offset += krb5->cksum_len;
|
||||
*_len -= krb5->cksum_len;
|
||||
return;
|
||||
return 0;
|
||||
case KRB5_ENCRYPT_MODE:
|
||||
if (*_len < krb5->conf_len + krb5->cksum_len)
|
||||
return -EBADMSG;
|
||||
*_offset += krb5->conf_len;
|
||||
*_len -= krb5->conf_len + krb5->cksum_len;
|
||||
return;
|
||||
return 0;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_where_is_the_data);
|
||||
|
||||
/**
|
||||
* crypto_krb5_check_data_len - Check a message is big enough
|
||||
* @krb5: The encoding to use.
|
||||
* @mode: Mode of operation.
|
||||
* @len: The length of the secure blob.
|
||||
* @min_content: Minimum length of the content inside the blob.
|
||||
*
|
||||
* Check that a message is large enough to hold whatever bits the encryption
|
||||
* type wants to glue on (nonce, checksum) plus a minimum amount of content.
|
||||
*
|
||||
* Return: 0 if successful, -EBADMSG if the message is too short or -EINVAL if
|
||||
* the mode is unsupported.
|
||||
*/
|
||||
int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t len, size_t min_content)
|
||||
{
|
||||
switch (mode) {
|
||||
case KRB5_CHECKSUM_MODE:
|
||||
if (len < krb5->cksum_len ||
|
||||
len - krb5->cksum_len < min_content)
|
||||
return -EBADMSG;
|
||||
return 0;
|
||||
case KRB5_ENCRYPT_MODE:
|
||||
if (len < krb5->conf_len + krb5->cksum_len ||
|
||||
len - (krb5->conf_len + krb5->cksum_len) < min_content)
|
||||
return -EBADMSG;
|
||||
return 0;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_check_data_len);
|
||||
|
||||
/*
|
||||
* Prepare the encryption with derived key data.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -582,12 +582,10 @@ static int btintel_pcie_get_mac_access(struct btintel_pcie_data *data)
|
|||
|
||||
reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
|
||||
|
||||
reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_STOP_MAC_ACCESS_DIS;
|
||||
reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_XTAL_CLK_REQ;
|
||||
if ((reg & BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS) == 0)
|
||||
if (!(reg & BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ)) {
|
||||
reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ;
|
||||
|
||||
btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
|
||||
btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
|
||||
}
|
||||
|
||||
do {
|
||||
reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
|
||||
|
|
@ -607,16 +605,10 @@ static void btintel_pcie_release_mac_access(struct btintel_pcie_data *data)
|
|||
|
||||
reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
|
||||
|
||||
if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ)
|
||||
if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ) {
|
||||
reg &= ~BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ;
|
||||
|
||||
if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_STOP_MAC_ACCESS_DIS)
|
||||
reg &= ~BTINTEL_PCIE_CSR_FUNC_CTRL_STOP_MAC_ACCESS_DIS;
|
||||
|
||||
if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_XTAL_CLK_REQ)
|
||||
reg &= ~BTINTEL_PCIE_CSR_FUNC_CTRL_XTAL_CLK_REQ;
|
||||
|
||||
btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
|
||||
btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void *btintel_pcie_copy_tlv(void *dest, enum btintel_pcie_tlv_type type,
|
||||
|
|
|
|||
|
|
@ -34,9 +34,6 @@
|
|||
#define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS (BIT(20))
|
||||
|
||||
#define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ (BIT(21))
|
||||
/* Stop MAC Access disconnection request */
|
||||
#define BTINTEL_PCIE_CSR_FUNC_CTRL_STOP_MAC_ACCESS_DIS (BIT(22))
|
||||
#define BTINTEL_PCIE_CSR_FUNC_CTRL_XTAL_CLK_REQ (BIT(23))
|
||||
|
||||
#define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_STS (BIT(28))
|
||||
#define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON (BIT(29))
|
||||
|
|
|
|||
|
|
@ -537,6 +537,7 @@ static void btmtk_usb_wmt_recv(struct urb *urb)
|
|||
return;
|
||||
} else if (urb->status == -ENOENT) {
|
||||
/* Avoid suspend failed when usb_kill_urb */
|
||||
kfree(urb->setup_packet);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -610,6 +611,7 @@ static int btmtk_usb_submit_wmt_recv_urb(struct hci_dev *hdev)
|
|||
if (err != -EPERM && err != -ENODEV)
|
||||
bt_dev_err(hdev, "urb %p submission failed (%d)",
|
||||
urb, -err);
|
||||
kfree(dr);
|
||||
usb_unanchor_urb(urb);
|
||||
}
|
||||
|
||||
|
|
@ -719,8 +721,8 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
|
|||
case BTMTK_WMT_FUNC_CTRL:
|
||||
if (!skb_pull_data(data->evt_skb,
|
||||
sizeof(wmt_evt_funcc->status))) {
|
||||
err = -EINVAL;
|
||||
goto err_free_skb;
|
||||
status = BTMTK_WMT_ON_UNDONE;
|
||||
break;
|
||||
}
|
||||
|
||||
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
|
||||
|
|
|
|||
|
|
@ -194,7 +194,15 @@ void hci_uart_init_work(struct work_struct *work)
|
|||
err = hci_register_dev(hu->hdev);
|
||||
if (err < 0) {
|
||||
BT_ERR("Can't register HCI device");
|
||||
|
||||
percpu_down_write(&hu->proto_lock);
|
||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
percpu_up_write(&hu->proto_lock);
|
||||
|
||||
/* Safely cancel work after clearing flags */
|
||||
cancel_work_sync(&hu->write_work);
|
||||
|
||||
/* Close protocol before freeing hdev */
|
||||
hu->proto->close(hu);
|
||||
hdev = hu->hdev;
|
||||
hu->hdev = NULL;
|
||||
|
|
@ -263,8 +271,12 @@ static int hci_uart_open(struct hci_dev *hdev)
|
|||
/* Close device */
|
||||
static int hci_uart_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("hdev %p", hdev);
|
||||
|
||||
cancel_work_sync(&hu->write_work);
|
||||
|
||||
hci_uart_flush(hdev);
|
||||
hdev->flush = NULL;
|
||||
return 0;
|
||||
|
|
@ -531,6 +543,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
|
|||
{
|
||||
struct hci_uart *hu = tty->disc_data;
|
||||
struct hci_dev *hdev;
|
||||
bool proto_ready;
|
||||
|
||||
BT_DBG("tty %p", tty);
|
||||
|
||||
|
|
@ -540,24 +553,38 @@ static void hci_uart_tty_close(struct tty_struct *tty)
|
|||
if (!hu)
|
||||
return;
|
||||
|
||||
hdev = hu->hdev;
|
||||
if (hdev)
|
||||
hci_uart_close(hdev);
|
||||
/* Wait for init_ready to finish to prevent registration races */
|
||||
cancel_work_sync(&hu->init_ready);
|
||||
|
||||
if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
|
||||
proto_ready = test_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
if (proto_ready) {
|
||||
percpu_down_write(&hu->proto_lock);
|
||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
percpu_up_write(&hu->proto_lock);
|
||||
}
|
||||
|
||||
cancel_work_sync(&hu->init_ready);
|
||||
cancel_work_sync(&hu->write_work);
|
||||
/*
|
||||
* Unconditionally cancel write_work AFTER clearing PROTO_READY.
|
||||
* This ensures that concurrent protocol timers cannot requeue
|
||||
* write_work via hci_uart_tx_wakeup(), permanently preventing
|
||||
* double-free races and UAFs.
|
||||
*/
|
||||
cancel_work_sync(&hu->write_work);
|
||||
|
||||
hdev = hu->hdev;
|
||||
if (hdev)
|
||||
hci_uart_close(hdev); /* proto->flush is safely skipped */
|
||||
|
||||
if (proto_ready) {
|
||||
if (hdev) {
|
||||
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
|
||||
hci_unregister_dev(hdev);
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
/* Close protocol before freeing hdev (intrinsically purges queues) */
|
||||
hu->proto->close(hu);
|
||||
|
||||
if (hdev)
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
clear_bit(HCI_UART_PROTO_SET, &hu->flags);
|
||||
|
||||
|
|
@ -625,11 +652,12 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
|
|||
* tty caller
|
||||
*/
|
||||
hu->proto->recv(hu, data, count);
|
||||
percpu_up_read(&hu->proto_lock);
|
||||
|
||||
if (hu->hdev)
|
||||
hu->hdev->stat.byte_rx += count;
|
||||
|
||||
percpu_up_read(&hu->proto_lock);
|
||||
|
||||
tty_unthrottle(tty);
|
||||
}
|
||||
|
||||
|
|
@ -695,6 +723,10 @@ static int hci_uart_register_dev(struct hci_uart *hu)
|
|||
percpu_down_write(&hu->proto_lock);
|
||||
clear_bit(HCI_UART_PROTO_INIT, &hu->flags);
|
||||
percpu_up_write(&hu->proto_lock);
|
||||
/* Cancel work after clearing flags */
|
||||
cancel_work_sync(&hu->write_work);
|
||||
|
||||
/* Close protocol before freeing hdev */
|
||||
hu->proto->close(hu);
|
||||
hu->hdev = NULL;
|
||||
hci_free_dev(hdev);
|
||||
|
|
|
|||
|
|
@ -48,13 +48,12 @@
|
|||
#define HCI_MAX_IBS_SIZE 10
|
||||
|
||||
#define IBS_WAKE_RETRANS_TIMEOUT_MS 100
|
||||
#define IBS_BTSOC_TX_IDLE_TIMEOUT_MS 200
|
||||
#define IBS_BTSOC_TX_IDLE_TIMEOUT msecs_to_jiffies(200)
|
||||
#define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000
|
||||
#define CMD_TRANS_TIMEOUT_MS 100
|
||||
#define MEMDUMP_TIMEOUT_MS 8000
|
||||
#define IBS_DISABLE_SSR_TIMEOUT_MS \
|
||||
(MEMDUMP_TIMEOUT_MS + FW_DOWNLOAD_TIMEOUT_MS)
|
||||
#define FW_DOWNLOAD_TIMEOUT_MS 3000
|
||||
#define CMD_TRANS_TIMEOUT msecs_to_jiffies(100)
|
||||
#define MEMDUMP_TIMEOUT msecs_to_jiffies(8000)
|
||||
#define FW_DOWNLOAD_TIMEOUT msecs_to_jiffies(3000)
|
||||
#define IBS_DISABLE_SSR_TIMEOUT (MEMDUMP_TIMEOUT + FW_DOWNLOAD_TIMEOUT)
|
||||
|
||||
/* susclk rate */
|
||||
#define SUSCLK_RATE_32KHZ 32768
|
||||
|
|
@ -1096,7 +1095,7 @@ static void qca_controller_memdump(struct work_struct *work)
|
|||
|
||||
queue_delayed_work(qca->workqueue,
|
||||
&qca->ctrl_memdump_timeout,
|
||||
msecs_to_jiffies(MEMDUMP_TIMEOUT_MS));
|
||||
MEMDUMP_TIMEOUT);
|
||||
skb_pull(skb, sizeof(qca_memdump->ram_dump_size));
|
||||
qca_memdump->current_seq_no = 0;
|
||||
qca_memdump->received_dump = 0;
|
||||
|
|
@ -1369,7 +1368,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
|
|||
|
||||
if (hu->serdev)
|
||||
serdev_device_wait_until_sent(hu->serdev,
|
||||
msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
|
||||
CMD_TRANS_TIMEOUT);
|
||||
|
||||
/* Give the controller time to process the request */
|
||||
switch (qca_soc_type(hu)) {
|
||||
|
|
@ -1401,8 +1400,8 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
|
|||
|
||||
static int qca_send_power_pulse(struct hci_uart *hu, bool on)
|
||||
{
|
||||
int timeout = CMD_TRANS_TIMEOUT;
|
||||
int ret;
|
||||
int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
|
||||
u8 cmd = on ? QCA_WCN3990_POWERON_PULSE : QCA_WCN3990_POWEROFF_PULSE;
|
||||
|
||||
/* These power pulses are single byte command which are sent
|
||||
|
|
@ -1607,7 +1606,7 @@ static void qca_wait_for_dump_collection(struct hci_dev *hdev)
|
|||
struct qca_data *qca = hu->priv;
|
||||
|
||||
wait_on_bit_timeout(&qca->flags, QCA_MEMDUMP_COLLECTION,
|
||||
TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT_MS);
|
||||
TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT);
|
||||
|
||||
clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
|
||||
}
|
||||
|
|
@ -2591,7 +2590,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
|
|||
static void qca_serdev_shutdown(struct serdev_device *serdev)
|
||||
{
|
||||
int ret;
|
||||
int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
|
||||
int timeout = CMD_TRANS_TIMEOUT;
|
||||
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
||||
struct hci_uart *hu = &qcadev->serdev_hu;
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
|
|
@ -2648,7 +2647,7 @@ static int __maybe_unused qca_suspend(struct device *dev)
|
|||
bool tx_pending = false;
|
||||
int ret = 0;
|
||||
u8 cmd;
|
||||
u32 wait_timeout = 0;
|
||||
unsigned long wait_timeout = 0;
|
||||
|
||||
set_bit(QCA_SUSPENDING, &qca->flags);
|
||||
|
||||
|
|
@ -2669,15 +2668,15 @@ static int __maybe_unused qca_suspend(struct device *dev)
|
|||
if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
|
||||
test_bit(QCA_SSR_TRIGGERED, &qca->flags)) {
|
||||
wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ?
|
||||
IBS_DISABLE_SSR_TIMEOUT_MS :
|
||||
FW_DOWNLOAD_TIMEOUT_MS;
|
||||
IBS_DISABLE_SSR_TIMEOUT :
|
||||
FW_DOWNLOAD_TIMEOUT;
|
||||
|
||||
/* QCA_IBS_DISABLED flag is set to true, During FW download
|
||||
* and during memory dump collection. It is reset to false,
|
||||
* After FW download complete.
|
||||
*/
|
||||
wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED,
|
||||
TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout));
|
||||
TASK_UNINTERRUPTIBLE, wait_timeout);
|
||||
|
||||
if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
|
||||
bt_dev_err(hu->hdev, "SSR or FW download time out");
|
||||
|
|
@ -2729,7 +2728,7 @@ static int __maybe_unused qca_suspend(struct device *dev)
|
|||
|
||||
if (tx_pending) {
|
||||
serdev_device_wait_until_sent(hu->serdev,
|
||||
msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
|
||||
CMD_TRANS_TIMEOUT);
|
||||
serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
|
||||
}
|
||||
|
||||
|
|
@ -2738,7 +2737,7 @@ static int __maybe_unused qca_suspend(struct device *dev)
|
|||
*/
|
||||
ret = wait_event_interruptible_timeout(qca->suspend_wait_q,
|
||||
qca->rx_ibs_state == HCI_IBS_RX_ASLEEP,
|
||||
msecs_to_jiffies(IBS_BTSOC_TX_IDLE_TIMEOUT_MS));
|
||||
IBS_BTSOC_TX_IDLE_TIMEOUT);
|
||||
if (ret == 0) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto error;
|
||||
|
|
|
|||
|
|
@ -1394,8 +1394,8 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
|
|||
|
||||
err_register:
|
||||
dpll_pin_put(pin->dpll_pin, &pin->tracker);
|
||||
pin->dpll_pin = NULL;
|
||||
err_pin_get:
|
||||
pin->dpll_pin = NULL;
|
||||
fwnode_handle_put(pin->fwnode);
|
||||
pin->fwnode = NULL;
|
||||
zl3073x_pin_props_put(props);
|
||||
|
|
@ -1563,8 +1563,10 @@ zl3073x_dpll_pins_register(struct zl3073x_dpll *zldpll)
|
|||
}
|
||||
|
||||
rc = zl3073x_dpll_pin_register(pin, index);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
zl3073x_dpll_pin_free(pin);
|
||||
goto error;
|
||||
}
|
||||
|
||||
list_add(&pin->list, &zldpll->pins);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1297,7 +1297,9 @@ static int ipoib_hard_header(struct sk_buff *skb,
|
|||
return IPOIB_HARD_LEN;
|
||||
}
|
||||
|
||||
static void ipoib_set_mcast_list(struct net_device *dev)
|
||||
static void ipoib_set_rx_mode_async(struct net_device *dev,
|
||||
struct netdev_hw_addr_list *uc,
|
||||
struct netdev_hw_addr_list *mc)
|
||||
{
|
||||
struct ipoib_dev_priv *priv = ipoib_priv(dev);
|
||||
|
||||
|
|
@ -2160,7 +2162,7 @@ static const struct net_device_ops ipoib_netdev_ops_pf = {
|
|||
.ndo_fix_features = ipoib_fix_features,
|
||||
.ndo_start_xmit = ipoib_start_xmit,
|
||||
.ndo_tx_timeout = ipoib_timeout,
|
||||
.ndo_set_rx_mode = ipoib_set_mcast_list,
|
||||
.ndo_set_rx_mode_async = ipoib_set_rx_mode_async,
|
||||
.ndo_get_iflink = ipoib_get_iflink,
|
||||
.ndo_set_vf_link_state = ipoib_set_vf_link_state,
|
||||
.ndo_get_vf_config = ipoib_get_vf_config,
|
||||
|
|
@ -2183,7 +2185,7 @@ static const struct net_device_ops ipoib_netdev_ops_vf = {
|
|||
.ndo_fix_features = ipoib_fix_features,
|
||||
.ndo_start_xmit = ipoib_start_xmit,
|
||||
.ndo_tx_timeout = ipoib_timeout,
|
||||
.ndo_set_rx_mode = ipoib_set_mcast_list,
|
||||
.ndo_set_rx_mode_async = ipoib_set_rx_mode_async,
|
||||
.ndo_get_iflink = ipoib_get_iflink,
|
||||
.ndo_get_stats64 = ipoib_get_stats,
|
||||
.ndo_eth_ioctl = ipoib_ioctl,
|
||||
|
|
|
|||
|
|
@ -1023,12 +1023,16 @@ mt7530_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
|
|||
unsigned int age_count;
|
||||
unsigned int age_unit;
|
||||
|
||||
/* Applied timer is (AGE_CNT + 1) * (AGE_UNIT + 1) seconds */
|
||||
if (secs < 1 || secs > (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1))
|
||||
return -ERANGE;
|
||||
|
||||
/* iterate through all possible age_count to find the closest pair */
|
||||
for (tmp_age_count = 0; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
|
||||
/* Applied timer is (AGE_CNT + 1) * (AGE_UNIT + 1) seconds.
|
||||
* The DSA core has already validated the range using
|
||||
* ds->ageing_time_min and ds->ageing_time_max.
|
||||
*
|
||||
* Iterate through all possible age_count values to find the closest
|
||||
* pair. Start from 1 because the per-entry aging counter is
|
||||
* initialized to AGE_CNT and a value of 0 means the entry will
|
||||
* never be aged out.
|
||||
*/
|
||||
for (tmp_age_count = 1; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
|
||||
unsigned int tmp_age_unit = secs / (tmp_age_count + 1) - 1;
|
||||
|
||||
if (tmp_age_unit <= AGE_UNIT_MAX) {
|
||||
|
|
@ -1296,37 +1300,40 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
|
|||
static void
|
||||
mt753x_trap_frames(struct mt7530_priv *priv)
|
||||
{
|
||||
/* Trap 802.1X PAE frames and BPDUs to the CPU port(s) and egress them
|
||||
* VLAN-untagged.
|
||||
/* Trap 802.1X PAE frames and BPDUs to the CPU port(s) and egress
|
||||
* them with the EG_TAG attribute set to disabled (system default)
|
||||
* so that any VLAN tags in the frame are not modified by the
|
||||
* switch egress VLAN tag processing. This preserves VLAN tags
|
||||
* for reception on VLAN sub-interfaces.
|
||||
*/
|
||||
mt7530_rmw(priv, MT753X_BPC,
|
||||
PAE_BPDU_FR | PAE_EG_TAG_MASK | PAE_PORT_FW_MASK |
|
||||
BPDU_EG_TAG_MASK | BPDU_PORT_FW_MASK,
|
||||
PAE_BPDU_FR | PAE_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
|
||||
PAE_BPDU_FR | PAE_EG_TAG(MT7530_VLAN_EG_DISABLED) |
|
||||
PAE_PORT_FW(TO_CPU_FW_CPU_ONLY) |
|
||||
BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
|
||||
BPDU_EG_TAG(MT7530_VLAN_EG_DISABLED) |
|
||||
TO_CPU_FW_CPU_ONLY);
|
||||
|
||||
/* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and egress
|
||||
* them VLAN-untagged.
|
||||
/* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and
|
||||
* egress them with EG_TAG disabled.
|
||||
*/
|
||||
mt7530_rmw(priv, MT753X_RGAC1,
|
||||
R02_BPDU_FR | R02_EG_TAG_MASK | R02_PORT_FW_MASK |
|
||||
R01_BPDU_FR | R01_EG_TAG_MASK | R01_PORT_FW_MASK,
|
||||
R02_BPDU_FR | R02_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
|
||||
R02_BPDU_FR | R02_EG_TAG(MT7530_VLAN_EG_DISABLED) |
|
||||
R02_PORT_FW(TO_CPU_FW_CPU_ONLY) | R01_BPDU_FR |
|
||||
R01_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
|
||||
R01_EG_TAG(MT7530_VLAN_EG_DISABLED) |
|
||||
TO_CPU_FW_CPU_ONLY);
|
||||
|
||||
/* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and egress
|
||||
* them VLAN-untagged.
|
||||
/* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and
|
||||
* egress them with EG_TAG disabled.
|
||||
*/
|
||||
mt7530_rmw(priv, MT753X_RGAC2,
|
||||
R0E_BPDU_FR | R0E_EG_TAG_MASK | R0E_PORT_FW_MASK |
|
||||
R03_BPDU_FR | R03_EG_TAG_MASK | R03_PORT_FW_MASK,
|
||||
R0E_BPDU_FR | R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
|
||||
R0E_BPDU_FR | R0E_EG_TAG(MT7530_VLAN_EG_DISABLED) |
|
||||
R0E_PORT_FW(TO_CPU_FW_CPU_ONLY) | R03_BPDU_FR |
|
||||
R03_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
|
||||
R03_EG_TAG(MT7530_VLAN_EG_DISABLED) |
|
||||
TO_CPU_FW_CPU_ONLY);
|
||||
}
|
||||
|
||||
|
|
@ -1616,6 +1623,49 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
|
||||
{
|
||||
struct mt7530_dummy_poll p;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
|
||||
mt7530_write(priv, MT7530_VTCR, val);
|
||||
|
||||
INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
|
||||
ret = readx_poll_timeout(_mt7530_read, &p, val,
|
||||
!(val & VTCR_BUSY), 20, 20000);
|
||||
if (ret < 0) {
|
||||
dev_err(priv->dev, "poll timeout\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
val = mt7530_read(priv, MT7530_VTCR);
|
||||
if (val & VTCR_INVALID) {
|
||||
dev_err(priv->dev, "read VTCR invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7530_setup_vlan0(struct mt7530_priv *priv)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Validate the entry with independent learning, keep the original
|
||||
* ingress tag attribute.
|
||||
*/
|
||||
val = IVL_MAC | EG_CON | PORT_MEM(MT7530_ALL_MEMBERS) | FID(FID_BRIDGED) |
|
||||
VLAN_VALID;
|
||||
mt7530_write(priv, MT7530_VAWD1, val);
|
||||
mt7530_write(priv, MT7530_VAWD2, 0);
|
||||
|
||||
return mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
|
||||
{
|
||||
|
|
@ -1641,6 +1691,8 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
|
|||
G0_PORT_VID_DEF);
|
||||
|
||||
for (i = 0; i < priv->ds->num_ports; i++) {
|
||||
if (i == port)
|
||||
continue;
|
||||
if (dsa_is_user_port(ds, i) &&
|
||||
dsa_port_is_vlan_filtering(dsa_to_port(ds, i))) {
|
||||
all_user_ports_removed = false;
|
||||
|
|
@ -1652,13 +1704,9 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
|
|||
* the CPU port get out of VLAN filtering mode.
|
||||
*/
|
||||
if (all_user_ports_removed) {
|
||||
struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
struct dsa_port *cpu_dp = dp->cpu_dp;
|
||||
|
||||
mt7530_write(priv, MT7530_PCR_P(cpu_dp->index),
|
||||
PCR_MATRIX(dsa_user_ports(priv->ds)));
|
||||
mt7530_write(priv, MT7530_PVC_P(cpu_dp->index), PORT_SPEC_TAG
|
||||
| PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
mt7530_setup_vlan0(priv);
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1846,33 +1894,6 @@ mt7530_port_mdb_del(struct dsa_switch *ds, int port,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
|
||||
{
|
||||
struct mt7530_dummy_poll p;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
|
||||
mt7530_write(priv, MT7530_VTCR, val);
|
||||
|
||||
INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
|
||||
ret = readx_poll_timeout(_mt7530_read, &p, val,
|
||||
!(val & VTCR_BUSY), 20, 20000);
|
||||
if (ret < 0) {
|
||||
dev_err(priv->dev, "poll timeout\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
val = mt7530_read(priv, MT7530_VTCR);
|
||||
if (val & VTCR_INVALID) {
|
||||
dev_err(priv->dev, "read VTCR invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
|
||||
struct netlink_ext_ack *extack)
|
||||
|
|
@ -1977,21 +1998,6 @@ mt7530_hw_vlan_update(struct mt7530_priv *priv, u16 vid,
|
|||
mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, vid);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7530_setup_vlan0(struct mt7530_priv *priv)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Validate the entry with independent learning, keep the original
|
||||
* ingress tag attribute.
|
||||
*/
|
||||
val = IVL_MAC | EG_CON | PORT_MEM(MT7530_ALL_MEMBERS) | FID(FID_BRIDGED) |
|
||||
VLAN_VALID;
|
||||
mt7530_write(priv, MT7530_VAWD1, val);
|
||||
|
||||
return mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7530_port_vlan_add(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_vlan *vlan,
|
||||
|
|
@ -2004,9 +2010,18 @@ mt7530_port_vlan_add(struct dsa_switch *ds, int port,
|
|||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
|
||||
/* VID 0 is managed exclusively by mt7530_setup_vlan0() for
|
||||
* VLAN-unaware bridge operation. Don't let the bridge overwrite
|
||||
* its EG_CON flag with VTAG_EN and corrupt PORT_MEM.
|
||||
*/
|
||||
if (vlan->vid == 0)
|
||||
goto skip_vlan_table;
|
||||
|
||||
mt7530_hw_vlan_entry_init(&new_entry, port, untagged);
|
||||
mt7530_hw_vlan_update(priv, vlan->vid, &new_entry, mt7530_hw_vlan_add);
|
||||
|
||||
skip_vlan_table:
|
||||
|
||||
if (pvid) {
|
||||
priv->ports[port].pvid = vlan->vid;
|
||||
|
||||
|
|
@ -2046,10 +2061,15 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,
|
|||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
|
||||
/* VID 0 is managed exclusively by mt7530_setup_vlan0(). */
|
||||
if (vlan->vid == 0)
|
||||
goto skip_vlan_table;
|
||||
|
||||
mt7530_hw_vlan_entry_init(&target_entry, port, 0);
|
||||
mt7530_hw_vlan_update(priv, vlan->vid, &target_entry,
|
||||
mt7530_hw_vlan_del);
|
||||
|
||||
skip_vlan_table:
|
||||
/* PVID is being restored to the default whenever the PVID port
|
||||
* is being removed from the VLAN.
|
||||
*/
|
||||
|
|
@ -2427,7 +2447,10 @@ mt7530_setup(struct dsa_switch *ds)
|
|||
}
|
||||
|
||||
ds->assisted_learning_on_cpu_port = true;
|
||||
ds->untag_vlan_aware_bridge_pvid = true;
|
||||
ds->mtu_enforcement_ingress = true;
|
||||
ds->ageing_time_min = 2 * 1000;
|
||||
ds->ageing_time_max = (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1) * 1000;
|
||||
|
||||
if (priv->id == ID_MT7530) {
|
||||
regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
|
||||
|
|
@ -2616,7 +2639,10 @@ mt7531_setup_common(struct dsa_switch *ds)
|
|||
int ret, i;
|
||||
|
||||
ds->assisted_learning_on_cpu_port = true;
|
||||
ds->untag_vlan_aware_bridge_pvid = true;
|
||||
ds->mtu_enforcement_ingress = true;
|
||||
ds->ageing_time_min = 2 * 1000;
|
||||
ds->ageing_time_max = (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1) * 1000;
|
||||
|
||||
mt753x_trap_frames(priv);
|
||||
|
||||
|
|
|
|||
1543
drivers/net/ethernet/3com/3c509.c
Normal file
1543
drivers/net/ethernet/3com/3c509.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -17,6 +17,20 @@ config NET_VENDOR_3COM
|
|||
|
||||
if NET_VENDOR_3COM
|
||||
|
||||
config EL3
|
||||
tristate "3c509/3c579 \"EtherLink III\" support"
|
||||
depends on (ISA || EISA)
|
||||
help
|
||||
If you have a network (Ethernet) card belonging to the 3Com
|
||||
EtherLinkIII series, say Y here.
|
||||
|
||||
If your card is not working you may need to use the DOS
|
||||
setup disk to disable Plug & Play mode, and to select the default
|
||||
media type.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called 3c509.
|
||||
|
||||
config VORTEX
|
||||
tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support"
|
||||
depends on (PCI || EISA) && HAS_IOPORT_MAP
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@
|
|||
# Makefile for the 3Com Ethernet device drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_EL3) += 3c509.o
|
||||
obj-$(CONFIG_VORTEX) += 3c59x.o
|
||||
obj-$(CONFIG_TYPHOON) += typhoon.o
|
||||
|
|
|
|||
|
|
@ -1793,11 +1793,8 @@ static int airoha_set_gdm2_loopback(struct airoha_gdm_port *port)
|
|||
u32 val, pse_port, chan;
|
||||
int i, src_port;
|
||||
|
||||
/* Forward the traffic to the proper GDM port */
|
||||
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
|
||||
: FE_PSE_PORT_GDM4;
|
||||
airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
|
||||
pse_port);
|
||||
FE_PSE_PORT_DROP);
|
||||
airoha_fe_clear(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
|
||||
GDM_STRIP_CRC_MASK);
|
||||
|
||||
|
|
@ -1815,6 +1812,11 @@ static int airoha_set_gdm2_loopback(struct airoha_gdm_port *port)
|
|||
GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
|
||||
FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
|
||||
FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_MTU));
|
||||
/* Forward the traffic to the proper GDM port */
|
||||
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
|
||||
: FE_PSE_PORT_GDM4;
|
||||
airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
|
||||
pse_port);
|
||||
|
||||
/* Disable VIP and IFC for GDM2 */
|
||||
airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX));
|
||||
|
|
|
|||
|
|
@ -64,9 +64,14 @@ DEFINE_SHOW_ATTRIBUTE(identity);
|
|||
|
||||
void pdsc_debugfs_add_ident(struct pdsc *pdsc)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
|
||||
/* This file will already exist in the reset flow */
|
||||
if (debugfs_lookup("identity", pdsc->dentry))
|
||||
dentry = debugfs_lookup("identity", pdsc->dentry);
|
||||
if (!IS_ERR_OR_NULL(dentry)) {
|
||||
dput(dentry);
|
||||
return;
|
||||
}
|
||||
|
||||
debugfs_create_file("identity", 0400, pdsc->dentry,
|
||||
pdsc, &identity_fops);
|
||||
|
|
|
|||
|
|
@ -162,12 +162,19 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds)
|
|||
dev_dbg(dev, "DEVCMD %d %s after %ld secs\n",
|
||||
opcode, pdsc_devcmd_str(opcode), duration / HZ);
|
||||
|
||||
if ((!done || timeout) && running) {
|
||||
if (!running) {
|
||||
dev_err(dev, "DEVCMD %d %s fw not running\n",
|
||||
opcode, pdsc_devcmd_str(opcode));
|
||||
pdsc_devcmd_clean(pdsc);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (!done || timeout) {
|
||||
dev_err(dev, "DEVCMD %d %s timeout, done %d timeout %d max_seconds=%d\n",
|
||||
opcode, pdsc_devcmd_str(opcode), done, timeout,
|
||||
max_seconds);
|
||||
err = -ETIMEDOUT;
|
||||
pdsc_devcmd_clean(pdsc);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
status = pdsc_devcmd_status(pdsc);
|
||||
|
|
|
|||
|
|
@ -122,12 +122,14 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
|
|||
|
||||
listlen = min(fw_list.num_fw_slots, ARRAY_SIZE(fw_list.fw_names));
|
||||
for (i = 0; i < listlen; i++) {
|
||||
char *fw_ver = fw_list.fw_names[i].fw_version;
|
||||
|
||||
if (i < ARRAY_SIZE(fw_slotnames))
|
||||
strscpy(buf, fw_slotnames[i], sizeof(buf));
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "fw.slot_%d", i);
|
||||
err = devlink_info_version_stored_put(req, buf,
|
||||
fw_list.fw_names[i].fw_version);
|
||||
fw_ver[sizeof(fw_list.fw_names[i].fw_version) - 1] = '\0';
|
||||
err = devlink_info_version_stored_put(req, buf, fw_ver);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1856,6 +1856,9 @@ static int ag71xx_probe(struct platform_device *pdev)
|
|||
ag71xx_int_disable(ag, AG71XX_INT_POLL);
|
||||
|
||||
ndev->irq = platform_get_irq(pdev, 0);
|
||||
if (ndev->irq < 0)
|
||||
return ndev->irq;
|
||||
|
||||
err = devm_request_irq(&pdev->dev, ndev->irq, ag71xx_interrupt,
|
||||
0x0, dev_name(&pdev->dev), ndev);
|
||||
if (err) {
|
||||
|
|
|
|||
|
|
@ -1368,13 +1368,12 @@ void bcmgenet_eee_enable_set(struct net_device *dev, bool enable)
|
|||
reg &= ~(TBUF_EEE_EN | TBUF_PM_EN);
|
||||
bcmgenet_writel(reg, priv->base + off);
|
||||
|
||||
/* Do the same for thing for RBUF */
|
||||
/* RBUF EEE/PM can break the RX path on GENET. Keep it disabled. */
|
||||
reg = bcmgenet_rbuf_readl(priv, RBUF_ENERGY_CTRL);
|
||||
if (enable)
|
||||
reg |= RBUF_EEE_EN | RBUF_PM_EN;
|
||||
else
|
||||
if (reg & (RBUF_EEE_EN | RBUF_PM_EN)) {
|
||||
reg &= ~(RBUF_EEE_EN | RBUF_PM_EN);
|
||||
bcmgenet_rbuf_writel(priv, reg, RBUF_ENERGY_CTRL);
|
||||
bcmgenet_rbuf_writel(priv, reg, RBUF_ENERGY_CTRL);
|
||||
}
|
||||
|
||||
if (!enable && priv->clk_eee_enabled) {
|
||||
clk_disable_unprepare(priv->clk_eee);
|
||||
|
|
|
|||
|
|
@ -56,11 +56,21 @@ static inline u32 enetc_vsi_set_msize(u32 size)
|
|||
}
|
||||
|
||||
#define ENETC_PSIMSGRR 0x204
|
||||
#define ENETC_PSIMSGRR_MR_MASK GENMASK(2, 1)
|
||||
#define ENETC_PSIMSGRR_MR(n) BIT((n) + 1) /* n = VSI index */
|
||||
#define ENETC_PSIVMSGRCVAR0(n) (0x210 + (n) * 0x8) /* n = VSI index */
|
||||
#define ENETC_PSIVMSGRCVAR1(n) (0x214 + (n) * 0x8)
|
||||
|
||||
/* Message received mask, n is the active number of VSIs.
|
||||
* It is available for ENETC_PSIMSGRR, ENETC_PSIIER, and
|
||||
* ENETC_PSIIDR registers.
|
||||
*/
|
||||
#define ENETC_PSIMR_MASK(n) \
|
||||
({ typeof(n) _n = (n); (_n) ? GENMASK((_n), 1) : 0; })
|
||||
|
||||
/* Message received bit, n is VSI index. It is available for
|
||||
* ENETC_PSIMSGRR, ENETC_PSIIER, and ENETC_PSIIDR registers.
|
||||
*/
|
||||
#define ENETC_PSIMR_BIT(n) BIT((n) + 1)
|
||||
|
||||
#define ENETC_VSIMSGSR 0x204 /* RO */
|
||||
#define ENETC_VSIMSGSR_MB BIT(0)
|
||||
#define ENETC_VSIMSGSR_MS BIT(1)
|
||||
|
|
@ -94,7 +104,6 @@ static inline u32 enetc_vsi_set_msize(u32 size)
|
|||
#define ENETC_SICAPR1 0x904
|
||||
|
||||
#define ENETC_PSIIER 0xa00
|
||||
#define ENETC_PSIIER_MR_MASK GENMASK(2, 1)
|
||||
#define ENETC_PSIIDR 0xa08
|
||||
#define ENETC_SITXIDR 0xa18
|
||||
#define ENETC_SIRXIDR 0xa28
|
||||
|
|
|
|||
|
|
@ -3,18 +3,25 @@
|
|||
|
||||
#include "enetc_pf.h"
|
||||
|
||||
static void enetc_msg_disable_mr_int(struct enetc_hw *hw)
|
||||
static void enetc_msg_disable_mr_int(struct enetc_pf *pf)
|
||||
{
|
||||
u32 psiier = enetc_rd(hw, ENETC_PSIIER);
|
||||
struct enetc_hw *hw = &pf->si->hw;
|
||||
u32 psiier;
|
||||
|
||||
psiier = enetc_rd(hw, ENETC_PSIIER) & ~ENETC_PSIMR_MASK(pf->num_vfs);
|
||||
|
||||
/* disable MR int source(s) */
|
||||
enetc_wr(hw, ENETC_PSIIER, psiier & ~ENETC_PSIIER_MR_MASK);
|
||||
enetc_wr(hw, ENETC_PSIIER, psiier);
|
||||
}
|
||||
|
||||
static void enetc_msg_enable_mr_int(struct enetc_hw *hw)
|
||||
static void enetc_msg_enable_mr_int(struct enetc_pf *pf)
|
||||
{
|
||||
u32 psiier = enetc_rd(hw, ENETC_PSIIER);
|
||||
struct enetc_hw *hw = &pf->si->hw;
|
||||
u32 psiier;
|
||||
|
||||
enetc_wr(hw, ENETC_PSIIER, psiier | ENETC_PSIIER_MR_MASK);
|
||||
psiier = enetc_rd(hw, ENETC_PSIIER) | ENETC_PSIMR_MASK(pf->num_vfs);
|
||||
|
||||
enetc_wr(hw, ENETC_PSIIER, psiier);
|
||||
}
|
||||
|
||||
static irqreturn_t enetc_msg_psi_msix(int irq, void *data)
|
||||
|
|
@ -22,7 +29,7 @@ static irqreturn_t enetc_msg_psi_msix(int irq, void *data)
|
|||
struct enetc_si *si = (struct enetc_si *)data;
|
||||
struct enetc_pf *pf = enetc_si_priv(si);
|
||||
|
||||
enetc_msg_disable_mr_int(&si->hw);
|
||||
enetc_msg_disable_mr_int(pf);
|
||||
schedule_work(&pf->msg_task);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -31,33 +38,35 @@ static irqreturn_t enetc_msg_psi_msix(int irq, void *data)
|
|||
static void enetc_msg_task(struct work_struct *work)
|
||||
{
|
||||
struct enetc_pf *pf = container_of(work, struct enetc_pf, msg_task);
|
||||
u32 mr_mask = ENETC_PSIMR_MASK(pf->num_vfs);
|
||||
struct enetc_hw *hw = &pf->si->hw;
|
||||
unsigned long mr_mask;
|
||||
u32 mr_status;
|
||||
int i;
|
||||
|
||||
for (;;) {
|
||||
mr_mask = enetc_rd(hw, ENETC_PSIMSGRR) & ENETC_PSIMSGRR_MR_MASK;
|
||||
if (!mr_mask) {
|
||||
/* re-arm MR interrupts, w1c the IDR reg */
|
||||
enetc_wr(hw, ENETC_PSIIDR, ENETC_PSIIER_MR_MASK);
|
||||
enetc_msg_enable_mr_int(hw);
|
||||
return;
|
||||
}
|
||||
mr_status = (enetc_rd(hw, ENETC_PSIMSGRR) & mr_mask) |
|
||||
(enetc_rd(hw, ENETC_PSIIDR) & mr_mask);
|
||||
if (!mr_status)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < pf->num_vfs; i++) {
|
||||
u32 psimsgrr;
|
||||
u16 msg_code;
|
||||
for (i = 0; i < pf->num_vfs; i++) {
|
||||
u32 psimsgrr;
|
||||
u16 msg_code;
|
||||
|
||||
if (!(ENETC_PSIMSGRR_MR(i) & mr_mask))
|
||||
continue;
|
||||
if (!(ENETC_PSIMR_BIT(i) & mr_status))
|
||||
continue;
|
||||
|
||||
enetc_msg_handle_rxmsg(pf, i, &msg_code);
|
||||
enetc_msg_handle_rxmsg(pf, i, &msg_code);
|
||||
|
||||
psimsgrr = ENETC_SIMSGSR_SET_MC(msg_code);
|
||||
psimsgrr |= ENETC_PSIMSGRR_MR(i); /* w1c */
|
||||
enetc_wr(hw, ENETC_PSIMSGRR, psimsgrr);
|
||||
}
|
||||
/* w1c to clear the corresponding VF MR bit */
|
||||
enetc_wr(hw, ENETC_PSIIDR, ENETC_PSIMR_BIT(i));
|
||||
|
||||
psimsgrr = ENETC_SIMSGSR_SET_MC(msg_code);
|
||||
psimsgrr |= ENETC_PSIMR_BIT(i); /* w1c */
|
||||
enetc_wr(hw, ENETC_PSIMSGRR, psimsgrr);
|
||||
}
|
||||
|
||||
out:
|
||||
enetc_msg_enable_mr_int(pf);
|
||||
}
|
||||
|
||||
/* Init */
|
||||
|
|
@ -96,12 +105,12 @@ static void enetc_msg_free_mbx(struct enetc_si *si, int idx)
|
|||
struct enetc_hw *hw = &si->hw;
|
||||
struct enetc_msg_swbd *msg;
|
||||
|
||||
enetc_wr(hw, ENETC_PSIVMSGRCVAR0(idx), 0);
|
||||
enetc_wr(hw, ENETC_PSIVMSGRCVAR1(idx), 0);
|
||||
|
||||
msg = &pf->rxmsg[idx];
|
||||
dma_free_coherent(&si->pdev->dev, msg->size, msg->vaddr, msg->dma);
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
|
||||
enetc_wr(hw, ENETC_PSIVMSGRCVAR0(idx), 0);
|
||||
enetc_wr(hw, ENETC_PSIVMSGRCVAR1(idx), 0);
|
||||
}
|
||||
|
||||
int enetc_msg_psi_init(struct enetc_pf *pf)
|
||||
|
|
@ -109,6 +118,15 @@ int enetc_msg_psi_init(struct enetc_pf *pf)
|
|||
struct enetc_si *si = pf->si;
|
||||
int vector, i, err;
|
||||
|
||||
for (i = 0; i < pf->num_vfs; i++) {
|
||||
err = enetc_msg_alloc_mbx(si, i);
|
||||
if (err)
|
||||
goto free_mbx;
|
||||
}
|
||||
|
||||
/* initialize PSI mailbox */
|
||||
INIT_WORK(&pf->msg_task, enetc_msg_task);
|
||||
|
||||
/* register message passing interrupt handler */
|
||||
snprintf(pf->msg_int_name, sizeof(pf->msg_int_name), "%s-vfmsg",
|
||||
si->ndev->name);
|
||||
|
|
@ -117,32 +135,21 @@ int enetc_msg_psi_init(struct enetc_pf *pf)
|
|||
if (err) {
|
||||
dev_err(&si->pdev->dev,
|
||||
"PSI messaging: request_irq() failed!\n");
|
||||
return err;
|
||||
goto free_mbx;
|
||||
}
|
||||
|
||||
/* set one IRQ entry for PSI message receive notification (SI int) */
|
||||
enetc_wr(&si->hw, ENETC_SIMSIVR, ENETC_SI_INT_IDX);
|
||||
|
||||
/* initialize PSI mailbox */
|
||||
INIT_WORK(&pf->msg_task, enetc_msg_task);
|
||||
|
||||
for (i = 0; i < pf->num_vfs; i++) {
|
||||
err = enetc_msg_alloc_mbx(si, i);
|
||||
if (err)
|
||||
goto err_init_mbx;
|
||||
}
|
||||
|
||||
/* enable MR interrupts */
|
||||
enetc_msg_enable_mr_int(&si->hw);
|
||||
enetc_msg_enable_mr_int(pf);
|
||||
|
||||
return 0;
|
||||
|
||||
err_init_mbx:
|
||||
free_mbx:
|
||||
for (i--; i >= 0; i--)
|
||||
enetc_msg_free_mbx(si, i);
|
||||
|
||||
free_irq(vector, si);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -151,14 +158,17 @@ void enetc_msg_psi_free(struct enetc_pf *pf)
|
|||
struct enetc_si *si = pf->si;
|
||||
int i;
|
||||
|
||||
cancel_work_sync(&pf->msg_task);
|
||||
|
||||
/* disable MR interrupts */
|
||||
enetc_msg_disable_mr_int(&si->hw);
|
||||
|
||||
for (i = 0; i < pf->num_vfs; i++)
|
||||
enetc_msg_free_mbx(si, i);
|
||||
enetc_msg_disable_mr_int(pf);
|
||||
|
||||
/* de-register message passing interrupt handler */
|
||||
free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si);
|
||||
|
||||
cancel_work_sync(&pf->msg_task);
|
||||
|
||||
/* MR interrupts may be re-enabled by workqueue */
|
||||
enetc_msg_disable_mr_int(pf);
|
||||
|
||||
for (i = 0; i < pf->num_vfs; i++)
|
||||
enetc_msg_free_mbx(si, i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,8 +252,12 @@ static int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)
|
|||
return -EADDRNOTAVAIL;
|
||||
|
||||
vf_state = &pf->vf_state[vf];
|
||||
|
||||
mutex_lock(&vf_state->lock);
|
||||
vf_state->flags |= ENETC_VF_FLAG_PF_SET_MAC;
|
||||
enetc_pf_set_primary_mac_addr(&priv->si->hw, vf + 1, mac);
|
||||
mutex_unlock(&vf_state->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -478,49 +482,77 @@ static void enetc_configure_port(struct enetc_pf *pf)
|
|||
|
||||
/* Messaging */
|
||||
static u16 enetc_msg_pf_set_vf_primary_mac_addr(struct enetc_pf *pf,
|
||||
int vf_id)
|
||||
int vf_id, void *msg)
|
||||
{
|
||||
struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
|
||||
struct enetc_msg_swbd *msg = &pf->rxmsg[vf_id];
|
||||
struct enetc_msg_cmd_set_primary_mac *cmd;
|
||||
struct enetc_msg_cmd_set_primary_mac *cmd = msg;
|
||||
struct device *dev = &pf->si->pdev->dev;
|
||||
u16 cmd_id;
|
||||
u16 cmd_id = cmd->header.id;
|
||||
char *addr;
|
||||
|
||||
cmd = (struct enetc_msg_cmd_set_primary_mac *)msg->vaddr;
|
||||
cmd_id = cmd->header.id;
|
||||
if (cmd_id != ENETC_MSG_CMD_MNG_ADD)
|
||||
return ENETC_MSG_CMD_STATUS_FAIL;
|
||||
|
||||
addr = cmd->mac.sa_data;
|
||||
if (vf_state->flags & ENETC_VF_FLAG_PF_SET_MAC)
|
||||
dev_warn(dev, "Attempt to override PF set mac addr for VF%d\n",
|
||||
vf_id);
|
||||
else
|
||||
enetc_pf_set_primary_mac_addr(&pf->si->hw, vf_id + 1, addr);
|
||||
if (!is_valid_ether_addr(addr)) {
|
||||
dev_err_ratelimited(dev, "VF%d attempted to set invalid MAC\n",
|
||||
vf_id);
|
||||
return ENETC_MSG_CMD_STATUS_FAIL;
|
||||
}
|
||||
|
||||
mutex_lock(&vf_state->lock);
|
||||
if (vf_state->flags & ENETC_VF_FLAG_PF_SET_MAC) {
|
||||
mutex_unlock(&vf_state->lock);
|
||||
dev_err_ratelimited(dev,
|
||||
"VF%d attempted to override PF set MAC\n",
|
||||
vf_id);
|
||||
return ENETC_MSG_CMD_STATUS_FAIL;
|
||||
}
|
||||
|
||||
enetc_pf_set_primary_mac_addr(&pf->si->hw, vf_id + 1, addr);
|
||||
mutex_unlock(&vf_state->lock);
|
||||
|
||||
return ENETC_MSG_CMD_STATUS_OK;
|
||||
}
|
||||
|
||||
void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id, u16 *status)
|
||||
{
|
||||
struct enetc_msg_swbd *msg = &pf->rxmsg[vf_id];
|
||||
struct enetc_msg_swbd *msg_swbd = &pf->rxmsg[vf_id];
|
||||
struct device *dev = &pf->si->pdev->dev;
|
||||
struct enetc_msg_cmd_header *cmd_hdr;
|
||||
u16 cmd_type;
|
||||
u8 *msg;
|
||||
|
||||
*status = ENETC_MSG_CMD_STATUS_OK;
|
||||
cmd_hdr = (struct enetc_msg_cmd_header *)msg->vaddr;
|
||||
msg = kzalloc_objs(*msg, msg_swbd->size);
|
||||
if (!msg) {
|
||||
dev_err_ratelimited(dev,
|
||||
"Failed to allocate message buffer\n");
|
||||
*status = ENETC_MSG_CMD_STATUS_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Currently, only ENETC_MSG_CMD_MNG_MAC command is supported, so
|
||||
* only sizeof(struct enetc_msg_cmd_set_primary_mac) bytes need to
|
||||
* be copied. This data already includes the cmd_type field, so it
|
||||
* can correctly return an error code.
|
||||
*/
|
||||
memcpy(msg, msg_swbd->vaddr,
|
||||
sizeof(struct enetc_msg_cmd_set_primary_mac));
|
||||
cmd_hdr = (struct enetc_msg_cmd_header *)msg;
|
||||
cmd_type = cmd_hdr->type;
|
||||
|
||||
switch (cmd_type) {
|
||||
case ENETC_MSG_CMD_MNG_MAC:
|
||||
*status = enetc_msg_pf_set_vf_primary_mac_addr(pf, vf_id);
|
||||
*status = enetc_msg_pf_set_vf_primary_mac_addr(pf, vf_id, msg);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "command not supported (cmd_type: 0x%x)\n",
|
||||
cmd_type);
|
||||
*status = ENETC_MSG_CMD_STATUS_FAIL;
|
||||
dev_err_ratelimited(dev,
|
||||
"command not supported (cmd_type: 0x%x)\n",
|
||||
cmd_type);
|
||||
}
|
||||
|
||||
kfree(msg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
|
|
@ -531,9 +563,9 @@ static int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
|
|||
int err;
|
||||
|
||||
if (!num_vfs) {
|
||||
pci_disable_sriov(pdev);
|
||||
enetc_msg_psi_free(pf);
|
||||
pf->num_vfs = 0;
|
||||
pci_disable_sriov(pdev);
|
||||
} else {
|
||||
pf->num_vfs = num_vfs;
|
||||
|
||||
|
|
@ -960,8 +992,13 @@ static int enetc_pf_probe(struct pci_dev *pdev,
|
|||
if (pf->total_vfs) {
|
||||
pf->vf_state = kzalloc_objs(struct enetc_vf_state,
|
||||
pf->total_vfs);
|
||||
if (!pf->vf_state)
|
||||
if (!pf->vf_state) {
|
||||
err = -ENOMEM;
|
||||
goto err_alloc_vf_state;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pf->total_vfs; i++)
|
||||
mutex_init(&pf->vf_state[i].lock);
|
||||
}
|
||||
|
||||
err = enetc_setup_mac_addresses(node, pf);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ enum enetc_vf_flags {
|
|||
};
|
||||
|
||||
struct enetc_vf_state {
|
||||
struct mutex lock; /* Prevent concurrent access */
|
||||
enum enetc_vf_flags flags;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3682,7 +3682,7 @@ int ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
|
|||
ret = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx,
|
||||
ICE_MCAST_VLAN_PROMISC_BITS,
|
||||
vid);
|
||||
if (ret)
|
||||
if (ret && ret != -EEXIST)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
|
@ -4104,6 +4104,12 @@ int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked)
|
|||
}
|
||||
ice_pf_dcb_recfg(pf, locked);
|
||||
ice_vsi_open(vsi);
|
||||
/* Rx rings are reallocated during VSI rebuild and lose their ptp_rx
|
||||
* flag. Restore timestamp mode so newly allocated rings are set up
|
||||
* for hardware Rx timestamping.
|
||||
*/
|
||||
if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
|
||||
ice_ptp_restore_timestamp_mode(pf);
|
||||
goto done;
|
||||
|
||||
rebuild_err:
|
||||
|
|
|
|||
|
|
@ -2141,16 +2141,23 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port)
|
|||
}
|
||||
incval = (u64)hi << 32 | lo;
|
||||
|
||||
if (!ice_ptp_lock(hw)) {
|
||||
dev_err(ice_hw_to_dev(hw), "Failed to acquire PTP semaphore\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
err = ice_write_40b_ptp_reg_eth56g(hw, port, PHY_REG_TIMETUS_L, incval);
|
||||
if (err)
|
||||
return err;
|
||||
goto err_ptp_unlock;
|
||||
|
||||
err = ice_ptp_one_port_cmd(hw, port, ICE_PTP_INIT_INCVAL);
|
||||
if (err)
|
||||
return err;
|
||||
goto err_ptp_unlock;
|
||||
|
||||
ice_ptp_exec_tmr_cmd(hw);
|
||||
|
||||
ice_ptp_unlock(hw);
|
||||
|
||||
err = ice_sync_phy_timer_eth56g(hw, port);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
@ -2166,6 +2173,10 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port)
|
|||
ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port);
|
||||
|
||||
return 0;
|
||||
|
||||
err_ptp_unlock:
|
||||
ice_ptp_unlock(hw);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -4503,18 +4514,17 @@ static int
|
|||
ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
|
||||
{
|
||||
struct ice_e810_params *params = &hw->ptp.phy.e810;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
spin_lock_irqsave(¶ms->atqbal_wq.lock, flags);
|
||||
spin_lock_irq(¶ms->atqbal_wq.lock);
|
||||
|
||||
/* Wait for any pending in-progress low latency interrupt */
|
||||
err = wait_event_interruptible_locked_irq(params->atqbal_wq,
|
||||
!(params->atqbal_flags &
|
||||
ATQBAL_FLAGS_INTR_IN_PROGRESS));
|
||||
if (err) {
|
||||
spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -4529,7 +4539,7 @@ ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
|
|||
REG_LL_PROXY_H);
|
||||
if (err) {
|
||||
ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n");
|
||||
spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -4539,7 +4549,7 @@ ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
|
|||
/* Read the low 32 bit value and set the TS valid bit */
|
||||
*lo = rd32(hw, REG_LL_PROXY_L) | TS_VALID;
|
||||
|
||||
spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -5254,9 +5264,13 @@ static void ice_ptp_init_phy_e830(struct ice_ptp_hw *ptp)
|
|||
*/
|
||||
bool ice_ptp_lock(struct ice_hw *hw)
|
||||
{
|
||||
struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
|
||||
u32 hw_lock;
|
||||
int i;
|
||||
|
||||
if (!ice_is_primary(hw))
|
||||
hw = ice_get_primary_hw(pf);
|
||||
|
||||
#define MAX_TRIES 15
|
||||
|
||||
for (i = 0; i < MAX_TRIES; i++) {
|
||||
|
|
@ -5283,6 +5297,11 @@ bool ice_ptp_lock(struct ice_hw *hw)
|
|||
*/
|
||||
void ice_ptp_unlock(struct ice_hw *hw)
|
||||
{
|
||||
struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
|
||||
|
||||
if (!ice_is_primary(hw))
|
||||
hw = ice_get_primary_hw(pf);
|
||||
|
||||
wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -840,7 +840,7 @@ int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
|
|||
|
||||
if (qpi->rxq.databuffer_size != 0 &&
|
||||
(qpi->rxq.databuffer_size > ((16 * 1024) - 128) ||
|
||||
qpi->rxq.databuffer_size < 1024))
|
||||
qpi->rxq.databuffer_size < 128))
|
||||
goto error_param;
|
||||
|
||||
ring->rx_buf_len = qpi->rxq.databuffer_size;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ static int igc_fpe_init_smd_frame(struct igc_ring *ring,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
buffer->type = IGC_TX_BUFFER_TYPE_SKB;
|
||||
buffer->skb = skb;
|
||||
buffer->protocol = 0;
|
||||
buffer->bytecount = skb->len;
|
||||
|
|
@ -109,10 +110,16 @@ static int igc_fpe_xmit_smd_frame(struct igc_adapter *adapter,
|
|||
__netif_tx_lock(nq, cpu);
|
||||
|
||||
err = igc_fpe_init_tx_descriptor(ring, skb, type);
|
||||
if (err)
|
||||
goto err_free_skb_any;
|
||||
|
||||
igc_flush_tx_descriptors(ring);
|
||||
|
||||
__netif_tx_unlock(nq);
|
||||
return 0;
|
||||
|
||||
err_free_skb_any:
|
||||
__netif_tx_unlock(nq);
|
||||
dev_kfree_skb_any(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1221,6 +1221,7 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
|
|||
ether_addr_equal(rx_ring->netdev->dev_addr,
|
||||
eth_hdr(skb)->h_source)) {
|
||||
dev_kfree_skb_irq(skb);
|
||||
skb = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1294,13 +1294,18 @@ static inline void link_status_user_format(u64 lstat,
|
|||
struct cgx_link_user_info *linfo,
|
||||
struct cgx *cgx, u8 lmac_id)
|
||||
{
|
||||
unsigned int speed;
|
||||
|
||||
linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat);
|
||||
linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat);
|
||||
linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)];
|
||||
linfo->an = FIELD_GET(RESP_LINKSTAT_AN, lstat);
|
||||
linfo->fec = FIELD_GET(RESP_LINKSTAT_FEC, lstat);
|
||||
linfo->lmac_type_id = FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, lstat);
|
||||
|
||||
speed = FIELD_GET(RESP_LINKSTAT_SPEED, lstat);
|
||||
linfo->speed = speed < ARRAY_SIZE(cgx_speed_mbps) ?
|
||||
cgx_speed_mbps[speed] : 0;
|
||||
|
||||
if (linfo->lmac_type_id >= LMAC_MODE_MAX) {
|
||||
dev_err(&cgx->pdev->dev, "Unknown lmac_type_id %d reported by firmware on cgx port%d:%d",
|
||||
linfo->lmac_type_id, cgx->cgx_id, lmac_id);
|
||||
|
|
|
|||
|
|
@ -990,7 +990,7 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
|
|||
u16 vf_func;
|
||||
|
||||
/* Only CGX PF/VF can add allmulticast entry */
|
||||
if (is_lbk_vf(rvu, pcifunc) && is_sdp_vf(rvu, pcifunc))
|
||||
if (is_lbk_vf(rvu, pcifunc) || is_sdp_vf(rvu, pcifunc))
|
||||
return;
|
||||
|
||||
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
|
||||
|
|
|
|||
|
|
@ -619,11 +619,13 @@ static int cn20k_pool_aq_init(struct otx2_nic *pfvf, u16 pool_id,
|
|||
err = otx2_sync_mbox_msg(&pfvf->mbox);
|
||||
if (err) {
|
||||
qmem_free(pfvf->dev, pool->stack);
|
||||
pool->stack = NULL;
|
||||
return err;
|
||||
}
|
||||
aq = otx2_mbox_alloc_msg_npa_cn20k_aq_enq(&pfvf->mbox);
|
||||
if (!aq) {
|
||||
qmem_free(pfvf->dev, pool->stack);
|
||||
pool->stack = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1482,11 +1482,13 @@ int otx2_pool_aq_init(struct otx2_nic *pfvf, u16 pool_id,
|
|||
err = otx2_sync_mbox_msg(&pfvf->mbox);
|
||||
if (err) {
|
||||
qmem_free(pfvf->dev, pool->stack);
|
||||
pool->stack = NULL;
|
||||
return err;
|
||||
}
|
||||
aq = otx2_mbox_alloc_msg_npa_aq_enq(&pfvf->mbox);
|
||||
if (!aq) {
|
||||
qmem_free(pfvf->dev, pool->stack);
|
||||
pool->stack = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -609,7 +609,7 @@ static int rvu_rep_rsrc_init(struct otx2_nic *priv)
|
|||
|
||||
err = otx2_init_hw_resources(priv);
|
||||
if (err)
|
||||
goto err_free_rsrc;
|
||||
goto err_free_mem;
|
||||
|
||||
/* Set maximum frame size allowed in HW */
|
||||
err = otx2_hw_set_mtu(priv, priv->hw.max_mtu);
|
||||
|
|
@ -621,6 +621,7 @@ static int rvu_rep_rsrc_init(struct otx2_nic *priv)
|
|||
|
||||
err_free_rsrc:
|
||||
otx2_free_hw_resources(priv);
|
||||
err_free_mem:
|
||||
otx2_free_queue_mem(qset);
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,13 +160,13 @@ static int mlx5e_tx_reporter_timeout_recover(void *ctx)
|
|||
* channels are being closed for other reason and this work is not
|
||||
* relevant anymore.
|
||||
*/
|
||||
while (!netdev_trylock(sq->netdev)) {
|
||||
while (!netdev_trylock(priv->netdev)) {
|
||||
if (!test_bit(MLX5E_STATE_CHANNELS_ACTIVE, &priv->state))
|
||||
return 0;
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
err = mlx5e_health_channel_eq_recover(sq->netdev, eq, sq->cq.ch_stats);
|
||||
err = mlx5e_health_channel_eq_recover(priv->netdev, eq, sq->cq.ch_stats);
|
||||
if (!err) {
|
||||
to_ctx->status = 0; /* this sq recovered */
|
||||
goto out;
|
||||
|
|
@ -186,7 +186,7 @@ static int mlx5e_tx_reporter_timeout_recover(void *ctx)
|
|||
"mlx5e_safe_reopen_channels failed recovering from a tx_timeout, err(%d).\n",
|
||||
err);
|
||||
out:
|
||||
netdev_unlock(sq->netdev);
|
||||
netdev_unlock(priv->netdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -792,8 +792,10 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
|
|||
sa_entry->dev = dev;
|
||||
sa_entry->ipsec = ipsec;
|
||||
/* Check if this SA is originated from acquire flow temporary SA */
|
||||
if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ)
|
||||
goto out;
|
||||
if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ) {
|
||||
x->xso.offload_handle = (unsigned long)sa_entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = mlx5e_xfrm_validate_state(priv->mdev, x, extack);
|
||||
if (err)
|
||||
|
|
@ -870,7 +872,6 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
|
|||
xa_unlock_bh(&ipsec->sadb);
|
||||
}
|
||||
|
||||
out:
|
||||
x->xso.offload_handle = (unsigned long)sa_entry;
|
||||
if (allow_tunnel_mode)
|
||||
mlx5_eswitch_unblock_encap(priv->mdev);
|
||||
|
|
|
|||
|
|
@ -1574,8 +1574,11 @@ static int mlx5e_create_rxfh_context(struct net_device *dev,
|
|||
rxfh->indir, rxfh->key,
|
||||
hfunc == ETH_RSS_HASH_NO_CHANGE ? NULL : &hfunc,
|
||||
rxfh->input_xfrm == RXH_XFRM_NO_CHANGE ? NULL : &symmetric);
|
||||
if (err)
|
||||
if (err) {
|
||||
WARN_ON(mlx5e_rx_res_rss_destroy(priv->rx_res,
|
||||
rxfh->rss_context));
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
mlx5e_rx_res_rss_get_rxfh(priv->rx_res, rxfh->rss_context,
|
||||
ethtool_rxfh_context_indir(ctx),
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
|
|||
mlx5e_cq_arm(&c->xdpsq->cq);
|
||||
|
||||
if (unlikely(aff_change && busy_xsk)) {
|
||||
mlx5e_trigger_irq(&c->icosq);
|
||||
mlx5e_trigger_napi_async_icosq(c);
|
||||
ch_stats->force_irq++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -142,7 +142,8 @@ static int mlx5_esw_ipsec_modify_flow_dests(struct mlx5_eswitch *esw,
|
|||
|
||||
attr = flow->attr;
|
||||
esw_attr = attr->esw_attr;
|
||||
if (esw_attr->out_count - esw_attr->split_count > 1)
|
||||
if (!esw_attr->out_count ||
|
||||
esw_attr->out_count - esw_attr->split_count > 1)
|
||||
return 0;
|
||||
|
||||
err = mlx5_eswitch_restore_ipsec_rule(esw, flow->rule[0], esw_attr,
|
||||
|
|
|
|||
|
|
@ -908,6 +908,24 @@ static void esw_vport_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport
|
|||
esw_vport_cleanup_acl(esw, vport);
|
||||
}
|
||||
|
||||
static void mlx5_esw_vport_set_max_tx_speed(struct mlx5_eswitch *esw,
|
||||
struct mlx5_vport *vport)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!MLX5_CAP_ESW(esw->dev, esw_vport_state_max_tx_speed))
|
||||
return;
|
||||
|
||||
ret = mlx5_modify_vport_max_tx_speed(esw->dev,
|
||||
MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
|
||||
vport->vport, true,
|
||||
vport->agg_max_tx_speed);
|
||||
if (ret)
|
||||
mlx5_core_dbg(esw->dev,
|
||||
"Failed to set vport %d speed %d, err=%d\n",
|
||||
vport->vport, vport->agg_max_tx_speed, ret);
|
||||
}
|
||||
|
||||
int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
|
||||
enum mlx5_eswitch_vport_event enabled_events)
|
||||
{
|
||||
|
|
@ -948,6 +966,9 @@ int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
|
|||
|
||||
esw->enabled_vports++;
|
||||
esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num);
|
||||
|
||||
if (vport->agg_max_tx_speed)
|
||||
mlx5_esw_vport_set_max_tx_speed(esw, vport);
|
||||
done:
|
||||
mutex_unlock(&esw->state_lock);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -247,6 +247,7 @@ struct mlx5_vport {
|
|||
enum mlx5_eswitch_vport_event enabled_events;
|
||||
int index;
|
||||
struct mlx5_devlink_port *dl_port;
|
||||
u32 agg_max_tx_speed;
|
||||
};
|
||||
|
||||
struct mlx5_esw_indir_table;
|
||||
|
|
|
|||
|
|
@ -1274,6 +1274,11 @@ static void mlx5_lag_modify_device_vports_speed(struct mlx5_core_dev *mdev,
|
|||
if (vport->vport == MLX5_VPORT_UPLINK)
|
||||
continue;
|
||||
|
||||
vport->agg_max_tx_speed = speed;
|
||||
|
||||
if (!vport->enabled)
|
||||
continue;
|
||||
|
||||
ret = mlx5_modify_vport_max_tx_speed(mdev, op_mod,
|
||||
vport->vport, true, speed);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -77,21 +77,19 @@ static int mana_hwc_post_rx_wqe(const struct hwc_wq *hwc_rxq,
|
|||
}
|
||||
|
||||
static void mana_hwc_handle_resp(struct hw_channel_context *hwc, u32 resp_len,
|
||||
struct hwc_work_request *rx_req)
|
||||
struct hwc_work_request *rx_req, u16 msg_id)
|
||||
{
|
||||
const struct gdma_resp_hdr *resp_msg = rx_req->buf_va;
|
||||
struct hwc_caller_ctx *ctx;
|
||||
int err;
|
||||
|
||||
if (!test_bit(resp_msg->response.hwc_msg_id,
|
||||
hwc->inflight_msg_res.map)) {
|
||||
dev_err(hwc->dev, "hwc_rx: invalid msg_id = %u\n",
|
||||
resp_msg->response.hwc_msg_id);
|
||||
if (!test_bit(msg_id, hwc->inflight_msg_res.map)) {
|
||||
dev_err(hwc->dev, "hwc_rx: invalid msg_id = %u\n", msg_id);
|
||||
mana_hwc_post_rx_wqe(hwc->rxq, rx_req);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = hwc->caller_ctx + resp_msg->response.hwc_msg_id;
|
||||
ctx = hwc->caller_ctx + msg_id;
|
||||
err = mana_hwc_verify_resp_msg(ctx, resp_msg, resp_len);
|
||||
if (err)
|
||||
goto out;
|
||||
|
|
@ -251,6 +249,7 @@ static void mana_hwc_rx_event_handler(void *ctx, u32 gdma_rxq_id,
|
|||
struct gdma_sge *sge;
|
||||
u64 rq_base_addr;
|
||||
u64 rx_req_idx;
|
||||
u16 msg_id;
|
||||
u8 *wqe;
|
||||
|
||||
if (WARN_ON_ONCE(hwc_rxq->gdma_wq->id != gdma_rxq_id))
|
||||
|
|
@ -266,16 +265,26 @@ static void mana_hwc_rx_event_handler(void *ctx, u32 gdma_rxq_id,
|
|||
rq_base_addr = hwc_rxq->msg_buf->mem_info.dma_handle;
|
||||
rx_req_idx = (sge->address - rq_base_addr) / hwc->max_req_msg_size;
|
||||
|
||||
rx_req = &hwc_rxq->msg_buf->reqs[rx_req_idx];
|
||||
resp = (struct gdma_resp_hdr *)rx_req->buf_va;
|
||||
|
||||
if (resp->response.hwc_msg_id >= hwc->num_inflight_msg) {
|
||||
dev_err(hwc->dev, "HWC RX: wrong msg_id=%u\n",
|
||||
resp->response.hwc_msg_id);
|
||||
if (rx_req_idx >= hwc_rxq->msg_buf->num_reqs) {
|
||||
dev_err(hwc->dev, "HWC RX: wrong rx_req_idx=%llu, num_reqs=%u\n",
|
||||
rx_req_idx, hwc_rxq->msg_buf->num_reqs);
|
||||
return;
|
||||
}
|
||||
|
||||
mana_hwc_handle_resp(hwc, rx_oob->tx_oob_data_size, rx_req);
|
||||
rx_req = &hwc_rxq->msg_buf->reqs[rx_req_idx];
|
||||
resp = (struct gdma_resp_hdr *)rx_req->buf_va;
|
||||
|
||||
/* Read msg_id once from DMA buffer to prevent TOCTOU:
|
||||
* DMA memory is shared/unencrypted in CVMs - host can
|
||||
* modify it between reads.
|
||||
*/
|
||||
msg_id = READ_ONCE(resp->response.hwc_msg_id);
|
||||
if (msg_id >= hwc->num_inflight_msg) {
|
||||
dev_err(hwc->dev, "HWC RX: wrong msg_id=%u\n", msg_id);
|
||||
return;
|
||||
}
|
||||
|
||||
mana_hwc_handle_resp(hwc, rx_oob->tx_oob_data_size, rx_req, msg_id);
|
||||
|
||||
/* Can no longer use 'resp', because the buffer is posted to the HW
|
||||
* in mana_hwc_handle_resp() above.
|
||||
|
|
|
|||
|
|
@ -1036,11 +1036,13 @@ static void qed_cid_map_free(struct qed_hwfn *p_hwfn)
|
|||
|
||||
for (type = 0; type < MAX_CONN_TYPES; type++) {
|
||||
bitmap_free(p_mngr->acquired[type].cid_map);
|
||||
p_mngr->acquired[type].cid_map = NULL;
|
||||
p_mngr->acquired[type].max_count = 0;
|
||||
p_mngr->acquired[type].start_cid = 0;
|
||||
|
||||
for (vf = 0; vf < MAX_NUM_VFS; vf++) {
|
||||
bitmap_free(p_mngr->acquired_vf[type][vf].cid_map);
|
||||
p_mngr->acquired_vf[type][vf].cid_map = NULL;
|
||||
p_mngr->acquired_vf[type][vf].max_count = 0;
|
||||
p_mngr->acquired_vf[type][vf].start_cid = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,8 +213,8 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
|
|||
ep = rmnet_get_endpoint(real_port, mux_id);
|
||||
if (ep) {
|
||||
hlist_del_init_rcu(&ep->hlnode);
|
||||
rmnet_vnd_dellink(mux_id, real_port, ep);
|
||||
kfree(ep);
|
||||
real_port->nr_rmnet_devs--;
|
||||
kfree_rcu(ep, rcu);
|
||||
}
|
||||
|
||||
netdev_upper_dev_unlink(real_dev, dev);
|
||||
|
|
@ -238,9 +238,9 @@ static void rmnet_force_unassociate_device(struct net_device *real_dev)
|
|||
hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
|
||||
unregister_netdevice_queue(ep->egress_dev, &list);
|
||||
netdev_upper_dev_unlink(real_dev, ep->egress_dev);
|
||||
rmnet_vnd_dellink(ep->mux_id, port, ep);
|
||||
hlist_del_init_rcu(&ep->hlnode);
|
||||
kfree(ep);
|
||||
port->nr_rmnet_devs--;
|
||||
kfree_rcu(ep, rcu);
|
||||
}
|
||||
rmnet_unregister_real_device(real_dev);
|
||||
unregister_netdevice_many(&list);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ struct rmnet_endpoint {
|
|||
u8 mux_id;
|
||||
struct net_device *egress_dev;
|
||||
struct hlist_node hlnode;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
struct rmnet_egress_agg_params {
|
||||
|
|
|
|||
|
|
@ -28,13 +28,16 @@
|
|||
|
||||
/*
|
||||
* TX/RX Clock Delay Bit Masks:
|
||||
* - TX Delay: bits [14:8] — TX_CLK delay (unit: 0.1ns per bit)
|
||||
* - RX Delay: bits [30:24] — RX_CLK delay (unit: 0.1ns per bit)
|
||||
* - TX Delay: bits [14:8] — TX_CLK delay (unit: 0.02ns per bit)
|
||||
* - RX Delay: bits [30:24] — RX_CLK delay (unit: 0.02ns per bit)
|
||||
*/
|
||||
#define EIC7700_ETH_TX_ADJ_DELAY GENMASK(14, 8)
|
||||
#define EIC7700_ETH_RX_ADJ_DELAY GENMASK(30, 24)
|
||||
|
||||
#define EIC7700_MAX_DELAY_UNIT 0x7F
|
||||
#define EIC7700_MAX_DELAY_STEPS 0x7F
|
||||
#define EIC7700_DELAY_STEP_PS 20
|
||||
#define EIC7700_MAX_DELAY_PS \
|
||||
(EIC7700_MAX_DELAY_STEPS * EIC7700_DELAY_STEP_PS)
|
||||
|
||||
static const char * const eic7700_clk_names[] = {
|
||||
"tx", "axi", "cfg",
|
||||
|
|
@ -42,6 +45,15 @@ static const char * const eic7700_clk_names[] = {
|
|||
|
||||
struct eic7700_qos_priv {
|
||||
struct plat_stmmacenet_data *plat_dat;
|
||||
struct regmap *eic7700_hsp_regmap;
|
||||
u32 eth_axi_lp_ctrl_offset;
|
||||
u32 eth_phy_ctrl_offset;
|
||||
u32 eth_clk_offset;
|
||||
u32 eth_txd_offset;
|
||||
u32 eth_rxd_offset;
|
||||
u32 eth_clk_dly_param;
|
||||
bool has_txd_offset;
|
||||
bool has_rxd_offset;
|
||||
};
|
||||
|
||||
static int eic7700_clks_config(void *priv, bool enabled)
|
||||
|
|
@ -61,8 +73,34 @@ static int eic7700_clks_config(void *priv, bool enabled)
|
|||
static int eic7700_dwmac_init(struct device *dev, void *priv)
|
||||
{
|
||||
struct eic7700_qos_priv *dwc = priv;
|
||||
int ret;
|
||||
|
||||
return eic7700_clks_config(dwc, true);
|
||||
ret = eic7700_clks_config(dwc, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_set_bits(dwc->eic7700_hsp_regmap,
|
||||
dwc->eth_phy_ctrl_offset,
|
||||
EIC7700_ETH_TX_CLK_SEL |
|
||||
EIC7700_ETH_PHY_INTF_SELI);
|
||||
if (ret) {
|
||||
eic7700_clks_config(dwc, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_axi_lp_ctrl_offset,
|
||||
EIC7700_ETH_CSYSREQ_VAL);
|
||||
|
||||
if (dwc->has_txd_offset)
|
||||
regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_txd_offset, 0);
|
||||
|
||||
if (dwc->has_rxd_offset)
|
||||
regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_rxd_offset, 0);
|
||||
|
||||
regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_clk_offset,
|
||||
dwc->eth_clk_dly_param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eic7700_dwmac_exit(struct device *dev, void *priv)
|
||||
|
|
@ -93,13 +131,7 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
|
|||
struct plat_stmmacenet_data *plat_dat;
|
||||
struct stmmac_resources stmmac_res;
|
||||
struct eic7700_qos_priv *dwc_priv;
|
||||
struct regmap *eic7700_hsp_regmap;
|
||||
u32 eth_axi_lp_ctrl_offset;
|
||||
u32 eth_phy_ctrl_offset;
|
||||
u32 eth_phy_ctrl_regset;
|
||||
u32 eth_rxd_dly_offset;
|
||||
u32 eth_dly_param = 0;
|
||||
u32 delay_ps;
|
||||
u32 delay_ps, val;
|
||||
int i, ret;
|
||||
|
||||
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
|
||||
|
|
@ -119,10 +151,20 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
|
|||
/* Read rx-internal-delay-ps and update rx_clk delay */
|
||||
if (!of_property_read_u32(pdev->dev.of_node,
|
||||
"rx-internal-delay-ps", &delay_ps)) {
|
||||
u32 val = min(delay_ps / 100, EIC7700_MAX_DELAY_UNIT);
|
||||
if (delay_ps % EIC7700_DELAY_STEP_PS)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"rx delay must be multiple of %dps\n",
|
||||
EIC7700_DELAY_STEP_PS);
|
||||
|
||||
eth_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
|
||||
eth_dly_param |= FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
|
||||
if (delay_ps > EIC7700_MAX_DELAY_PS)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"rx delay out of range\n");
|
||||
|
||||
val = delay_ps / EIC7700_DELAY_STEP_PS;
|
||||
|
||||
dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
|
||||
dwc_priv->eth_clk_dly_param |=
|
||||
FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
|
||||
} else {
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"missing required property rx-internal-delay-ps\n");
|
||||
|
|
@ -131,55 +173,65 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
|
|||
/* Read tx-internal-delay-ps and update tx_clk delay */
|
||||
if (!of_property_read_u32(pdev->dev.of_node,
|
||||
"tx-internal-delay-ps", &delay_ps)) {
|
||||
u32 val = min(delay_ps / 100, EIC7700_MAX_DELAY_UNIT);
|
||||
if (delay_ps % EIC7700_DELAY_STEP_PS)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"tx delay must be multiple of %dps\n",
|
||||
EIC7700_DELAY_STEP_PS);
|
||||
|
||||
eth_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
|
||||
eth_dly_param |= FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val);
|
||||
if (delay_ps > EIC7700_MAX_DELAY_PS)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"tx delay out of range\n");
|
||||
|
||||
val = delay_ps / EIC7700_DELAY_STEP_PS;
|
||||
|
||||
dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
|
||||
dwc_priv->eth_clk_dly_param |=
|
||||
FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val);
|
||||
} else {
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"missing required property tx-internal-delay-ps\n");
|
||||
}
|
||||
|
||||
eic7700_hsp_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
"eswin,hsp-sp-csr");
|
||||
if (IS_ERR(eic7700_hsp_regmap))
|
||||
dwc_priv->eic7700_hsp_regmap =
|
||||
syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
"eswin,hsp-sp-csr");
|
||||
if (IS_ERR(dwc_priv->eic7700_hsp_regmap))
|
||||
return dev_err_probe(&pdev->dev,
|
||||
PTR_ERR(eic7700_hsp_regmap),
|
||||
PTR_ERR(dwc_priv->eic7700_hsp_regmap),
|
||||
"Failed to get hsp-sp-csr regmap\n");
|
||||
|
||||
ret = of_property_read_u32_index(pdev->dev.of_node,
|
||||
"eswin,hsp-sp-csr",
|
||||
1, ð_phy_ctrl_offset);
|
||||
1, &dwc_priv->eth_phy_ctrl_offset);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"can't get eth_phy_ctrl_offset\n");
|
||||
|
||||
regmap_read(eic7700_hsp_regmap, eth_phy_ctrl_offset,
|
||||
ð_phy_ctrl_regset);
|
||||
eth_phy_ctrl_regset |=
|
||||
(EIC7700_ETH_TX_CLK_SEL | EIC7700_ETH_PHY_INTF_SELI);
|
||||
regmap_write(eic7700_hsp_regmap, eth_phy_ctrl_offset,
|
||||
eth_phy_ctrl_regset);
|
||||
|
||||
ret = of_property_read_u32_index(pdev->dev.of_node,
|
||||
"eswin,hsp-sp-csr",
|
||||
2, ð_axi_lp_ctrl_offset);
|
||||
2, &dwc_priv->eth_axi_lp_ctrl_offset);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"can't get eth_axi_lp_ctrl_offset\n");
|
||||
|
||||
regmap_write(eic7700_hsp_regmap, eth_axi_lp_ctrl_offset,
|
||||
EIC7700_ETH_CSYSREQ_VAL);
|
||||
ret = of_property_read_u32_index(pdev->dev.of_node,
|
||||
"eswin,hsp-sp-csr",
|
||||
3, &dwc_priv->eth_clk_offset);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"can't get eth_clk_offset\n");
|
||||
|
||||
ret = of_property_read_u32_index(pdev->dev.of_node,
|
||||
"eswin,hsp-sp-csr",
|
||||
3, ð_rxd_dly_offset);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"can't get eth_rxd_dly_offset\n");
|
||||
4, &dwc_priv->eth_txd_offset);
|
||||
if (!ret)
|
||||
dwc_priv->has_txd_offset = true;
|
||||
|
||||
regmap_write(eic7700_hsp_regmap, eth_rxd_dly_offset,
|
||||
eth_dly_param);
|
||||
ret = of_property_read_u32_index(pdev->dev.of_node,
|
||||
"eswin,hsp-sp-csr",
|
||||
5, &dwc_priv->eth_rxd_offset);
|
||||
if (!ret)
|
||||
dwc_priv->has_rxd_offset = true;
|
||||
|
||||
plat_dat->num_clks = ARRAY_SIZE(eic7700_clk_names);
|
||||
plat_dat->clks = devm_kcalloc(&pdev->dev,
|
||||
|
|
|
|||
|
|
@ -211,12 +211,12 @@ static void ifb_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
|
|||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
for (i = 0; i < dev->real_num_rx_queues; i++)
|
||||
for (i = 0; i < dev->num_tx_queues; i++)
|
||||
for (j = 0; j < IFB_Q_STATS_LEN; j++)
|
||||
ethtool_sprintf(&p, "rx_queue_%u_%.18s",
|
||||
i, ifb_q_stats_desc[j].desc);
|
||||
|
||||
for (i = 0; i < dev->real_num_tx_queues; i++)
|
||||
for (i = 0; i < dev->num_tx_queues; i++)
|
||||
for (j = 0; j < IFB_Q_STATS_LEN; j++)
|
||||
ethtool_sprintf(&p, "tx_queue_%u_%.18s",
|
||||
i, ifb_q_stats_desc[j].desc);
|
||||
|
|
@ -229,8 +229,7 @@ static int ifb_get_sset_count(struct net_device *dev, int sset)
|
|||
{
|
||||
switch (sset) {
|
||||
case ETH_SS_STATS:
|
||||
return IFB_Q_STATS_LEN * (dev->real_num_rx_queues +
|
||||
dev->real_num_tx_queues);
|
||||
return IFB_Q_STATS_LEN * dev->num_tx_queues * 2;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -262,12 +261,12 @@ static void ifb_get_ethtool_stats(struct net_device *dev,
|
|||
struct ifb_q_private *txp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev->real_num_rx_queues; i++) {
|
||||
for (i = 0; i < dev->num_tx_queues; i++) {
|
||||
txp = dp->tx_private + i;
|
||||
ifb_fill_stats_data(&data, &txp->rx_stats);
|
||||
}
|
||||
|
||||
for (i = 0; i < dev->real_num_tx_queues; i++) {
|
||||
for (i = 0; i < dev->num_tx_queues; i++) {
|
||||
txp = dp->tx_private + i;
|
||||
ifb_fill_stats_data(&data, &txp->tx_stats);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ void ovpn_decrypt_post(void *data, int ret)
|
|||
skb = NULL;
|
||||
drop:
|
||||
if (unlikely(skb))
|
||||
dev_dstats_rx_dropped(peer->ovpn->dev);
|
||||
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
|
||||
kfree_skb(skb);
|
||||
drop_nocount:
|
||||
if (likely(peer))
|
||||
|
|
@ -225,7 +225,7 @@ void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb)
|
|||
net_info_ratelimited("%s: no available key for peer %u, key-id: %u\n",
|
||||
netdev_name(peer->ovpn->dev), peer->id,
|
||||
key_id);
|
||||
dev_dstats_rx_dropped(peer->ovpn->dev);
|
||||
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
|
||||
kfree_skb(skb);
|
||||
ovpn_peer_put(peer);
|
||||
return;
|
||||
|
|
@ -301,7 +301,7 @@ void ovpn_encrypt_post(void *data, int ret)
|
|||
rcu_read_unlock();
|
||||
err:
|
||||
if (unlikely(skb))
|
||||
dev_dstats_tx_dropped(peer->ovpn->dev);
|
||||
ovpn_dev_dstats_tx_dropped(peer->ovpn->dev);
|
||||
if (likely(peer))
|
||||
ovpn_peer_put(peer);
|
||||
if (likely(ks))
|
||||
|
|
@ -343,7 +343,7 @@ static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff *skb,
|
|||
*/
|
||||
skb_list_walk_safe(skb, curr, next) {
|
||||
if (unlikely(!ovpn_encrypt_one(peer, curr))) {
|
||||
dev_dstats_tx_dropped(ovpn->dev);
|
||||
ovpn_dev_dstats_tx_dropped(ovpn->dev);
|
||||
kfree_skb(curr);
|
||||
}
|
||||
}
|
||||
|
|
@ -414,7 +414,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (unlikely(!curr)) {
|
||||
net_err_ratelimited("%s: skb_share_check failed for payload packet\n",
|
||||
netdev_name(dev));
|
||||
dev_dstats_tx_dropped(ovpn->dev);
|
||||
ovpn_dev_dstats_tx_dropped(ovpn->dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -440,7 +440,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
drop:
|
||||
ovpn_peer_put(peer);
|
||||
drop_no_peer:
|
||||
dev_dstats_tx_dropped(ovpn->dev);
|
||||
ovpn_dev_dstats_tx_dropped(ovpn->dev);
|
||||
skb_tx_error(skb);
|
||||
kfree_skb_list(skb);
|
||||
return NETDEV_TX_OK;
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ static void ovpn_net_uninit(struct net_device *dev)
|
|||
{
|
||||
struct ovpn_priv *ovpn = netdev_priv(dev);
|
||||
|
||||
disable_delayed_work_sync(&ovpn->keepalive_work);
|
||||
ovpn_peers_free(ovpn, NULL, OVPN_DEL_PEER_REASON_TEARDOWN);
|
||||
gro_cells_destroy(&ovpn->gro_cells);
|
||||
}
|
||||
|
||||
|
|
@ -208,15 +210,6 @@ static int ovpn_newlink(struct net_device *dev,
|
|||
return register_netdevice(dev);
|
||||
}
|
||||
|
||||
static void ovpn_dellink(struct net_device *dev, struct list_head *head)
|
||||
{
|
||||
struct ovpn_priv *ovpn = netdev_priv(dev);
|
||||
|
||||
cancel_delayed_work_sync(&ovpn->keepalive_work);
|
||||
ovpn_peers_free(ovpn, NULL, OVPN_DEL_PEER_REASON_TEARDOWN);
|
||||
unregister_netdevice_queue(dev, head);
|
||||
}
|
||||
|
||||
static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
||||
{
|
||||
struct ovpn_priv *ovpn = netdev_priv(dev);
|
||||
|
|
@ -235,7 +228,6 @@ static struct rtnl_link_ops ovpn_link_ops = {
|
|||
.policy = ovpn_policy,
|
||||
.maxtype = IFLA_OVPN_MAX,
|
||||
.newlink = ovpn_newlink,
|
||||
.dellink = ovpn_dellink,
|
||||
.fill_info = ovpn_fill_info,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -462,10 +462,12 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
|
|||
sock_release:
|
||||
ovpn_socket_release(peer);
|
||||
peer_release:
|
||||
/* release right away because peer was not yet hashed, thus it is not
|
||||
* used in any context
|
||||
/* For UDP, the peer is unreachable until added to the hashtables, so
|
||||
* dropping the initial reference is enough. For TCP, the peer may be
|
||||
* concurrently reachable via sk_user_data->peer until
|
||||
* ovpn_socket_release() detaches; rely on the refcount.
|
||||
*/
|
||||
ovpn_peer_release(peer);
|
||||
ovpn_peer_put(peer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ static void ovpn_peer_release_rcu(struct rcu_head *head)
|
|||
* ovpn_peer_release - release peer private members
|
||||
* @peer: the peer to release
|
||||
*/
|
||||
void ovpn_peer_release(struct ovpn_peer *peer)
|
||||
static void ovpn_peer_release(struct ovpn_peer *peer)
|
||||
{
|
||||
ovpn_crypto_state_release(&peer->crypto);
|
||||
spin_lock_bh(&peer->lock);
|
||||
|
|
@ -1034,14 +1034,29 @@ static int ovpn_peer_add_p2p(struct ovpn_priv *ovpn, struct ovpn_peer *peer)
|
|||
*/
|
||||
int ovpn_peer_add(struct ovpn_priv *ovpn, struct ovpn_peer *peer)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
|
||||
/* Prevent adding new peers while destroying the ovpn interface.
|
||||
* Failing to do so would end up holding the device reference
|
||||
* endlessly hostage of the new peer object with no chance of
|
||||
* release..
|
||||
*/
|
||||
netdev_lock(ovpn->dev);
|
||||
if (ovpn->dev->reg_state != NETREG_REGISTERED)
|
||||
goto out;
|
||||
|
||||
switch (ovpn->mode) {
|
||||
case OVPN_MODE_MP:
|
||||
return ovpn_peer_add_mp(ovpn, peer);
|
||||
ret = ovpn_peer_add_mp(ovpn, peer);
|
||||
break;
|
||||
case OVPN_MODE_P2P:
|
||||
return ovpn_peer_add_p2p(ovpn, peer);
|
||||
ret = ovpn_peer_add_p2p(ovpn, peer);
|
||||
break;
|
||||
}
|
||||
out:
|
||||
netdev_unlock(ovpn->dev);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ static inline bool ovpn_peer_hold(struct ovpn_peer *peer)
|
|||
return kref_get_unless_zero(&peer->refcount);
|
||||
}
|
||||
|
||||
void ovpn_peer_release(struct ovpn_peer *peer);
|
||||
void ovpn_peer_release_kref(struct kref *kref);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef _NET_OVPN_OVPNSTATS_H_
|
||||
#define _NET_OVPN_OVPNSTATS_H_
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
/* one stat */
|
||||
struct ovpn_peer_stat {
|
||||
atomic64_t bytes;
|
||||
|
|
@ -44,4 +46,18 @@ static inline void ovpn_peer_stats_increment_tx(struct ovpn_peer_stats *stats,
|
|||
ovpn_peer_stats_increment(&stats->tx, n);
|
||||
}
|
||||
|
||||
static inline void ovpn_dev_dstats_tx_dropped(struct net_device *dev)
|
||||
{
|
||||
local_bh_disable();
|
||||
dev_dstats_tx_dropped(dev);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
static inline void ovpn_dev_dstats_rx_dropped(struct net_device *dev)
|
||||
{
|
||||
local_bh_disable();
|
||||
dev_dstats_rx_dropped(dev);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
#endif /* _NET_OVPN_OVPNSTATS_H_ */
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
|
|||
if (WARN_ON(!ovpn_peer_hold(peer)))
|
||||
goto err_nopeer;
|
||||
schedule_work(&peer->tcp.defer_del_work);
|
||||
dev_dstats_rx_dropped(peer->ovpn->dev);
|
||||
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
|
||||
err_nopeer:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
|
@ -298,9 +298,9 @@ static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk)
|
|||
} while (peer->tcp.out_msg.len > 0);
|
||||
|
||||
if (!peer->tcp.out_msg.len) {
|
||||
preempt_disable();
|
||||
local_bh_disable();
|
||||
dev_dstats_tx_add(peer->ovpn->dev, skb->len);
|
||||
preempt_enable();
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
kfree_skb(peer->tcp.out_msg.skb);
|
||||
|
|
@ -331,7 +331,7 @@ static void ovpn_tcp_send_sock_skb(struct ovpn_peer *peer, struct sock *sk,
|
|||
ovpn_tcp_send_sock(peer, sk);
|
||||
|
||||
if (peer->tcp.out_msg.skb) {
|
||||
dev_dstats_tx_dropped(peer->ovpn->dev);
|
||||
ovpn_dev_dstats_tx_dropped(peer->ovpn->dev);
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
|
@ -353,7 +353,7 @@ void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct sock *sk,
|
|||
if (sock_owned_by_user(sk)) {
|
||||
if (skb_queue_len(&peer->tcp.out_queue) >=
|
||||
READ_ONCE(net_hotdata.max_backlog)) {
|
||||
dev_dstats_tx_dropped(peer->ovpn->dev);
|
||||
ovpn_dev_dstats_tx_dropped(peer->ovpn->dev);
|
||||
kfree_skb(skb);
|
||||
goto unlock;
|
||||
}
|
||||
|
|
@ -581,14 +581,19 @@ static void ovpn_tcp_close(struct sock *sk, long timeout)
|
|||
|
||||
rcu_read_lock();
|
||||
sock = rcu_dereference_sk_user_data(sk);
|
||||
if (!sock || !sock->peer || !ovpn_peer_hold(sock->peer)) {
|
||||
if (!sock) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
peer = sock->peer;
|
||||
if (!peer || !ovpn_peer_hold(peer)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
ovpn_peer_del(sock->peer, OVPN_DEL_PEER_REASON_TRANSPORT_DISCONNECT);
|
||||
ovpn_peer_del(peer, OVPN_DEL_PEER_REASON_TRANSPORT_DISCONNECT);
|
||||
peer->tcp.sk_cb.prot->close(sk, timeout);
|
||||
ovpn_peer_put(peer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ static int ovpn_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
|
|||
return 0;
|
||||
|
||||
drop:
|
||||
dev_dstats_rx_dropped(ovpn->dev);
|
||||
ovpn_dev_dstats_rx_dropped(ovpn->dev);
|
||||
drop_noovpn:
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -940,6 +940,14 @@ EXPORT_SYMBOL_GPL(genphy_c45_read_eee_abilities);
|
|||
*/
|
||||
int genphy_c45_an_config_eee_aneg(struct phy_device *phydev)
|
||||
{
|
||||
/* Writing MMD AN advertisements while autoneg is disabled has no
|
||||
* effect on link-partner negotiation, but on some PHYs (e.g. the
|
||||
* Broadcom BCM54213PE) the write itself disturbs the receive
|
||||
* datapath. Skip it.
|
||||
*/
|
||||
if (phydev->autoneg == AUTONEG_DISABLE)
|
||||
return 0;
|
||||
|
||||
if (!phydev->eee_cfg.eee_enabled) {
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {};
|
||||
|
||||
|
|
|
|||
|
|
@ -2877,7 +2877,8 @@ EXPORT_SYMBOL(phy_advertise_supported);
|
|||
*/
|
||||
void phy_advertise_eee_all(struct phy_device *phydev)
|
||||
{
|
||||
linkmode_copy(phydev->advertising_eee, phydev->supported_eee);
|
||||
linkmode_andnot(phydev->advertising_eee, phydev->supported_eee,
|
||||
phydev->eee_disabled_modes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_advertise_eee_all);
|
||||
|
||||
|
|
@ -2903,7 +2904,8 @@ EXPORT_SYMBOL_GPL(phy_advertise_eee_all);
|
|||
*/
|
||||
void phy_support_eee(struct phy_device *phydev)
|
||||
{
|
||||
linkmode_copy(phydev->advertising_eee, phydev->supported_eee);
|
||||
linkmode_andnot(phydev->advertising_eee, phydev->supported_eee,
|
||||
phydev->eee_disabled_modes);
|
||||
phydev->eee_cfg.tx_lpi_enabled = true;
|
||||
phydev->eee_cfg.eee_enabled = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ static int of_load_pse_pis(struct pse_controller_dev *pcdev)
|
|||
ret = of_load_pse_pi_pairsets(node, &pi, ret);
|
||||
if (ret)
|
||||
goto out;
|
||||
} else if (ret != ENOENT) {
|
||||
} else if (ret != -ENOENT) {
|
||||
dev_err(pcdev->dev,
|
||||
"error: wrong number of pairsets. Should be 1 or 2, got %d (%pOF)\n",
|
||||
ret, node);
|
||||
|
|
|
|||
|
|
@ -919,11 +919,11 @@ static long tap_ioctl(struct file *file, unsigned int cmd,
|
|||
struct tap_queue *q = file->private_data;
|
||||
struct tap_dev *tap;
|
||||
void __user *argp = (void __user *)arg;
|
||||
struct sockaddr_storage ss = {};
|
||||
struct ifreq __user *ifr = argp;
|
||||
unsigned int __user *up = argp;
|
||||
unsigned short u;
|
||||
int __user *sp = argp;
|
||||
struct sockaddr_storage ss;
|
||||
int s;
|
||||
int ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
|
|
@ -1947,15 +1946,15 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
|
|||
ret = -ESHUTDOWN;
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"drop wmi command %d, hardware is wedged\n", cmd_id);
|
||||
} else {
|
||||
/* try to send pending beacons first. they take priority */
|
||||
ath10k_wmi_tx_beacons_nowait(ar);
|
||||
|
||||
ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id);
|
||||
|
||||
if (ret && test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
|
||||
ret = -ESHUTDOWN;
|
||||
}
|
||||
/* try to send pending beacons first. they take priority */
|
||||
ath10k_wmi_tx_beacons_nowait(ar);
|
||||
|
||||
ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id);
|
||||
|
||||
if (ret && test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
|
||||
ret = -ESHUTDOWN;
|
||||
|
||||
(ret != -EAGAIN);
|
||||
}), 3 * HZ);
|
||||
|
||||
|
|
|
|||
|
|
@ -1761,6 +1761,7 @@ static int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar,
|
|||
int buf_first_hdr_len, buf_first_len;
|
||||
struct hal_rx_desc *ldesc;
|
||||
int space_extra, rem_len, buf_len;
|
||||
bool is_continuation;
|
||||
u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
|
||||
|
||||
/* As the msdu is spread across multiple rx buffers,
|
||||
|
|
@ -1810,7 +1811,8 @@ static int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar,
|
|||
rem_len = msdu_len - buf_first_len;
|
||||
while ((skb = __skb_dequeue(msdu_list)) != NULL && rem_len > 0) {
|
||||
rxcb = ATH11K_SKB_RXCB(skb);
|
||||
if (rxcb->is_continuation)
|
||||
is_continuation = rxcb->is_continuation;
|
||||
if (is_continuation)
|
||||
buf_len = DP_RX_BUFFER_SIZE - hal_rx_desc_sz;
|
||||
else
|
||||
buf_len = rem_len;
|
||||
|
|
@ -1828,7 +1830,7 @@ static int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar,
|
|||
dev_kfree_skb_any(skb);
|
||||
|
||||
rem_len -= buf_len;
|
||||
if (!rxcb->is_continuation)
|
||||
if (!is_continuation)
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2214,8 +2216,7 @@ ath11k_dp_rx_h_find_peer(struct ath11k_base *ab, struct sk_buff *msdu)
|
|||
|
||||
lockdep_assert_held(&ab->base_lock);
|
||||
|
||||
if (rxcb->peer_id)
|
||||
peer = ath11k_peer_find_by_id(ab, rxcb->peer_id);
|
||||
peer = ath11k_peer_find_by_id(ab, rxcb->peer_id);
|
||||
|
||||
if (peer)
|
||||
return peer;
|
||||
|
|
|
|||
|
|
@ -1387,14 +1387,22 @@ EXPORT_SYMBOL(ath11k_hal_srng_deinit);
|
|||
|
||||
void ath11k_hal_srng_clear(struct ath11k_base *ab)
|
||||
{
|
||||
/* No need to memset rdp and wrp memory since each individual
|
||||
* segment would get cleared in ath11k_hal_srng_src_hw_init()
|
||||
* and ath11k_hal_srng_dst_hw_init().
|
||||
/*
|
||||
* Preserve the shared pointer buffers, but clear the previous
|
||||
* firmware instance's hp/tp state before handing them back to FW.
|
||||
* LMAC rings reuse this shared memory without going through the
|
||||
* normal SRNG hw-init path that zeros non-LMAC ring pointers.
|
||||
*/
|
||||
memset(ab->hal.srng_list, 0,
|
||||
sizeof(ab->hal.srng_list));
|
||||
memset(ab->hal.shadow_reg_addr, 0,
|
||||
sizeof(ab->hal.shadow_reg_addr));
|
||||
if (ab->hal.rdp.vaddr)
|
||||
memset(ab->hal.rdp.vaddr, 0,
|
||||
sizeof(*ab->hal.rdp.vaddr) * HAL_SRNG_RING_ID_MAX);
|
||||
if (ab->hal.wrp.vaddr)
|
||||
memset(ab->hal.wrp.vaddr, 0,
|
||||
sizeof(*ab->hal.wrp.vaddr) * HAL_SRNG_NUM_LMAC_RINGS);
|
||||
ab->hal.avail_blk_resource = 0;
|
||||
ab->hal.current_blk_index = 0;
|
||||
ab->hal.num_shadow_reg_configured = 0;
|
||||
|
|
|
|||
|
|
@ -1467,11 +1467,8 @@ ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab,
|
|||
case HAL_RX_MPDU_START: {
|
||||
struct hal_rx_mpdu_info *mpdu_info =
|
||||
(struct hal_rx_mpdu_info *)tlv_data;
|
||||
u16 peer_id;
|
||||
|
||||
peer_id = ath11k_hal_rx_mpduinfo_get_peerid(ab, mpdu_info);
|
||||
if (peer_id)
|
||||
ppdu_info->peer_id = peer_id;
|
||||
ppdu_info->peer_id = ath11k_hal_rx_mpduinfo_get_peerid(ab, mpdu_info);
|
||||
break;
|
||||
}
|
||||
case HAL_RXPCU_PPDU_END_INFO: {
|
||||
|
|
|
|||
|
|
@ -457,6 +457,7 @@ static int ath11k_tm_cmd_wmi_ftm(struct ath11k *ar, struct nlattr *tb[])
|
|||
ret = ath11k_wmi_cmd_send(wmi, skb, cmd_id);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send wmi ftm command: %d\n", ret);
|
||||
dev_kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9299,7 +9299,7 @@ int ath11k_wmi_hw_data_filter_cmd(struct ath11k *ar, u32 vdev_id,
|
|||
{
|
||||
struct wmi_hw_data_filter_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
int len;
|
||||
int ret, len;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
|
||||
|
|
@ -9324,7 +9324,13 @@ int ath11k_wmi_hw_data_filter_cmd(struct ath11k *ar, u32 vdev_id,
|
|||
"hw data filter enable %d filter_bitmap 0x%x\n",
|
||||
enable, filter_bitmap);
|
||||
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_HW_DATA_FILTER_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_HW_DATA_FILTER_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_HW_DATA_FILTER_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar)
|
||||
|
|
@ -9332,6 +9338,7 @@ int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar)
|
|||
struct wmi_wow_host_wakeup_ind *cmd;
|
||||
struct sk_buff *skb;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
|
||||
|
|
@ -9345,14 +9352,20 @@ int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar)
|
|||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow host wakeup ind\n");
|
||||
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_wow_enable(struct ath11k *ar)
|
||||
{
|
||||
struct wmi_wow_enable_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
int len;
|
||||
int ret, len;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
|
||||
|
|
@ -9367,7 +9380,13 @@ int ath11k_wmi_wow_enable(struct ath11k *ar)
|
|||
cmd->pause_iface_config = WOW_IFACE_PAUSE_ENABLED;
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow enable\n");
|
||||
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_WOW_ENABLE_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar,
|
||||
|
|
@ -9376,7 +9395,7 @@ int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar,
|
|||
struct sk_buff *skb;
|
||||
struct wmi_scan_prob_req_oui_cmd *cmd;
|
||||
u32 prob_req_oui;
|
||||
int len;
|
||||
int ret, len;
|
||||
|
||||
prob_req_oui = (((u32)mac_addr[0]) << 16) |
|
||||
(((u32)mac_addr[1]) << 8) | mac_addr[2];
|
||||
|
|
@ -9395,7 +9414,13 @@ int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar,
|
|||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "scan prob req oui %d\n",
|
||||
prob_req_oui);
|
||||
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SCAN_PROB_REQ_OUI_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SCAN_PROB_REQ_OUI_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_SCAN_PROB_REQ_OUI_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_wow_add_wakeup_event(struct ath11k *ar, u32 vdev_id,
|
||||
|
|
@ -9405,6 +9430,7 @@ int ath11k_wmi_wow_add_wakeup_event(struct ath11k *ar, u32 vdev_id,
|
|||
struct wmi_wow_add_del_event_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
|
||||
|
|
@ -9422,7 +9448,13 @@ int ath11k_wmi_wow_add_wakeup_event(struct ath11k *ar, u32 vdev_id,
|
|||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow add wakeup event %s enable %d vdev_id %d\n",
|
||||
wow_wakeup_event(event), enable, vdev_id);
|
||||
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_wow_add_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id,
|
||||
|
|
@ -9435,6 +9467,7 @@ int ath11k_wmi_wow_add_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id,
|
|||
struct sk_buff *skb;
|
||||
u8 *ptr;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = sizeof(*cmd) +
|
||||
sizeof(*tlv) + /* array struct */
|
||||
|
|
@ -9527,7 +9560,13 @@ int ath11k_wmi_wow_add_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id,
|
|||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow add pattern vdev_id %d pattern_id %d pattern_offset %d\n",
|
||||
vdev_id, pattern_id, pattern_offset);
|
||||
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ADD_WAKE_PATTERN_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ADD_WAKE_PATTERN_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_WOW_ADD_WAKE_PATTERN_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_wow_del_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id)
|
||||
|
|
@ -9535,6 +9574,7 @@ int ath11k_wmi_wow_del_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id)
|
|||
struct wmi_wow_del_pattern_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
|
||||
|
|
@ -9553,7 +9593,13 @@ int ath11k_wmi_wow_del_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id)
|
|||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow del pattern vdev_id %d pattern_id %d\n",
|
||||
vdev_id, pattern_id);
|
||||
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_DEL_WAKE_PATTERN_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_DEL_WAKE_PATTERN_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_WOW_DEL_WAKE_PATTERN_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
|
|
@ -9697,6 +9743,7 @@ int ath11k_wmi_wow_config_pno(struct ath11k *ar, u32 vdev_id,
|
|||
struct wmi_pno_scan_req *pno_scan)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
if (pno_scan->enable)
|
||||
skb = ath11k_wmi_op_gen_config_pno_start(ar, vdev_id, pno_scan);
|
||||
|
|
@ -9706,7 +9753,13 @@ int ath11k_wmi_wow_config_pno(struct ath11k *ar, u32 vdev_id,
|
|||
if (IS_ERR_OR_NULL(skb))
|
||||
return -ENOMEM;
|
||||
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath11k_wmi_fill_ns_offload(struct ath11k *ar,
|
||||
|
|
@ -9824,6 +9877,7 @@ int ath11k_wmi_arp_ns_offload(struct ath11k *ar,
|
|||
u8 *buf_ptr;
|
||||
size_t len;
|
||||
u8 ns_cnt, ns_ext_tuples = 0;
|
||||
int ret;
|
||||
|
||||
offload = &arvif->arp_ns_offload;
|
||||
ns_cnt = offload->ipv6_count;
|
||||
|
|
@ -9862,7 +9916,13 @@ int ath11k_wmi_arp_ns_offload(struct ath11k *ar,
|
|||
if (ns_ext_tuples)
|
||||
ath11k_wmi_fill_ns_offload(ar, offload, &buf_ptr, enable, 1);
|
||||
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SET_ARP_NS_OFFLOAD_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SET_ARP_NS_OFFLOAD_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_SET_ARP_NS_OFFLOAD_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_gtk_rekey_offload(struct ath11k *ar,
|
||||
|
|
@ -9870,7 +9930,7 @@ int ath11k_wmi_gtk_rekey_offload(struct ath11k *ar,
|
|||
{
|
||||
struct wmi_gtk_rekey_offload_cmd *cmd;
|
||||
struct ath11k_rekey_data *rekey_data = &arvif->rekey_data;
|
||||
int len;
|
||||
int ret, len;
|
||||
struct sk_buff *skb;
|
||||
__le64 replay_ctr;
|
||||
|
||||
|
|
@ -9904,14 +9964,20 @@ int ath11k_wmi_gtk_rekey_offload(struct ath11k *ar,
|
|||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "offload gtk rekey vdev: %d %d\n",
|
||||
arvif->vdev_id, enable);
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_GTK_OFFLOAD_CMDID offload\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_gtk_rekey_getinfo(struct ath11k *ar,
|
||||
struct ath11k_vif *arvif)
|
||||
{
|
||||
struct wmi_gtk_rekey_offload_cmd *cmd;
|
||||
int len;
|
||||
int ret, len;
|
||||
struct sk_buff *skb;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
|
|
@ -9928,7 +9994,13 @@ int ath11k_wmi_gtk_rekey_getinfo(struct ath11k *ar,
|
|||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "get gtk rekey vdev_id: %d\n",
|
||||
arvif->vdev_id);
|
||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_GTK_OFFLOAD_CMDID getinfo\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_val)
|
||||
|
|
@ -9938,6 +10010,7 @@ int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_va
|
|||
struct sk_buff *skb;
|
||||
u8 *buf_ptr;
|
||||
u32 len, sar_len_aligned, rsvd_len_aligned;
|
||||
int ret;
|
||||
|
||||
sar_len_aligned = roundup(BIOS_SAR_TABLE_LEN, sizeof(u32));
|
||||
rsvd_len_aligned = roundup(BIOS_SAR_RSVD1_LEN, sizeof(u32));
|
||||
|
|
@ -9968,7 +10041,13 @@ int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_va
|
|||
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
|
||||
FIELD_PREP(WMI_TLV_LEN, rsvd_len_aligned);
|
||||
|
||||
return ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar)
|
||||
|
|
@ -9979,6 +10058,7 @@ int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar)
|
|||
struct sk_buff *skb;
|
||||
u8 *buf_ptr;
|
||||
u32 len, rsvd_len_aligned;
|
||||
int ret;
|
||||
|
||||
rsvd_len_aligned = roundup(BIOS_SAR_RSVD2_LEN, sizeof(u32));
|
||||
len = sizeof(*cmd) + TLV_HDR_SIZE + rsvd_len_aligned;
|
||||
|
|
@ -9998,7 +10078,13 @@ int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar)
|
|||
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
|
||||
FIELD_PREP(WMI_TLV_LEN, rsvd_len_aligned);
|
||||
|
||||
return ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath11k_wmi_sta_keepalive(struct ath11k *ar,
|
||||
|
|
@ -10009,6 +10095,7 @@ int ath11k_wmi_sta_keepalive(struct ath11k *ar,
|
|||
struct wmi_sta_keepalive_arp_resp *arp;
|
||||
struct sk_buff *skb;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = sizeof(*cmd) + sizeof(*arp);
|
||||
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
|
||||
|
|
@ -10040,7 +10127,13 @@ int ath11k_wmi_sta_keepalive(struct ath11k *ar,
|
|||
"sta keepalive vdev %d enabled %d method %d interval %d\n",
|
||||
arg->vdev_id, arg->enabled, arg->method, arg->interval);
|
||||
|
||||
return ath11k_wmi_cmd_send(wmi, skb, WMI_STA_KEEPALIVE_CMDID);
|
||||
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_KEEPALIVE_CMDID);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send WMI_STA_KEEPALIVE_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar)
|
||||
|
|
|
|||
|
|
@ -3446,7 +3446,9 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
|
|||
arg->peer_eht_mcs_count++;
|
||||
fallthrough;
|
||||
default:
|
||||
if (!(link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
|
||||
if ((vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_MESH_POINT) &&
|
||||
!(link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
|
||||
bw_20 = &eht_cap->eht_mcs_nss_supp.only_20mhz;
|
||||
|
||||
|
|
@ -3475,7 +3477,9 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
|
|||
arg->punct_bitmap = ~arvif->punct_bitmap;
|
||||
arg->eht_disable_mcs15 = link_conf->eht_disable_mcs15;
|
||||
|
||||
if (!(link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
|
||||
if ((vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_MESH_POINT) &&
|
||||
!(link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
|
||||
if (bw_20->rx_tx_mcs13_max_nss)
|
||||
max_nss = max(max_nss, u8_get_bits(bw_20->rx_tx_mcs13_max_nss,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
* Copyright (C) 2024-2026 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_mld_constants_h__
|
||||
#define __iwl_mld_constants_h__
|
||||
|
||||
#define IWL_MLD_MISSED_BEACONS_SINCE_RX_THOLD 4
|
||||
#define IWL_MLD_MISSED_BEACONS_SINCE_RX_THOLD 6
|
||||
#define IWL_MLD_MISSED_BEACONS_THRESHOLD 8
|
||||
#define IWL_MLD_MISSED_BEACONS_THRESHOLD_LONG 19
|
||||
#define IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS 5
|
||||
|
|
|
|||
|
|
@ -1930,12 +1930,12 @@ int iwl_mld_wowlan_suspend(struct iwl_mld *mld, struct cfg80211_wowlan *wowlan)
|
|||
if (WARN_ON(!wowlan))
|
||||
return 1;
|
||||
|
||||
IWL_DEBUG_WOWLAN(mld, "Starting the wowlan suspend flow\n");
|
||||
|
||||
bss_vif = iwl_mld_get_bss_vif(mld);
|
||||
if (WARN_ON(!bss_vif))
|
||||
if (!bss_vif)
|
||||
return 1;
|
||||
|
||||
IWL_DEBUG_WOWLAN(mld, "Starting the wowlan suspend flow\n");
|
||||
|
||||
if (!bss_vif->cfg.assoc) {
|
||||
int ret;
|
||||
/* If we're not associated, this must be netdetect */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
* Copyright (C) 2024-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "constants.h"
|
||||
|
|
@ -504,7 +504,6 @@ void iwl_mld_remove_link(struct iwl_mld *mld,
|
|||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif);
|
||||
struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf);
|
||||
bool is_deflink = link == &mld_vif->deflink;
|
||||
u8 fw_id = link->fw_id;
|
||||
|
||||
if (WARN_ON(!link || link->active))
|
||||
return;
|
||||
|
|
@ -512,15 +511,15 @@ void iwl_mld_remove_link(struct iwl_mld *mld,
|
|||
iwl_mld_rm_link_from_fw(mld, bss_conf);
|
||||
/* Continue cleanup on failure */
|
||||
|
||||
if (!is_deflink)
|
||||
kfree_rcu(link, rcu_head);
|
||||
|
||||
RCU_INIT_POINTER(mld_vif->link[bss_conf->link_id], NULL);
|
||||
|
||||
if (WARN_ON(fw_id >= mld->fw->ucode_capa.num_links))
|
||||
if (WARN_ON(link->fw_id >= mld->fw->ucode_capa.num_links))
|
||||
return;
|
||||
|
||||
RCU_INIT_POINTER(mld->fw_id_to_bss_conf[fw_id], NULL);
|
||||
RCU_INIT_POINTER(mld->fw_id_to_bss_conf[link->fw_id], NULL);
|
||||
|
||||
if (!is_deflink)
|
||||
kfree_rcu(link, rcu_head);
|
||||
}
|
||||
|
||||
void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld,
|
||||
|
|
|
|||
|
|
@ -834,7 +834,7 @@ static int iwl_mld_tx_tso_segment(struct iwl_mld *mld, struct sk_buff *skb,
|
|||
return -EINVAL;
|
||||
|
||||
max_tid_amsdu_len = sta->cur->max_tid_amsdu_len[tid];
|
||||
if (!max_tid_amsdu_len)
|
||||
if (!max_tid_amsdu_len || max_tid_amsdu_len == 1)
|
||||
return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skbs);
|
||||
|
||||
/* Sub frame header + SNAP + IP header + TCP header + MSS */
|
||||
|
|
@ -846,6 +846,9 @@ static int iwl_mld_tx_tso_segment(struct iwl_mld *mld, struct sk_buff *skb,
|
|||
*/
|
||||
num_subframes = (max_tid_amsdu_len + pad) / (subf_len + pad);
|
||||
|
||||
if (WARN_ON_ONCE(!num_subframes))
|
||||
return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skbs);
|
||||
|
||||
if (sta->max_amsdu_subframes &&
|
||||
num_subframes > sta->max_amsdu_subframes)
|
||||
num_subframes = sta->max_amsdu_subframes;
|
||||
|
|
@ -970,6 +973,16 @@ void iwl_mld_tx_from_txq(struct iwl_mld *mld, struct ieee80211_txq *txq)
|
|||
struct sk_buff *skb = NULL;
|
||||
u8 zero_addr[ETH_ALEN] = {};
|
||||
|
||||
/*
|
||||
* Don't transmit during firmware restart. The firmware is dead,
|
||||
* so iwl_trans_tx() would return -EIO for each frame. Avoid the
|
||||
* overhead of dequeuing from mac80211 only to immediately free
|
||||
* the skbs, and the potential memory pressure from rapid skb
|
||||
* allocation churn during high-throughput restart scenarios.
|
||||
*/
|
||||
if (unlikely(mld->fw_status.in_hw_restart))
|
||||
return;
|
||||
|
||||
/*
|
||||
* No need for threads to be pending here, they can leave the first
|
||||
* taker all the work.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -927,13 +927,18 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,
|
|||
|
||||
u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)
|
||||
{
|
||||
u16 flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
|
||||
bool is_new_rate = iwl_fw_lookup_cmd_ver(fw, BEACON_TEMPLATE_CMD, 0) > 10;
|
||||
u16 flags = 0;
|
||||
|
||||
if (rate_idx <= IWL_LAST_CCK_RATE)
|
||||
flags |= is_new_rate ? IWL_MAC_BEACON_CCK
|
||||
: IWL_MAC_BEACON_CCK_V1;
|
||||
|
||||
if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
|
||||
flags |= iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
|
||||
else
|
||||
flags |= iwl_fw_rate_idx_to_plcp(rate_idx);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
|
@ -962,6 +967,7 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
|
|||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct ieee80211_tx_info *info;
|
||||
u32 rate_n_flags = 0;
|
||||
u8 rate;
|
||||
u32 tx_flags;
|
||||
|
||||
|
|
@ -981,18 +987,21 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
|
|||
IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) {
|
||||
iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx);
|
||||
|
||||
tx_params->rate_n_flags =
|
||||
cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
|
||||
RATE_MCS_ANT_POS);
|
||||
rate_n_flags |= BIT(mvm->mgmt_last_antenna_idx) <<
|
||||
RATE_MCS_ANT_POS;
|
||||
}
|
||||
|
||||
rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);
|
||||
|
||||
tx_params->rate_n_flags |=
|
||||
cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate));
|
||||
if (rate == IWL_FIRST_CCK_RATE)
|
||||
tx_params->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK_V1);
|
||||
if (rate < IWL_FIRST_OFDM_RATE)
|
||||
rate_n_flags |= RATE_MCS_MOD_TYPE_CCK;
|
||||
else
|
||||
rate_n_flags |= RATE_MCS_MOD_TYPE_LEGACY_OFDM;
|
||||
|
||||
rate_n_flags |= iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate);
|
||||
|
||||
tx_params->rate_n_flags = iwl_mvm_v3_rate_to_fw(rate_n_flags,
|
||||
mvm->fw_rates_ver);
|
||||
}
|
||||
|
||||
int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -159,15 +159,9 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
|
|||
|
||||
u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx)
|
||||
{
|
||||
if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
|
||||
/* In the new rate legacy rates are indexed:
|
||||
* 0 - 3 for CCK and 0 - 7 for OFDM.
|
||||
*/
|
||||
return (rate_idx >= IWL_FIRST_OFDM_RATE ?
|
||||
rate_idx - IWL_FIRST_OFDM_RATE :
|
||||
rate_idx);
|
||||
|
||||
return iwl_fw_rate_idx_to_plcp(rate_idx);
|
||||
return rate_idx >= IWL_FIRST_OFDM_RATE ?
|
||||
rate_idx - IWL_FIRST_OFDM_RATE :
|
||||
rate_idx;
|
||||
}
|
||||
|
||||
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac)
|
||||
|
|
|
|||
|
|
@ -398,9 +398,9 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans)
|
|||
mutex_unlock(&trans_pcie->mutex);
|
||||
|
||||
if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
|
||||
trans->step_urm = !!(iwl_read_umac_prph(trans,
|
||||
CNVI_PMU_STEP_FLOW) &
|
||||
CNVI_PMU_STEP_FLOW_FORCE_URM);
|
||||
trans->step_urm = !!(iwl_read_prph(trans,
|
||||
CNVI_PMU_STEP_FLOW) &
|
||||
CNVI_PMU_STEP_FLOW_FORCE_URM);
|
||||
}
|
||||
|
||||
static bool iwl_pcie_set_ltr(struct iwl_trans *trans)
|
||||
|
|
|
|||
|
|
@ -1265,7 +1265,7 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
|
|||
|
||||
ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto fail;
|
||||
|
||||
wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);
|
||||
reg &= ~BIT(10);
|
||||
|
|
|
|||
|
|
@ -1425,6 +1425,8 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
|
|||
protocol_init_fail:
|
||||
cancel_work_sync(&ipc_imem->run_state_worker);
|
||||
ipc_task_deinit(ipc_imem->ipc_task);
|
||||
if (ipc_imem->ipc_protocol)
|
||||
ipc_protocol_deinit(ipc_imem->ipc_protocol);
|
||||
ipc_task_init_fail:
|
||||
kfree(ipc_imem->ipc_task);
|
||||
ipc_task_fail:
|
||||
|
|
|
|||
|
|
@ -121,9 +121,12 @@ size_t crypto_krb5_how_much_buffer(const struct krb5_enctype *krb5,
|
|||
size_t crypto_krb5_how_much_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_buffer_size, size_t *_offset);
|
||||
void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_offset, size_t *_len);
|
||||
int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_offset, size_t *_len);
|
||||
int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t len, size_t min_content);
|
||||
struct crypto_aead *crypto_krb5_prepare_encryption(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
u32 usage, gfp_t gfp);
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@ static inline void airoha_ppe_dev_check_skb(struct airoha_ppe_dev *dev,
|
|||
#define NPU_RX1_DESC_NUM 512
|
||||
|
||||
/* CTRL */
|
||||
#define NPU_RX_DMA_DESC_LAST_MASK BIT(27)
|
||||
#define NPU_RX_DMA_DESC_LEN_MASK GENMASK(26, 14)
|
||||
#define NPU_RX_DMA_DESC_CUR_LEN_MASK GENMASK(13, 1)
|
||||
#define NPU_RX_DMA_DESC_LAST_MASK BIT(29)
|
||||
#define NPU_RX_DMA_DESC_LEN_MASK GENMASK(28, 15)
|
||||
#define NPU_RX_DMA_DESC_CUR_LEN_MASK GENMASK(14, 1)
|
||||
#define NPU_RX_DMA_DESC_DONE_MASK BIT(0)
|
||||
/* INFO */
|
||||
#define NPU_RX_DMA_PKT_COUNT_MASK GENMASK(31, 29)
|
||||
|
|
|
|||
|
|
@ -398,6 +398,7 @@ void baswap(bdaddr_t *dst, const bdaddr_t *src);
|
|||
struct bt_sock {
|
||||
struct sock sk;
|
||||
struct list_head accept_q;
|
||||
spinlock_t accept_q_lock; /* protects accept_q */
|
||||
struct sock *parent;
|
||||
unsigned long flags;
|
||||
void (*skb_msg_name)(struct sk_buff *, void *, int *);
|
||||
|
|
|
|||
|
|
@ -1186,8 +1186,9 @@ struct netns_ipvs {
|
|||
struct timer_list dest_trash_timer; /* expiration timer */
|
||||
struct mutex service_mutex; /* service reconfig */
|
||||
struct rw_semaphore svc_resize_sem; /* svc_table resizing */
|
||||
struct rw_semaphore svc_replace_sem; /* svc_table replace */
|
||||
struct delayed_work svc_resize_work; /* resize svc_table */
|
||||
atomic_t svc_table_changes;/* ++ on new table */
|
||||
atomic_t svc_table_changes;/* ++ on table changes */
|
||||
/* Service counters */
|
||||
atomic_t num_services[IP_VS_AF_MAX]; /* Services */
|
||||
atomic_t fwm_services[IP_VS_AF_MAX]; /* Services */
|
||||
|
|
|
|||
|
|
@ -489,11 +489,15 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
|
|||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
|
||||
{
|
||||
unsigned int seq, hh_alen;
|
||||
unsigned int seq, hh_alen = HH_DATA_ALIGN(ETH_HLEN);
|
||||
int err;
|
||||
|
||||
err = skb_cow_head(skb, hh_alen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
do {
|
||||
seq = read_seqbegin(&hh->hh_lock);
|
||||
hh_alen = HH_DATA_ALIGN(ETH_HLEN);
|
||||
memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN);
|
||||
} while (read_seqretry(&hh->hh_lock, seq));
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ struct net_shaper {
|
|||
|
||||
/* private: */
|
||||
u32 leaves; /* accounted only for NODE scope */
|
||||
bool valid;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ struct nf_queue_entry {
|
|||
struct list_head list;
|
||||
struct rhash_head hash_node;
|
||||
struct sk_buff *skb;
|
||||
struct net_device *skb_dev;
|
||||
unsigned int id;
|
||||
unsigned int hook_index; /* index in hook_entries->hook[] */
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
|
|
|
|||
|
|
@ -65,8 +65,6 @@ static inline void tcp_orphan_count_dec(void)
|
|||
this_cpu_dec(tcp_orphan_count);
|
||||
}
|
||||
|
||||
DECLARE_PER_CPU(u32, tcp_tw_isn);
|
||||
|
||||
void tcp_time_wait(struct sock *sk, int state, int timeo);
|
||||
|
||||
#define MAX_TCP_HEADER L1_CACHE_ALIGN(128 + MAX_HEADER)
|
||||
|
|
@ -1102,10 +1100,13 @@ struct tcp_skb_cb {
|
|||
__u32 seq; /* Starting sequence number */
|
||||
__u32 end_seq; /* SEQ + FIN + SYN + datalen */
|
||||
union {
|
||||
/* Note :
|
||||
/* Notes :
|
||||
* tcp_tw_isn is used in input path only
|
||||
* (isn chosen by tcp_timewait_state_process())
|
||||
* tcp_gso_segs/size are used in write queue only,
|
||||
* cf tcp_skb_pcount()/tcp_skb_mss()
|
||||
*/
|
||||
u32 tcp_tw_isn;
|
||||
struct {
|
||||
u16 tcp_gso_segs;
|
||||
u16 tcp_gso_size;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
EM(rxkad_abort_resp_unknown_tkt, "rxkad-resp-unknown-tkt") \
|
||||
EM(rxkad_abort_resp_version, "rxkad-resp-version") \
|
||||
/* RxGK security errors */ \
|
||||
EM(rxgk_abort_1_short_header, "rxgk1-short-hdr") \
|
||||
EM(rxgk_abort_1_verify_mic_eproto, "rxgk1-vfy-mic-eproto") \
|
||||
EM(rxgk_abort_2_decrypt_eproto, "rxgk2-dec-eproto") \
|
||||
EM(rxgk_abort_2_short_data, "rxgk2-short-data") \
|
||||
|
|
|
|||
|
|
@ -542,6 +542,11 @@ int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb,
|
|||
struct ddpehdr *ddp = (struct ddpehdr *)skb->data;
|
||||
int ft = 2;
|
||||
|
||||
if (!at) {
|
||||
kfree_skb(skb);
|
||||
return NET_XMIT_DROP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compressible ?
|
||||
*
|
||||
|
|
|
|||
|
|
@ -224,6 +224,8 @@ static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
|
|||
hard_iface->bat_iv.ogm_buff = NULL;
|
||||
|
||||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
||||
cancel_delayed_work_sync(&hard_iface->bat_iv.reschedule_work);
|
||||
}
|
||||
|
||||
static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
|
||||
|
|
@ -536,8 +538,10 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
|
|||
* @if_incoming: interface where the packet was received
|
||||
* @if_outgoing: interface for which the retransmission should be considered
|
||||
* @own_packet: true if it is a self-generated ogm
|
||||
*
|
||||
* Return: whether forward packet was scheduled
|
||||
*/
|
||||
static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
|
||||
static bool batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
|
||||
int packet_len, unsigned long send_time,
|
||||
bool direct_link,
|
||||
struct batadv_hard_iface *if_incoming,
|
||||
|
|
@ -561,13 +565,13 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
|
|||
|
||||
skb = netdev_alloc_skb_ip_align(NULL, skb_size);
|
||||
if (!skb)
|
||||
return;
|
||||
return false;
|
||||
|
||||
forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing,
|
||||
queue_left, bat_priv, skb);
|
||||
if (!forw_packet_aggr) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
forw_packet_aggr->skb->priority = TC_PRIO_CONTROL;
|
||||
|
|
@ -590,6 +594,8 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
|
|||
batadv_iv_send_outstanding_bat_ogm_packet);
|
||||
|
||||
batadv_forw_packet_ogmv1_queue(bat_priv, forw_packet_aggr, send_time);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* aggregate a new packet into the existing ogm packet */
|
||||
|
|
@ -617,8 +623,10 @@ static void batadv_iv_ogm_aggregate(struct batadv_forw_packet *forw_packet_aggr,
|
|||
* @if_outgoing: interface for which the retransmission should be considered
|
||||
* @own_packet: true if it is a self-generated ogm
|
||||
* @send_time: timestamp (jiffies) when the packet is to be sent
|
||||
*
|
||||
* Return: whether forward packet was scheduled
|
||||
*/
|
||||
static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
|
||||
static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
|
||||
unsigned char *packet_buff,
|
||||
int packet_len,
|
||||
struct batadv_hard_iface *if_incoming,
|
||||
|
|
@ -670,14 +678,16 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
|
|||
if (!own_packet && atomic_read(&bat_priv->aggregated_ogms))
|
||||
send_time += max_aggregation_jiffies;
|
||||
|
||||
batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
|
||||
send_time, direct_link,
|
||||
if_incoming, if_outgoing,
|
||||
own_packet);
|
||||
return batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
|
||||
send_time, direct_link,
|
||||
if_incoming, if_outgoing,
|
||||
own_packet);
|
||||
} else {
|
||||
batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff,
|
||||
packet_len, direct_link);
|
||||
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -790,6 +800,9 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
|
|||
u32 seqno;
|
||||
u16 tvlv_len = 0;
|
||||
unsigned long send_time;
|
||||
bool reschedule = false;
|
||||
bool scheduled;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
||||
|
|
@ -813,9 +826,15 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
|
|||
* appended as it may alter the tt tvlv container
|
||||
*/
|
||||
batadv_tt_local_commit_changes(bat_priv);
|
||||
tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
|
||||
ogm_buff_len,
|
||||
BATADV_OGM_HLEN);
|
||||
ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
|
||||
ogm_buff_len,
|
||||
BATADV_OGM_HLEN);
|
||||
if (ret < 0) {
|
||||
reschedule = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tvlv_len = ret;
|
||||
}
|
||||
|
||||
batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff);
|
||||
|
|
@ -834,8 +853,11 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
|
|||
/* OGMs from secondary interfaces are only scheduled on their
|
||||
* respective interfaces.
|
||||
*/
|
||||
batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
|
||||
hard_iface, hard_iface, 1, send_time);
|
||||
scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
|
||||
hard_iface, hard_iface, 1, send_time);
|
||||
if (!scheduled)
|
||||
reschedule = true;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -847,15 +869,28 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
|
|||
if (!kref_get_unless_zero(&tmp_hard_iface->refcount))
|
||||
continue;
|
||||
|
||||
batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
|
||||
*ogm_buff_len, hard_iface,
|
||||
tmp_hard_iface, 1, send_time);
|
||||
|
||||
scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
|
||||
*ogm_buff_len, hard_iface,
|
||||
tmp_hard_iface, 1, send_time);
|
||||
batadv_hardif_put(tmp_hard_iface);
|
||||
|
||||
if (!scheduled && tmp_hard_iface == hard_iface)
|
||||
reschedule = true;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
out:
|
||||
if (reschedule) {
|
||||
/* there was a failure scheduling the own forward packet.
|
||||
* as result, the batadv_iv_send_outstanding_bat_ogm_packet()
|
||||
* work item is no longer scheduled. it is therefore necessary
|
||||
* to reschedule it manually
|
||||
*/
|
||||
queue_delayed_work(batadv_event_workqueue,
|
||||
&hard_iface->bat_iv.reschedule_work,
|
||||
msecs_to_jiffies(atomic_read(&bat_priv->orig_interval)));
|
||||
}
|
||||
|
||||
batadv_hardif_put(primary_if);
|
||||
}
|
||||
|
||||
|
|
@ -870,6 +905,17 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
|
|||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
}
|
||||
|
||||
static void batadv_iv_ogm_reschedule(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
|
||||
hard_iface = container_of(delayed_work,
|
||||
struct batadv_hard_iface,
|
||||
bat_iv.reschedule_work);
|
||||
batadv_iv_ogm_schedule(hard_iface);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_orig_ifinfo_sum() - Get bcast_own sum for originator over interface
|
||||
* @orig_node: originator which reproadcasted the OGMs directly
|
||||
|
|
@ -2262,6 +2308,8 @@ batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
|
|||
|
||||
static void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
INIT_DELAYED_WORK(&hard_iface->bat_iv.reschedule_work, batadv_iv_ogm_reschedule);
|
||||
|
||||
/* begin scheduling originator messages on that interface */
|
||||
batadv_iv_ogm_schedule(hard_iface);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,14 +113,14 @@ static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
|
|||
|
||||
/**
|
||||
* batadv_v_ogm_send_to_if() - send a batman ogm using a given interface
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @skb: the OGM to send
|
||||
* @hard_iface: the interface to use to send the OGM
|
||||
*/
|
||||
static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
|
||||
static void batadv_v_ogm_send_to_if(struct batadv_priv *bat_priv,
|
||||
struct sk_buff *skb,
|
||||
struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
|
||||
|
||||
if (hard_iface->if_status != BATADV_IF_ACTIVE) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
|
|
@ -187,6 +187,7 @@ static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
|
|||
|
||||
/**
|
||||
* batadv_v_ogm_aggr_send() - flush & send aggregation queue
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @hard_iface: the interface with the aggregation queue to flush
|
||||
*
|
||||
* Aggregates all OGMv2 packets currently in the aggregation queue into a
|
||||
|
|
@ -196,7 +197,8 @@ static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
|
|||
*
|
||||
* Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
|
||||
*/
|
||||
static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface)
|
||||
static void batadv_v_ogm_aggr_send(struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
unsigned int aggr_len = hard_iface->bat_v.aggr_len;
|
||||
struct sk_buff *skb_aggr;
|
||||
|
|
@ -226,27 +228,32 @@ static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface)
|
|||
consume_skb(skb);
|
||||
}
|
||||
|
||||
batadv_v_ogm_send_to_if(skb_aggr, hard_iface);
|
||||
batadv_v_ogm_send_to_if(bat_priv, skb_aggr, hard_iface);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_ogm_queue_on_if() - queue a batman ogm on a given interface
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @skb: the OGM to queue
|
||||
* @hard_iface: the interface to queue the OGM on
|
||||
*/
|
||||
static void batadv_v_ogm_queue_on_if(struct sk_buff *skb,
|
||||
static void batadv_v_ogm_queue_on_if(struct batadv_priv *bat_priv,
|
||||
struct sk_buff *skb,
|
||||
struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
|
||||
if (hard_iface->mesh_iface != bat_priv->mesh_iface) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!atomic_read(&bat_priv->aggregated_ogms)) {
|
||||
batadv_v_ogm_send_to_if(skb, hard_iface);
|
||||
batadv_v_ogm_send_to_if(bat_priv, skb, hard_iface);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
|
||||
if (!batadv_v_ogm_queue_left(skb, hard_iface))
|
||||
batadv_v_ogm_aggr_send(hard_iface);
|
||||
batadv_v_ogm_aggr_send(bat_priv, hard_iface);
|
||||
|
||||
hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb);
|
||||
__skb_queue_tail(&hard_iface->bat_v.aggr_list, skb);
|
||||
|
|
@ -262,10 +269,10 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv)
|
|||
struct batadv_hard_iface *hard_iface;
|
||||
struct batadv_ogm2_packet *ogm_packet;
|
||||
struct sk_buff *skb, *skb_tmp;
|
||||
unsigned char *ogm_buff;
|
||||
unsigned char **ogm_buff;
|
||||
struct list_head *iter;
|
||||
int ogm_buff_len;
|
||||
u16 tvlv_len = 0;
|
||||
int *ogm_buff_len;
|
||||
u16 tvlv_len;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex);
|
||||
|
|
@ -273,25 +280,27 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv)
|
|||
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
|
||||
goto out;
|
||||
|
||||
ogm_buff = bat_priv->bat_v.ogm_buff;
|
||||
ogm_buff_len = bat_priv->bat_v.ogm_buff_len;
|
||||
ogm_buff = &bat_priv->bat_v.ogm_buff;
|
||||
ogm_buff_len = &bat_priv->bat_v.ogm_buff_len;
|
||||
|
||||
/* tt changes have to be committed before the tvlv data is
|
||||
* appended as it may alter the tt tvlv container
|
||||
*/
|
||||
batadv_tt_local_commit_changes(bat_priv);
|
||||
tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
|
||||
&ogm_buff_len,
|
||||
BATADV_OGM2_HLEN);
|
||||
ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
|
||||
ogm_buff_len,
|
||||
BATADV_OGM2_HLEN);
|
||||
if (ret < 0)
|
||||
goto reschedule;
|
||||
|
||||
bat_priv->bat_v.ogm_buff = ogm_buff;
|
||||
bat_priv->bat_v.ogm_buff_len = ogm_buff_len;
|
||||
tvlv_len = ret;
|
||||
|
||||
skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len);
|
||||
skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + *ogm_buff_len);
|
||||
if (!skb)
|
||||
goto reschedule;
|
||||
|
||||
skb_reserve(skb, ETH_HLEN);
|
||||
skb_put_data(skb, ogm_buff, ogm_buff_len);
|
||||
skb_put_data(skb, *ogm_buff, *ogm_buff_len);
|
||||
|
||||
ogm_packet = (struct batadv_ogm2_packet *)skb->data;
|
||||
ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
|
||||
|
|
@ -343,7 +352,7 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv)
|
|||
break;
|
||||
}
|
||||
|
||||
batadv_v_ogm_queue_on_if(skb_tmp, hard_iface);
|
||||
batadv_v_ogm_queue_on_if(bat_priv, skb_tmp, hard_iface);
|
||||
batadv_hardif_put(hard_iface);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
|
@ -383,12 +392,14 @@ void batadv_v_ogm_aggr_work(struct work_struct *work)
|
|||
{
|
||||
struct batadv_hard_iface_bat_v *batv;
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
struct batadv_priv *bat_priv;
|
||||
|
||||
batv = container_of(work, struct batadv_hard_iface_bat_v, aggr_wq.work);
|
||||
hard_iface = container_of(batv, struct batadv_hard_iface, bat_v);
|
||||
bat_priv = netdev_priv(hard_iface->mesh_iface);
|
||||
|
||||
spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
|
||||
batadv_v_ogm_aggr_send(hard_iface);
|
||||
batadv_v_ogm_aggr_send(bat_priv, hard_iface);
|
||||
spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
|
||||
|
||||
batadv_v_ogm_start_queue_timer(hard_iface);
|
||||
|
|
@ -578,7 +589,7 @@ static void batadv_v_ogm_forward(struct batadv_priv *bat_priv,
|
|||
if_outgoing->net_dev->name, ntohl(ogm_forward->throughput),
|
||||
ogm_forward->ttl, if_incoming->net_dev->name);
|
||||
|
||||
batadv_v_ogm_queue_on_if(skb, if_outgoing);
|
||||
batadv_v_ogm_queue_on_if(bat_priv, skb, if_outgoing);
|
||||
|
||||
out:
|
||||
batadv_orig_ifinfo_put(orig_ifinfo);
|
||||
|
|
|
|||
|
|
@ -356,12 +356,14 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, const u8 *mac,
|
|||
sizeof(local_claim_dest));
|
||||
local_claim_dest.type = claimtype;
|
||||
|
||||
mesh_iface = primary_if->mesh_iface;
|
||||
mesh_iface = READ_ONCE(primary_if->mesh_iface);
|
||||
if (!mesh_iface)
|
||||
goto out;
|
||||
|
||||
skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
|
||||
/* IP DST: 0.0.0.0 */
|
||||
zeroip,
|
||||
primary_if->mesh_iface,
|
||||
mesh_iface,
|
||||
/* IP SRC: 0.0.0.0 */
|
||||
zeroip,
|
||||
/* Ethernet DST: Broadcast */
|
||||
|
|
@ -514,8 +516,8 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, const u8 *orig,
|
|||
entry->crc = BATADV_BLA_CRC_INIT;
|
||||
entry->bat_priv = bat_priv;
|
||||
spin_lock_init(&entry->crc_lock);
|
||||
atomic_set(&entry->request_sent, 0);
|
||||
atomic_set(&entry->wait_periods, 0);
|
||||
entry->state = BATADV_BLA_BACKBONE_GW_SYNCED;
|
||||
entry->wait_periods = 0;
|
||||
ether_addr_copy(entry->orig, orig);
|
||||
INIT_WORK(&entry->report_work, batadv_bla_loopdetect_report);
|
||||
kref_init(&entry->refcount);
|
||||
|
|
@ -544,9 +546,13 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, const u8 *orig,
|
|||
batadv_bla_send_announce(bat_priv, entry);
|
||||
|
||||
/* this will be decreased in the worker thread */
|
||||
atomic_inc(&entry->request_sent);
|
||||
atomic_set(&entry->wait_periods, BATADV_BLA_WAIT_PERIODS);
|
||||
atomic_inc(&bat_priv->bla.num_requests);
|
||||
spin_lock_bh(&bat_priv->bla.num_requests_lock);
|
||||
if (entry->state == BATADV_BLA_BACKBONE_GW_SYNCED) {
|
||||
entry->state = BATADV_BLA_BACKBONE_GW_UNSYNCED;
|
||||
entry->wait_periods = BATADV_BLA_WAIT_PERIODS;
|
||||
atomic_inc(&bat_priv->bla.num_requests);
|
||||
}
|
||||
spin_unlock_bh(&bat_priv->bla.num_requests_lock);
|
||||
}
|
||||
|
||||
return entry;
|
||||
|
|
@ -649,10 +655,12 @@ static void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw)
|
|||
backbone_gw->vid, BATADV_CLAIM_TYPE_REQUEST);
|
||||
|
||||
/* no local broadcasts should be sent or received, for now. */
|
||||
if (!atomic_read(&backbone_gw->request_sent)) {
|
||||
spin_lock_bh(&backbone_gw->bat_priv->bla.num_requests_lock);
|
||||
if (backbone_gw->state == BATADV_BLA_BACKBONE_GW_SYNCED) {
|
||||
backbone_gw->state = BATADV_BLA_BACKBONE_GW_UNSYNCED;
|
||||
atomic_inc(&backbone_gw->bat_priv->bla.num_requests);
|
||||
atomic_set(&backbone_gw->request_sent, 1);
|
||||
}
|
||||
spin_unlock_bh(&backbone_gw->bat_priv->bla.num_requests_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -873,10 +881,12 @@ static bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
|
|||
/* if we have sent a request and the crc was OK,
|
||||
* we can allow traffic again.
|
||||
*/
|
||||
if (atomic_read(&backbone_gw->request_sent)) {
|
||||
spin_lock_bh(&bat_priv->bla.num_requests_lock);
|
||||
if (backbone_gw->state == BATADV_BLA_BACKBONE_GW_UNSYNCED) {
|
||||
backbone_gw->state = BATADV_BLA_BACKBONE_GW_SYNCED;
|
||||
atomic_dec(&backbone_gw->bat_priv->bla.num_requests);
|
||||
atomic_set(&backbone_gw->request_sent, 0);
|
||||
}
|
||||
spin_unlock_bh(&bat_priv->bla.num_requests_lock);
|
||||
}
|
||||
|
||||
batadv_backbone_gw_put(backbone_gw);
|
||||
|
|
@ -1224,6 +1234,7 @@ static void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now)
|
|||
struct hlist_head *head;
|
||||
struct batadv_hashtable *hash;
|
||||
spinlock_t *list_lock; /* protects write access to the hash lists */
|
||||
bool purged;
|
||||
int i;
|
||||
|
||||
hash = bat_priv->bla.backbone_hash;
|
||||
|
|
@ -1234,30 +1245,49 @@ static void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now)
|
|||
head = &hash->table[i];
|
||||
list_lock = &hash->list_locks[i];
|
||||
|
||||
spin_lock_bh(list_lock);
|
||||
hlist_for_each_entry_safe(backbone_gw, node_tmp,
|
||||
head, hash_entry) {
|
||||
if (now)
|
||||
goto purge_now;
|
||||
if (!batadv_has_timed_out(backbone_gw->lasttime,
|
||||
BATADV_BLA_BACKBONE_TIMEOUT))
|
||||
continue;
|
||||
do {
|
||||
purged = false;
|
||||
|
||||
batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
|
||||
"%s(): backbone gw %pM timed out\n",
|
||||
__func__, backbone_gw->orig);
|
||||
spin_lock_bh(list_lock);
|
||||
hlist_for_each_entry_safe(backbone_gw, node_tmp,
|
||||
head, hash_entry) {
|
||||
if (now)
|
||||
goto purge_now;
|
||||
if (!batadv_has_timed_out(backbone_gw->lasttime,
|
||||
BATADV_BLA_BACKBONE_TIMEOUT))
|
||||
continue;
|
||||
|
||||
batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
|
||||
"%s(): backbone gw %pM timed out\n",
|
||||
__func__, backbone_gw->orig);
|
||||
|
||||
purge_now:
|
||||
/* don't wait for the pending request anymore */
|
||||
if (atomic_read(&backbone_gw->request_sent))
|
||||
atomic_dec(&bat_priv->bla.num_requests);
|
||||
purged = true;
|
||||
|
||||
batadv_bla_del_backbone_claims(backbone_gw);
|
||||
/* don't wait for the pending request anymore */
|
||||
spin_lock_bh(&bat_priv->bla.num_requests_lock);
|
||||
if (backbone_gw->state == BATADV_BLA_BACKBONE_GW_UNSYNCED)
|
||||
atomic_dec(&bat_priv->bla.num_requests);
|
||||
|
||||
hlist_del_rcu(&backbone_gw->hash_entry);
|
||||
batadv_backbone_gw_put(backbone_gw);
|
||||
}
|
||||
spin_unlock_bh(list_lock);
|
||||
backbone_gw->state = BATADV_BLA_BACKBONE_GW_STOPPED;
|
||||
spin_unlock_bh(&bat_priv->bla.num_requests_lock);
|
||||
|
||||
batadv_bla_del_backbone_claims(backbone_gw);
|
||||
|
||||
hlist_del_rcu(&backbone_gw->hash_entry);
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(list_lock);
|
||||
|
||||
if (purged) {
|
||||
/* reference for pending report_work */
|
||||
if (cancel_work_sync(&backbone_gw->report_work))
|
||||
batadv_backbone_gw_put(backbone_gw);
|
||||
|
||||
/* reference for hash_entry */
|
||||
batadv_backbone_gw_put(backbone_gw);
|
||||
}
|
||||
} while (purged);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1492,7 +1522,7 @@ static void batadv_bla_periodic_work(struct work_struct *work)
|
|||
batadv_bla_send_loopdetect(bat_priv,
|
||||
backbone_gw);
|
||||
|
||||
/* request_sent is only set after creation to avoid
|
||||
/* state is only set to unsynced after creation to avoid
|
||||
* problems when we are not yet known as backbone gw
|
||||
* in the backbone.
|
||||
*
|
||||
|
|
@ -1501,14 +1531,21 @@ static void batadv_bla_periodic_work(struct work_struct *work)
|
|||
* some grace time.
|
||||
*/
|
||||
|
||||
if (atomic_read(&backbone_gw->request_sent) == 0)
|
||||
continue;
|
||||
spin_lock_bh(&bat_priv->bla.num_requests_lock);
|
||||
if (backbone_gw->state != BATADV_BLA_BACKBONE_GW_UNSYNCED)
|
||||
goto unlock_next;
|
||||
|
||||
if (!atomic_dec_and_test(&backbone_gw->wait_periods))
|
||||
continue;
|
||||
if (backbone_gw->wait_periods > 0)
|
||||
backbone_gw->wait_periods--;
|
||||
|
||||
if (backbone_gw->wait_periods > 0)
|
||||
goto unlock_next;
|
||||
|
||||
backbone_gw->state = BATADV_BLA_BACKBONE_GW_SYNCED;
|
||||
atomic_dec(&backbone_gw->bat_priv->bla.num_requests);
|
||||
atomic_set(&backbone_gw->request_sent, 0);
|
||||
|
||||
unlock_next:
|
||||
spin_unlock_bh(&bat_priv->bla.num_requests_lock);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -696,6 +696,9 @@ static bool batadv_dat_forward_data(struct batadv_priv *bat_priv,
|
|||
goto free_orig;
|
||||
|
||||
tmp_skb = pskb_copy_for_clone(skb, GFP_ATOMIC);
|
||||
if (!tmp_skb)
|
||||
goto free_neigh;
|
||||
|
||||
if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, tmp_skb,
|
||||
cand[i].orig_node,
|
||||
packet_subtype)) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/lockdep.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
|
@ -80,9 +81,9 @@ void batadv_frag_purge_orig(struct batadv_orig_node *orig_node,
|
|||
*
|
||||
* Return: the maximum size of payload that can be fragmented.
|
||||
*/
|
||||
static int batadv_frag_size_limit(void)
|
||||
static size_t batadv_frag_size_limit(void)
|
||||
{
|
||||
int limit = BATADV_FRAG_MAX_FRAG_SIZE;
|
||||
size_t limit = BATADV_FRAG_MAX_FRAG_SIZE;
|
||||
|
||||
limit -= sizeof(struct batadv_frag_packet);
|
||||
limit *= BATADV_FRAG_MAX_FRAGMENTS;
|
||||
|
|
@ -143,7 +144,9 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
|
|||
struct batadv_frag_packet *frag_packet;
|
||||
u8 bucket;
|
||||
u16 seqno, hdr_size = sizeof(struct batadv_frag_packet);
|
||||
bool overflow = false;
|
||||
bool ret = false;
|
||||
size_t data_len;
|
||||
|
||||
/* Linearize packet to avoid linearizing 16 packets in a row when doing
|
||||
* the later merge. Non-linear merge should be added to remove this
|
||||
|
|
@ -153,6 +156,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
|
|||
goto err;
|
||||
|
||||
frag_packet = (struct batadv_frag_packet *)skb->data;
|
||||
data_len = skb->len - hdr_size;
|
||||
seqno = ntohs(frag_packet->seqno);
|
||||
bucket = seqno % BATADV_FRAG_BUFFER_COUNT;
|
||||
|
||||
|
|
@ -171,7 +175,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
|
|||
spin_lock_bh(&chain->lock);
|
||||
if (batadv_frag_init_chain(chain, seqno)) {
|
||||
hlist_add_head(&frag_entry_new->list, &chain->fragment_list);
|
||||
chain->size = skb->len - hdr_size;
|
||||
chain->size = data_len;
|
||||
chain->timestamp = jiffies;
|
||||
chain->total_size = ntohs(frag_packet->total_size);
|
||||
ret = true;
|
||||
|
|
@ -188,7 +192,11 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
|
|||
if (frag_entry_curr->no < frag_entry_new->no) {
|
||||
hlist_add_before(&frag_entry_new->list,
|
||||
&frag_entry_curr->list);
|
||||
chain->size += skb->len - hdr_size;
|
||||
|
||||
if (check_add_overflow(chain->size, data_len,
|
||||
&chain->size))
|
||||
overflow = true;
|
||||
|
||||
chain->timestamp = jiffies;
|
||||
ret = true;
|
||||
goto out;
|
||||
|
|
@ -201,13 +209,16 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
|
|||
/* Reached the end of the list, so insert after 'frag_entry_last'. */
|
||||
if (likely(frag_entry_last)) {
|
||||
hlist_add_behind(&frag_entry_new->list, &frag_entry_last->list);
|
||||
chain->size += skb->len - hdr_size;
|
||||
|
||||
if (check_add_overflow(chain->size, data_len, &chain->size))
|
||||
overflow = true;
|
||||
|
||||
chain->timestamp = jiffies;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
out:
|
||||
if (chain->size > batadv_frag_size_limit() ||
|
||||
if (overflow || chain->size > batadv_frag_size_limit() ||
|
||||
chain->total_size != ntohs(frag_packet->total_size) ||
|
||||
chain->total_size > batadv_frag_size_limit()) {
|
||||
/* Clear chain if total size of either the list or the packet
|
||||
|
|
@ -293,6 +304,31 @@ batadv_frag_merge_packets(struct hlist_head *chain)
|
|||
return skb_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_skb_is_frag() - check if newly merged skb contains unicast fragment
|
||||
* @skb: newly merged skb
|
||||
*
|
||||
* Return: if newly merged skb is of type BATADV_UNICAST_FRAG
|
||||
*/
|
||||
static bool batadv_skb_is_frag(struct sk_buff *skb)
|
||||
{
|
||||
struct batadv_ogm_packet *batadv_ogm_packet;
|
||||
|
||||
/* packet should hold at least type and version */
|
||||
if (unlikely(!pskb_may_pull(skb, 2)))
|
||||
return false;
|
||||
|
||||
batadv_ogm_packet = (struct batadv_ogm_packet *)skb->data;
|
||||
|
||||
if (batadv_ogm_packet->version != BATADV_COMPAT_VERSION)
|
||||
return false;
|
||||
|
||||
if (batadv_ogm_packet->packet_type != BATADV_UNICAST_FRAG)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_frag_skb_buffer() - buffer fragment for later merge
|
||||
* @skb: skb to buffer
|
||||
|
|
@ -326,6 +362,16 @@ bool batadv_frag_skb_buffer(struct sk_buff **skb,
|
|||
if (!skb_out)
|
||||
goto out_err;
|
||||
|
||||
/* fragment in fragment is not allowed. otherwise it is possible
|
||||
* to exhaust the stack when receiving a matryoshka-style
|
||||
* "fragments in a fragment packet"
|
||||
*/
|
||||
if (batadv_skb_is_frag(skb_out)) {
|
||||
kfree_skb(skb_out);
|
||||
skb_out = NULL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
out:
|
||||
ret = true;
|
||||
out_err:
|
||||
|
|
|
|||
|
|
@ -478,10 +478,14 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
|
|||
*/
|
||||
void batadv_gw_node_free(struct batadv_priv *bat_priv)
|
||||
{
|
||||
struct batadv_gw_node *curr_gw;
|
||||
struct batadv_gw_node *gw_node;
|
||||
struct hlist_node *node_tmp;
|
||||
|
||||
spin_lock_bh(&bat_priv->gw.list_lock);
|
||||
curr_gw = rcu_replace_pointer(bat_priv->gw.curr_gw, NULL, true);
|
||||
batadv_gw_node_put(curr_gw);
|
||||
|
||||
hlist_for_each_entry_safe(gw_node, node_tmp,
|
||||
&bat_priv->gw.gateway_list, list) {
|
||||
hlist_del_init_rcu(&gw_node->list);
|
||||
|
|
|
|||
|
|
@ -787,6 +787,7 @@ static int batadv_meshif_init_late(struct net_device *dev)
|
|||
atomic_set(&bat_priv->tt.ogm_append_cnt, 0);
|
||||
#ifdef CONFIG_BATMAN_ADV_BLA
|
||||
atomic_set(&bat_priv->bla.num_requests, 0);
|
||||
spin_lock_init(&bat_priv->bla.num_requests_lock);
|
||||
#endif
|
||||
atomic_set(&bat_priv->tp_num, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -835,8 +835,6 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
|
|||
|
||||
orig_node = container_of(rcu, struct batadv_orig_node, rcu);
|
||||
|
||||
batadv_mcast_purge_orig(orig_node);
|
||||
|
||||
batadv_frag_purge_orig(orig_node, NULL);
|
||||
|
||||
kfree(orig_node->tt_buff);
|
||||
|
|
@ -887,6 +885,8 @@ void batadv_orig_node_release(struct kref *ref)
|
|||
}
|
||||
spin_unlock_bh(&orig_node->vlan_list_lock);
|
||||
|
||||
batadv_mcast_purge_orig(orig_node);
|
||||
|
||||
call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu);
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user