Merge tag '5.3-rc3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 8 Aug 2019 16:57:50 +0000 (09:57 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 8 Aug 2019 16:57:50 +0000 (09:57 -0700)
Pull cifs fixes from Steve French:
 "Six small SMB3 fixes, two for stable"

* tag '5.3-rc3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  SMB3: Kernel oops mounting a encryptData share with CONFIG_DEBUG_VIRTUAL
  smb3: update TODO list of missing features
  smb3: send CAP_DFS capability during session setup
  SMB3: Fix potential memory leak when processing compound chain
  SMB3: Fix deadlock in validate negotiate hits reconnect
  cifs: fix rmmod regression in cifs.ko caused by force_sig changes

260 files changed:
Documentation/admin-guide/hw-vuln/spectre.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/devicetree/bindings/spi/spi-controller.yaml
Documentation/networking/tls-offload.rst
MAINTAINERS
arch/mips/cavium-octeon/octeon-usb.c
arch/mips/kernel/cacheinfo.c
arch/mips/kernel/i8253.c
arch/mips/kvm/emulate.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/pci/ops-bcm63xx.c
arch/x86/entry/calling.h
arch/x86/entry/entry_64.S
arch/x86/include/asm/cpufeatures.h
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
drivers/atm/iphase.c
drivers/hid/hid-a4tech.c
drivers/hid/hid-holtek-kbd.c
drivers/hid/hid-ids.h
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-quirks.c
drivers/hid/hid-sony.c
drivers/hid/hid-tmff.c
drivers/hid/usbhid/hiddev.c
drivers/hid/wacom_wac.c
drivers/hwmon/lm75.c
drivers/hwmon/nct7802.c
drivers/isdn/hardware/mISDN/hfcsusb.c
drivers/net/arcnet/arc-rimi.c
drivers/net/arcnet/com20020-isa.c
drivers/net/arcnet/com90io.c
drivers/net/arcnet/com90xx.c
drivers/net/bonding/bond_main.c
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/can/rcar/rcar_canfd.c
drivers/net/can/sja1000/peak_pcmcia.c
drivers/net/can/spi/mcp251x.c
drivers/net/can/usb/peak_usb/pcan_usb_core.c
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/qca8k.c
drivers/net/dsa/sja1105/sja1105_dynamic_config.c
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/dsa/sja1105/sja1105_ptp.c
drivers/net/ethernet/8390/Kconfig
drivers/net/ethernet/agere/et131x.c
drivers/net/ethernet/allwinner/sun4i-emac.c
drivers/net/ethernet/amd/Kconfig
drivers/net/ethernet/apple/Kconfig
drivers/net/ethernet/atheros/ag71xx.c
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/cavium/thunder/thunder_bgx.c
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/enetc/Kconfig
drivers/net/ethernet/freescale/fman/fman.c
drivers/net/ethernet/google/gve/gve.h
drivers/net/ethernet/google/gve/gve_ethtool.c
drivers/net/ethernet/google/gve/gve_rx.c
drivers/net/ethernet/hisilicon/hip04_eth.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/marvell/mvmdio.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mediatek/Kconfig
drivers/net/ethernet/mellanox/mlx5/core/dev.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/params.h
drivers/net/ethernet/mellanox/mlx5/core/en/port.c
drivers/net/ethernet/mellanox/mlx5/core/en/port.h
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
drivers/net/ethernet/ni/Kconfig
drivers/net/ethernet/packetengines/Kconfig
drivers/net/ethernet/packetengines/Makefile
drivers/net/ethernet/qlogic/qed/qed_int.c
drivers/net/ethernet/qlogic/qed/qed_rdma.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/rocker/rocker_main.c
drivers/net/ethernet/samsung/Kconfig
drivers/net/ethernet/smsc/smc911x.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
drivers/net/ethernet/toshiba/spider_net.c
drivers/net/ethernet/xscale/Kconfig
drivers/net/hamradio/baycom_epp.c
drivers/net/phy/fixed_phy.c
drivers/net/phy/mscc.c
drivers/net/phy/phy_device.c
drivers/net/phy/phy_led_triggers.c
drivers/net/phy/phylink.c
drivers/net/ppp/pppoe.c
drivers/net/ppp/pppox.c
drivers/net/ppp/pptp.c
drivers/net/tun.c
drivers/net/usb/pegasus.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/wan/sdla.c
drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
drivers/net/wireless/intel/iwlwifi/fw/dbg.c
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.h
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/mvm/utils.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/marvell/mwifiex/main.h
drivers/net/wireless/marvell/mwifiex/scan.c
drivers/nfc/nfcmrvl/main.c
drivers/nfc/nfcmrvl/uart.c
drivers/nfc/nfcmrvl/usb.c
drivers/nfc/st-nci/se.c
drivers/nfc/st21nfca/se.c
drivers/regulator/axp20x-regulator.c
drivers/regulator/lp87565-regulator.c
drivers/regulator/of_regulator.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-fsl-qspi.c
drivers/spi/spi-gpio.c
drivers/spi/spi-pxa2xx.c
fs/compat_ioctl.c
include/linux/dim.h
include/linux/filter.h
include/linux/if_pppox.h
include/linux/if_rmnet.h
include/linux/mlx5/fs.h
include/linux/mlx5/mlx5_ifc.h
include/linux/skmsg.h
include/net/cfg80211.h
include/net/tc_act/tc_police.h
include/net/tc_act/tc_sample.h
include/net/tcp.h
include/net/tls.h
include/uapi/linux/netfilter/xt_connlabel.h
include/uapi/linux/socket.h
kernel/bpf/verifier.c
lib/dim/dim.c
lib/dim/net_dim.c
net/bridge/br.c
net/bridge/br_multicast.c
net/bridge/br_private.h
net/bridge/br_vlan.c
net/bridge/netfilter/ebtables.c
net/bridge/netfilter/nft_meta_bridge.c
net/can/gw.c
net/core/dev.c
net/core/filter.c
net/core/skmsg.c
net/core/sock_map.c
net/dsa/tag_sja1105.c
net/ipv4/inet_fragment.c
net/ipv4/ipip.c
net/ipv4/tcp_ulp.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_tunnel.c
net/ipv6/route.c
net/iucv/af_iucv.c
net/l2tp/l2tp_ppp.c
net/mac80211/iface.c
net/mac80211/mlme.c
net/mac80211/util.c
net/netfilter/ipset/ip_set_bitmap_ipmac.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_ipmac.c
net/netfilter/nft_meta.c
net/netrom/af_netrom.c
net/openvswitch/datapath.c
net/rds/rdma_transport.c
net/rxrpc/ar-internal.h
net/rxrpc/peer_event.c
net/rxrpc/peer_object.c
net/rxrpc/sendmsg.c
net/sched/act_bpf.c
net/sched/act_connmark.c
net/sched/act_csum.c
net/sched/act_ct.c
net/sched/act_ctinfo.c
net/sched/act_gact.c
net/sched/act_ife.c
net/sched/act_mirred.c
net/sched/act_mpls.c
net/sched/act_nat.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_sample.c
net/sched/act_simple.c
net/sched/act_skbedit.c
net/sched/act_skbmod.c
net/sched/act_tunnel_key.c
net/sched/act_vlan.c
net/sched/sch_codel.c
net/sctp/socket.c
net/smc/af_smc.c
net/tipc/netlink_compat.c
net/tipc/socket.c
net/tls/tls_main.c
net/tls/tls_sw.c
net/vmw_vsock/hyperv_transport.c
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/util.c
tools/lib/bpf/btf.c
tools/lib/bpf/libbpf.c
tools/lib/bpf/xsk.c
tools/testing/selftests/bpf/Makefile
tools/testing/selftests/bpf/progs/sendmsg6_prog.c
tools/testing/selftests/bpf/test_xdp_vlan.sh
tools/testing/selftests/bpf/test_xdp_vlan_mode_generic.sh [new file with mode: 0755]
tools/testing/selftests/bpf/test_xdp_vlan_mode_native.sh [new file with mode: 0755]
tools/testing/selftests/bpf/verifier/ctx_skb.c
tools/testing/selftests/kselftest.h
tools/testing/selftests/livepatch/functions.sh
tools/testing/selftests/net/.gitignore
tools/testing/selftests/net/forwarding/gre_multipath.sh
tools/testing/selftests/net/tls.c
tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json

index 25f3b253219859a6fa120850b9fcd99bd775b1bd..e05e581af5cfe617f38112907aadea8d03f2a9d6 100644 (file)
@@ -41,10 +41,11 @@ Related CVEs
 
 The following CVE entries describe Spectre variants:
 
-   =============   =======================  =================
+   =============   =======================  ==========================
    CVE-2017-5753   Bounds check bypass      Spectre variant 1
    CVE-2017-5715   Branch target injection  Spectre variant 2
-   =============   =======================  =================
+   CVE-2019-1125   Spectre v1 swapgs        Spectre variant 1 (swapgs)
+   =============   =======================  ==========================
 
 Problem
 -------
@@ -78,6 +79,13 @@ There are some extensions of Spectre variant 1 attacks for reading data
 over the network, see :ref:`[12] <spec_ref12>`. However such attacks
 are difficult, low bandwidth, fragile, and are considered low risk.
 
+Note that, despite "Bounds Check Bypass" name, Spectre variant 1 is not
+only about user-controlled array bounds checks.  It can affect any
+conditional checks.  The kernel entry code interrupt, exception, and NMI
+handlers all have conditional swapgs checks.  Those may be problematic
+in the context of Spectre v1, as kernel code can speculatively run with
+a user GS.
+
 Spectre variant 2 (Branch Target Injection)
 -------------------------------------------
 
@@ -132,6 +140,9 @@ not cover all possible attack vectors.
 1. A user process attacking the kernel
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+Spectre variant 1
+~~~~~~~~~~~~~~~~~
+
    The attacker passes a parameter to the kernel via a register or
    via a known address in memory during a syscall. Such parameter may
    be used later by the kernel as an index to an array or to derive
@@ -144,7 +155,40 @@ not cover all possible attack vectors.
    potentially be influenced for Spectre attacks, new "nospec" accessor
    macros are used to prevent speculative loading of data.
 
-   Spectre variant 2 attacker can :ref:`poison <poison_btb>` the branch
+Spectre variant 1 (swapgs)
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+   An attacker can train the branch predictor to speculatively skip the
+   swapgs path for an interrupt or exception.  If they initialize
+   the GS register to a user-space value, if the swapgs is speculatively
+   skipped, subsequent GS-related percpu accesses in the speculation
+   window will be done with the attacker-controlled GS value.  This
+   could cause privileged memory to be accessed and leaked.
+
+   For example:
+
+   ::
+
+     if (coming from user space)
+         swapgs
+     mov %gs:<percpu_offset>, %reg
+     mov (%reg), %reg1
+
+   When coming from user space, the CPU can speculatively skip the
+   swapgs, and then do a speculative percpu load using the user GS
+   value.  So the user can speculatively force a read of any kernel
+   value.  If a gadget exists which uses the percpu value as an address
+   in another load/store, then the contents of the kernel value may
+   become visible via an L1 side channel attack.
+
+   A similar attack exists when coming from kernel space.  The CPU can
+   speculatively do the swapgs, causing the user GS to get used for the
+   rest of the speculative window.
+
+Spectre variant 2
+~~~~~~~~~~~~~~~~~
+
+   A spectre variant 2 attacker can :ref:`poison <poison_btb>` the branch
    target buffer (BTB) before issuing syscall to launch an attack.
    After entering the kernel, the kernel could use the poisoned branch
    target buffer on indirect jump and jump to gadget code in speculative
@@ -280,11 +324,18 @@ The sysfs file showing Spectre variant 1 mitigation status is:
 
 The possible values in this file are:
 
-  =======================================  =================================
-  'Mitigation: __user pointer sanitation'  Protection in kernel on a case by
-                                           case base with explicit pointer
-                                           sanitation.
-  =======================================  =================================
+  .. list-table::
+
+     * - 'Not affected'
+       - The processor is not vulnerable.
+     * - 'Vulnerable: __user pointer sanitization and usercopy barriers only; no swapgs barriers'
+       - The swapgs protections are disabled; otherwise it has
+         protection in the kernel on a case by case base with explicit
+         pointer sanitation and usercopy LFENCE barriers.
+     * - 'Mitigation: usercopy/swapgs barriers and __user pointer sanitization'
+       - Protection in the kernel on a case by case base with explicit
+         pointer sanitation, usercopy LFENCE barriers, and swapgs LFENCE
+         barriers.
 
 However, the protections are put in place on a case by case basis,
 and there is no guarantee that all possible attack vectors for Spectre
@@ -366,12 +417,27 @@ Turning on mitigation for Spectre variant 1 and Spectre variant 2
 1. Kernel mitigation
 ^^^^^^^^^^^^^^^^^^^^
 
+Spectre variant 1
+~~~~~~~~~~~~~~~~~
+
    For the Spectre variant 1, vulnerable kernel code (as determined
    by code audit or scanning tools) is annotated on a case by case
    basis to use nospec accessor macros for bounds clipping :ref:`[2]
    <spec_ref2>` to avoid any usable disclosure gadgets. However, it may
    not cover all attack vectors for Spectre variant 1.
 
+   Copy-from-user code has an LFENCE barrier to prevent the access_ok()
+   check from being mis-speculated.  The barrier is done by the
+   barrier_nospec() macro.
+
+   For the swapgs variant of Spectre variant 1, LFENCE barriers are
+   added to interrupt, exception and NMI entry where needed.  These
+   barriers are done by the FENCE_SWAPGS_KERNEL_ENTRY and
+   FENCE_SWAPGS_USER_ENTRY macros.
+
+Spectre variant 2
+~~~~~~~~~~~~~~~~~
+
    For Spectre variant 2 mitigation, the compiler turns indirect calls or
    jumps in the kernel into equivalent return trampolines (retpolines)
    :ref:`[3] <spec_ref3>` :ref:`[9] <spec_ref9>` to go to the target
@@ -473,6 +539,12 @@ Mitigation control on the kernel command line
 Spectre variant 2 mitigation can be disabled or force enabled at the
 kernel command line.
 
+       nospectre_v1
+
+               [X86,PPC] Disable mitigations for Spectre Variant 1
+               (bounds check bypass). With this option data leaks are
+               possible in the system.
+
        nospectre_v2
 
                [X86] Disable all mitigations for the Spectre variant 2
index 7ccd158b3894e7841f16c11597ddbcadf1f7c34d..47d981a86e2f8a5c2115d1834eda3ab7af5ccaae 100644 (file)
                                expose users to several CPU vulnerabilities.
                                Equivalent to: nopti [X86,PPC]
                                               kpti=0 [ARM64]
-                                              nospectre_v1 [PPC]
+                                              nospectre_v1 [X86,PPC]
                                               nobp=0 [S390]
                                               nospectre_v2 [X86,PPC,S390,ARM64]
                                               spectre_v2_user=off [X86]
                        nosmt=force: Force disable SMT, cannot be undone
                                     via the sysfs control file.
 
-       nospectre_v1    [PPC] Disable mitigations for Spectre Variant 1 (bounds
-                       check bypass). With this option data leaks are possible
-                       in the system.
+       nospectre_v1    [X86,PPC] Disable mitigations for Spectre Variant 1
+                       (bounds check bypass). With this option data leaks are
+                       possible in the system.
 
        nospectre_v2    [X86,PPC_FSL_BOOK3E,ARM64] Disable all mitigations for
                        the Spectre variant 2 (indirect branch prediction)
index 876c0623f322916a1d228da85371a381230d37a4..a02e2fe2bfb22350773759da4b27fc13800f1c49 100644 (file)
@@ -73,7 +73,6 @@ patternProperties:
           Compatible of the SPI device.
 
       reg:
-        maxItems: 1
         minimum: 0
         maximum: 256
         description:
index 048e5ca44824b4bd7304ee26b5a4c0b7185f828c..b70b70dc4524d4524ce1a744b0286eafade8afdc 100644 (file)
@@ -424,13 +424,24 @@ Statistics
 Following minimum set of TLS-related statistics should be reported
 by the driver:
 
- * ``rx_tls_decrypted`` - number of successfully decrypted TLS segments
- * ``tx_tls_encrypted`` - number of in-order TLS segments passed to device
-   for encryption
+ * ``rx_tls_decrypted_packets`` - number of successfully decrypted RX packets
+   which were part of a TLS stream.
+ * ``rx_tls_decrypted_bytes`` - number of TLS payload bytes in RX packets
+   which were successfully decrypted.
+ * ``tx_tls_encrypted_packets`` - number of TX packets passed to the device
+   for encryption of their TLS payload.
+ * ``tx_tls_encrypted_bytes`` - number of TLS payload bytes in TX packets
+   passed to the device for encryption.
+ * ``tx_tls_ctx`` - number of TLS TX HW offload contexts added to device for
+   encryption.
  * ``tx_tls_ooo`` - number of TX packets which were part of a TLS stream
-   but did not arrive in the expected order
- * ``tx_tls_drop_no_sync_data`` - number of TX packets dropped because
-   they arrived out of order and associated record could not be found
+   but did not arrive in the expected order.
+ * ``tx_tls_drop_no_sync_data`` - number of TX packets which were part of
+   a TLS stream dropped, because they arrived out of order and associated
+   record could not be found.
+ * ``tx_tls_drop_bypass_req`` - number of TX packets which were part of a TLS
+   stream dropped, because they contain both data that has been encrypted by
+   software and data that expects hardware crypto offload.
 
 Notable corner cases, exceptions and additional requirements
 ============================================================
index a2c343ee3b2ca13e4cbe7257a9e4a58d69a11285..47800d32cfbc77c0d60f2083481d9833197f0d6e 100644 (file)
@@ -6827,13 +6827,6 @@ F:       Documentation/filesystems/gfs2*.txt
 F:     fs/gfs2/
 F:     include/uapi/linux/gfs2_ondisk.h
 
-GIGASET ISDN DRIVERS
-M:     Paul Bolle <pebolle@tiscali.nl>
-L:     gigaset307x-common@lists.sourceforge.net
-W:     http://gigaset307x.sourceforge.net/
-S:     Odd Fixes
-F:     drivers/staging/isdn/gigaset/
-
 GNSS SUBSYSTEM
 M:     Johan Hovold <johan@kernel.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss.git
@@ -11149,6 +11142,7 @@ L:      netdev@vger.kernel.org
 S:     Maintained
 W:     https://fedorahosted.org/dropwatch/
 F:     net/core/drop_monitor.c
+F:     include/uapi/linux/net_dropmon.h
 
 NETWORKING DRIVERS
 M:     "David S. Miller" <davem@davemloft.net>
@@ -11287,6 +11281,7 @@ M:      Aviad Yehezkel <aviadye@mellanox.com>
 M:     Dave Watson <davejwatson@fb.com>
 M:     John Fastabend <john.fastabend@gmail.com>
 M:     Daniel Borkmann <daniel@iogearbox.net>
+M:     Jakub Kicinski <jakub.kicinski@netronome.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     net/tls/*
@@ -17565,7 +17560,6 @@ M:      Jakub Kicinski <jakub.kicinski@netronome.com>
 M:     Jesper Dangaard Brouer <hawk@kernel.org>
 M:     John Fastabend <john.fastabend@gmail.com>
 L:     netdev@vger.kernel.org
-L:     xdp-newbies@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     net/core/xdp.c
index 1f730ded52245739e5aadcb404acdde23a10c573..cc88a08bc1f736422a561a093f3cd24cf757ea2b 100644 (file)
@@ -398,6 +398,7 @@ static int dwc3_octeon_clocks_start(struct device *dev, u64 base)
        default:
                dev_err(dev, "Invalid ref_clk %u, using 100000000 instead\n",
                        clock_rate);
+               /* fall through */
        case 100000000:
                mpll_mul = 0x19;
                if (ref_clk_sel < 2)
index e0dd66881da68ce927bf17a9b9aa0ed064b0cc7a..f777e44653d5767b953483f22158d24e84e6461f 100644 (file)
@@ -69,6 +69,8 @@ static int __populate_cache_leaves(unsigned int cpu)
        if (c->tcache.waysize)
                populate_cache(tcache, this_leaf, 3, CACHE_TYPE_UNIFIED);
 
+       this_cpu_ci->cpu_map_populated = true;
+
        return 0;
 }
 
index 5f209f111e59e3ad9c6e31bee8352623cacc3e68..df7ddd246eaac730333bc24cc361f1893be100aa 100644 (file)
@@ -32,7 +32,8 @@ void __init setup_pit_timer(void)
 
 static int __init init_pit_clocksource(void)
 {
-       if (num_possible_cpus() > 1) /* PIT does not scale! */
+       if (num_possible_cpus() > 1 || /* PIT does not scale! */
+           !clockevent_state_periodic(&i8253_clockevent))
                return 0;
 
        return clocksource_i8253_init();
index e5de6bac81979122f0a8464d66c2df81c1eeafd2..754094b40a75332c1f8cb58266a5181a44ef142d 100644 (file)
@@ -140,6 +140,7 @@ static int kvm_compute_return_epc(struct kvm_vcpu *vcpu, unsigned long instpc,
                /* These are unconditional and in j_format. */
        case jal_op:
                arch->gprs[31] = instpc + 8;
+               /* fall through */
        case j_op:
                epc += 4;
                epc >>= 28;
index 7c04b17f4a488aa8e50186be84dd0fcc50125ba2..96c13a0ab0788904d7e06319c26927f4a11da260 100644 (file)
@@ -172,12 +172,15 @@ static void mipsxx_cpu_setup(void *args)
        case 4:
                w_c0_perfctrl3(0);
                w_c0_perfcntr3(reg.counter[3]);
+               /* fall through */
        case 3:
                w_c0_perfctrl2(0);
                w_c0_perfcntr2(reg.counter[2]);
+               /* fall through */
        case 2:
                w_c0_perfctrl1(0);
                w_c0_perfcntr1(reg.counter[1]);
+               /* fall through */
        case 1:
                w_c0_perfctrl0(0);
                w_c0_perfcntr0(reg.counter[0]);
@@ -195,10 +198,13 @@ static void mipsxx_cpu_start(void *args)
        switch (counters) {
        case 4:
                w_c0_perfctrl3(WHAT | reg.control[3]);
+               /* fall through */
        case 3:
                w_c0_perfctrl2(WHAT | reg.control[2]);
+               /* fall through */
        case 2:
                w_c0_perfctrl1(WHAT | reg.control[1]);
+               /* fall through */
        case 1:
                w_c0_perfctrl0(WHAT | reg.control[0]);
        }
@@ -215,10 +221,13 @@ static void mipsxx_cpu_stop(void *args)
        switch (counters) {
        case 4:
                w_c0_perfctrl3(0);
+               /* fall through */
        case 3:
                w_c0_perfctrl2(0);
+               /* fall through */
        case 2:
                w_c0_perfctrl1(0);
+               /* fall through */
        case 1:
                w_c0_perfctrl0(0);
        }
@@ -236,6 +245,7 @@ static int mipsxx_perfcount_handler(void)
 
        switch (counters) {
 #define HANDLE_COUNTER(n)                                              \
+       /* fall through */                                              \
        case n + 1:                                                     \
                control = r_c0_perfctrl ## n();                         \
                counter = r_c0_perfcntr ## n();                         \
@@ -297,12 +307,15 @@ static void reset_counters(void *arg)
        case 4:
                w_c0_perfctrl3(0);
                w_c0_perfcntr3(0);
+               /* fall through */
        case 3:
                w_c0_perfctrl2(0);
                w_c0_perfcntr2(0);
+               /* fall through */
        case 2:
                w_c0_perfctrl1(0);
                w_c0_perfcntr1(0);
+               /* fall through */
        case 1:
                w_c0_perfctrl0(0);
                w_c0_perfcntr0(0);
index d02eb9d16b55590e9740d1bde1e1b1178569896a..925c72348fb6ea5c95d1483acb7875c6bc613045 100644 (file)
@@ -474,6 +474,7 @@ static int bcm63xx_pcie_can_access(struct pci_bus *bus, int devfn)
                if (PCI_SLOT(devfn) == 0)
                        return bcm_pcie_readl(PCIE_DLSTATUS_REG)
                                        & DLSTATUS_PHYLINKUP;
+               /* else, fall through */
        default:
                return false;
        }
index 830bd984182b6bc05c09b868a9100d0917691381..515c0ceeb4a3608bbdd0cb9afad747417e8a7f88 100644 (file)
@@ -314,6 +314,23 @@ For 32-bit we have the following conventions - kernel is built with
 
 #endif
 
+/*
+ * Mitigate Spectre v1 for conditional swapgs code paths.
+ *
+ * FENCE_SWAPGS_USER_ENTRY is used in the user entry swapgs code path, to
+ * prevent a speculative swapgs when coming from kernel space.
+ *
+ * FENCE_SWAPGS_KERNEL_ENTRY is used in the kernel entry non-swapgs code path,
+ * to prevent the swapgs from getting speculatively skipped when coming from
+ * user space.
+ */
+.macro FENCE_SWAPGS_USER_ENTRY
+       ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_USER
+.endm
+.macro FENCE_SWAPGS_KERNEL_ENTRY
+       ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_KERNEL
+.endm
+
 .macro STACKLEAK_ERASE_NOCLOBBER
 #ifdef CONFIG_GCC_PLUGIN_STACKLEAK
        PUSH_AND_CLEAR_REGS
index 3f5a978a02a7d0906237e517580b6d5440a7fcba..be9ca198c581aea7ed29f4417aae9c1c1b835473 100644 (file)
@@ -519,7 +519,7 @@ ENTRY(interrupt_entry)
        testb   $3, CS-ORIG_RAX+8(%rsp)
        jz      1f
        SWAPGS
-
+       FENCE_SWAPGS_USER_ENTRY
        /*
         * Switch to the thread stack. The IRET frame and orig_ax are
         * on the stack, as well as the return address. RDI..R12 are
@@ -549,8 +549,10 @@ ENTRY(interrupt_entry)
        UNWIND_HINT_FUNC
 
        movq    (%rdi), %rdi
+       jmp     2f
 1:
-
+       FENCE_SWAPGS_KERNEL_ENTRY
+2:
        PUSH_AND_CLEAR_REGS save_ret=1
        ENCODE_FRAME_POINTER 8
 
@@ -1238,6 +1240,13 @@ ENTRY(paranoid_entry)
         */
        SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14
 
+       /*
+        * The above SAVE_AND_SWITCH_TO_KERNEL_CR3 macro doesn't do an
+        * unconditional CR3 write, even in the PTI case.  So do an lfence
+        * to prevent GS speculation, regardless of whether PTI is enabled.
+        */
+       FENCE_SWAPGS_KERNEL_ENTRY
+
        ret
 END(paranoid_entry)
 
@@ -1288,6 +1297,7 @@ ENTRY(error_entry)
         * from user mode due to an IRET fault.
         */
        SWAPGS
+       FENCE_SWAPGS_USER_ENTRY
        /* We have user CR3.  Change to kernel CR3. */
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
 
@@ -1301,6 +1311,8 @@ ENTRY(error_entry)
        pushq   %r12
        ret
 
+.Lerror_entry_done_lfence:
+       FENCE_SWAPGS_KERNEL_ENTRY
 .Lerror_entry_done:
        ret
 
@@ -1318,7 +1330,7 @@ ENTRY(error_entry)
        cmpq    %rax, RIP+8(%rsp)
        je      .Lbstep_iret
        cmpq    $.Lgs_change, RIP+8(%rsp)
-       jne     .Lerror_entry_done
+       jne     .Lerror_entry_done_lfence
 
        /*
         * hack: .Lgs_change can fail with user gsbase.  If this happens, fix up
@@ -1326,6 +1338,7 @@ ENTRY(error_entry)
         * .Lgs_change's error handler with kernel gsbase.
         */
        SWAPGS
+       FENCE_SWAPGS_USER_ENTRY
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
        jmp .Lerror_entry_done
 
@@ -1340,6 +1353,7 @@ ENTRY(error_entry)
         * gsbase and CR3.  Switch to kernel gsbase and CR3:
         */
        SWAPGS
+       FENCE_SWAPGS_USER_ENTRY
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
 
        /*
@@ -1431,6 +1445,7 @@ ENTRY(nmi)
 
        swapgs
        cld
+       FENCE_SWAPGS_USER_ENTRY
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rdx
        movq    %rsp, %rdx
        movq    PER_CPU_VAR(cpu_current_top_of_stack), %rsp
index 998c2cc083633f2c564f3cae528b787f7f712f25..e880f2408e29d5e56bb659d851ccb254cc9a148e 100644 (file)
 #define X86_FEATURE_CQM_OCCUP_LLC      (11*32+ 1) /* LLC occupancy monitoring */
 #define X86_FEATURE_CQM_MBM_TOTAL      (11*32+ 2) /* LLC Total MBM monitoring */
 #define X86_FEATURE_CQM_MBM_LOCAL      (11*32+ 3) /* LLC Local MBM monitoring */
+#define X86_FEATURE_FENCE_SWAPGS_USER  (11*32+ 4) /* "" LFENCE in user entry SWAPGS path */
+#define X86_FEATURE_FENCE_SWAPGS_KERNEL        (11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX512_BF16                (12*32+ 5) /* AVX512 BFLOAT16 instructions */
 #define X86_BUG_L1TF                   X86_BUG(18) /* CPU is affected by L1 Terminal Fault */
 #define X86_BUG_MDS                    X86_BUG(19) /* CPU is affected by Microarchitectural data sampling */
 #define X86_BUG_MSBDS_ONLY             X86_BUG(20) /* CPU is only affected by the  MSDBS variant of BUG_MDS */
+#define X86_BUG_SWAPGS                 X86_BUG(21) /* CPU is affected by speculation through SWAPGS */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index 801ecd1c3fd58723c124fa5e0424f024fe5f889c..c6fa3ef10b4ef2f400ac256973958b51861479db 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "cpu.h"
 
+static void __init spectre_v1_select_mitigation(void);
 static void __init spectre_v2_select_mitigation(void);
 static void __init ssb_select_mitigation(void);
 static void __init l1tf_select_mitigation(void);
@@ -98,17 +99,11 @@ void __init check_bugs(void)
        if (boot_cpu_has(X86_FEATURE_STIBP))
                x86_spec_ctrl_mask |= SPEC_CTRL_STIBP;
 
-       /* Select the proper spectre mitigation before patching alternatives */
+       /* Select the proper CPU mitigations before patching alternatives: */
+       spectre_v1_select_mitigation();
        spectre_v2_select_mitigation();
-
-       /*
-        * Select proper mitigation for any exposure to the Speculative Store
-        * Bypass vulnerability.
-        */
        ssb_select_mitigation();
-
        l1tf_select_mitigation();
-
        mds_select_mitigation();
 
        arch_smt_update();
@@ -273,6 +268,98 @@ static int __init mds_cmdline(char *str)
 }
 early_param("mds", mds_cmdline);
 
+#undef pr_fmt
+#define pr_fmt(fmt)     "Spectre V1 : " fmt
+
+enum spectre_v1_mitigation {
+       SPECTRE_V1_MITIGATION_NONE,
+       SPECTRE_V1_MITIGATION_AUTO,
+};
+
+static enum spectre_v1_mitigation spectre_v1_mitigation __ro_after_init =
+       SPECTRE_V1_MITIGATION_AUTO;
+
+static const char * const spectre_v1_strings[] = {
+       [SPECTRE_V1_MITIGATION_NONE] = "Vulnerable: __user pointer sanitization and usercopy barriers only; no swapgs barriers",
+       [SPECTRE_V1_MITIGATION_AUTO] = "Mitigation: usercopy/swapgs barriers and __user pointer sanitization",
+};
+
+/*
+ * Does SMAP provide full mitigation against speculative kernel access to
+ * userspace?
+ */
+static bool smap_works_speculatively(void)
+{
+       if (!boot_cpu_has(X86_FEATURE_SMAP))
+               return false;
+
+       /*
+        * On CPUs which are vulnerable to Meltdown, SMAP does not
+        * prevent speculative access to user data in the L1 cache.
+        * Consider SMAP to be non-functional as a mitigation on these
+        * CPUs.
+        */
+       if (boot_cpu_has(X86_BUG_CPU_MELTDOWN))
+               return false;
+
+       return true;
+}
+
+static void __init spectre_v1_select_mitigation(void)
+{
+       if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1) || cpu_mitigations_off()) {
+               spectre_v1_mitigation = SPECTRE_V1_MITIGATION_NONE;
+               return;
+       }
+
+       if (spectre_v1_mitigation == SPECTRE_V1_MITIGATION_AUTO) {
+               /*
+                * With Spectre v1, a user can speculatively control either
+                * path of a conditional swapgs with a user-controlled GS
+                * value.  The mitigation is to add lfences to both code paths.
+                *
+                * If FSGSBASE is enabled, the user can put a kernel address in
+                * GS, in which case SMAP provides no protection.
+                *
+                * [ NOTE: Don't check for X86_FEATURE_FSGSBASE until the
+                *         FSGSBASE enablement patches have been merged. ]
+                *
+                * If FSGSBASE is disabled, the user can only put a user space
+                * address in GS.  That makes an attack harder, but still
+                * possible if there's no SMAP protection.
+                */
+               if (!smap_works_speculatively()) {
+                       /*
+                        * Mitigation can be provided from SWAPGS itself or
+                        * PTI as the CR3 write in the Meltdown mitigation
+                        * is serializing.
+                        *
+                        * If neither is there, mitigate with an LFENCE to
+                        * stop speculation through swapgs.
+                        */
+                       if (boot_cpu_has_bug(X86_BUG_SWAPGS) &&
+                           !boot_cpu_has(X86_FEATURE_PTI))
+                               setup_force_cpu_cap(X86_FEATURE_FENCE_SWAPGS_USER);
+
+                       /*
+                        * Enable lfences in the kernel entry (non-swapgs)
+                        * paths, to prevent user entry from speculatively
+                        * skipping swapgs.
+                        */
+                       setup_force_cpu_cap(X86_FEATURE_FENCE_SWAPGS_KERNEL);
+               }
+       }
+
+       pr_info("%s\n", spectre_v1_strings[spectre_v1_mitigation]);
+}
+
+static int __init nospectre_v1_cmdline(char *str)
+{
+       spectre_v1_mitigation = SPECTRE_V1_MITIGATION_NONE;
+       return 0;
+}
+early_param("nospectre_v1", nospectre_v1_cmdline);
+
 #undef pr_fmt
 #define pr_fmt(fmt)     "Spectre V2 : " fmt
 
@@ -1290,7 +1377,7 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
                break;
 
        case X86_BUG_SPECTRE_V1:
-               return sprintf(buf, "Mitigation: __user pointer sanitization\n");
+               return sprintf(buf, "%s\n", spectre_v1_strings[spectre_v1_mitigation]);
 
        case X86_BUG_SPECTRE_V2:
                return sprintf(buf, "%s%s%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
index 11472178e17f5b45f6de5dfb20a8987cbba75a2f..f125bf7ecb6fbca590df390956f53b46d95aec48 100644 (file)
@@ -1022,6 +1022,7 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
 #define NO_L1TF                BIT(3)
 #define NO_MDS         BIT(4)
 #define MSBDS_ONLY     BIT(5)
+#define NO_SWAPGS      BIT(6)
 
 #define VULNWL(_vendor, _family, _model, _whitelist)   \
        { X86_VENDOR_##_vendor, _family, _model, X86_FEATURE_ANY, _whitelist }
@@ -1048,30 +1049,38 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
        VULNWL_INTEL(ATOM_BONNELL,              NO_SPECULATION),
        VULNWL_INTEL(ATOM_BONNELL_MID,          NO_SPECULATION),
 
-       VULNWL_INTEL(ATOM_SILVERMONT,           NO_SSB | NO_L1TF | MSBDS_ONLY),
-       VULNWL_INTEL(ATOM_SILVERMONT_X,         NO_SSB | NO_L1TF | MSBDS_ONLY),
-       VULNWL_INTEL(ATOM_SILVERMONT_MID,       NO_SSB | NO_L1TF | MSBDS_ONLY),
-       VULNWL_INTEL(ATOM_AIRMONT,              NO_SSB | NO_L1TF | MSBDS_ONLY),
-       VULNWL_INTEL(XEON_PHI_KNL,              NO_SSB | NO_L1TF | MSBDS_ONLY),
-       VULNWL_INTEL(XEON_PHI_KNM,              NO_SSB | NO_L1TF | MSBDS_ONLY),
+       VULNWL_INTEL(ATOM_SILVERMONT,           NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+       VULNWL_INTEL(ATOM_SILVERMONT_X,         NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+       VULNWL_INTEL(ATOM_SILVERMONT_MID,       NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+       VULNWL_INTEL(ATOM_AIRMONT,              NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+       VULNWL_INTEL(XEON_PHI_KNL,              NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+       VULNWL_INTEL(XEON_PHI_KNM,              NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
 
        VULNWL_INTEL(CORE_YONAH,                NO_SSB),
 
-       VULNWL_INTEL(ATOM_AIRMONT_MID,          NO_L1TF | MSBDS_ONLY),
+       VULNWL_INTEL(ATOM_AIRMONT_MID,          NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
 
-       VULNWL_INTEL(ATOM_GOLDMONT,             NO_MDS | NO_L1TF),
-       VULNWL_INTEL(ATOM_GOLDMONT_X,           NO_MDS | NO_L1TF),
-       VULNWL_INTEL(ATOM_GOLDMONT_PLUS,        NO_MDS | NO_L1TF),
+       VULNWL_INTEL(ATOM_GOLDMONT,             NO_MDS | NO_L1TF | NO_SWAPGS),
+       VULNWL_INTEL(ATOM_GOLDMONT_X,           NO_MDS | NO_L1TF | NO_SWAPGS),
+       VULNWL_INTEL(ATOM_GOLDMONT_PLUS,        NO_MDS | NO_L1TF | NO_SWAPGS),
+
+       /*
+        * Technically, swapgs isn't serializing on AMD (despite it previously
+        * being documented as such in the APM).  But according to AMD, %gs is
+        * updated non-speculatively, and the issuing of %gs-relative memory
+        * operands will be blocked until the %gs update completes, which is
+        * good enough for our purposes.
+        */
 
        /* AMD Family 0xf - 0x12 */
-       VULNWL_AMD(0x0f,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
-       VULNWL_AMD(0x10,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
-       VULNWL_AMD(0x11,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
-       VULNWL_AMD(0x12,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
+       VULNWL_AMD(0x0f,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
+       VULNWL_AMD(0x10,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
+       VULNWL_AMD(0x11,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
+       VULNWL_AMD(0x12,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
 
        /* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
-       VULNWL_AMD(X86_FAMILY_ANY,      NO_MELTDOWN | NO_L1TF | NO_MDS),
-       VULNWL_HYGON(X86_FAMILY_ANY,    NO_MELTDOWN | NO_L1TF | NO_MDS),
+       VULNWL_AMD(X86_FAMILY_ANY,      NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS),
+       VULNWL_HYGON(X86_FAMILY_ANY,    NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS),
        {}
 };
 
@@ -1108,6 +1117,9 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
                        setup_force_cpu_bug(X86_BUG_MSBDS_ONLY);
        }
 
+       if (!cpu_matches(NO_SWAPGS))
+               setup_force_cpu_bug(X86_BUG_SWAPGS);
+
        if (cpu_matches(NO_MELTDOWN))
                return;
 
index 302cf0ba16008740d8f0ecd231b6f27c73f0f97e..8c7a996d1f16cfd5d2b86a73effe5562ce1732b0 100644 (file)
@@ -63,6 +63,7 @@
 #include <asm/byteorder.h>  
 #include <linux/vmalloc.h>
 #include <linux/jiffies.h>
+#include <linux/nospec.h>
 #include "iphase.h"              
 #include "suni.h"                
 #define swap_byte_order(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8))
@@ -2760,8 +2761,11 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
    }
    if (copy_from_user(&ia_cmds, arg, sizeof ia_cmds)) return -EFAULT; 
    board = ia_cmds.status;
-   if ((board < 0) || (board > iadev_count))
-         board = 0;    
+
+       if ((board < 0) || (board > iadev_count))
+               board = 0;
+       board = array_index_nospec(board, iadev_count + 1);
+
    iadev = ia_dev[board];
    switch (ia_cmds.cmd) {
    case MEMDUMP:
index 98bf694626f71a7e50318ca5b2f3aaf8f2eb6d4f..3a8c4a5971f70d51e7c21f0ecf2c4417c102bd80 100644 (file)
 #define A4_2WHEEL_MOUSE_HACK_7 0x01
 #define A4_2WHEEL_MOUSE_HACK_B8        0x02
 
+#define A4_WHEEL_ORIENTATION   (HID_UP_GENDESK | 0x000000b8)
+
 struct a4tech_sc {
        unsigned long quirks;
        unsigned int hw_wheel;
        __s32 delayed_value;
 };
 
+static int a4_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+                           struct hid_field *field, struct hid_usage *usage,
+                           unsigned long **bit, int *max)
+{
+       struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+
+       if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8 &&
+           usage->hid == A4_WHEEL_ORIENTATION) {
+               /*
+                * We do not want to have this usage mapped to anything as it's
+                * nonstandard and doesn't really behave like an HID report.
+                * It's only selecting the orientation (vertical/horizontal) of
+                * the previous mouse wheel report. The input_events will be
+                * generated once both reports are recorded in a4_event().
+                */
+               return -1;
+       }
+
+       return 0;
+
+}
+
 static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
@@ -52,8 +76,7 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field,
        struct a4tech_sc *a4 = hid_get_drvdata(hdev);
        struct input_dev *input;
 
-       if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
-                       !usage->type)
+       if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput)
                return 0;
 
        input = field->hidinput->input;
@@ -64,7 +87,7 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field,
                        return 1;
                }
 
-               if (usage->hid == 0x000100b8) {
+               if (usage->hid == A4_WHEEL_ORIENTATION) {
                        input_event(input, EV_REL, value ? REL_HWHEEL :
                                        REL_WHEEL, a4->delayed_value);
                        input_event(input, EV_REL, value ? REL_HWHEEL_HI_RES :
@@ -131,6 +154,7 @@ MODULE_DEVICE_TABLE(hid, a4_devices);
 static struct hid_driver a4_driver = {
        .name = "a4tech",
        .id_table = a4_devices,
+       .input_mapping = a4_input_mapping,
        .input_mapped = a4_input_mapped,
        .event = a4_event,
        .probe = a4_probe,
index b3d502421b79d327a5032f4429ff3d39327ea051..0a38e8e9bc783051f8bc634cff597885fdcb6161 100644 (file)
@@ -123,9 +123,14 @@ static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type,
 
        /* Locate the boot interface, to receive the LED change events */
        struct usb_interface *boot_interface = usb_ifnum_to_if(usb_dev, 0);
+       struct hid_device *boot_hid;
+       struct hid_input *boot_hid_input;
 
-       struct hid_device *boot_hid = usb_get_intfdata(boot_interface);
-       struct hid_input *boot_hid_input = list_first_entry(&boot_hid->inputs,
+       if (unlikely(boot_interface == NULL))
+               return -ENODEV;
+
+       boot_hid = usb_get_intfdata(boot_interface);
+       boot_hid_input = list_first_entry(&boot_hid->inputs,
                struct hid_input, list);
 
        return boot_hid_input->input->event(boot_hid_input->input, type, code,
index 0d695f8e1b2c4cb5771e6fdf28d75af076d886fa..0a00be19f7a0de2f1d8d4ddcf5c96ece894f7fcf 100644 (file)
 #define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A  0x0b4a
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE         0x134a
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A    0x094a
+#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641    0x0641
 
 #define USB_VENDOR_ID_HUION            0x256c
 #define USB_DEVICE_ID_HUION_TABLET     0x006e
 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER           0xc52f
 #define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2     0xc532
 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2         0xc534
-#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING    0xc539
+#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED        0xc539
+#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
 #define USB_DEVICE_ID_SPACETRAVELLER   0xc623
 #define USB_DEVICE_ID_SPACENAVIGATOR   0xc626
 #define USB_DEVICE_ID_DINOVO_DESKTOP   0xc704
 #define USB_DEVICE_ID_SAITEK_RAT7      0x0cd7
 #define USB_DEVICE_ID_SAITEK_RAT9      0x0cfa
 #define USB_DEVICE_ID_SAITEK_MMO7      0x0cd0
+#define USB_DEVICE_ID_SAITEK_X52       0x075c
 
 #define USB_VENDOR_ID_SAMSUNG          0x0419
 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE        0x0001
index 6196217a7d936c6371743354619c3564cd9e0c69..cc47f948c1d0c54632e683a0d094cc1ae4902b32 100644 (file)
@@ -1125,7 +1125,7 @@ static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
                                    HID_REQ_SET_REPORT);
 
        kfree(hidpp_report);
-       return retval;
+       return (retval < 0) ? retval : 0;
 }
 
 static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
@@ -1832,13 +1832,17 @@ static const struct hid_device_id logi_dj_receivers[] = {
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
                         USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2),
         .driver_data = recvr_type_hidpp},
-       { /* Logitech gaming receiver (0xc539) */
+       { /* Logitech lightspeed receiver (0xc539) */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
-               USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING),
+               USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED),
         .driver_data = recvr_type_gaming_hidpp},
        { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
         .driver_data = recvr_type_27mhz},
+       { /* Logitech powerplay receiver (0xc53a) */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+               USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY),
+        .driver_data = recvr_type_gaming_hidpp},
        { /* Logitech 27 MHz HID++ 1.0 receiver (0xc517) */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
                USB_DEVICE_ID_S510_RECEIVER_2),
index e3b6245bf4b23454423724ea18d2ef3e3664ad5b..21268c9fa71a6654a3e0bd6ba73a6570d4b4b1bd 100644 (file)
@@ -3749,15 +3749,45 @@ static const struct hid_device_id hidpp_devices[] = {
 
        { L27MHZ_DEVICE(HID_ANY_ID) },
 
-       { /* Logitech G403 Gaming Mouse over USB */
+       { /* Logitech G203/Prodigy Gaming Mouse */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC084) },
+       { /* Logitech G302 Gaming Mouse */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07F) },
+       { /* Logitech G303 Gaming Mouse */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC080) },
+       { /* Logitech G400 Gaming Mouse */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07E) },
+       { /* Logitech G403 Wireless Gaming Mouse over USB */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC082) },
+       { /* Logitech G403 Gaming Mouse */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC083) },
+       { /* Logitech G403 Hero Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC08F) },
+       { /* Logitech G502 Proteus Core Gaming Mouse */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07D) },
+       { /* Logitech G502 Proteus Spectrum Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC332) },
+       { /* Logitech G502 Hero Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC08B) },
        { /* Logitech G700 Gaming Mouse over USB */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC06B) },
+       { /* Logitech G700s Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07C) },
+       { /* Logitech G703 Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC087) },
+       { /* Logitech G703 Hero Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC090) },
        { /* Logitech G900 Gaming Mouse over USB */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC081) },
+       { /* Logitech G903 Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC086) },
+       { /* Logitech G903 Hero Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC091) },
        { /* Logitech G920 Wheel over USB */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
                .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
+       { /* Logitech G Pro Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) },
 
        { /* MX5000 keyboard over Bluetooth */
          HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305),
index 185a577c46f61b0fd7888de55ca9e86e526e9844..166f41f3173b8baa52bb033141f89db9ca9b967b 100644 (file)
@@ -92,6 +92,7 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
@@ -141,6 +142,7 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPAD), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
        { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
        { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
index 93942063b51b6011dd0e73fce7e4a07fdfa0d459..49dd2d905c7f6b7f799e9de24c484a901808eddb 100644 (file)
@@ -585,10 +585,14 @@ static void sony_set_leds(struct sony_sc *sc);
 static inline void sony_schedule_work(struct sony_sc *sc,
                                      enum sony_worker which)
 {
+       unsigned long flags;
+
        switch (which) {
        case SONY_WORKER_STATE:
-               if (!sc->defer_initialization)
+               spin_lock_irqsave(&sc->lock, flags);
+               if (!sc->defer_initialization && sc->state_worker_initialized)
                        schedule_work(&sc->state_worker);
+               spin_unlock_irqrestore(&sc->lock, flags);
                break;
        case SONY_WORKER_HOTPLUG:
                if (sc->hotplug_worker_initialized)
@@ -2558,13 +2562,18 @@ static inline void sony_init_output_report(struct sony_sc *sc,
 
 static inline void sony_cancel_work_sync(struct sony_sc *sc)
 {
+       unsigned long flags;
+
        if (sc->hotplug_worker_initialized)
                cancel_work_sync(&sc->hotplug_worker);
-       if (sc->state_worker_initialized)
+       if (sc->state_worker_initialized) {
+               spin_lock_irqsave(&sc->lock, flags);
+               sc->state_worker_initialized = 0;
+               spin_unlock_irqrestore(&sc->lock, flags);
                cancel_work_sync(&sc->state_worker);
+       }
 }
 
-
 static int sony_input_configured(struct hid_device *hdev,
                                        struct hid_input *hidinput)
 {
index e12f2588ddebb028712ea212876154f50a1c7830..bdfc5ff3b2c5c9211291f71d8f0304e233f076bd 100644 (file)
@@ -22,6 +22,8 @@
 
 #include "hid-ids.h"
 
+#define THRUSTMASTER_DEVICE_ID_2_IN_1_DT       0xb320
+
 static const signed short ff_rumble[] = {
        FF_RUMBLE,
        -1
@@ -76,6 +78,7 @@ static int tmff_play(struct input_dev *dev, void *data,
        struct hid_field *ff_field = tmff->ff_field;
        int x, y;
        int left, right;        /* Rumbling */
+       int motor_swap;
 
        switch (effect->type) {
        case FF_CONSTANT:
@@ -100,6 +103,13 @@ static int tmff_play(struct input_dev *dev, void *data,
                                        ff_field->logical_minimum,
                                        ff_field->logical_maximum);
 
+               /* 2-in-1 strong motor is left */
+               if (hid->product == THRUSTMASTER_DEVICE_ID_2_IN_1_DT) {
+                       motor_swap = left;
+                       left = right;
+                       right = motor_swap;
+               }
+
                dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
                ff_field->value[0] = left;
                ff_field->value[1] = right;
@@ -226,6 +236,8 @@ static const struct hid_device_id tm_devices[] = {
                .driver_data = (unsigned long)ff_rumble },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304),   /* FireStorm Dual Power 2 (and 3) */
                .driver_data = (unsigned long)ff_rumble },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, THRUSTMASTER_DEVICE_ID_2_IN_1_DT),   /* Dual Trigger 2-in-1 */
+               .driver_data = (unsigned long)ff_rumble },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323),   /* Dual Trigger 3-in-1 (PC Mode) */
                .driver_data = (unsigned long)ff_rumble },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324),   /* Dual Trigger 3-in-1 (PS3 Mode) */
index 55b72573066b93ce070708b2f9496d4570e0c381..4e11cc6fc34bc68afc856a20315e0092ed8f97c7 100644 (file)
@@ -284,6 +284,14 @@ static int hiddev_open(struct inode *inode, struct file *file)
        spin_unlock_irq(&list->hiddev->list_lock);
 
        mutex_lock(&hiddev->existancelock);
+       /*
+        * recheck exist with existance lock held to
+        * avoid opening a disconnected device
+        */
+       if (!list->hiddev->exist) {
+               res = -ENODEV;
+               goto bail_unlock;
+       }
        if (!list->hiddev->open++)
                if (list->hiddev->exist) {
                        struct hid_device *hid = hiddev->hid;
@@ -300,6 +308,10 @@ bail_normal_power:
        hid_hw_power(hid, PM_HINT_NORMAL);
 bail_unlock:
        mutex_unlock(&hiddev->existancelock);
+
+       spin_lock_irq(&list->hiddev->list_lock);
+       list_del(&list->node);
+       spin_unlock_irq(&list->hiddev->list_lock);
 bail:
        file->private_data = NULL;
        vfree(list);
index 8fc36a28081bbe4b42e2d8beb3d4cff714a87faa..7a8ddc999a8e3b8fdb05c6e41ca17d20badbff7a 100644 (file)
@@ -533,14 +533,14 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
                 */
                buttons = (data[4] << 1) | (data[3] & 0x01);
        } else if (features->type == CINTIQ_COMPANION_2) {
-               /* d-pad right  -> data[4] & 0x10
-                * d-pad up     -> data[4] & 0x20
-                * d-pad left   -> data[4] & 0x40
-                * d-pad down   -> data[4] & 0x80
-                * d-pad center -> data[3] & 0x01
+               /* d-pad right  -> data[2] & 0x10
+                * d-pad up     -> data[2] & 0x20
+                * d-pad left   -> data[2] & 0x40
+                * d-pad down   -> data[2] & 0x80
+                * d-pad center -> data[1] & 0x01
                 */
                buttons = ((data[2] >> 4) << 7) |
-                         ((data[1] & 0x04) << 6) |
+                         ((data[1] & 0x04) << 4) |
                          ((data[2] & 0x0F) << 2) |
                          (data[1] & 0x03);
        } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
index 3fb9c0a2d6d0bc2241d6777901d9a7da49057ceb..ce5ec403ec739c819ee8f896e5958d63380246ee 100644 (file)
@@ -343,7 +343,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
                data->sample_time = MSEC_PER_SEC / 2;
                break;
        case tmp75b:  /* not one-shot mode, Conversion rate 37Hz */
-               clr_mask |= 1 << 15 | 0x3 << 13;
+               clr_mask |= 1 << 7 | 0x3 << 5;
                data->resolution = 12;
                data->sample_time = MSEC_PER_SEC / 37;
                break;
index ec7bcf8d7cd66d3280e752481c21774c2310fc17..f3dd2a17bd426244d72d26a8d027fa24523cbb00 100644 (file)
@@ -704,7 +704,7 @@ static struct attribute *nct7802_in_attrs[] = {
        &sensor_dev_attr_in3_alarm.dev_attr.attr,
        &sensor_dev_attr_in3_beep.dev_attr.attr,
 
-       &sensor_dev_attr_in4_input.dev_attr.attr,       /* 17 */
+       &sensor_dev_attr_in4_input.dev_attr.attr,       /* 16 */
        &sensor_dev_attr_in4_min.dev_attr.attr,
        &sensor_dev_attr_in4_max.dev_attr.attr,
        &sensor_dev_attr_in4_alarm.dev_attr.attr,
@@ -730,9 +730,9 @@ static umode_t nct7802_in_is_visible(struct kobject *kobj,
 
        if (index >= 6 && index < 11 && (reg & 0x03) != 0x03)   /* VSEN1 */
                return 0;
-       if (index >= 11 && index < 17 && (reg & 0x0c) != 0x0c)  /* VSEN2 */
+       if (index >= 11 && index < 16 && (reg & 0x0c) != 0x0c)  /* VSEN2 */
                return 0;
-       if (index >= 17 && (reg & 0x30) != 0x30)                /* VSEN3 */
+       if (index >= 16 && (reg & 0x30) != 0x30)                /* VSEN3 */
                return 0;
 
        return attr->mode;
index 0e224232f74644e1a1b620ca9c3d1067891e34d9..008a74a1ed444720a29537f037dedfac821d46d1 100644 (file)
@@ -1394,6 +1394,7 @@ start_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb,
                                printk(KERN_DEBUG
                                       "%s: %s: alloc urb for fifo %i failed",
                                       hw->name, __func__, fifo->fifonum);
+                               continue;
                        }
                        fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
                        fifo->iso[i].indx = i;
@@ -1692,13 +1693,23 @@ hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel)
 static int
 setup_hfcsusb(struct hfcsusb *hw)
 {
+       void *dmabuf = kmalloc(sizeof(u_char), GFP_KERNEL);
        u_char b;
+       int ret;
 
        if (debug & DBG_HFC_CALL_TRACE)
                printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
 
+       if (!dmabuf)
+               return -ENOMEM;
+
+       ret = read_reg_atomic(hw, HFCUSB_CHIP_ID, dmabuf);
+
+       memcpy(&b, dmabuf, sizeof(u_char));
+       kfree(dmabuf);
+
        /* check the chip id */
-       if (read_reg_atomic(hw, HFCUSB_CHIP_ID, &b) != 1) {
+       if (ret != 1) {
                printk(KERN_DEBUG "%s: %s: cannot read chip id\n",
                       hw->name, __func__);
                return 1;
index 11c5bad95226698ab2888f2ad971220a2c5df8e4..14a5fb3781453526914bdab493c9b68beaa596b3 100644 (file)
@@ -363,10 +363,13 @@ static int __init arcrimi_setup(char *s)
        switch (ints[0]) {
        default:                /* ERROR */
                pr_err("Too many arguments\n");
+               /* Fall through */
        case 3:         /* Node ID */
                node = ints[3];
+               /* Fall through */
        case 2:         /* IRQ */
                irq = ints[2];
+               /* Fall through */
        case 1:         /* IO address */
                io = ints[1];
        }
index 28510e33924fbd7099f232a869c7715656eccc4e..cd27fdc1059b908900fe72d7e23503750dface0a 100644 (file)
@@ -197,16 +197,22 @@ static int __init com20020isa_setup(char *s)
        switch (ints[0]) {
        default:                /* ERROR */
                pr_info("Too many arguments\n");
+               /* Fall through */
        case 6:         /* Timeout */
                timeout = ints[6];
+               /* Fall through */
        case 5:         /* CKP value */
                clockp = ints[5];
+               /* Fall through */
        case 4:         /* Backplane flag */
                backplane = ints[4];
+               /* Fall through */
        case 3:         /* Node ID */
                node = ints[3];
+               /* Fall through */
        case 2:         /* IRQ */
                irq = ints[2];
+               /* Fall through */
        case 1:         /* IO address */
                io = ints[1];
        }
index 2c546013a98014b4c83b759d293ed24f91b3c940..186bbf87bc849f1e3e80180068412de2a5ff1606 100644 (file)
@@ -363,8 +363,10 @@ static int __init com90io_setup(char *s)
        switch (ints[0]) {
        default:                /* ERROR */
                pr_err("Too many arguments\n");
+               /* Fall through */
        case 2:         /* IRQ */
                irq = ints[2];
+               /* Fall through */
        case 1:         /* IO address */
                io = ints[1];
        }
index ca4a57c30bf89ed8d565d228aca9953153a3adf4..bd75d06ad7dfc98c982a3c7f033508a8e398d3ae 100644 (file)
@@ -693,10 +693,13 @@ static int __init com90xx_setup(char *s)
        switch (ints[0]) {
        default:                /* ERROR */
                pr_err("Too many arguments\n");
+               /* Fall through */
        case 3:         /* Mem address */
                shmem = ints[3];
+               /* Fall through */
        case 2:         /* IRQ */
                irq = ints[2];
+               /* Fall through */
        case 1:         /* IO address */
                io = ints[1];
        }
index 9b7016abca2f6c4a89185fb23b0bd719e18c08e4..02fd7822c14a4286f1b5ec6379bd22fcd4d21330 100644 (file)
@@ -2196,6 +2196,15 @@ static void bond_miimon_commit(struct bonding *bond)
        bond_for_each_slave(bond, slave, iter) {
                switch (slave->new_link) {
                case BOND_LINK_NOCHANGE:
+                       /* For 802.3ad mode, check current slave speed and
+                        * duplex again in case its port was disabled after
+                        * invalid speed/duplex reporting but recovered before
+                        * link monitoring could make a decision on the actual
+                        * link status
+                        */
+                       if (BOND_MODE(bond) == BOND_MODE_8023AD &&
+                           slave->link == BOND_LINK_UP)
+                               bond_3ad_adapter_speed_duplex_changed(slave);
                        continue;
 
                case BOND_LINK_UP:
index b6b93a2d93a59293dccbfe00158857aae5a21965..483d270664cc87efd828993641406e24818db334 100644 (file)
@@ -1249,6 +1249,8 @@ int register_candev(struct net_device *dev)
                return -EINVAL;
 
        dev->rtnl_link_ops = &can_link_ops;
+       netif_carrier_off(dev);
+
        return register_netdev(dev);
 }
 EXPORT_SYMBOL_GPL(register_candev);
index f2fe344593d58ce66697515326efae700dab22ce..fcec8bcb53d64cd246b1e003de157432ec32bd41 100644 (file)
@@ -400,9 +400,10 @@ static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable)
        priv->write(reg_mcr, &regs->mcr);
 }
 
-static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv)
+static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
 {
        struct flexcan_regs __iomem *regs = priv->regs;
+       unsigned int ackval;
        u32 reg_mcr;
 
        reg_mcr = priv->read(&regs->mcr);
@@ -412,20 +413,37 @@ static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv)
        /* enable stop request */
        regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
                           1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
+
+       /* get stop acknowledgment */
+       if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr,
+                                    ackval, ackval & (1 << priv->stm.ack_bit),
+                                    0, FLEXCAN_TIMEOUT_US))
+               return -ETIMEDOUT;
+
+       return 0;
 }
 
-static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv)
+static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
 {
        struct flexcan_regs __iomem *regs = priv->regs;
+       unsigned int ackval;
        u32 reg_mcr;
 
        /* remove stop request */
        regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
                           1 << priv->stm.req_bit, 0);
 
+       /* get stop acknowledgment */
+       if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr,
+                                    ackval, !(ackval & (1 << priv->stm.ack_bit)),
+                                    0, FLEXCAN_TIMEOUT_US))
+               return -ETIMEDOUT;
+
        reg_mcr = priv->read(&regs->mcr);
        reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
        priv->write(reg_mcr, &regs->mcr);
+
+       return 0;
 }
 
 static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv)
@@ -1437,10 +1455,10 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
 
        priv = netdev_priv(dev);
        priv->stm.gpr = syscon_node_to_regmap(gpr_np);
-       of_node_put(gpr_np);
        if (IS_ERR(priv->stm.gpr)) {
                dev_dbg(&pdev->dev, "could not find gpr regmap\n");
-               return PTR_ERR(priv->stm.gpr);
+               ret = PTR_ERR(priv->stm.gpr);
+               goto out_put_node;
        }
 
        priv->stm.req_gpr = out_val[1];
@@ -1455,7 +1473,9 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
 
        device_set_wakeup_capable(&pdev->dev, true);
 
-       return 0;
+out_put_node:
+       of_node_put(gpr_np);
+       return ret;
 }
 
 static const struct of_device_id flexcan_of_match[] = {
@@ -1612,7 +1632,9 @@ static int __maybe_unused flexcan_suspend(struct device *device)
                 */
                if (device_may_wakeup(device)) {
                        enable_irq_wake(dev->irq);
-                       flexcan_enter_stop_mode(priv);
+                       err = flexcan_enter_stop_mode(priv);
+                       if (err)
+                               return err;
                } else {
                        err = flexcan_chip_disable(priv);
                        if (err)
@@ -1662,10 +1684,13 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device)
 {
        struct net_device *dev = dev_get_drvdata(device);
        struct flexcan_priv *priv = netdev_priv(dev);
+       int err;
 
        if (netif_running(dev) && device_may_wakeup(device)) {
                flexcan_enable_wakeup_irq(priv, false);
-               flexcan_exit_stop_mode(priv);
+               err = flexcan_exit_stop_mode(priv);
+               if (err)
+                       return err;
        }
 
        return 0;
index 05410008aa6b6ee2ac1a6a957c2b0b838f9ee2fc..de34a4b82d4ad474ff2ba253ba29f52d5347d8f3 100644 (file)
@@ -1508,10 +1508,11 @@ static int rcar_canfd_rx_poll(struct napi_struct *napi, int quota)
 
        /* All packets processed */
        if (num_pkts < quota) {
-               napi_complete_done(napi, num_pkts);
-               /* Enable Rx FIFO interrupts */
-               rcar_canfd_set_bit(priv->base, RCANFD_RFCC(ridx),
-                                  RCANFD_RFCC_RFIE);
+               if (napi_complete_done(napi, num_pkts)) {
+                       /* Enable Rx FIFO interrupts */
+                       rcar_canfd_set_bit(priv->base, RCANFD_RFCC(ridx),
+                                          RCANFD_RFCC_RFIE);
+               }
        }
        return num_pkts;
 }
index 185c7f7d38a4ae15f64e6c38539534e007273411..5e0d5e8101c86913955525f93c1aacad0b83268b 100644 (file)
@@ -479,7 +479,7 @@ static void pcan_free_channels(struct pcan_pccard *card)
                if (!netdev)
                        continue;
 
-               strncpy(name, netdev->name, IFNAMSIZ);
+               strlcpy(name, netdev->name, IFNAMSIZ);
 
                unregister_sja1000dev(netdev);
 
index 234cf1042df6b03bc48af4e35f808b8d329c7231..12358f06d19400bed0dab5d094d04e5e3da2a436 100644 (file)
@@ -664,17 +664,6 @@ static int mcp251x_power_enable(struct regulator *reg, int enable)
                return regulator_disable(reg);
 }
 
-static void mcp251x_open_clean(struct net_device *net)
-{
-       struct mcp251x_priv *priv = netdev_priv(net);
-       struct spi_device *spi = priv->spi;
-
-       free_irq(spi->irq, priv);
-       mcp251x_hw_sleep(spi);
-       mcp251x_power_enable(priv->transceiver, 0);
-       close_candev(net);
-}
-
 static int mcp251x_stop(struct net_device *net)
 {
        struct mcp251x_priv *priv = netdev_priv(net);
@@ -941,37 +930,43 @@ static int mcp251x_open(struct net_device *net)
                                   flags | IRQF_ONESHOT, DEVICE_NAME, priv);
        if (ret) {
                dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
-               mcp251x_power_enable(priv->transceiver, 0);
-               close_candev(net);
-               goto open_unlock;
+               goto out_close;
        }
 
        priv->wq = alloc_workqueue("mcp251x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
                                   0);
+       if (!priv->wq) {
+               ret = -ENOMEM;
+               goto out_clean;
+       }
        INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
        INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
 
        ret = mcp251x_hw_reset(spi);
-       if (ret) {
-               mcp251x_open_clean(net);
-               goto open_unlock;
-       }
+       if (ret)
+               goto out_free_wq;
        ret = mcp251x_setup(net, spi);
-       if (ret) {
-               mcp251x_open_clean(net);
-               goto open_unlock;
-       }
+       if (ret)
+               goto out_free_wq;
        ret = mcp251x_set_normal_mode(spi);
-       if (ret) {
-               mcp251x_open_clean(net);
-               goto open_unlock;
-       }
+       if (ret)
+               goto out_free_wq;
 
        can_led_event(net, CAN_LED_EVENT_OPEN);
 
        netif_wake_queue(net);
+       mutex_unlock(&priv->mcp_lock);
 
-open_unlock:
+       return 0;
+
+out_free_wq:
+       destroy_workqueue(priv->wq);
+out_clean:
+       free_irq(spi->irq, priv);
+       mcp251x_hw_sleep(spi);
+out_close:
+       mcp251x_power_enable(priv->transceiver, 0);
+       close_candev(net);
        mutex_unlock(&priv->mcp_lock);
        return ret;
 }
index 458154c9b48298b45c1e93a83fc98afe47eb1caa..65dce642b86b54c8378bece93bfdc738573470ae 100644 (file)
@@ -568,16 +568,16 @@ static int peak_usb_ndo_stop(struct net_device *netdev)
        dev->state &= ~PCAN_USB_STATE_STARTED;
        netif_stop_queue(netdev);
 
+       close_candev(netdev);
+
+       dev->can.state = CAN_STATE_STOPPED;
+
        /* unlink all pending urbs and free used memory */
        peak_usb_unlink_all_urbs(dev);
 
        if (dev->adapter->dev_stop)
                dev->adapter->dev_stop(dev);
 
-       close_candev(netdev);
-
-       dev->can.state = CAN_STATE_STOPPED;
-
        /* can set bus off now */
        if (dev->adapter->dev_set_bus) {
                int err = dev->adapter->dev_set_bus(dev, 0);
@@ -855,7 +855,7 @@ static void peak_usb_disconnect(struct usb_interface *intf)
 
                dev_prev_siblings = dev->prev_siblings;
                dev->state &= ~PCAN_USB_STATE_CONNECTED;
-               strncpy(name, netdev->name, IFNAMSIZ);
+               strlcpy(name, netdev->name, IFNAMSIZ);
 
                unregister_netdev(netdev);
 
index 34761c3a62867d1001f48224bd9e51b1685bbb74..47cc1ff5b88e828fe65899b8ef38b447ae1da098 100644 (file)
@@ -841,7 +841,7 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
                        goto err_out;
 
                /* allocate command buffer once for all for the interface */
-               pdev->cmd_buffer_addr = kmalloc(PCAN_UFD_CMD_BUFFER_SIZE,
+               pdev->cmd_buffer_addr = kzalloc(PCAN_UFD_CMD_BUFFER_SIZE,
                                                GFP_KERNEL);
                if (!pdev->cmd_buffer_addr)
                        goto err_out_1;
index 178bb7cff0c1a10378ea711af07d380367021b26..53cb2f72bdd0574b4fe6bcd654dd12cf57179546 100644 (file)
@@ -494,7 +494,7 @@ static int pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded)
        u8 *buffer;
        int err;
 
-       buffer = kmalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL);
+       buffer = kzalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
 
index 6b17cd961d061285b7f3c258ab37445559e8b04f..d0a97eb73a37678b8fba381a200399c7736769cc 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/platform_data/mv88e6xxx.h>
 #include <linux/netdevice.h>
 #include <linux/gpio/consumer.h>
-#include <linux/phy.h>
 #include <linux/phylink.h>
 #include <net/dsa.h>
 
@@ -430,7 +429,7 @@ int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
                return 0;
 
        /* Port's MAC control must not be changed unless the link is down */
-       err = chip->info->ops->port_set_link(chip, port, 0);
+       err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
        if (err)
                return err;
 
@@ -482,30 +481,6 @@ static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
        return port < chip->info->num_internal_phys;
 }
 
-/* We expect the switch to perform auto negotiation if there is a real
- * phy. However, in the case of a fixed link phy, we force the port
- * settings from the fixed link settings.
- */
-static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
-                                 struct phy_device *phydev)
-{
-       struct mv88e6xxx_chip *chip = ds->priv;
-       int err;
-
-       if (!phy_is_pseudo_fixed_link(phydev) &&
-           mv88e6xxx_phy_is_internal(ds, port))
-               return;
-
-       mv88e6xxx_reg_lock(chip);
-       err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
-                                      phydev->duplex, phydev->pause,
-                                      phydev->interface);
-       mv88e6xxx_reg_unlock(chip);
-
-       if (err && err != -EOPNOTSUPP)
-               dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
-}
-
 static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
                                       unsigned long *mask,
                                       struct phylink_link_state *state)
@@ -2721,6 +2696,7 @@ static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
                        err = mv88e6xxx_mdio_register(chip, child, true);
                        if (err) {
                                mv88e6xxx_mdios_unregister(chip);
+                               of_node_put(child);
                                return err;
                        }
                }
@@ -4638,7 +4614,6 @@ static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
 static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
        .get_tag_protocol       = mv88e6xxx_get_tag_protocol,
        .setup                  = mv88e6xxx_setup,
-       .adjust_link            = mv88e6xxx_adjust_link,
        .phylink_validate       = mv88e6xxx_validate,
        .phylink_mac_link_state = mv88e6xxx_link_state,
        .phylink_mac_config     = mv88e6xxx_mac_config,
index 232e8cc96f6dee10ecfba315cc9fc9eb7a9975fb..16f15c93a102c9b66d76c22ae0e8e310a6b6edf5 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
  * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved.
  * Copyright (c) 2016 John Crispin <john@phrozen.org>
  */
 
@@ -583,8 +583,11 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
 
        for_each_available_child_of_node(ports, port) {
                err = of_property_read_u32(port, "reg", &reg);
-               if (err)
+               if (err) {
+                       of_node_put(port);
+                       of_node_put(ports);
                        return err;
+               }
 
                if (!dsa_is_user_port(priv->ds, reg))
                        continue;
@@ -595,6 +598,7 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
                        internal_mdio_mask |= BIT(reg);
        }
 
+       of_node_put(ports);
        if (!external_mdio_mask && !internal_mdio_mask) {
                dev_err(priv->dev, "no PHYs are defined.\n");
                return -EINVAL;
@@ -935,6 +939,8 @@ qca8k_port_enable(struct dsa_switch *ds, int port,
        qca8k_port_set_status(priv, port, 1);
        priv->port_sts[port].enabled = 1;
 
+       phy_support_asym_pause(phy);
+
        return 0;
 }
 
index 6bfb1696a6f2806dc4b875329b9e0ae720517d90..9988c9d185678a678ca262e9dfdc6b5f09ce30ae 100644 (file)
@@ -277,6 +277,18 @@ sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
                        SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op);
 }
 
+static size_t sja1105et_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
+                                                   enum packing_op op)
+{
+       struct sja1105_l2_lookup_entry *entry = entry_ptr;
+       u8 *cmd = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
+       const int size = SJA1105_SIZE_DYN_CMD;
+
+       sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
+
+       return sja1105et_l2_lookup_entry_packing(buf, entry_ptr, op);
+}
+
 static void
 sja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
                                 enum packing_op op)
@@ -477,7 +489,7 @@ sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
 /* SJA1105E/T: First generation */
 struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
        [BLK_IDX_L2_LOOKUP] = {
-               .entry_packing = sja1105et_l2_lookup_entry_packing,
+               .entry_packing = sja1105et_dyn_l2_lookup_entry_packing,
                .cmd_packing = sja1105et_l2_lookup_cmd_packing,
                .access = (OP_READ | OP_WRITE | OP_DEL),
                .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
index 32bf3a7cc3b6db9961ec7df11cc0e9bb127de4a8..d073baffc20b042d92fbbbcc4657d7fb6cee5c5a 100644 (file)
@@ -218,7 +218,7 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
                /* This selects between Independent VLAN Learning (IVL) and
                 * Shared VLAN Learning (SVL)
                 */
-               .shared_learn = false,
+               .shared_learn = true,
                /* Don't discard management traffic based on ENFPORT -
                 * we don't perform SMAC port enforcement anyway, so
                 * what we are setting here doesn't matter.
@@ -625,6 +625,7 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
                if (of_property_read_u32(child, "reg", &index) < 0) {
                        dev_err(dev, "Port number not defined in device tree "
                                "(property \"reg\")\n");
+                       of_node_put(child);
                        return -ENODEV;
                }
 
@@ -634,6 +635,7 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
                        dev_err(dev, "Failed to read phy-mode or "
                                "phy-interface-type property for port %d\n",
                                index);
+                       of_node_put(child);
                        return -ENODEV;
                }
                ports[index].phy_mode = phy_mode;
@@ -643,6 +645,7 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
                        if (!of_phy_is_fixed_link(child)) {
                                dev_err(dev, "phy-handle or fixed-link "
                                        "properties missing!\n");
+                               of_node_put(child);
                                return -ENODEV;
                        }
                        /* phy-handle is missing, but fixed-link isn't.
@@ -1089,8 +1092,13 @@ int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port,
        l2_lookup.vlanid = vid;
        l2_lookup.iotag = SJA1105_S_TAG;
        l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0);
-       l2_lookup.mask_vlanid = VLAN_VID_MASK;
-       l2_lookup.mask_iotag = BIT(0);
+       if (dsa_port_is_vlan_filtering(&ds->ports[port])) {
+               l2_lookup.mask_vlanid = VLAN_VID_MASK;
+               l2_lookup.mask_iotag = BIT(0);
+       } else {
+               l2_lookup.mask_vlanid = 0;
+               l2_lookup.mask_iotag = 0;
+       }
        l2_lookup.destports = BIT(port);
 
        rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
@@ -1147,8 +1155,13 @@ int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port,
        l2_lookup.vlanid = vid;
        l2_lookup.iotag = SJA1105_S_TAG;
        l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0);
-       l2_lookup.mask_vlanid = VLAN_VID_MASK;
-       l2_lookup.mask_iotag = BIT(0);
+       if (dsa_port_is_vlan_filtering(&ds->ports[port])) {
+               l2_lookup.mask_vlanid = VLAN_VID_MASK;
+               l2_lookup.mask_iotag = BIT(0);
+       } else {
+               l2_lookup.mask_vlanid = 0;
+               l2_lookup.mask_iotag = 0;
+       }
        l2_lookup.destports = BIT(port);
 
        rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
@@ -1178,60 +1191,31 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port,
                           const unsigned char *addr, u16 vid)
 {
        struct sja1105_private *priv = ds->priv;
-       u16 rx_vid, tx_vid;
-       int rc, i;
 
-       if (dsa_port_is_vlan_filtering(&ds->ports[port]))
-               return priv->info->fdb_add_cmd(ds, port, addr, vid);
-
-       /* Since we make use of VLANs even when the bridge core doesn't tell us
-        * to, translate these FDB entries into the correct dsa_8021q ones.
-        * The basic idea (also repeats for removal below) is:
-        * - Each of the other front-panel ports needs to be able to forward a
-        *   pvid-tagged (aka tagged with their rx_vid) frame that matches this
-        *   DMAC.
-        * - The CPU port (aka the tx_vid of this port) needs to be able to
-        *   send a frame matching this DMAC to the specified port.
-        * For a better picture see net/dsa/tag_8021q.c.
+       /* dsa_8021q is in effect when the bridge's vlan_filtering isn't,
+        * so the switch still does some VLAN processing internally.
+        * But Shared VLAN Learning (SVL) is also active, and it will take
+        * care of autonomous forwarding between the unique pvid's of each
+        * port.  Here we just make sure that users can't add duplicate FDB
+        * entries when in this mode - the actual VID doesn't matter except
+        * for what gets printed in 'bridge fdb show'.  In the case of zero,
+        * no VID gets printed at all.
         */
-       for (i = 0; i < SJA1105_NUM_PORTS; i++) {
-               if (i == port)
-                       continue;
-               if (i == dsa_upstream_port(priv->ds, port))
-                       continue;
+       if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
+               vid = 0;
 
-               rx_vid = dsa_8021q_rx_vid(ds, i);
-               rc = priv->info->fdb_add_cmd(ds, port, addr, rx_vid);
-               if (rc < 0)
-                       return rc;
-       }
-       tx_vid = dsa_8021q_tx_vid(ds, port);
-       return priv->info->fdb_add_cmd(ds, port, addr, tx_vid);
+       return priv->info->fdb_add_cmd(ds, port, addr, vid);
 }
 
 static int sja1105_fdb_del(struct dsa_switch *ds, int port,
                           const unsigned char *addr, u16 vid)
 {
        struct sja1105_private *priv = ds->priv;
-       u16 rx_vid, tx_vid;
-       int rc, i;
-
-       if (dsa_port_is_vlan_filtering(&ds->ports[port]))
-               return priv->info->fdb_del_cmd(ds, port, addr, vid);
 
-       for (i = 0; i < SJA1105_NUM_PORTS; i++) {
-               if (i == port)
-                       continue;
-               if (i == dsa_upstream_port(priv->ds, port))
-                       continue;
+       if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
+               vid = 0;
 
-               rx_vid = dsa_8021q_rx_vid(ds, i);
-               rc = priv->info->fdb_del_cmd(ds, port, addr, rx_vid);
-               if (rc < 0)
-                       return rc;
-       }
-       tx_vid = dsa_8021q_tx_vid(ds, port);
-       return priv->info->fdb_del_cmd(ds, port, addr, tx_vid);
+       return priv->info->fdb_del_cmd(ds, port, addr, vid);
 }
 
 static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
@@ -1270,39 +1254,9 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
                        continue;
                u64_to_ether_addr(l2_lookup.macaddr, macaddr);
 
-               /* On SJA1105 E/T, the switch doesn't implement the LOCKEDS
-                * bit, so it doesn't tell us whether a FDB entry is static
-                * or not.
-                * But, of course, we can find out - we're the ones who added
-                * it in the first place.
-                */
-               if (priv->info->device_id == SJA1105E_DEVICE_ID ||
-                   priv->info->device_id == SJA1105T_DEVICE_ID) {
-                       int match;
-
-                       match = sja1105_find_static_fdb_entry(priv, port,
-                                                             &l2_lookup);
-                       l2_lookup.lockeds = (match >= 0);
-               }
-
-               /* We need to hide the dsa_8021q VLANs from the user. This
-                * basically means hiding the duplicates and only showing
-                * the pvid that is supposed to be active in standalone and
-                * non-vlan_filtering modes (aka 1).
-                * - For statically added FDB entries (bridge fdb add), we
-                *   can convert the TX VID (coming from the CPU port) into the
-                *   pvid and ignore the RX VIDs of the other ports.
-                * - For dynamically learned FDB entries, a single entry with
-                *   no duplicates is learned - that which has the real port's
-                *   pvid, aka RX VID.
-                */
-               if (!dsa_port_is_vlan_filtering(&ds->ports[port])) {
-                       if (l2_lookup.vlanid == tx_vid ||
-                           l2_lookup.vlanid == rx_vid)
-                               l2_lookup.vlanid = 1;
-                       else
-                               continue;
-               }
+               /* We need to hide the dsa_8021q VLANs from the user. */
+               if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
+                       l2_lookup.vlanid = 0;
                cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
        }
        return 0;
@@ -1594,6 +1548,7 @@ static int sja1105_vlan_prepare(struct dsa_switch *ds, int port,
  */
 static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
 {
+       struct sja1105_l2_lookup_params_entry *l2_lookup_params;
        struct sja1105_general_params_entry *general_params;
        struct sja1105_private *priv = ds->priv;
        struct sja1105_table *table;
@@ -1622,6 +1577,28 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
        general_params->incl_srcpt1 = enabled;
        general_params->incl_srcpt0 = enabled;
 
+       /* VLAN filtering => independent VLAN learning.
+        * No VLAN filtering => shared VLAN learning.
+        *
+        * In shared VLAN learning mode, untagged traffic still gets
+        * pvid-tagged, and the FDB table gets populated with entries
+        * containing the "real" (pvid or from VLAN tag) VLAN ID.
+        * However the switch performs a masked L2 lookup in the FDB,
+        * effectively only looking up a frame's DMAC (and not VID) for the
+        * forwarding decision.
+        *
+        * This is extremely convenient for us, because in modes with
+        * vlan_filtering=0, dsa_8021q actually installs unique pvid's into
+        * each front panel port. This is good for identification but breaks
+        * learning badly - the VID of the learnt FDB entry is unique, aka
+        * no frames coming from any other port are going to have it. So
+        * for forwarding purposes, this is as though learning was broken
+        * (all frames get flooded).
+        */
+       table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS];
+       l2_lookup_params = table->entries;
+       l2_lookup_params->shared_learn = !enabled;
+
        rc = sja1105_static_config_reload(priv);
        if (rc)
                dev_err(ds->dev, "Failed to change VLAN Ethertype\n");
@@ -1751,6 +1728,8 @@ static void sja1105_teardown(struct dsa_switch *ds)
 
        cancel_work_sync(&priv->tagger_data.rxtstamp_work);
        skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue);
+       sja1105_ptp_clock_unregister(priv);
+       sja1105_static_config_free(&priv->static_config);
 }
 
 static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
@@ -2208,9 +2187,7 @@ static int sja1105_remove(struct spi_device *spi)
 {
        struct sja1105_private *priv = spi_get_drvdata(spi);
 
-       sja1105_ptp_clock_unregister(priv);
        dsa_unregister_switch(priv->ds);
-       sja1105_static_config_free(&priv->static_config);
        return 0;
 }
 
index d19cfdf681af499ad4cae2e03aa0b9e73a754f03..d8e8dd59f3d1bba07a9b1c2a5a415818b7444020 100644 (file)
@@ -369,16 +369,15 @@ int sja1105_ptp_clock_register(struct sja1105_private *priv)
                .mult = SJA1105_CC_MULT,
        };
        mutex_init(&priv->ptp_lock);
-       INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check);
-
-       schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL);
-
        priv->ptp_caps = sja1105_ptp_caps;
 
        priv->clock = ptp_clock_register(&priv->ptp_caps, ds->dev);
        if (IS_ERR_OR_NULL(priv->clock))
                return PTR_ERR(priv->clock);
 
+       INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check);
+       schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL);
+
        return sja1105_ptp_reset(priv);
 }
 
index 2a3e2450968eeb066a8636001442d12413f78f3c..a9478577b49560f21a1b4c0f54f49f1dda0f15c4 100644 (file)
@@ -12,8 +12,8 @@ config NET_VENDOR_8390
 
          Note that the answer to this question doesn't directly affect the
          kernel: saying N will just cause the configurator to skip all
-         the questions about Western Digital cards. If you say Y, you will be
-         asked for your specific card in the following questions.
+         the questions about National Semiconductor 8390 cards. If you say Y,
+         you will be asked for your specific card in the following questions.
 
 if NET_VENDOR_8390
 
index ea34bcb868b57fba300df2d9d393aaa2ad82a926..edbb4b3604c751e9b02e4c4643b0406021514ed9 100644 (file)
@@ -2362,7 +2362,7 @@ static int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter)
 
        /* Allocate memory for the TCB's (Transmit Control Block) */
        tx_ring->tcb_ring = kcalloc(NUM_TCB, sizeof(struct tcb),
-                                   GFP_ATOMIC | GFP_DMA);
+                                   GFP_KERNEL | GFP_DMA);
        if (!tx_ring->tcb_ring)
                return -ENOMEM;
 
index 3434730a76990b6ed78f4207428c1eabc8d49155..0537df06a9b58ae47f3f139266d12dd906ce9be6 100644 (file)
@@ -860,7 +860,9 @@ static int emac_probe(struct platform_device *pdev)
                goto out_clk_disable_unprepare;
        }
 
-       db->phy_node = of_parse_phandle(np, "phy", 0);
+       db->phy_node = of_parse_phandle(np, "phy-handle", 0);
+       if (!db->phy_node)
+               db->phy_node = of_parse_phandle(np, "phy", 0);
        if (!db->phy_node) {
                dev_err(&pdev->dev, "no associated PHY\n");
                ret = -ENODEV;
index de4950d2022e0a6d6efdc4a255cba93e2edbd77b..9f965cdfff5c99db9ff3f8d1d94a1f753cbbbd3a 100644 (file)
@@ -14,7 +14,7 @@ config NET_VENDOR_AMD
          say Y.
 
          Note that the answer to this question does not directly affect
-         the kernel: saying N will just case the configurator to skip all
+         the kernel: saying N will just cause the configurator to skip all
          the questions regarding AMD chipsets. If you say Y, you will be asked
          for your specific chipset/driver in the following questions.
 
index fde7ae33e302b6bc169469928c4e25bde2e2161b..f78b9c841296c94b92089c40d1c82e33a75f689c 100644 (file)
@@ -11,8 +11,8 @@ config NET_VENDOR_APPLE
          If you have a network (Ethernet) card belonging to this class, say Y.
 
          Note that the answer to this question doesn't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about IBM devices. If you say Y, you will be asked for
+         kernel: saying N will just cause the configurator to skip all the
+         questions about Apple devices. If you say Y, you will be asked for
          your specific card in the following questions.
 
 if NET_VENDOR_APPLE
index 8b69d0d7e7269e0b8d6c92f942ad5b0df535a55a..6703960c7cf5035a6af2fd8af53fa39e9a026d96 100644 (file)
@@ -1141,7 +1141,7 @@ static int ag71xx_rings_init(struct ag71xx *ag)
 
        tx->descs_cpu = dma_alloc_coherent(&ag->pdev->dev,
                                           ring_size * AG71XX_DESC_SIZE,
-                                          &tx->descs_dma, GFP_ATOMIC);
+                                          &tx->descs_dma, GFP_KERNEL);
        if (!tx->descs_cpu) {
                kfree(tx->buf);
                tx->buf = NULL;
index e9017caf024dcf33fba30506bb8a953b686ad560..e24f5d2b6afe35477940a4a6b86c55795f855a07 100644 (file)
@@ -14,9 +14,9 @@ config NET_VENDOR_BROADCOM
          say Y.
 
          Note that the answer to this question does not directly affect
-         the kernel: saying N will just case the configurator to skip all
-         the questions regarding AMD chipsets. If you say Y, you will be asked
-         for your specific chipset/driver in the following questions.
+         the kernel: saying N will just cause the configurator to skip all
+         the questions regarding Broadcom chipsets. If you say Y, you will
+         be asked for your specific chipset/driver in the following questions.
 
 if NET_VENDOR_BROADCOM
 
index b9c5cea8db168c2284846cd8b9e1f980ae78189e..9483553ce44452e6b742b278f18c277691568ed6 100644 (file)
@@ -992,7 +992,7 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
 {
        struct bcm_sysport_priv *priv =
                container_of(napi, struct bcm_sysport_priv, napi);
-       struct dim_sample dim_sample;
+       struct dim_sample dim_sample = {};
        unsigned int work_done = 0;
 
        work_done = bcm_sysport_desc_rx(priv, budget);
index e2be5a685130dce81c5371dcd9df8d6ff72ccc0c..e47ea92e2ae3a320d2b02d51865ade6eccdfcb90 100644 (file)
@@ -1934,8 +1934,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
        }
 
        /* select a non-FCoE queue */
-       return netdev_pick_tx(dev, skb, NULL) %
-              (BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos);
+       return netdev_pick_tx(dev, skb, NULL) % (BNX2X_NUM_ETH_QUEUES(bp));
 }
 
 void bnx2x_set_num_queues(struct bnx2x *bp)
index 7134d2c3eb1c4ccdcdd9cdd97497adedddefa159..7070349915bc5412a52e556de427fb8ed6174480 100644 (file)
@@ -2136,7 +2136,7 @@ static int bnxt_poll(struct napi_struct *napi, int budget)
                }
        }
        if (bp->flags & BNXT_FLAG_DIM) {
-               struct dim_sample dim_sample;
+               struct dim_sample dim_sample = {};
 
                dim_update_sample(cpr->event_ctr,
                                  cpr->rx_packets,
index a2b57807453b6f4c57fc53c408e488d10b217b66..d3a0b614dbfa2148d4243238bf18495bf36c456f 100644 (file)
@@ -1895,7 +1895,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget)
 {
        struct bcmgenet_rx_ring *ring = container_of(napi,
                        struct bcmgenet_rx_ring, napi);
-       struct dim_sample dim_sample;
+       struct dim_sample dim_sample = {};
        unsigned int work_done;
 
        work_done = bcmgenet_desc_rx(ring, budget);
index ad22554857bf35df096408cea9184e5d786f7dc3..acb016834f0470ffbb9f0f79a57ef8809d2e567e 100644 (file)
@@ -1381,24 +1381,18 @@ static int acpi_get_mac_address(struct device *dev, struct acpi_device *adev,
                                u8 *dst)
 {
        u8 mac[ETH_ALEN];
-       int ret;
+       u8 *addr;
 
-       ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev),
-                                           "mac-address", mac, ETH_ALEN);
-       if (ret)
-               goto out;
-
-       if (!is_valid_ether_addr(mac)) {
+       addr = fwnode_get_mac_address(acpi_fwnode_handle(adev), mac, ETH_ALEN);
+       if (!addr) {
                dev_err(dev, "MAC address invalid: %pM\n", mac);
-               ret = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        dev_info(dev, "MAC address set to: %pM\n", mac);
 
-       memcpy(dst, mac, ETH_ALEN);
-out:
-       return ret;
+       ether_addr_copy(dst, mac);
+       return 0;
 }
 
 /* Currently only sets the MAC address. */
index 1e82b9efe447191799f8e5c881d32da7e7cf96ec..58f89f6a040fe39ef02d18d1fa65123d7cc7619a 100644 (file)
@@ -3269,7 +3269,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!adapter->regs) {
                dev_err(&pdev->dev, "cannot map device registers\n");
                err = -ENOMEM;
-               goto out_free_adapter;
+               goto out_free_adapter_nofail;
        }
 
        adapter->pdev = pdev;
@@ -3397,6 +3397,9 @@ out_free_dev:
                if (adapter->port[i])
                        free_netdev(adapter->port[i]);
 
+out_free_adapter_nofail:
+       kfree_skb(adapter->nofail_skb);
+
 out_free_adapter:
        kfree(adapter);
 
index ef5d61d57597d25de28e5ce613f9a378a9878a06..323976c811e96f74c5f834c0fa29ddf62ff9d0e7 100644 (file)
@@ -550,7 +550,7 @@ int be_process_mcc(struct be_adapter *adapter)
        int num = 0, status = 0;
        struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
 
-       spin_lock(&adapter->mcc_cq_lock);
+       spin_lock_bh(&adapter->mcc_cq_lock);
 
        while ((compl = be_mcc_compl_get(adapter))) {
                if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
@@ -566,7 +566,7 @@ int be_process_mcc(struct be_adapter *adapter)
        if (num)
                be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num);
 
-       spin_unlock(&adapter->mcc_cq_lock);
+       spin_unlock_bh(&adapter->mcc_cq_lock);
        return status;
 }
 
@@ -581,9 +581,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
                if (be_check_error(adapter, BE_ERROR_ANY))
                        return -EIO;
 
-               local_bh_disable();
                status = be_process_mcc(adapter);
-               local_bh_enable();
 
                if (atomic_read(&mcc_obj->q.used) == 0)
                        break;
index 2edb86ec9fe9ec5945c0de54706eb79dd187d967..4d8e40ac66d23144ea8b6c864c264f9a1ee98d31 100644 (file)
@@ -5630,9 +5630,7 @@ static void be_worker(struct work_struct *work)
         * mcc completions
         */
        if (!netif_running(adapter->netdev)) {
-               local_bh_disable();
                be_process_mcc(adapter);
-               local_bh_enable();
                goto reschedule;
        }
 
index ed0d010c7cf260f0e8cfb98f8935207bfdbc9114..04a59db03f2bc93073dc6e0d8a71024f33bd7b02 100644 (file)
@@ -2,6 +2,7 @@
 config FSL_ENETC
        tristate "ENETC PF driver"
        depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST)
+       select PHYLIB
        help
          This driver supports NXP ENETC gigabit ethernet controller PCIe
          physical function (PF) devices, managing ENETC Ports at a privileged
@@ -12,6 +13,7 @@ config FSL_ENETC
 config FSL_ENETC_VF
        tristate "ENETC VF driver"
        depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST)
+       select PHYLIB
        help
          This driver supports NXP ENETC gigabit ethernet controller PCIe
          virtual function (VF) devices enabled by the ENETC PF driver.
index e80fedb27cee81411019914f483590c7ec6c1871..210749bf1eac11537376244a7bd7b68740a5bba8 100644 (file)
@@ -2439,9 +2439,6 @@ MODULE_PARM_DESC(fsl_fm_rx_extra_headroom, "Extra headroom for Rx buffers");
  * buffers when not using jumbo frames.
  * Must be large enough to accommodate the network MTU, but small enough
  * to avoid wasting skb memory.
- *
- * Could be overridden once, at boot-time, via the
- * fm_set_max_frm() callback.
  */
 static int fsl_fm_max_frm = FSL_FM_MAX_FRAME_SIZE;
 module_param(fsl_fm_max_frm, int, 0);
index 92372dc43be877807849fda3b90869cb5b618880..ebc37e2569221a9c6425704f3dade054ab86c9f1 100644 (file)
@@ -31,9 +31,6 @@
 struct gve_rx_desc_queue {
        struct gve_rx_desc *desc_ring; /* the descriptor ring */
        dma_addr_t bus; /* the bus for the desc_ring */
-       u32 cnt; /* free-running total number of completed packets */
-       u32 fill_cnt; /* free-running total number of descriptors posted */
-       u32 mask; /* masks the cnt to the size of the ring */
        u8 seqno; /* the next expected seqno for this desc*/
 };
 
@@ -60,8 +57,6 @@ struct gve_rx_data_queue {
        dma_addr_t data_bus; /* dma mapping of the slots */
        struct gve_rx_slot_page_info *page_info; /* page info of the buffers */
        struct gve_queue_page_list *qpl; /* qpl assigned to this queue */
-       u32 mask; /* masks the cnt to the size of the ring */
-       u32 cnt; /* free-running total number of completed packets */
 };
 
 struct gve_priv;
@@ -73,6 +68,9 @@ struct gve_rx_ring {
        struct gve_rx_data_queue data;
        u64 rbytes; /* free-running bytes received */
        u64 rpackets; /* free-running packets received */
+       u32 cnt; /* free-running total number of completed packets */
+       u32 fill_cnt; /* free-running total number of descs and buffs posted */
+       u32 mask; /* masks the cnt and fill_cnt to the size of the ring */
        u32 q_num; /* queue index */
        u32 ntfy_id; /* notification block index */
        struct gve_queue_resources *q_resources; /* head and tail pointer idx */
index 26540b8565410d558050177bec051305a4cc6891..d8fa816f44737ceed90cd731d46488dfb0ceb72a 100644 (file)
@@ -138,8 +138,8 @@ gve_get_ethtool_stats(struct net_device *netdev,
                for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) {
                        struct gve_rx_ring *rx = &priv->rx[ring];
 
-                       data[i++] = rx->desc.cnt;
-                       data[i++] = rx->desc.fill_cnt;
+                       data[i++] = rx->cnt;
+                       data[i++] = rx->fill_cnt;
                }
        } else {
                i += priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS;
index 1914b8350da7022434fcd70e6316bc0010bda24e..59564ac99d2a6df5c589d89521b5513f78ae16fc 100644 (file)
@@ -37,7 +37,7 @@ static void gve_rx_free_ring(struct gve_priv *priv, int idx)
        rx->data.qpl = NULL;
        kvfree(rx->data.page_info);
 
-       slots = rx->data.mask + 1;
+       slots = rx->mask + 1;
        bytes = sizeof(*rx->data.data_ring) * slots;
        dma_free_coherent(dev, bytes, rx->data.data_ring,
                          rx->data.data_bus);
@@ -64,7 +64,7 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
        /* Allocate one page per Rx queue slot. Each page is split into two
         * packet buffers, when possible we "page flip" between the two.
         */
-       slots = rx->data.mask + 1;
+       slots = rx->mask + 1;
 
        rx->data.page_info = kvzalloc(slots *
                                      sizeof(*rx->data.page_info), GFP_KERNEL);
@@ -111,7 +111,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
        rx->q_num = idx;
 
        slots = priv->rx_pages_per_qpl;
-       rx->data.mask = slots - 1;
+       rx->mask = slots - 1;
 
        /* alloc rx data ring */
        bytes = sizeof(*rx->data.data_ring) * slots;
@@ -125,7 +125,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
                err = -ENOMEM;
                goto abort_with_slots;
        }
-       rx->desc.fill_cnt = filled_pages;
+       rx->fill_cnt = filled_pages;
        /* Ensure data ring slots (packet buffers) are visible. */
        dma_wmb();
 
@@ -156,8 +156,8 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
                err = -ENOMEM;
                goto abort_with_q_resources;
        }
-       rx->desc.mask = slots - 1;
-       rx->desc.cnt = 0;
+       rx->mask = slots - 1;
+       rx->cnt = 0;
        rx->desc.seqno = 1;
        gve_rx_add_to_block(priv, idx);
 
@@ -213,7 +213,7 @@ void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx)
 {
        u32 db_idx = be32_to_cpu(rx->q_resources->db_index);
 
-       iowrite32be(rx->desc.fill_cnt, &priv->db_bar2[db_idx]);
+       iowrite32be(rx->fill_cnt, &priv->db_bar2[db_idx]);
 }
 
 static enum pkt_hash_types gve_rss_type(__be16 pkt_flags)
@@ -273,7 +273,7 @@ static void gve_rx_flip_buff(struct gve_rx_slot_page_info *page_info,
 }
 
 static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
-                  netdev_features_t feat)
+                  netdev_features_t feat, u32 idx)
 {
        struct gve_rx_slot_page_info *page_info;
        struct gve_priv *priv = rx->gve;
@@ -282,14 +282,12 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
        struct sk_buff *skb;
        int pagecount;
        u16 len;
-       u32 idx;
 
        /* drop this packet */
        if (unlikely(rx_desc->flags_seq & GVE_RXF_ERR))
                return true;
 
        len = be16_to_cpu(rx_desc->len) - GVE_RX_PAD;
-       idx = rx->data.cnt & rx->data.mask;
        page_info = &rx->data.page_info[idx];
 
        /* gvnic can only receive into registered segments. If the buffer
@@ -340,8 +338,6 @@ have_skb:
        if (!skb)
                return true;
 
-       rx->data.cnt++;
-
        if (likely(feat & NETIF_F_RXCSUM)) {
                /* NIC passes up the partial sum */
                if (rx_desc->csum)
@@ -370,7 +366,7 @@ static bool gve_rx_work_pending(struct gve_rx_ring *rx)
        __be16 flags_seq;
        u32 next_idx;
 
-       next_idx = rx->desc.cnt & rx->desc.mask;
+       next_idx = rx->cnt & rx->mask;
        desc = rx->desc.desc_ring + next_idx;
 
        flags_seq = desc->flags_seq;
@@ -385,8 +381,8 @@ bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
 {
        struct gve_priv *priv = rx->gve;
        struct gve_rx_desc *desc;
-       u32 cnt = rx->desc.cnt;
-       u32 idx = cnt & rx->desc.mask;
+       u32 cnt = rx->cnt;
+       u32 idx = cnt & rx->mask;
        u32 work_done = 0;
        u64 bytes = 0;
 
@@ -401,10 +397,10 @@ bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
                           rx->q_num, GVE_SEQNO(desc->flags_seq),
                           rx->desc.seqno);
                bytes += be16_to_cpu(desc->len) - GVE_RX_PAD;
-               if (!gve_rx(rx, desc, feat))
+               if (!gve_rx(rx, desc, feat, idx))
                        gve_schedule_reset(priv);
                cnt++;
-               idx = cnt & rx->desc.mask;
+               idx = cnt & rx->mask;
                desc = rx->desc.desc_ring + idx;
                rx->desc.seqno = gve_next_seqno(rx->desc.seqno);
                work_done++;
@@ -417,8 +413,8 @@ bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
        rx->rpackets += work_done;
        rx->rbytes += bytes;
        u64_stats_update_end(&rx->statss);
-       rx->desc.cnt = cnt;
-       rx->desc.fill_cnt += work_done;
+       rx->cnt = cnt;
+       rx->fill_cnt += work_done;
 
        /* restock desc ring slots */
        dma_wmb();      /* Ensure descs are visible before ringing doorbell */
index d60452845539f3acbd42cdfebc94865bf2f61e02..c84167447abe650c36186eae40343b2584ac4fbb 100644 (file)
@@ -220,6 +220,7 @@ struct hip04_priv {
        unsigned int reg_inten;
 
        struct napi_struct napi;
+       struct device *dev;
        struct net_device *ndev;
 
        struct tx_desc *tx_desc;
@@ -248,7 +249,7 @@ struct hip04_priv {
 
 static inline unsigned int tx_count(unsigned int head, unsigned int tail)
 {
-       return (head - tail) % (TX_DESC_NUM - 1);
+       return (head - tail) % TX_DESC_NUM;
 }
 
 static void hip04_config_port(struct net_device *ndev, u32 speed, u32 duplex)
@@ -465,7 +466,7 @@ static int hip04_tx_reclaim(struct net_device *ndev, bool force)
                }
 
                if (priv->tx_phys[tx_tail]) {
-                       dma_unmap_single(&ndev->dev, priv->tx_phys[tx_tail],
+                       dma_unmap_single(priv->dev, priv->tx_phys[tx_tail],
                                         priv->tx_skb[tx_tail]->len,
                                         DMA_TO_DEVICE);
                        priv->tx_phys[tx_tail] = 0;
@@ -516,8 +517,8 @@ hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                return NETDEV_TX_BUSY;
        }
 
-       phys = dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE);
-       if (dma_mapping_error(&ndev->dev, phys)) {
+       phys = dma_map_single(priv->dev, skb->data, skb->len, DMA_TO_DEVICE);
+       if (dma_mapping_error(priv->dev, phys)) {
                dev_kfree_skb(skb);
                return NETDEV_TX_OK;
        }
@@ -585,6 +586,9 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
        u16 len;
        u32 err;
 
+       /* clean up tx descriptors */
+       tx_remaining = hip04_tx_reclaim(ndev, false);
+
        while (cnt && !last) {
                buf = priv->rx_buf[priv->rx_head];
                skb = build_skb(buf, priv->rx_buf_size);
@@ -593,7 +597,7 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
                        goto refill;
                }
 
-               dma_unmap_single(&ndev->dev, priv->rx_phys[priv->rx_head],
+               dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head],
                                 RX_BUF_SIZE, DMA_FROM_DEVICE);
                priv->rx_phys[priv->rx_head] = 0;
 
@@ -622,9 +626,9 @@ refill:
                buf = netdev_alloc_frag(priv->rx_buf_size);
                if (!buf)
                        goto done;
-               phys = dma_map_single(&ndev->dev, buf,
+               phys = dma_map_single(priv->dev, buf,
                                      RX_BUF_SIZE, DMA_FROM_DEVICE);
-               if (dma_mapping_error(&ndev->dev, phys))
+               if (dma_mapping_error(priv->dev, phys))
                        goto done;
                priv->rx_buf[priv->rx_head] = buf;
                priv->rx_phys[priv->rx_head] = phys;
@@ -645,8 +649,7 @@ refill:
        }
        napi_complete_done(napi, rx);
 done:
-       /* clean up tx descriptors and start a new timer if necessary */
-       tx_remaining = hip04_tx_reclaim(ndev, false);
+       /* start a new timer if necessary */
        if (rx < budget && tx_remaining)
                hip04_start_tx_timer(priv);
 
@@ -728,9 +731,9 @@ static int hip04_mac_open(struct net_device *ndev)
        for (i = 0; i < RX_DESC_NUM; i++) {
                dma_addr_t phys;
 
-               phys = dma_map_single(&ndev->dev, priv->rx_buf[i],
+               phys = dma_map_single(priv->dev, priv->rx_buf[i],
                                      RX_BUF_SIZE, DMA_FROM_DEVICE);
-               if (dma_mapping_error(&ndev->dev, phys))
+               if (dma_mapping_error(priv->dev, phys))
                        return -EIO;
 
                priv->rx_phys[i] = phys;
@@ -764,7 +767,7 @@ static int hip04_mac_stop(struct net_device *ndev)
 
        for (i = 0; i < RX_DESC_NUM; i++) {
                if (priv->rx_phys[i]) {
-                       dma_unmap_single(&ndev->dev, priv->rx_phys[i],
+                       dma_unmap_single(priv->dev, priv->rx_phys[i],
                                         RX_BUF_SIZE, DMA_FROM_DEVICE);
                        priv->rx_phys[i] = 0;
                }
@@ -907,6 +910,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        priv = netdev_priv(ndev);
+       priv->dev = d;
        priv->ndev = ndev;
        platform_set_drvdata(pdev, ndev);
        SET_NETDEV_DEV(ndev, &pdev->dev);
index 4138a84803478a5b0b3ad9c7adce1e0e51f28cb3..cca71ba7a74a02b72d3c188368d6197278864243 100644 (file)
@@ -3251,7 +3251,7 @@ static int ehea_mem_notifier(struct notifier_block *nb,
        switch (action) {
        case MEM_CANCEL_OFFLINE:
                pr_info("memory offlining canceled");
-               /* Fall through: re-add canceled memory block */
+               /* Fall through - re-add canceled memory block */
 
        case MEM_ONLINE:
                pr_info("memory is going online");
index f660cc2b82583fdc6d20cd1e0761dc71b294603b..0b9e851f3da4fb1a37989e1aed311a5ad282353f 100644 (file)
@@ -319,20 +319,33 @@ static int orion_mdio_probe(struct platform_device *pdev)
 
        init_waitqueue_head(&dev->smi_busy_wait);
 
-       for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
-               dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
-               if (PTR_ERR(dev->clk[i]) == -EPROBE_DEFER) {
+       if (pdev->dev.of_node) {
+               for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
+                       dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
+                       if (PTR_ERR(dev->clk[i]) == -EPROBE_DEFER) {
+                               ret = -EPROBE_DEFER;
+                               goto out_clk;
+                       }
+                       if (IS_ERR(dev->clk[i]))
+                               break;
+                       clk_prepare_enable(dev->clk[i]);
+               }
+
+               if (!IS_ERR(of_clk_get(pdev->dev.of_node,
+                                      ARRAY_SIZE(dev->clk))))
+                       dev_warn(&pdev->dev,
+                                "unsupported number of clocks, limiting to the first "
+                                __stringify(ARRAY_SIZE(dev->clk)) "\n");
+       } else {
+               dev->clk[0] = clk_get(&pdev->dev, NULL);
+               if (PTR_ERR(dev->clk[0]) == -EPROBE_DEFER) {
                        ret = -EPROBE_DEFER;
                        goto out_clk;
                }
-               if (IS_ERR(dev->clk[i]))
-                       break;
-               clk_prepare_enable(dev->clk[i]);
+               if (!IS_ERR(dev->clk[0]))
+                       clk_prepare_enable(dev->clk[0]);
        }
 
-       if (!IS_ERR(of_clk_get(pdev->dev.of_node, ARRAY_SIZE(dev->clk))))
-               dev_warn(&pdev->dev, "unsupported number of clocks, limiting to the first "
-                        __stringify(ARRAY_SIZE(dev->clk)) "\n");
 
        dev->err_interrupt = platform_get_irq(pdev, 0);
        if (dev->err_interrupt > 0 &&
index c51f1d5b550b1131d18fc7240e5503d461c43f4f..ccdd47f3b8fb5dbf474e2086711b2569f62a46bd 100644 (file)
@@ -811,6 +811,26 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
        return 0;
 }
 
+static void mvpp2_set_hw_csum(struct mvpp2_port *port,
+                             enum mvpp2_bm_pool_log_num new_long_pool)
+{
+       const netdev_features_t csums = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+
+       /* Update L4 checksum when jumbo enable/disable on port.
+        * Only port 0 supports hardware checksum offload due to
+        * the Tx FIFO size limitation.
+        * Also, don't set NETIF_F_HW_CSUM because L3_offset in TX descriptor
+        * has 7 bits, so the maximum L3 offset is 128.
+        */
+       if (new_long_pool == MVPP2_BM_JUMBO && port->id != 0) {
+               port->dev->features &= ~csums;
+               port->dev->hw_features &= ~csums;
+       } else {
+               port->dev->features |= csums;
+               port->dev->hw_features |= csums;
+       }
+}
+
 static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
 {
        struct mvpp2_port *port = netdev_priv(dev);
@@ -843,15 +863,7 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
                /* Add port to new short & long pool */
                mvpp2_swf_bm_pool_init(port);
 
-               /* Update L4 checksum when jumbo enable/disable on port */
-               if (new_long_pool == MVPP2_BM_JUMBO && port->id != 0) {
-                       dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-                       dev->hw_features &= ~(NETIF_F_IP_CSUM |
-                                             NETIF_F_IPV6_CSUM);
-               } else {
-                       dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-                       dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-               }
+               mvpp2_set_hw_csum(port, new_long_pool);
        }
 
        dev->mtu = mtu;
@@ -3700,6 +3712,7 @@ static int mvpp2_set_mac_address(struct net_device *dev, void *p)
 static int mvpp2_change_mtu(struct net_device *dev, int mtu)
 {
        struct mvpp2_port *port = netdev_priv(dev);
+       bool running = netif_running(dev);
        int err;
 
        if (!IS_ALIGNED(MVPP2_RX_PKT_SIZE(mtu), 8)) {
@@ -3708,40 +3721,24 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu)
                mtu = ALIGN(MVPP2_RX_PKT_SIZE(mtu), 8);
        }
 
-       if (!netif_running(dev)) {
-               err = mvpp2_bm_update_mtu(dev, mtu);
-               if (!err) {
-                       port->pkt_size =  MVPP2_RX_PKT_SIZE(mtu);
-                       return 0;
-               }
-
-               /* Reconfigure BM to the original MTU */
-               err = mvpp2_bm_update_mtu(dev, dev->mtu);
-               if (err)
-                       goto log_error;
-       }
-
-       mvpp2_stop_dev(port);
+       if (running)
+               mvpp2_stop_dev(port);
 
        err = mvpp2_bm_update_mtu(dev, mtu);
-       if (!err) {
+       if (err) {
+               netdev_err(dev, "failed to change MTU\n");
+               /* Reconfigure BM to the original MTU */
+               mvpp2_bm_update_mtu(dev, dev->mtu);
+       } else {
                port->pkt_size =  MVPP2_RX_PKT_SIZE(mtu);
-               goto out_start;
        }
 
-       /* Reconfigure BM to the original MTU */
-       err = mvpp2_bm_update_mtu(dev, dev->mtu);
-       if (err)
-               goto log_error;
-
-out_start:
-       mvpp2_start_dev(port);
-       mvpp2_egress_enable(port);
-       mvpp2_ingress_enable(port);
+       if (running) {
+               mvpp2_start_dev(port);
+               mvpp2_egress_enable(port);
+               mvpp2_ingress_enable(port);
+       }
 
-       return 0;
-log_error:
-       netdev_err(dev, "failed to change MTU\n");
        return err;
 }
 
@@ -4739,9 +4736,9 @@ static void mvpp2_xlg_config(struct mvpp2_port *port, unsigned int mode,
        else
                ctrl0 &= ~MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN;
 
-       ctrl4 &= ~MVPP22_XLG_CTRL4_MACMODSELECT_GMAC;
-       ctrl4 |= MVPP22_XLG_CTRL4_FWD_FC | MVPP22_XLG_CTRL4_FWD_PFC |
-                MVPP22_XLG_CTRL4_EN_IDLE_CHECK;
+       ctrl4 &= ~(MVPP22_XLG_CTRL4_MACMODSELECT_GMAC |
+                  MVPP22_XLG_CTRL4_EN_IDLE_CHECK);
+       ctrl4 |= MVPP22_XLG_CTRL4_FWD_FC | MVPP22_XLG_CTRL4_FWD_PFC;
 
        if (old_ctrl0 != ctrl0)
                writel(ctrl0, port->base + MVPP22_XLG_CTRL0_REG);
@@ -5208,10 +5205,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
                dev->features |= NETIF_F_NTUPLE;
        }
 
-       if (port->pool_long->id == MVPP2_BM_JUMBO && port->id != 0) {
-               dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-               dev->hw_features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-       }
+       mvpp2_set_hw_csum(port, port->pool_long->id);
 
        dev->vlan_features |= features;
        dev->gso_max_segs = MVPP2_MAX_TSO_SEGS;
@@ -5759,9 +5753,6 @@ static int mvpp2_remove(struct platform_device *pdev)
 
        mvpp2_dbgfs_cleanup(priv);
 
-       flush_workqueue(priv->stats_queue);
-       destroy_workqueue(priv->stats_queue);
-
        fwnode_for_each_available_child_node(fwnode, port_fwnode) {
                if (priv->port_list[i]) {
                        mutex_destroy(&priv->port_list[i]->gather_stats_lock);
@@ -5770,6 +5761,8 @@ static int mvpp2_remove(struct platform_device *pdev)
                i++;
        }
 
+       destroy_workqueue(priv->stats_queue);
+
        for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) {
                struct mvpp2_bm_pool *bm_pool = &priv->bm_pools[i];
 
index f518312ffe695470bf1dd4239d9e2b1b08e5ea54..a01c75ede871a378ac6e32e7b939c4bdd1d112a6 100644 (file)
@@ -4924,6 +4924,13 @@ static const struct dmi_system_id msi_blacklist[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
                },
        },
+       {
+               .ident = "ASUS P6T",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "P6T"),
+               },
+       },
        {}
 };
 
index 263cd0909fe0de39eb6d48c39e194f904b39b846..1f7fff81f24dbb96a964326ae0a306315198afa2 100644 (file)
@@ -9,7 +9,6 @@ if NET_VENDOR_MEDIATEK
 
 config NET_MEDIATEK_SOC
        tristate "MediaTek SoC Gigabit Ethernet support"
-       depends on NET_VENDOR_MEDIATEK
        select PHYLIB
        ---help---
          This driver supports the gigabit ethernet MACs in the
index 5bb6a26ea2672ea3ce25a8ddd6750be2ecb7733a..50862275544e52cd0610831694f8c415e1da8ed0 100644 (file)
@@ -213,7 +213,7 @@ void mlx5_unregister_device(struct mlx5_core_dev *dev)
        struct mlx5_interface *intf;
 
        mutex_lock(&mlx5_intf_mutex);
-       list_for_each_entry(intf, &intf_list, list)
+       list_for_each_entry_reverse(intf, &intf_list, list)
                mlx5_remove_device(intf, priv);
        list_del(&priv->dev_list);
        mutex_unlock(&mlx5_intf_mutex);
index 79d93d6c7d7a7fc2175d53052108a411bd3960c6..ce1be2a84231a775c1f6496b07b94ec10b684f97 100644 (file)
@@ -159,7 +159,7 @@ do {                                                            \
 enum mlx5e_rq_group {
        MLX5E_RQ_GROUP_REGULAR,
        MLX5E_RQ_GROUP_XSK,
-       MLX5E_NUM_RQ_GROUPS /* Keep last. */
+#define MLX5E_NUM_RQ_GROUPS(g) (1 + MLX5E_RQ_GROUP_##g)
 };
 
 static inline u16 mlx5_min_rx_wqes(int wq_type, u32 wq_size)
@@ -182,14 +182,6 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
                min_t(int, mlx5_comp_vectors_count(mdev), MLX5E_MAX_NUM_CHANNELS);
 }
 
-/* Use this function to get max num channels after netdev was created */
-static inline int mlx5e_get_netdev_max_channels(struct net_device *netdev)
-{
-       return min_t(unsigned int,
-                    netdev->num_rx_queues / MLX5E_NUM_RQ_GROUPS,
-                    netdev->num_tx_queues);
-}
-
 struct mlx5e_tx_wqe {
        struct mlx5_wqe_ctrl_seg ctrl;
        struct mlx5_wqe_eth_seg  eth;
@@ -830,6 +822,7 @@ struct mlx5e_priv {
        struct net_device         *netdev;
        struct mlx5e_stats         stats;
        struct mlx5e_channel_stats channel_stats[MLX5E_MAX_NUM_CHANNELS];
+       u16                        max_nch;
        u8                         max_opened_tc;
        struct hwtstamp_config     tstamp;
        u16                        q_counter;
@@ -871,6 +864,7 @@ struct mlx5e_profile {
                mlx5e_fp_handle_rx_cqe handle_rx_cqe_mpwqe;
        } rx_handlers;
        int     max_tc;
+       u8      rq_groups;
 };
 
 void mlx5e_build_ptys2ethtool_map(void);
index bd882b5ee9a746f7a6ccca891835b167a19d1ccb..3a615d663d84ec51c2142514bdbfde897cb18f2d 100644 (file)
@@ -66,9 +66,10 @@ static inline void mlx5e_qid_get_ch_and_group(struct mlx5e_params *params,
        *group = qid / nch;
 }
 
-static inline bool mlx5e_qid_validate(struct mlx5e_params *params, u64 qid)
+static inline bool mlx5e_qid_validate(const struct mlx5e_profile *profile,
+                                     struct mlx5e_params *params, u64 qid)
 {
-       return qid < params->num_channels * MLX5E_NUM_RQ_GROUPS;
+       return qid < params->num_channels * profile->rq_groups;
 }
 
 /* Parameter calculations */
index d5e5afbdca6dcbacb776571c97eef74e033cf356..f777994f3005ea2b68b707bbadb0440ecb9c51e9 100644 (file)
@@ -78,9 +78,10 @@ static const u32 mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = {
 };
 
 static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
-                                    const u32 **arr, u32 *size)
+                                    const u32 **arr, u32 *size,
+                                    bool force_legacy)
 {
-       bool ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
+       bool ext = force_legacy ? false : MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
 
        *size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
                      ARRAY_SIZE(mlx5e_link_speed);
@@ -152,7 +153,8 @@ int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
                            sizeof(out), MLX5_REG_PTYS, 0, 1);
 }
 
-u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper)
+u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
+                         bool force_legacy)
 {
        unsigned long temp = eth_proto_oper;
        const u32 *table;
@@ -160,7 +162,7 @@ u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper)
        u32 max_size;
        int i;
 
-       mlx5e_port_get_speed_arr(mdev, &table, &max_size);
+       mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
        i = find_first_bit(&temp, max_size);
        if (i < max_size)
                speed = table[i];
@@ -170,6 +172,7 @@ u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper)
 int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
 {
        struct mlx5e_port_eth_proto eproto;
+       bool force_legacy = false;
        bool ext;
        int err;
 
@@ -177,8 +180,13 @@ int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
        err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
        if (err)
                goto out;
-
-       *speed = mlx5e_port_ptys2speed(mdev, eproto.oper);
+       if (ext && !eproto.admin) {
+               force_legacy = true;
+               err = mlx5_port_query_eth_proto(mdev, 1, false, &eproto);
+               if (err)
+                       goto out;
+       }
+       *speed = mlx5e_port_ptys2speed(mdev, eproto.oper, force_legacy);
        if (!(*speed))
                err = -EINVAL;
 
@@ -201,7 +209,7 @@ int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
        if (err)
                return err;
 
-       mlx5e_port_get_speed_arr(mdev, &table, &max_size);
+       mlx5e_port_get_speed_arr(mdev, &table, &max_size, false);
        for (i = 0; i < max_size; ++i)
                if (eproto.cap & MLX5E_PROT_MASK(i))
                        max_speed = max(max_speed, table[i]);
@@ -210,14 +218,15 @@ int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
        return 0;
 }
 
-u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed)
+u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
+                              bool force_legacy)
 {
        u32 link_modes = 0;
        const u32 *table;
        u32 max_size;
        int i;
 
-       mlx5e_port_get_speed_arr(mdev, &table, &max_size);
+       mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
        for (i = 0; i < max_size; ++i) {
                if (table[i] == speed)
                        link_modes |= MLX5E_PROT_MASK(i);
index 70f536ec51c47523b76070a1f0971de668698b1d..4a7f4497692bc7655ce6852cc497807a935e6a59 100644 (file)
@@ -48,10 +48,12 @@ void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status,
                                 u8 *an_disable_cap, u8 *an_disable_admin);
 int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
                           u32 proto_admin, bool ext);
-u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper);
+u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
+                         bool force_legacy);
 int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
 int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
-u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed);
+u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
+                              bool force_legacy);
 
 int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out);
 int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in);
index ea032f54197e17a8b829d4b6b37a24573fe7237e..3766545ce2599699a59deb89d2d59de6e8335e0b 100644 (file)
@@ -412,7 +412,7 @@ struct sk_buff *mlx5e_ktls_handle_tx_skb(struct net_device *netdev,
                goto out;
 
        tls_ctx = tls_get_ctx(skb->sk);
-       if (unlikely(tls_ctx->netdev != netdev))
+       if (unlikely(WARN_ON_ONCE(tls_ctx->netdev != netdev)))
                goto err_out;
 
        priv_tx = mlx5e_get_ktls_tx_priv_ctx(tls_ctx);
index 126ec41812865d99b8d32ea0ca9c2908d68763ca..03bed714bac3f919675517b5bb759a1c7e9e2d6a 100644 (file)
@@ -391,7 +391,7 @@ void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv,
 {
        mutex_lock(&priv->state_lock);
 
-       ch->max_combined   = mlx5e_get_netdev_max_channels(priv->netdev);
+       ch->max_combined   = priv->max_nch;
        ch->combined_count = priv->channels.params.num_channels;
        if (priv->xsk.refcnt) {
                /* The upper half are XSK queues. */
@@ -785,7 +785,7 @@ static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings
 }
 
 static void get_speed_duplex(struct net_device *netdev,
-                            u32 eth_proto_oper,
+                            u32 eth_proto_oper, bool force_legacy,
                             struct ethtool_link_ksettings *link_ksettings)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -795,7 +795,7 @@ static void get_speed_duplex(struct net_device *netdev,
        if (!netif_carrier_ok(netdev))
                goto out;
 
-       speed = mlx5e_port_ptys2speed(priv->mdev, eth_proto_oper);
+       speed = mlx5e_port_ptys2speed(priv->mdev, eth_proto_oper, force_legacy);
        if (!speed) {
                speed = SPEED_UNKNOWN;
                goto out;
@@ -914,8 +914,8 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
        /* Fields: eth_proto_admin and ext_eth_proto_admin  are
         * mutually exclusive. Hence try reading legacy advertising
         * when extended advertising is zero.
-        * admin_ext indicates how eth_proto_admin should be
-        * interpreted
+        * admin_ext indicates which proto_admin (ext vs. legacy)
+        * should be read and interpreted
         */
        admin_ext = ext;
        if (ext && !eth_proto_admin) {
@@ -924,7 +924,7 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
                admin_ext = false;
        }
 
-       eth_proto_oper   = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
+       eth_proto_oper   = MLX5_GET_ETH_PROTO(ptys_reg, out, admin_ext,
                                              eth_proto_oper);
        eth_proto_lp        = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise);
        an_disable_admin    = MLX5_GET(ptys_reg, out, an_disable_admin);
@@ -939,7 +939,8 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
        get_supported(mdev, eth_proto_cap, link_ksettings);
        get_advertising(eth_proto_admin, tx_pause, rx_pause, link_ksettings,
                        admin_ext);
-       get_speed_duplex(priv->netdev, eth_proto_oper, link_ksettings);
+       get_speed_duplex(priv->netdev, eth_proto_oper, !admin_ext,
+                        link_ksettings);
 
        eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap;
 
@@ -1016,45 +1017,69 @@ static u32 mlx5e_ethtool2ptys_ext_adver_link(const unsigned long *link_modes)
        return ptys_modes;
 }
 
+static bool ext_link_mode_requested(const unsigned long *adver)
+{
+#define MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT ETHTOOL_LINK_MODE_50000baseKR_Full_BIT
+       int size = __ETHTOOL_LINK_MODE_MASK_NBITS - MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT;
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(modes);
+
+       bitmap_set(modes, MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT, size);
+       return bitmap_intersects(modes, adver, __ETHTOOL_LINK_MODE_MASK_NBITS);
+}
+
+static bool ext_speed_requested(u32 speed)
+{
+#define MLX5E_MAX_PTYS_LEGACY_SPEED 100000
+       return !!(speed > MLX5E_MAX_PTYS_LEGACY_SPEED);
+}
+
+static bool ext_requested(u8 autoneg, const unsigned long *adver, u32 speed)
+{
+       bool ext_link_mode = ext_link_mode_requested(adver);
+       bool ext_speed = ext_speed_requested(speed);
+
+       return  autoneg == AUTONEG_ENABLE ? ext_link_mode : ext_speed;
+}
+
 int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
                                     const struct ethtool_link_ksettings *link_ksettings)
 {
        struct mlx5_core_dev *mdev = priv->mdev;
        struct mlx5e_port_eth_proto eproto;
+       const unsigned long *adver;
        bool an_changes = false;
        u8 an_disable_admin;
        bool ext_supported;
-       bool ext_requested;
        u8 an_disable_cap;
        bool an_disable;
        u32 link_modes;
        u8 an_status;
+       u8 autoneg;
        u32 speed;
+       bool ext;
        int err;
 
        u32 (*ethtool2ptys_adver_func)(const unsigned long *adver);
 
-#define MLX5E_PTYS_EXT ((1ULL << ETHTOOL_LINK_MODE_50000baseKR_Full_BIT) - 1)
+       adver = link_ksettings->link_modes.advertising;
+       autoneg = link_ksettings->base.autoneg;
+       speed = link_ksettings->base.speed;
 
-       ext_requested = !!(link_ksettings->link_modes.advertising[0] >
-                       MLX5E_PTYS_EXT ||
-                       link_ksettings->link_modes.advertising[1]);
+       ext = ext_requested(autoneg, adver, speed),
        ext_supported = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
-       ext_requested &= ext_supported;
+       if (!ext_supported && ext)
+               return -EOPNOTSUPP;
 
-       speed = link_ksettings->base.speed;
-       ethtool2ptys_adver_func = ext_requested ?
-                                 mlx5e_ethtool2ptys_ext_adver_link :
+       ethtool2ptys_adver_func = ext ? mlx5e_ethtool2ptys_ext_adver_link :
                                  mlx5e_ethtool2ptys_adver_link;
-       err = mlx5_port_query_eth_proto(mdev, 1, ext_requested, &eproto);
+       err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
        if (err) {
                netdev_err(priv->netdev, "%s: query port eth proto failed: %d\n",
                           __func__, err);
                goto out;
        }
-       link_modes = link_ksettings->base.autoneg == AUTONEG_ENABLE ?
-               ethtool2ptys_adver_func(link_ksettings->link_modes.advertising) :
-               mlx5e_port_speed2linkmodes(mdev, speed);
+       link_modes = autoneg == AUTONEG_ENABLE ? ethtool2ptys_adver_func(adver) :
+               mlx5e_port_speed2linkmodes(mdev, speed, !ext);
 
        link_modes = link_modes & eproto.cap;
        if (!link_modes) {
@@ -1067,14 +1092,14 @@ int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
        mlx5_port_query_eth_autoneg(mdev, &an_status, &an_disable_cap,
                                    &an_disable_admin);
 
-       an_disable = link_ksettings->base.autoneg == AUTONEG_DISABLE;
+       an_disable = autoneg == AUTONEG_DISABLE;
        an_changes = ((!an_disable && an_disable_admin) ||
                      (an_disable && !an_disable_admin));
 
        if (!an_changes && link_modes == eproto.admin)
                goto out;
 
-       mlx5_port_set_eth_ptys(mdev, an_disable, link_modes, ext_requested);
+       mlx5_port_set_eth_ptys(mdev, an_disable, link_modes, ext);
        mlx5_toggle_port_link(mdev);
 
 out:
index ea3a490b569a58c46b49196b3637bec4923b7843..94304abc49e98102c50a6a1fcb63ca468335af96 100644 (file)
@@ -611,7 +611,8 @@ static int validate_flow(struct mlx5e_priv *priv,
                return -ENOSPC;
 
        if (fs->ring_cookie != RX_CLS_FLOW_DISC)
-               if (!mlx5e_qid_validate(&priv->channels.params, fs->ring_cookie))
+               if (!mlx5e_qid_validate(priv->profile, &priv->channels.params,
+                                       fs->ring_cookie))
                        return -EINVAL;
 
        switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
index 47eea6b3a1c385dc97339f671a1d56b49dc3c92b..6c712c5be4d81dec3ae3a58f5fb8d11c21456ebd 100644 (file)
@@ -331,12 +331,11 @@ static inline u64 mlx5e_get_mpwqe_offset(struct mlx5e_rq *rq, u16 wqe_ix)
 
 static void mlx5e_init_frags_partition(struct mlx5e_rq *rq)
 {
-       struct mlx5e_wqe_frag_info next_frag, *prev;
+       struct mlx5e_wqe_frag_info next_frag = {};
+       struct mlx5e_wqe_frag_info *prev = NULL;
        int i;
 
        next_frag.di = &rq->wqe.di[0];
-       next_frag.offset = 0;
-       prev = NULL;
 
        for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++) {
                struct mlx5e_rq_frag_info *frag_info = &rq->wqe.info.arr[0];
@@ -1677,10 +1676,10 @@ static int mlx5e_open_sqs(struct mlx5e_channel *c,
                          struct mlx5e_channel_param *cparam)
 {
        struct mlx5e_priv *priv = c->priv;
-       int err, tc, max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
+       int err, tc;
 
        for (tc = 0; tc < params->num_tc; tc++) {
-               int txq_ix = c->ix + tc * max_nch;
+               int txq_ix = c->ix + tc * priv->max_nch;
 
                err = mlx5e_open_txqsq(c, c->priv->tisn[tc], txq_ix,
                                       params, &cparam->sq, &c->sq[tc], tc);
@@ -2438,11 +2437,10 @@ int mlx5e_create_indirect_rqt(struct mlx5e_priv *priv)
 
 int mlx5e_create_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
 {
-       const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int err;
        int ix;
 
-       for (ix = 0; ix < max_nch; ix++) {
+       for (ix = 0; ix < priv->max_nch; ix++) {
                err = mlx5e_create_rqt(priv, 1 /*size */, &tirs[ix].rqt);
                if (unlikely(err))
                        goto err_destroy_rqts;
@@ -2460,10 +2458,9 @@ err_destroy_rqts:
 
 void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
 {
-       const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int i;
 
-       for (i = 0; i < max_nch; i++)
+       for (i = 0; i < priv->max_nch; i++)
                mlx5e_destroy_rqt(priv, &tirs[i].rqt);
 }
 
@@ -2557,7 +2554,7 @@ static void mlx5e_redirect_rqts(struct mlx5e_priv *priv,
                mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, rrp);
        }
 
-       for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) {
+       for (ix = 0; ix < priv->max_nch; ix++) {
                struct mlx5e_redirect_rqt_param direct_rrp = {
                        .is_rss = false,
                        {
@@ -2758,7 +2755,7 @@ static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
                        goto free_in;
        }
 
-       for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) {
+       for (ix = 0; ix < priv->max_nch; ix++) {
                err = mlx5_core_modify_tir(mdev, priv->direct_tir[ix].tirn,
                                           in, inlen);
                if (err)
@@ -2858,12 +2855,11 @@ static void mlx5e_netdev_set_tcs(struct net_device *netdev)
 
 static void mlx5e_build_tc2txq_maps(struct mlx5e_priv *priv)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int i, tc;
 
-       for (i = 0; i < max_nch; i++)
+       for (i = 0; i < priv->max_nch; i++)
                for (tc = 0; tc < priv->profile->max_tc; tc++)
-                       priv->channel_tc2txq[i][tc] = i + tc * max_nch;
+                       priv->channel_tc2txq[i][tc] = i + tc * priv->max_nch;
 }
 
 static void mlx5e_build_tx2sq_maps(struct mlx5e_priv *priv)
@@ -2884,7 +2880,7 @@ static void mlx5e_build_tx2sq_maps(struct mlx5e_priv *priv)
 void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
 {
        int num_txqs = priv->channels.num * priv->channels.params.num_tc;
-       int num_rxqs = priv->channels.num * MLX5E_NUM_RQ_GROUPS;
+       int num_rxqs = priv->channels.num * priv->profile->rq_groups;
        struct net_device *netdev = priv->netdev;
 
        mlx5e_netdev_set_tcs(netdev);
@@ -3306,7 +3302,6 @@ err_destroy_inner_tirs:
 
 int mlx5e_create_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
 {
-       const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        struct mlx5e_tir *tir;
        void *tirc;
        int inlen;
@@ -3319,7 +3314,7 @@ int mlx5e_create_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
        if (!in)
                return -ENOMEM;
 
-       for (ix = 0; ix < max_nch; ix++) {
+       for (ix = 0; ix < priv->max_nch; ix++) {
                memset(in, 0, inlen);
                tir = &tirs[ix];
                tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
@@ -3358,10 +3353,9 @@ void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc)
 
 void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
 {
-       const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int i;
 
-       for (i = 0; i < max_nch; i++)
+       for (i = 0; i < priv->max_nch; i++)
                mlx5e_destroy_tir(priv->mdev, &tirs[i]);
 }
 
@@ -3487,7 +3481,7 @@ void mlx5e_fold_sw_stats64(struct mlx5e_priv *priv, struct rtnl_link_stats64 *s)
 {
        int i;
 
-       for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) {
+       for (i = 0; i < priv->max_nch; i++) {
                struct mlx5e_channel_stats *channel_stats = &priv->channel_stats[i];
                struct mlx5e_rq_stats *xskrq_stats = &channel_stats->xskrq;
                struct mlx5e_rq_stats *rq_stats = &channel_stats->rq;
@@ -4960,8 +4954,7 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev,
                return err;
 
        mlx5e_build_nic_params(mdev, &priv->xsk, rss, &priv->channels.params,
-                              mlx5e_get_netdev_max_channels(netdev),
-                              netdev->mtu);
+                              priv->max_nch, netdev->mtu);
 
        mlx5e_timestamp_init(priv);
 
@@ -5164,6 +5157,7 @@ static const struct mlx5e_profile mlx5e_nic_profile = {
        .rx_handlers.handle_rx_cqe       = mlx5e_handle_rx_cqe,
        .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
        .max_tc            = MLX5E_MAX_NUM_TC,
+       .rq_groups         = MLX5E_NUM_RQ_GROUPS(XSK),
 };
 
 /* mlx5e generic netdev management API (move to en_common.c) */
@@ -5181,6 +5175,7 @@ int mlx5e_netdev_init(struct net_device *netdev,
        priv->profile     = profile;
        priv->ppriv       = ppriv;
        priv->msglevel    = MLX5E_MSG_LEVEL;
+       priv->max_nch     = netdev->num_rx_queues / max_t(u8, profile->rq_groups, 1);
        priv->max_opened_tc = 1;
 
        mutex_init(&priv->state_lock);
@@ -5218,7 +5213,7 @@ struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
 
        netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
                                    nch * profile->max_tc,
-                                   nch * MLX5E_NUM_RQ_GROUPS);
+                                   nch * profile->rq_groups);
        if (!netdev) {
                mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n");
                return NULL;
index 7f747cb1a4f4b6ba072cd75596cf042ae7380da7..d0684fdb69e1424cee0e17d147755d20fa938e85 100644 (file)
@@ -1701,6 +1701,7 @@ static const struct mlx5e_profile mlx5e_rep_profile = {
        .rx_handlers.handle_rx_cqe       = mlx5e_handle_rx_cqe_rep,
        .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
        .max_tc                 = 1,
+       .rq_groups              = MLX5E_NUM_RQ_GROUPS(REGULAR),
 };
 
 static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
@@ -1718,6 +1719,7 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
        .rx_handlers.handle_rx_cqe       = mlx5e_handle_rx_cqe_rep,
        .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
        .max_tc                 = MLX5E_MAX_NUM_TC,
+       .rq_groups              = MLX5E_NUM_RQ_GROUPS(REGULAR),
 };
 
 static bool
index 539b4d3656da1e3af54a2977024d4a0346c584f2..57f9f346d213b0ba9be9449c2947c06442d6c6c5 100644 (file)
@@ -172,7 +172,7 @@ static void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
 
        memset(s, 0, sizeof(*s));
 
-       for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) {
+       for (i = 0; i < priv->max_nch; i++) {
                struct mlx5e_channel_stats *channel_stats =
                        &priv->channel_stats[i];
                struct mlx5e_xdpsq_stats *xdpsq_red_stats = &channel_stats->xdpsq;
@@ -1395,7 +1395,7 @@ static const struct counter_desc ch_stats_desc[] = {
 
 static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
+       int max_nch = priv->max_nch;
 
        return (NUM_RQ_STATS * max_nch) +
               (NUM_CH_STATS * max_nch) +
@@ -1409,8 +1409,8 @@ static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv)
 static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data,
                                           int idx)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        bool is_xsk = priv->xsk.ever_used;
+       int max_nch = priv->max_nch;
        int i, j, tc;
 
        for (i = 0; i < max_nch; i++)
@@ -1452,8 +1452,8 @@ static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data,
 static int mlx5e_grp_channels_fill_stats(struct mlx5e_priv *priv, u64 *data,
                                         int idx)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        bool is_xsk = priv->xsk.ever_used;
+       int max_nch = priv->max_nch;
        int i, j, tc;
 
        for (i = 0; i < max_nch; i++)
index cc096f6011d964051405dd5fa3514b428086cc5a..7ecfc53cf5f6503df89dfc1983ed0b2290470247 100644 (file)
@@ -1230,13 +1230,13 @@ static struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow)
 void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
 {
        struct mlx5e_neigh *m_neigh = &nhe->m_neigh;
-       u64 bytes, packets, lastuse = 0;
        struct mlx5e_tc_flow *flow;
        struct mlx5e_encap_entry *e;
        struct mlx5_fc *counter;
        struct neigh_table *tbl;
        bool neigh_used = false;
        struct neighbour *n;
+       u64 lastuse;
 
        if (m_neigh->family == AF_INET)
                tbl = &arp_tbl;
@@ -1256,7 +1256,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
                                            encaps[efi->index]);
                        if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
                                counter = mlx5e_tc_get_counter(flow);
-                               mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
+                               lastuse = mlx5_fc_query_lastuse(counter);
                                if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
                                        neigh_used = true;
                                        break;
index c50b6f0769c8c5086946fb8618ca42fdc4f2079c..49b06b256c92955d8b0054ade614b2d33ee41c1e 100644 (file)
@@ -49,7 +49,7 @@ static inline bool mlx5e_channel_no_affinity_change(struct mlx5e_channel *c)
 static void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq)
 {
        struct mlx5e_sq_stats *stats = sq->stats;
-       struct dim_sample dim_sample;
+       struct dim_sample dim_sample = {};
 
        if (unlikely(!test_bit(MLX5E_SQ_STATE_AM, &sq->state)))
                return;
@@ -61,7 +61,7 @@ static void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq)
 static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq)
 {
        struct mlx5e_rq_stats *stats = rq->stats;
-       struct dim_sample dim_sample;
+       struct dim_sample dim_sample = {};
 
        if (unlikely(!test_bit(MLX5E_RQ_STATE_AM, &rq->state)))
                return;
index c48c382f926f33b5747c5f5603c18713a03e6bd0..c1252d6be0ef13f38fbe573e724b0a814f319230 100644 (file)
@@ -68,7 +68,7 @@ enum fs_flow_table_type {
        FS_FT_SNIFFER_RX        = 0X5,
        FS_FT_SNIFFER_TX        = 0X6,
        FS_FT_RDMA_RX           = 0X7,
-       FS_FT_MAX_TYPE = FS_FT_SNIFFER_TX,
+       FS_FT_MAX_TYPE = FS_FT_RDMA_RX,
 };
 
 enum fs_flow_table_op_mod {
@@ -275,7 +275,8 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev);
        (type == FS_FT_FDB) ? MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, cap) :           \
        (type == FS_FT_SNIFFER_RX) ? MLX5_CAP_FLOWTABLE_SNIFFER_RX(mdev, cap) :         \
        (type == FS_FT_SNIFFER_TX) ? MLX5_CAP_FLOWTABLE_SNIFFER_TX(mdev, cap) :         \
-       (BUILD_BUG_ON_ZERO(FS_FT_SNIFFER_TX != FS_FT_MAX_TYPE))\
+       (type == FS_FT_RDMA_RX) ? MLX5_CAP_FLOWTABLE_RDMA_RX(mdev, cap) :               \
+       (BUILD_BUG_ON_ZERO(FS_FT_RDMA_RX != FS_FT_MAX_TYPE))\
        )
 
 #endif
index b3762123a69c2188f1745965aaeeb80ca8d80bf6..1834d9f3aa1c019ee9057b141bfe86068ac757c2 100644 (file)
@@ -369,6 +369,11 @@ int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter,
 }
 EXPORT_SYMBOL(mlx5_fc_query);
 
+u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter)
+{
+       return counter->cache.lastuse;
+}
+
 void mlx5_fc_query_cached(struct mlx5_fc *counter,
                          u64 *bytes, u64 *packets, u64 *lastuse)
 {
index 6bfaaab362dc48dac5f5e76d91eb41578585b2fb..1a2560e3bf7c54d85390b1f8a93600ad5a84ead9 100644 (file)
@@ -88,8 +88,7 @@ int mlx5i_init(struct mlx5_core_dev *mdev,
        netdev->mtu = netdev->max_mtu;
 
        mlx5e_build_nic_params(mdev, NULL, &priv->rss_params, &priv->channels.params,
-                              mlx5e_get_netdev_max_channels(netdev),
-                              netdev->mtu);
+                              priv->max_nch, netdev->mtu);
        mlx5i_build_nic_params(mdev, &priv->channels.params);
 
        mlx5e_timestamp_init(priv);
@@ -118,11 +117,10 @@ void mlx5i_cleanup(struct mlx5e_priv *priv)
 
 static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        struct mlx5e_sw_stats s = { 0 };
        int i, j;
 
-       for (i = 0; i < max_nch; i++) {
+       for (i = 0; i < priv->max_nch; i++) {
                struct mlx5e_channel_stats *channel_stats;
                struct mlx5e_rq_stats *rq_stats;
 
@@ -436,6 +434,7 @@ static const struct mlx5e_profile mlx5i_nic_profile = {
        .rx_handlers.handle_rx_cqe       = mlx5i_handle_rx_cqe,
        .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */
        .max_tc            = MLX5I_MAX_NUM_TC,
+       .rq_groups         = MLX5E_NUM_RQ_GROUPS(REGULAR),
 };
 
 /* mlx5i netdev NDos */
index 6e56fa769d2eb97b593b2c3da4c5aa5c40c1afdc..c5a491e22e55547def2706fa6b28c8c08fa858d1 100644 (file)
@@ -355,6 +355,7 @@ static const struct mlx5e_profile mlx5i_pkey_nic_profile = {
        .rx_handlers.handle_rx_cqe       = mlx5i_handle_rx_cqe,
        .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */
        .max_tc            = MLX5I_MAX_NUM_TC,
+       .rq_groups         = MLX5E_NUM_RQ_GROUPS(REGULAR),
 };
 
 const struct mlx5e_profile *mlx5i_pkey_get_profile(void)
index 650638152bbc5d6bd5d06949c6920f175fb4f9ee..eda9c23e87b28fcca50b8935e006fb9c94e990c3 100644 (file)
@@ -6330,7 +6330,7 @@ static int __init mlxsw_sp_module_init(void)
        return 0;
 
 err_sp2_pci_driver_register:
-       mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver);
+       mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);
 err_sp1_pci_driver_register:
        mlxsw_core_driver_unregister(&mlxsw_sp2_driver);
 err_sp2_core_driver_register:
index 131f62ce9297a05e0ba5406995beb1a16c14bdfa..6664119fb0c8cfc39ffd24c8963657de2e47c98b 100644 (file)
@@ -951,4 +951,8 @@ void mlxsw_sp_port_nve_fini(struct mlxsw_sp_port *mlxsw_sp_port);
 int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp);
 void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp);
 
+/* spectrum_nve_vxlan.c */
+int mlxsw_sp_nve_inc_parsing_depth_get(struct mlxsw_sp *mlxsw_sp);
+void mlxsw_sp_nve_inc_parsing_depth_put(struct mlxsw_sp *mlxsw_sp);
+
 #endif
index 1537f70bc26d0fbef771b91e4c92f6d9dae1ac4f..888ba4300bcc3b5d1888e7d3c87b28d51200e7f7 100644 (file)
@@ -437,8 +437,8 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = {
                           MLXSW_SP1_SB_PR_CPU_SIZE, true, false),
 };
 
-#define MLXSW_SP2_SB_PR_INGRESS_SIZE   38128752
-#define MLXSW_SP2_SB_PR_EGRESS_SIZE    38128752
+#define MLXSW_SP2_SB_PR_INGRESS_SIZE   35297568
+#define MLXSW_SP2_SB_PR_EGRESS_SIZE    35297568
 #define MLXSW_SP2_SB_PR_CPU_SIZE       (256 * 1000)
 
 /* Order according to mlxsw_sp2_sb_pool_dess */
index 1df164a4b06d3516b45dd034b8dbd71cb7988ab1..17f334b46c4056c6689d41d8288d3812a263a406 100644 (file)
@@ -775,6 +775,7 @@ static void mlxsw_sp_nve_tunnel_fini(struct mlxsw_sp *mlxsw_sp)
                ops->fini(nve);
                mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
                                   nve->tunnel_index);
+               memset(&nve->config, 0, sizeof(nve->config));
        }
        nve->num_nve_tunnels--;
 }
index 0035640156a16ebbee0391f8c105b4bbd455dfb0..12f664f42f2108abfc85b381959905713d8971cf 100644 (file)
@@ -29,6 +29,7 @@ struct mlxsw_sp_nve {
        unsigned int num_max_mc_entries[MLXSW_SP_L3_PROTO_MAX];
        u32 tunnel_index;
        u16 ul_rif_index;       /* Reserved for Spectrum */
+       unsigned int inc_parsing_depth_refs;
 };
 
 struct mlxsw_sp_nve_ops {
index 93ccd9fc22662d78ea91f12de0d9a2ea01ab4d30..05517c7feaa563fe0b8d1a365ce26980ea93b4a4 100644 (file)
@@ -103,9 +103,9 @@ static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve,
        config->udp_dport = cfg->dst_port;
 }
 
-static int mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp,
-                                   unsigned int parsing_depth,
-                                   __be16 udp_dport)
+static int __mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp,
+                                     unsigned int parsing_depth,
+                                     __be16 udp_dport)
 {
        char mprs_pl[MLXSW_REG_MPRS_LEN];
 
@@ -113,6 +113,56 @@ static int mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp,
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl);
 }
 
+static int mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp,
+                                   __be16 udp_dport)
+{
+       int parsing_depth = mlxsw_sp->nve->inc_parsing_depth_refs ?
+                               MLXSW_SP_NVE_VXLAN_PARSING_DEPTH :
+                               MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH;
+
+       return __mlxsw_sp_nve_parsing_set(mlxsw_sp, parsing_depth, udp_dport);
+}
+
+static int
+__mlxsw_sp_nve_inc_parsing_depth_get(struct mlxsw_sp *mlxsw_sp,
+                                    __be16 udp_dport)
+{
+       int err;
+
+       mlxsw_sp->nve->inc_parsing_depth_refs++;
+
+       err = mlxsw_sp_nve_parsing_set(mlxsw_sp, udp_dport);
+       if (err)
+               goto err_nve_parsing_set;
+       return 0;
+
+err_nve_parsing_set:
+       mlxsw_sp->nve->inc_parsing_depth_refs--;
+       return err;
+}
+
+static void
+__mlxsw_sp_nve_inc_parsing_depth_put(struct mlxsw_sp *mlxsw_sp,
+                                    __be16 udp_dport)
+{
+       mlxsw_sp->nve->inc_parsing_depth_refs--;
+       mlxsw_sp_nve_parsing_set(mlxsw_sp, udp_dport);
+}
+
+int mlxsw_sp_nve_inc_parsing_depth_get(struct mlxsw_sp *mlxsw_sp)
+{
+       __be16 udp_dport = mlxsw_sp->nve->config.udp_dport;
+
+       return __mlxsw_sp_nve_inc_parsing_depth_get(mlxsw_sp, udp_dport);
+}
+
+void mlxsw_sp_nve_inc_parsing_depth_put(struct mlxsw_sp *mlxsw_sp)
+{
+       __be16 udp_dport = mlxsw_sp->nve->config.udp_dport;
+
+       __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, udp_dport);
+}
+
 static void
 mlxsw_sp_nve_vxlan_config_prepare(char *tngcr_pl,
                                  const struct mlxsw_sp_nve_config *config)
@@ -176,9 +226,7 @@ static int mlxsw_sp1_nve_vxlan_init(struct mlxsw_sp_nve *nve,
        struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp;
        int err;
 
-       err = mlxsw_sp_nve_parsing_set(mlxsw_sp,
-                                      MLXSW_SP_NVE_VXLAN_PARSING_DEPTH,
-                                      config->udp_dport);
+       err = __mlxsw_sp_nve_inc_parsing_depth_get(mlxsw_sp, config->udp_dport);
        if (err)
                return err;
 
@@ -203,8 +251,7 @@ err_promote_decap:
 err_rtdp_set:
        mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp);
 err_config_set:
-       mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH,
-                                config->udp_dport);
+       __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, 0);
        return err;
 }
 
@@ -216,8 +263,7 @@ static void mlxsw_sp1_nve_vxlan_fini(struct mlxsw_sp_nve *nve)
        mlxsw_sp_router_nve_demote_decap(mlxsw_sp, config->ul_tb_id,
                                         config->ul_proto, &config->ul_sip);
        mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp);
-       mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH,
-                                config->udp_dport);
+       __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, 0);
 }
 
 static int
@@ -320,9 +366,7 @@ static int mlxsw_sp2_nve_vxlan_init(struct mlxsw_sp_nve *nve,
        struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp;
        int err;
 
-       err = mlxsw_sp_nve_parsing_set(mlxsw_sp,
-                                      MLXSW_SP_NVE_VXLAN_PARSING_DEPTH,
-                                      config->udp_dport);
+       err = __mlxsw_sp_nve_inc_parsing_depth_get(mlxsw_sp, config->udp_dport);
        if (err)
                return err;
 
@@ -348,8 +392,7 @@ err_promote_decap:
 err_rtdp_set:
        mlxsw_sp2_nve_vxlan_config_clear(mlxsw_sp);
 err_config_set:
-       mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH,
-                                config->udp_dport);
+       __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, 0);
        return err;
 }
 
@@ -361,8 +404,7 @@ static void mlxsw_sp2_nve_vxlan_fini(struct mlxsw_sp_nve *nve)
        mlxsw_sp_router_nve_demote_decap(mlxsw_sp, config->ul_tb_id,
                                         config->ul_proto, &config->ul_sip);
        mlxsw_sp2_nve_vxlan_config_clear(mlxsw_sp);
-       mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH,
-                                config->udp_dport);
+       __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, 0);
 }
 
 const struct mlxsw_sp_nve_ops mlxsw_sp2_nve_vxlan_ops = {
index bd9c2bc2d5d6e0569935ad77aedf56f1db198594..63b07edd9d8161304793e7321b5c3ea726416a1e 100644 (file)
@@ -979,6 +979,9 @@ static int mlxsw_sp1_ptp_mtpppc_update(struct mlxsw_sp_port *mlxsw_sp_port,
 {
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_port *tmp;
+       u16 orig_ing_types = 0;
+       u16 orig_egr_types = 0;
+       int err;
        int i;
 
        /* MTPPPC configures timestamping globally, not per port. Find the
@@ -986,12 +989,26 @@ static int mlxsw_sp1_ptp_mtpppc_update(struct mlxsw_sp_port *mlxsw_sp_port,
         */
        for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) {
                tmp = mlxsw_sp->ports[i];
+               if (tmp) {
+                       orig_ing_types |= tmp->ptp.ing_types;
+                       orig_egr_types |= tmp->ptp.egr_types;
+               }
                if (tmp && tmp != mlxsw_sp_port) {
                        ing_types |= tmp->ptp.ing_types;
                        egr_types |= tmp->ptp.egr_types;
                }
        }
 
+       if ((ing_types || egr_types) && !(orig_ing_types || orig_egr_types)) {
+               err = mlxsw_sp_nve_inc_parsing_depth_get(mlxsw_sp);
+               if (err) {
+                       netdev_err(mlxsw_sp_port->dev, "Failed to increase parsing depth");
+                       return err;
+               }
+       }
+       if (!(ing_types || egr_types) && (orig_ing_types || orig_egr_types))
+               mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp);
+
        return mlxsw_sp1_ptp_mtpppc_set(mlxsw_sp_port->mlxsw_sp,
                                       ing_types, egr_types);
 }
index b71e4ecbe469a5ec19699ed740ab0a9e63abdd45..6932e615d4b089c68b4d847649bd3adb0f70d543 100644 (file)
@@ -1818,6 +1818,7 @@ EXPORT_SYMBOL(ocelot_init);
 
 void ocelot_deinit(struct ocelot *ocelot)
 {
+       cancel_delayed_work(&ocelot->stats_work);
        destroy_workqueue(ocelot->stats_queue);
        mutex_destroy(&ocelot->stats_lock);
        ocelot_ace_deinit();
index d9cbe84ac6ade4105af2e9c93a2f847f944cf8f6..1b840ee4733969a4b61e74e98bf2bfcd3ad2aecb 100644 (file)
@@ -444,12 +444,12 @@ static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data)
        data = nfp_pr_et(data, "hw_rx_csum_complete");
        data = nfp_pr_et(data, "hw_rx_csum_err");
        data = nfp_pr_et(data, "rx_replace_buf_alloc_fail");
-       data = nfp_pr_et(data, "rx_tls_decrypted");
+       data = nfp_pr_et(data, "rx_tls_decrypted_packets");
        data = nfp_pr_et(data, "hw_tx_csum");
        data = nfp_pr_et(data, "hw_tx_inner_csum");
        data = nfp_pr_et(data, "tx_gather");
        data = nfp_pr_et(data, "tx_lso");
-       data = nfp_pr_et(data, "tx_tls_encrypted");
+       data = nfp_pr_et(data, "tx_tls_encrypted_packets");
        data = nfp_pr_et(data, "tx_tls_ooo");
        data = nfp_pr_et(data, "tx_tls_drop_no_sync_data");
 
index 70b1a03c0953e696a92f51769e1db6388a55cab7..01229190132d484ff7d44ccc8606960d4bb76171 100644 (file)
@@ -11,7 +11,7 @@ config NET_VENDOR_NI
 
          Note that the answer to this question doesn't directly affect the
          kernel: saying N will just cause the configurator to skip all
-         the questions about National Instrument devices.
+         the questions about National Instruments devices.
          If you say Y, you will be asked for your specific device in the
          following questions.
 
index 8161e308e64b0f16e8f527e84145ca9a208bf23f..ead3750b4489d1bf9f2678af74ee7adaec3bd5fc 100644 (file)
@@ -1,10 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0-only
 #
-# Packet engine device configuration
+# Packet Engines device configuration
 #
 
 config NET_VENDOR_PACKET_ENGINES
-       bool "Packet Engine devices"
+       bool "Packet Engines devices"
        default y
        depends on PCI
        ---help---
@@ -12,7 +12,7 @@ config NET_VENDOR_PACKET_ENGINES
 
          Note that the answer to this question doesn't directly affect the
          kernel: saying N will just cause the configurator to skip all
-         the questions about packet engine devices. If you say Y, you will
+         the questions about Packet Engines devices. If you say Y, you will
          be asked for your specific card in the following questions.
 
 if NET_VENDOR_PACKET_ENGINES
index 1553c9cfc254d6f8a17aa1f84e0a225515ebff4e..cf054b796d1112316f9cebe199a375b24415f725 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 #
-# Makefile for the Packet Engine network device drivers.
+# Makefile for the Packet Engines network device drivers.
 #
 
 obj-$(CONFIG_HAMACHI) += hamachi.o
index 4e8118a0865455d9ff68447f7c7507d6cc92a8ee..9f5113639eaf0cf2649769e3b2f481f19ff9fec1 100644 (file)
@@ -1093,7 +1093,7 @@ static int qed_int_deassertion(struct qed_hwfn  *p_hwfn,
                                                snprintf(bit_name, 30,
                                                         p_aeu->bit_name, num);
                                        else
-                                               strncpy(bit_name,
+                                               strlcpy(bit_name,
                                                        p_aeu->bit_name, 30);
 
                                        /* We now need to pass bitmask in its
index 17c64e43d6c311e22042a7fca381b26261090b26..158ac07389118278766ae3c9836a13d8f5307981 100644 (file)
@@ -442,7 +442,7 @@ static void qed_rdma_init_devinfo(struct qed_hwfn *p_hwfn,
        /* Vendor specific information */
        dev->vendor_id = cdev->vendor_id;
        dev->vendor_part_id = cdev->device_id;
-       dev->hw_ver = 0;
+       dev->hw_ver = cdev->chip_rev;
        dev->fw_ver = (FW_MAJOR_VERSION << 24) | (FW_MINOR_VERSION << 16) |
                      (FW_REVISION_VERSION << 8) | (FW_ENGINEERING_VERSION);
 
index 60189923737a79f0735ffec15b96c3c110b579d6..21d38167f96180718fdcda68ed2433d73271b1bf 100644 (file)
@@ -206,9 +206,9 @@ rmnet_map_ipv4_ul_csum_header(void *iphdr,
        ul_header->csum_insert_offset = skb->csum_offset;
        ul_header->csum_enabled = 1;
        if (ip4h->protocol == IPPROTO_UDP)
-               ul_header->udp_ip4_ind = 1;
+               ul_header->udp_ind = 1;
        else
-               ul_header->udp_ip4_ind = 0;
+               ul_header->udp_ind = 0;
 
        /* Changing remaining fields to network order */
        hdr++;
@@ -239,6 +239,7 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr,
                              struct rmnet_map_ul_csum_header *ul_header,
                              struct sk_buff *skb)
 {
+       struct ipv6hdr *ip6h = (struct ipv6hdr *)ip6hdr;
        __be16 *hdr = (__be16 *)ul_header, offset;
 
        offset = htons((__force u16)(skb_transport_header(skb) -
@@ -246,7 +247,11 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr,
        ul_header->csum_start_offset = offset;
        ul_header->csum_insert_offset = skb->csum_offset;
        ul_header->csum_enabled = 1;
-       ul_header->udp_ip4_ind = 0;
+
+       if (ip6h->nexthdr == IPPROTO_UDP)
+               ul_header->udp_ind = 1;
+       else
+               ul_header->udp_ind = 0;
 
        /* Changing remaining fields to network order */
        hdr++;
@@ -419,7 +424,7 @@ sw_csum:
        ul_header->csum_start_offset = 0;
        ul_header->csum_insert_offset = 0;
        ul_header->csum_enabled = 0;
-       ul_header->udp_ip4_ind = 0;
+       ul_header->udp_ind = 0;
 
        priv->stats.csum_sw++;
 }
index 6272115b28480a55b081bd2c52ec051791835786..e1dd6ea60d67050f2784a08d2ec2589eef040a35 100644 (file)
@@ -6136,10 +6136,7 @@ static int r8169_phy_connect(struct rtl8169_private *tp)
        if (ret)
                return ret;
 
-       if (tp->supports_gmii)
-               phy_remove_link_mode(phydev,
-                                    ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
-       else
+       if (!tp->supports_gmii)
                phy_set_max_speed(phydev, SPEED_100);
 
        phy_support_asym_pause(phydev);
@@ -6589,13 +6586,18 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
 {
        unsigned int flags;
 
-       if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
                rtl_unlock_config_regs(tp);
                RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable);
                rtl_lock_config_regs(tp);
+               /* fall through */
+       case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_24:
                flags = PCI_IRQ_LEGACY;
-       } else {
+               break;
+       default:
                flags = PCI_IRQ_ALL_TYPES;
+               break;
        }
 
        return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags);
index 079f459c73a5d45a9802da81caf403c1c4e43d35..2c5d3f5b84dd6ef1096f3289b8c86ebc49b0348b 100644 (file)
@@ -2208,10 +2208,12 @@ static int rocker_router_fib_event(struct notifier_block *nb,
 
                        if (fen_info->fi->fib_nh_is_v6) {
                                NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported");
+                               kfree(fib_work);
                                return notifier_from_errno(-EINVAL);
                        }
                        if (fen_info->fi->nh) {
                                NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported");
+                               kfree(fib_work);
                                return notifier_from_errno(-EINVAL);
                        }
                }
index 027938017579130fd1072b0b3c0745a541933107..e92a178a76df0849600734c1193ee0cbdbc9ca19 100644 (file)
@@ -11,7 +11,7 @@ config NET_VENDOR_SAMSUNG
          say Y.
 
          Note that the answer to this question does not directly affect
-         the kernel: saying N will just case the configurator to skip all
+         the kernel: saying N will just cause the configurator to skip all
          the questions about Samsung chipsets. If you say Y, you will be asked
          for your specific chipset/driver in the following questions.
 
index bd14803545de30b7fb7c7a7ff0201227cdd39bdb..8d88e40834567fc23797515f55dbe0e08543622d 100644 (file)
@@ -712,6 +712,7 @@ static void smc911x_phy_detect(struct net_device *dev)
                                        /* Found an external PHY */
                                        break;
                        }
+                       /* Else, fall through */
                default:
                        /* Internal media only */
                        SMC_GET_PHY_ID1(lp, 1, id1);
index 01c2e2d83e76dc78eadbb6faef74ec620199d1a2..fc9954e4a7729e79b86313af8d916290006ba9c2 100644 (file)
@@ -85,6 +85,8 @@ static void dwmac4_rx_queue_priority(struct mac_device_info *hw,
        u32 value;
 
        base_register = (queue < 4) ? GMAC_RXQ_CTRL2 : GMAC_RXQ_CTRL3;
+       if (queue >= 4)
+               queue -= 4;
 
        value = readl(ioaddr + base_register);
 
@@ -102,6 +104,8 @@ static void dwmac4_tx_queue_priority(struct mac_device_info *hw,
        u32 value;
 
        base_register = (queue < 4) ? GMAC_TXQ_PRTY_MAP0 : GMAC_TXQ_PRTY_MAP1;
+       if (queue >= 4)
+               queue -= 4;
 
        value = readl(ioaddr + base_register);
 
index 7f86dffb264d352f57019c581baedda9a798e285..3174b701aa903f6b07f6267dbc4fac64cfc1c818 100644 (file)
 #define XGMAC_CORE_INIT_RX             0
 #define XGMAC_PACKET_FILTER            0x00000008
 #define XGMAC_FILTER_RA                        BIT(31)
+#define XGMAC_FILTER_HPF               BIT(10)
 #define XGMAC_FILTER_PCF               BIT(7)
 #define XGMAC_FILTER_PM                        BIT(4)
 #define XGMAC_FILTER_HMC               BIT(2)
 #define XGMAC_FILTER_PR                        BIT(0)
 #define XGMAC_HASH_TABLE(x)            (0x00000010 + (x) * 4)
+#define XGMAC_MAX_HASH_TABLE           8
 #define XGMAC_RXQ_CTRL0                        0x000000a0
 #define XGMAC_RXQEN(x)                 GENMASK((x) * 2 + 1, (x) * 2)
 #define XGMAC_RXQEN_SHIFT(x)           ((x) * 2)
 #define XGMAC_MDIO_ADDR                        0x00000200
 #define XGMAC_MDIO_DATA                        0x00000204
 #define XGMAC_MDIO_C22P                        0x00000220
-#define XGMAC_ADDR0_HIGH               0x00000300
+#define XGMAC_ADDRx_HIGH(x)            (0x00000300 + (x) * 0x8)
+#define XGMAC_ADDR_MAX                 32
 #define XGMAC_AE                       BIT(31)
 #define XGMAC_DCS                      GENMASK(19, 16)
 #define XGMAC_DCS_SHIFT                        16
-#define XGMAC_ADDR0_LOW                        0x00000304
+#define XGMAC_ADDRx_LOW(x)             (0x00000304 + (x) * 0x8)
 #define XGMAC_ARP_ADDR                 0x00000c10
 #define XGMAC_TIMESTAMP_STATUS         0x00000d20
 #define XGMAC_TXTSC                    BIT(15)
index 0a32c96a7854e95eef3b7f0834249131760bd612..85c68b7ee8c6a557cb8a306d5bbb6ae633432c0b 100644 (file)
@@ -4,6 +4,8 @@
  * stmmac XGMAC support.
  */
 
+#include <linux/bitrev.h>
+#include <linux/crc32.h>
 #include "stmmac.h"
 #include "dwxgmac2.h"
 
@@ -106,6 +108,8 @@ static void dwxgmac2_rx_queue_prio(struct mac_device_info *hw, u32 prio,
        u32 value, reg;
 
        reg = (queue < 4) ? XGMAC_RXQ_CTRL2 : XGMAC_RXQ_CTRL3;
+       if (queue >= 4)
+               queue -= 4;
 
        value = readl(ioaddr + reg);
        value &= ~XGMAC_PSRQ(queue);
@@ -169,6 +173,8 @@ static void dwxgmac2_map_mtl_to_dma(struct mac_device_info *hw, u32 queue,
        u32 value, reg;
 
        reg = (queue < 4) ? XGMAC_MTL_RXQ_DMA_MAP0 : XGMAC_MTL_RXQ_DMA_MAP1;
+       if (queue >= 4)
+               queue -= 4;
 
        value = readl(ioaddr + reg);
        value &= ~XGMAC_QxMDMACH(queue);
@@ -278,10 +284,10 @@ static void dwxgmac2_set_umac_addr(struct mac_device_info *hw,
        u32 value;
 
        value = (addr[5] << 8) | addr[4];
-       writel(value | XGMAC_AE, ioaddr + XGMAC_ADDR0_HIGH);
+       writel(value | XGMAC_AE, ioaddr + XGMAC_ADDRx_HIGH(reg_n));
 
        value = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
-       writel(value, ioaddr + XGMAC_ADDR0_LOW);
+       writel(value, ioaddr + XGMAC_ADDRx_LOW(reg_n));
 }
 
 static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
@@ -291,8 +297,8 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
        u32 hi_addr, lo_addr;
 
        /* Read the MAC address from the hardware */
-       hi_addr = readl(ioaddr + XGMAC_ADDR0_HIGH);
-       lo_addr = readl(ioaddr + XGMAC_ADDR0_LOW);
+       hi_addr = readl(ioaddr + XGMAC_ADDRx_HIGH(reg_n));
+       lo_addr = readl(ioaddr + XGMAC_ADDRx_LOW(reg_n));
 
        /* Extract the MAC address from the high and low words */
        addr[0] = lo_addr & 0xff;
@@ -303,19 +309,82 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
        addr[5] = (hi_addr >> 8) & 0xff;
 }
 
+static void dwxgmac2_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
+                               int mcbitslog2)
+{
+       int numhashregs, regs;
+
+       switch (mcbitslog2) {
+       case 6:
+               numhashregs = 2;
+               break;
+       case 7:
+               numhashregs = 4;
+               break;
+       case 8:
+               numhashregs = 8;
+               break;
+       default:
+               return;
+       }
+
+       for (regs = 0; regs < numhashregs; regs++)
+               writel(mcfilterbits[regs], ioaddr + XGMAC_HASH_TABLE(regs));
+}
+
 static void dwxgmac2_set_filter(struct mac_device_info *hw,
                                struct net_device *dev)
 {
        void __iomem *ioaddr = (void __iomem *)dev->base_addr;
-       u32 value = XGMAC_FILTER_RA;
+       u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
+       int mcbitslog2 = hw->mcast_bits_log2;
+       u32 mc_filter[8];
+       int i;
+
+       value &= ~(XGMAC_FILTER_PR | XGMAC_FILTER_HMC | XGMAC_FILTER_PM);
+       value |= XGMAC_FILTER_HPF;
+
+       memset(mc_filter, 0, sizeof(mc_filter));
 
        if (dev->flags & IFF_PROMISC) {
-               value |= XGMAC_FILTER_PR | XGMAC_FILTER_PCF;
+               value |= XGMAC_FILTER_PR;
+               value |= XGMAC_FILTER_PCF;
        } else if ((dev->flags & IFF_ALLMULTI) ||
-                  (netdev_mc_count(dev) > HASH_TABLE_SIZE)) {
+                  (netdev_mc_count(dev) > hw->multicast_filter_bins)) {
                value |= XGMAC_FILTER_PM;
-               writel(~0x0, ioaddr + XGMAC_HASH_TABLE(0));
-               writel(~0x0, ioaddr + XGMAC_HASH_TABLE(1));
+
+               for (i = 0; i < XGMAC_MAX_HASH_TABLE; i++)
+                       writel(~0x0, ioaddr + XGMAC_HASH_TABLE(i));
+       } else if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+
+               value |= XGMAC_FILTER_HMC;
+
+               netdev_for_each_mc_addr(ha, dev) {
+                       int nr = (bitrev32(~crc32_le(~0, ha->addr, 6)) >>
+                                       (32 - mcbitslog2));
+                       mc_filter[nr >> 5] |= (1 << (nr & 0x1F));
+               }
+       }
+
+       dwxgmac2_set_mchash(ioaddr, mc_filter, mcbitslog2);
+
+       /* Handle multiple unicast addresses */
+       if (netdev_uc_count(dev) > XGMAC_ADDR_MAX) {
+               value |= XGMAC_FILTER_PR;
+       } else {
+               struct netdev_hw_addr *ha;
+               int reg = 1;
+
+               netdev_for_each_uc_addr(ha, dev) {
+                       dwxgmac2_set_umac_addr(hw, ha->addr, reg);
+                       reg++;
+               }
+
+               for ( ; reg < XGMAC_ADDR_MAX; reg++) {
+                       writel(0, ioaddr + XGMAC_ADDRx_HIGH(reg));
+                       writel(0, ioaddr + XGMAC_ADDRx_LOW(reg));
+               }
        }
 
        writel(value, ioaddr + XGMAC_PACKET_FILTER);
index c7c9e5f162e6de73f2534dc5f8d5b5a38222e743..fd54c7c8748548e279cc5293ea3df19d656c6366 100644 (file)
@@ -814,20 +814,15 @@ static void stmmac_validate(struct phylink_config *config,
        phylink_set(mac_supported, 10baseT_Full);
        phylink_set(mac_supported, 100baseT_Half);
        phylink_set(mac_supported, 100baseT_Full);
+       phylink_set(mac_supported, 1000baseT_Half);
+       phylink_set(mac_supported, 1000baseT_Full);
+       phylink_set(mac_supported, 1000baseKX_Full);
 
        phylink_set(mac_supported, Autoneg);
        phylink_set(mac_supported, Pause);
        phylink_set(mac_supported, Asym_Pause);
        phylink_set_port_modes(mac_supported);
 
-       if (priv->plat->has_gmac ||
-           priv->plat->has_gmac4 ||
-           priv->plat->has_xgmac) {
-               phylink_set(mac_supported, 1000baseT_Half);
-               phylink_set(mac_supported, 1000baseT_Full);
-               phylink_set(mac_supported, 1000baseKX_Full);
-       }
-
        /* Cut down 1G if asked to */
        if ((max_speed > 0) && (max_speed < 1000)) {
                phylink_set(mask, 1000baseT_Full);
@@ -1295,6 +1290,8 @@ static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags)
                          "(%s) dma_rx_phy=0x%08x\n", __func__,
                          (u32)rx_q->dma_rx_phy);
 
+               stmmac_clear_rx_descriptors(priv, queue);
+
                for (i = 0; i < DMA_RX_SIZE; i++) {
                        struct dma_desc *p;
 
@@ -1312,8 +1309,6 @@ static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags)
                rx_q->cur_rx = 0;
                rx_q->dirty_rx = (unsigned int)(i - DMA_RX_SIZE);
 
-               stmmac_clear_rx_descriptors(priv, queue);
-
                /* Setup the chained descriptor addresses */
                if (priv->mode == STMMAC_CHAIN_MODE) {
                        if (priv->extend_desc)
@@ -1555,9 +1550,8 @@ static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv)
                        goto err_dma;
                }
 
-               rx_q->buf_pool = kmalloc_array(DMA_RX_SIZE,
-                                              sizeof(*rx_q->buf_pool),
-                                              GFP_KERNEL);
+               rx_q->buf_pool = kcalloc(DMA_RX_SIZE, sizeof(*rx_q->buf_pool),
+                                        GFP_KERNEL);
                if (!rx_q->buf_pool)
                        goto err_dma;
 
@@ -1608,15 +1602,15 @@ static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv)
                tx_q->queue_index = queue;
                tx_q->priv_data = priv;
 
-               tx_q->tx_skbuff_dma = kmalloc_array(DMA_TX_SIZE,
-                                                   sizeof(*tx_q->tx_skbuff_dma),
-                                                   GFP_KERNEL);
+               tx_q->tx_skbuff_dma = kcalloc(DMA_TX_SIZE,
+                                             sizeof(*tx_q->tx_skbuff_dma),
+                                             GFP_KERNEL);
                if (!tx_q->tx_skbuff_dma)
                        goto err_dma;
 
-               tx_q->tx_skbuff = kmalloc_array(DMA_TX_SIZE,
-                                               sizeof(struct sk_buff *),
-                                               GFP_KERNEL);
+               tx_q->tx_skbuff = kcalloc(DMA_TX_SIZE,
+                                         sizeof(struct sk_buff *),
+                                         GFP_KERNEL);
                if (!tx_q->tx_skbuff)
                        goto err_dma;
 
@@ -3277,9 +3271,11 @@ static inline int stmmac_rx_threshold_count(struct stmmac_rx_queue *rx_q)
 static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
 {
        struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
-       int dirty = stmmac_rx_dirty(priv, queue);
+       int len, dirty = stmmac_rx_dirty(priv, queue);
        unsigned int entry = rx_q->dirty_rx;
 
+       len = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE) * PAGE_SIZE;
+
        while (dirty-- > 0) {
                struct stmmac_rx_buffer *buf = &rx_q->buf_pool[entry];
                struct dma_desc *p;
@@ -3297,6 +3293,13 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
                }
 
                buf->addr = page_pool_get_dma_addr(buf->page);
+
+               /* Sync whole allocation to device. This will invalidate old
+                * data.
+                */
+               dma_sync_single_for_device(priv->device, buf->addr, len,
+                                          DMA_FROM_DEVICE);
+
                stmmac_set_desc_addr(priv, p, buf->addr);
                stmmac_refill_desc3(priv, rx_q, p);
 
@@ -3431,8 +3434,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
                        skb_copy_to_linear_data(skb, page_address(buf->page),
                                                frame_len);
                        skb_put(skb, frame_len);
-                       dma_sync_single_for_device(priv->device, buf->addr,
-                                                  frame_len, DMA_FROM_DEVICE);
 
                        if (netif_msg_pktdata(priv)) {
                                netdev_dbg(priv->dev, "frame received (%dbytes)",
@@ -4319,8 +4320,9 @@ int stmmac_dvr_probe(struct device *device,
                                       NAPI_POLL_WEIGHT);
                }
                if (queue < priv->plat->tx_queues_to_use) {
-                       netif_napi_add(ndev, &ch->tx_napi, stmmac_napi_poll_tx,
-                                      NAPI_POLL_WEIGHT);
+                       netif_tx_napi_add(ndev, &ch->tx_napi,
+                                         stmmac_napi_poll_tx,
+                                         NAPI_POLL_WEIGHT);
                }
        }
 
index 73fc2524372e25269a3f4e39987ae65270054ef3..154daf4d10724e9928770319167c16fadc5a476a 100644 (file)
@@ -370,6 +370,13 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
                return ERR_PTR(-ENOMEM);
 
        *mac = of_get_mac_address(np);
+       if (IS_ERR(*mac)) {
+               if (PTR_ERR(*mac) == -EPROBE_DEFER)
+                       return ERR_CAST(*mac);
+
+               *mac = NULL;
+       }
+
        plat->interface = of_get_phy_mode(np);
 
        /* Some wrapper drivers still rely on phy_node. Let's save it while
index 58ea18af9813ab950b1252cde08d626abe61c30e..37c0bc699cd9ca80dbfdb77e7893abaad150fe62 100644 (file)
@@ -37,7 +37,7 @@ static struct stmmac_tc_entry *tc_find_entry(struct stmmac_priv *priv,
                entry = &priv->tc_entries[i];
                if (!entry->in_use && !first && free)
                        first = entry;
-               if (entry->handle == loc && !free)
+               if ((entry->handle == loc) && !free && !entry->is_frag)
                        dup = entry;
        }
 
index 5b196ebfed492e44b381f46b5eaa1d5d0d2e8f3e..0f346761a2b294ecd519a3e7ed8f5d389dcc91f3 100644 (file)
@@ -788,6 +788,7 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
                        /* fallthrough, if we release the descriptors
                         * brutally (then we don't care about
                         * SPIDER_NET_DESCR_CARDOWNED) */
+                       /* Fall through */
 
                case SPIDER_NET_DESCR_RESPONSE_ERROR:
                case SPIDER_NET_DESCR_PROTECTION_ERROR:
index 2f354ba029a6149154a66de43e3abc44139996e7..cd0a8f46e7c6c1438231e7f845e5dcc025adc456 100644 (file)
@@ -13,7 +13,7 @@ config NET_VENDOR_XSCALE
 
          Note that the answer to this question does not directly affect the
          kernel: saying N will just cause the configurator to skip all
-         the questions about XSacle IXP devices. If you say Y, you will be
+         the questions about XScale IXP devices. If you say Y, you will be
          asked for your specific card in the following questions.
 
 if NET_VENDOR_XSCALE
index daab2c07d891dc3d718c7122708e695ea553507b..9303aeb2595f412cefa9ddcaca09ff93f9a4ecd8 100644 (file)
@@ -500,8 +500,9 @@ static int transmit(struct baycom_state *bc, int cnt, unsigned char stat)
                                }
                                break;
                        }
+                       /* fall through */
 
-               default:  /* fall through */
+               default:
                        if (bc->hdlctx.calibrate <= 0)
                                return 0;
                        i = min_t(int, cnt, bc->hdlctx.calibrate);
index 3ffe46df249ee2a482b748ac66a79ff31141690a..7c5265fd2b94d31f03ce61ce0f9505310d434f7b 100644 (file)
@@ -216,8 +216,10 @@ static struct gpio_desc *fixed_phy_get_gpiod(struct device_node *np)
        if (IS_ERR(gpiod)) {
                if (PTR_ERR(gpiod) == -EPROBE_DEFER)
                        return gpiod;
-               pr_err("error getting GPIO for fixed link %pOF, proceed without\n",
-                      fixed_link_node);
+
+               if (PTR_ERR(gpiod) != -ENOENT)
+                       pr_err("error getting GPIO for fixed link %pOF, proceed without\n",
+                              fixed_link_node);
                gpiod = NULL;
        }
 
index 28676af97b42c275f6d2df4a285d3d6d391ec7f6..645d354ffb4852605f19782ff60815f517d72e40 100644 (file)
@@ -2226,8 +2226,8 @@ static int vsc8514_probe(struct phy_device *phydev)
        vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
        vsc8531->hw_stats = vsc85xx_hw_stats;
        vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
-       vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
-                                           sizeof(u64), GFP_KERNEL);
+       vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
+                                     sizeof(u64), GFP_KERNEL);
        if (!vsc8531->stats)
                return -ENOMEM;
 
@@ -2251,8 +2251,8 @@ static int vsc8574_probe(struct phy_device *phydev)
        vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
        vsc8531->hw_stats = vsc8584_hw_stats;
        vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
-       vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
-                                           sizeof(u64), GFP_KERNEL);
+       vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
+                                     sizeof(u64), GFP_KERNEL);
        if (!vsc8531->stats)
                return -ENOMEM;
 
@@ -2281,8 +2281,8 @@ static int vsc8584_probe(struct phy_device *phydev)
        vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
        vsc8531->hw_stats = vsc8584_hw_stats;
        vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
-       vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
-                                           sizeof(u64), GFP_KERNEL);
+       vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
+                                     sizeof(u64), GFP_KERNEL);
        if (!vsc8531->stats)
                return -ENOMEM;
 
@@ -2311,8 +2311,8 @@ static int vsc85xx_probe(struct phy_device *phydev)
        vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
        vsc8531->hw_stats = vsc85xx_hw_stats;
        vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
-       vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
-                                           sizeof(u64), GFP_KERNEL);
+       vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
+                                     sizeof(u64), GFP_KERNEL);
        if (!vsc8531->stats)
                return -ENOMEM;
 
index 6b5cb87f38661d70b4e2d1ea30eccbe2e7200f73..7ddd91df99e3dc24db6d374ba7b5e911c4716f47 100644 (file)
@@ -1774,6 +1774,12 @@ done:
        phydev->link = status & BMSR_LSTATUS ? 1 : 0;
        phydev->autoneg_complete = status & BMSR_ANEGCOMPLETE ? 1 : 0;
 
+       /* Consider the case that autoneg was started and "aneg complete"
+        * bit has been reset, but "link up" bit not yet.
+        */
+       if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete)
+               phydev->link = 0;
+
        return 0;
 }
 EXPORT_SYMBOL(genphy_update_link);
index b86a4b2116f8156af6c32f82a6e8df9bfaa441d0..59a94e07e7c55b88d860cac214603228c22f021d 100644 (file)
@@ -48,8 +48,9 @@ void phy_led_trigger_change_speed(struct phy_device *phy)
                if (!phy->last_triggered)
                        led_trigger_event(&phy->led_link_trigger->trigger,
                                          LED_FULL);
+               else
+                       led_trigger_event(&phy->last_triggered->trigger, LED_OFF);
 
-               led_trigger_event(&phy->last_triggered->trigger, LED_OFF);
                led_trigger_event(&plt->trigger, LED_FULL);
                phy->last_triggered = plt;
        }
index 5d0af041b8f9f662d957d19353b05a8cb4bf4157..a45c5de96ab1c9688c0ed1eaa99f60fef3294230 100644 (file)
@@ -216,6 +216,8 @@ static int phylink_parse_fixedlink(struct phylink *pl,
                               pl->supported, true);
        linkmode_zero(pl->supported);
        phylink_set(pl->supported, MII);
+       phylink_set(pl->supported, Pause);
+       phylink_set(pl->supported, Asym_Pause);
        if (s) {
                __set_bit(s->bit, pl->supported);
        } else {
@@ -990,10 +992,10 @@ void phylink_start(struct phylink *pl)
        }
        if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
                mod_timer(&pl->link_poll, jiffies + HZ);
-       if (pl->sfp_bus)
-               sfp_upstream_start(pl->sfp_bus);
        if (pl->phydev)
                phy_start(pl->phydev);
+       if (pl->sfp_bus)
+               sfp_upstream_start(pl->sfp_bus);
 }
 EXPORT_SYMBOL_GPL(phylink_start);
 
@@ -1010,10 +1012,10 @@ void phylink_stop(struct phylink *pl)
 {
        ASSERT_RTNL();
 
-       if (pl->phydev)
-               phy_stop(pl->phydev);
        if (pl->sfp_bus)
                sfp_upstream_stop(pl->sfp_bus);
+       if (pl->phydev)
+               phy_stop(pl->phydev);
        del_timer_sync(&pl->link_poll);
        if (pl->link_irq) {
                free_irq(pl->link_irq, pl);
index 1d902ecb4aa8b76dc14147841cf51ce12ae02127..a44dd3c8af632565043be1639efb99910e9afc25 100644 (file)
@@ -1115,6 +1115,9 @@ static const struct proto_ops pppoe_ops = {
        .recvmsg        = pppoe_recvmsg,
        .mmap           = sock_no_mmap,
        .ioctl          = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = pppox_compat_ioctl,
+#endif
 };
 
 static const struct pppox_proto pppoe_proto = {
index 5ef422a43d70b479e44991062cbdc03de9aa8951..08364f10a43fae46642f57225121bec00b70a0e0 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/compat.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/net.h>
@@ -98,6 +99,18 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
 EXPORT_SYMBOL(pppox_ioctl);
 
+#ifdef CONFIG_COMPAT
+int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       if (cmd == PPPOEIOCSFWD32)
+               cmd = PPPOEIOCSFWD;
+
+       return pppox_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
+}
+
+EXPORT_SYMBOL(pppox_compat_ioctl);
+#endif
+
 static int pppox_create(struct net *net, struct socket *sock, int protocol,
                        int kern)
 {
index a8e52c8e4128370ca5bc3f44e5be55881846f02f..734de7de03f7893158e1370056f5193f82b7bd54 100644 (file)
@@ -623,6 +623,9 @@ static const struct proto_ops pptp_ops = {
        .recvmsg    = sock_no_recvmsg,
        .mmap       = sock_no_mmap,
        .ioctl      = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = pppox_compat_ioctl,
+#endif
 };
 
 static const struct pppox_proto pppox_pptp_proto = {
index 3d443597bd0496fc99e181f1df29a7ca70191125..db16d7a13e00c197574b1f9f70044775648bbd72 100644 (file)
@@ -1599,7 +1599,8 @@ static bool tun_can_build_skb(struct tun_struct *tun, struct tun_file *tfile,
        return true;
 }
 
-static struct sk_buff *__tun_build_skb(struct page_frag *alloc_frag, char *buf,
+static struct sk_buff *__tun_build_skb(struct tun_file *tfile,
+                                      struct page_frag *alloc_frag, char *buf,
                                       int buflen, int len, int pad)
 {
        struct sk_buff *skb = build_skb(buf, buflen);
@@ -1609,6 +1610,7 @@ static struct sk_buff *__tun_build_skb(struct page_frag *alloc_frag, char *buf,
 
        skb_reserve(skb, pad);
        skb_put(skb, len);
+       skb_set_owner_w(skb, tfile->socket.sk);
 
        get_page(alloc_frag->page);
        alloc_frag->offset += buflen;
@@ -1686,7 +1688,8 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
         */
        if (hdr->gso_type || !xdp_prog) {
                *skb_xdp = 1;
-               return __tun_build_skb(alloc_frag, buf, buflen, len, pad);
+               return __tun_build_skb(tfile, alloc_frag, buf, buflen, len,
+                                      pad);
        }
 
        *skb_xdp = 0;
@@ -1723,7 +1726,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
        rcu_read_unlock();
        local_bh_enable();
 
-       return __tun_build_skb(alloc_frag, buf, buflen, len, pad);
+       return __tun_build_skb(tfile, alloc_frag, buf, buflen, len, pad);
 
 err_xdp:
        put_page(alloc_frag->page);
index 6d25dea5ad4b2a956c7c0e4772e64c100c5bd5b1..f7d117d80cfbb81b7fad2e22dd13900290030dc9 100644 (file)
@@ -282,7 +282,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)
 static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata)
 {
        int i;
-       __u8 tmp;
+       __u8 tmp = 0;
        __le16 retdatai;
        int ret;
 
index 69e0a2acfcb05b140d5f953e7e4b8f663e9321dc..b6dc5d714b5e636c5b39fa199eb7fd64c1c125bd 100644 (file)
@@ -1295,6 +1295,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x2001, 0x7e3d, 4)},    /* D-Link DWM-222 A2 */
        {QMI_FIXED_INTF(0x2020, 0x2031, 4)},    /* Olicard 600 */
        {QMI_FIXED_INTF(0x2020, 0x2033, 4)},    /* BroadMobi BM806U */
+       {QMI_FIXED_INTF(0x2020, 0x2060, 4)},    /* BroadMobi BM818 */
        {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)},    /* Sierra Wireless MC7700 */
        {QMI_FIXED_INTF(0x114f, 0x68a2, 8)},    /* Sierra Wireless MC7750 */
        {QMI_FIXED_INTF(0x1199, 0x68a2, 8)},    /* Sierra Wireless MC7710 in QMI mode */
index 39e0768d734db45f1bc8f873bc4e3036e0f4f087..0cc03a9ff5457922a581cbdf5d76d34186575ae6 100644 (file)
@@ -50,7 +50,7 @@
 #define PLA_TEREDO_WAKE_BASE   0xc0c4
 #define PLA_MAR                        0xcd00
 #define PLA_BACKUP             0xd000
-#define PAL_BDC_CR             0xd1a0
+#define PLA_BDC_CR             0xd1a0
 #define PLA_TEREDO_TIMER       0xd2cc
 #define PLA_REALWOW_TIMER      0xd2e8
 #define PLA_SUSPEND_FLAG       0xd38a
 #define TEREDO_RS_EVENT_MASK   0x00fe
 #define OOB_TEREDO_EN          0x0001
 
-/* PAL_BDC_CR */
+/* PLA_BDC_CR */
 #define ALDPS_PROXY_MODE       0x0001
 
 /* PLA_EFUSE_CMD */
@@ -3191,9 +3191,9 @@ static void r8152b_enter_oob(struct r8152 *tp)
 
        rtl_rx_vlan_en(tp, true);
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR);
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR);
        ocp_data |= ALDPS_PROXY_MODE;
-       ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data);
 
        ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
        ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
@@ -3577,9 +3577,9 @@ static void r8153_enter_oob(struct r8152 *tp)
 
        rtl_rx_vlan_en(tp, true);
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR);
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR);
        ocp_data |= ALDPS_PROXY_MODE;
-       ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data);
 
        ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
        ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
index a9ac3f37b904f00fdadbcf3ba077fe818475bc7a..e2e679a01b65a2570f8bcd88870929622f3b7264 100644 (file)
@@ -413,6 +413,7 @@ static void sdla_errors(struct net_device *dev, int cmd, int dlci, int ret, int
                case SDLA_RET_NO_BUFS:
                        if (cmd == SDLA_INFORMATION_WRITE)
                                break;
+                       /* Else, fall through */
 
                default: 
                        netdev_dbg(dev, "Cmd 0x%02X generated return code 0x%02X\n",
index d55312ef58c9c61e257a257b16af8ff74a7c80dc..9b0bb89599fc3325a61c4fe283bace44e73b1448 100644 (file)
@@ -776,7 +776,6 @@ struct iwl_rss_config_cmd {
        u8 indirection_table[IWL_RSS_INDIRECTION_TABLE_SIZE];
 } __packed; /* RSS_CONFIG_CMD_API_S_VER_1 */
 
-#define IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE 128
 #define IWL_MULTI_QUEUE_SYNC_SENDER_POS 0
 #define IWL_MULTI_QUEUE_SYNC_SENDER_MSK 0xf
 
@@ -812,10 +811,12 @@ struct iwl_rxq_sync_notification {
  *
  * @IWL_MVM_RXQ_EMPTY: empty sync notification
  * @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
+ * @IWL_MVM_RXQ_NSSN_SYNC: notify all the RSS queues with the new NSSN
  */
 enum iwl_mvm_rxq_notif_type {
        IWL_MVM_RXQ_EMPTY,
        IWL_MVM_RXQ_NOTIF_DEL_BA,
+       IWL_MVM_RXQ_NSSN_SYNC,
 };
 
 /**
index e411ac98290dc39b744c781b888969f79bd2cf21..4d81776f576dc370091126d1c706b1532f956909 100644 (file)
@@ -2438,17 +2438,19 @@ static void iwl_fw_dbg_info_apply(struct iwl_fw_runtime *fwrt,
 {
        u32 img_name_len = le32_to_cpu(dbg_info->img_name_len);
        u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len);
-       const char err_str[] =
-               "WRT: ext=%d. Invalid %s name length %d, expected %d\n";
 
        if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
-               IWL_WARN(fwrt, err_str, ext, "image", img_name_len,
+               IWL_WARN(fwrt,
+                        "WRT: ext=%d. Invalid image name length %d, expected %d\n",
+                        ext, img_name_len,
                         IWL_FW_INI_MAX_IMG_NAME_LEN);
                return;
        }
 
        if (dbg_cfg_name_len != IWL_FW_INI_MAX_DBG_CFG_NAME_LEN) {
-               IWL_WARN(fwrt, err_str, ext, "debug cfg", dbg_cfg_name_len,
+               IWL_WARN(fwrt,
+                        "WRT: ext=%d. Invalid debug cfg name length %d, expected %d\n",
+                        ext, dbg_cfg_name_len,
                         IWL_FW_INI_MAX_DBG_CFG_NAME_LEN);
                return;
        }
@@ -2775,8 +2777,6 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
                struct iwl_ucode_tlv *tlv = iter;
                void *ini_tlv = (void *)tlv->data;
                u32 type = le32_to_cpu(tlv->type);
-               const char invalid_ap_str[] =
-                       "WRT: ext=%d. Invalid apply point %d for %s\n";
 
                switch (type) {
                case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
@@ -2786,8 +2786,9 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
                        struct iwl_fw_ini_allocation_data *buf_alloc = ini_tlv;
 
                        if (pnt != IWL_FW_INI_APPLY_EARLY) {
-                               IWL_ERR(fwrt, invalid_ap_str, ext, pnt,
-                                       "buffer allocation");
+                               IWL_ERR(fwrt,
+                                       "WRT: ext=%d. Invalid apply point %d for buffer allocation\n",
+                                       ext, pnt);
                                goto next;
                        }
 
@@ -2797,8 +2798,9 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
                }
                case IWL_UCODE_TLV_TYPE_HCMD:
                        if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
-                               IWL_ERR(fwrt, invalid_ap_str, ext, pnt,
-                                       "host command");
+                               IWL_ERR(fwrt,
+                                       "WRT: ext=%d. Invalid apply point %d for host command\n",
+                                       ext, pnt);
                                goto next;
                        }
                        iwl_fw_dbg_send_hcmd(fwrt, tlv, ext);
index 57d09049e615ce1f3b1ab7c737f1d50be429f857..38672dd5aae962c8da529c7a4b4cd75a6b140c6f 100644 (file)
@@ -1640,6 +1640,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans)
        init_completion(&drv->request_firmware_complete);
        INIT_LIST_HEAD(&drv->list);
 
+       iwl_load_fw_dbg_tlv(drv->trans->dev, drv->trans);
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        /* Create the device debugfs entries. */
        drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev),
@@ -1660,8 +1662,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans)
 err_fw:
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        debugfs_remove_recursive(drv->dbgfs_drv);
-       iwl_fw_dbg_free(drv->trans);
 #endif
+       iwl_fw_dbg_free(drv->trans);
        kfree(drv);
 err:
        return ERR_PTR(ret);
index 1d608e9e91018447465672734570a38c515e3bf7..5de54d1559dda8e2fb62bf659b24abf9339e56cf 100644 (file)
@@ -755,7 +755,7 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
 
        for (i = 0; i < n_profiles; i++) {
                /* the tables start at element 3 */
-               static int pos = 3;
+               int pos = 3;
 
                /* The EWRD profiles officially go from 2 to 4, but we
                 * save them in sar_profiles[1-3] (because we don't
@@ -880,6 +880,22 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
        return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd);
 }
 
+static bool iwl_mvm_sar_geo_support(struct iwl_mvm *mvm)
+{
+       /*
+        * The GEO_TX_POWER_LIMIT command is not supported on earlier
+        * firmware versions.  Unfortunately, we don't have a TLV API
+        * flag to rely on, so rely on the major version which is in
+        * the first byte of ucode_ver.  This was implemented
+        * initially on version 38 and then backported to 36, 29 and
+        * 17.
+        */
+       return IWL_UCODE_SERIAL(mvm->fw->ucode_ver) >= 38 ||
+              IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 36 ||
+              IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 29 ||
+              IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 17;
+}
+
 int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
 {
        struct iwl_geo_tx_power_profiles_resp *resp;
@@ -909,6 +925,9 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
                .data = { data },
        };
 
+       if (!iwl_mvm_sar_geo_support(mvm))
+               return -EOPNOTSUPP;
+
        ret = iwl_mvm_send_cmd(mvm, &cmd);
        if (ret) {
                IWL_ERR(mvm, "Failed to get geographic profile info %d\n", ret);
@@ -934,13 +953,7 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
        int ret, i, j;
        u16 cmd_wide_id =  WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT);
 
-       /*
-        * This command is not supported on earlier firmware versions.
-        * Unfortunately, we don't have a TLV API flag to rely on, so
-        * rely on the major version which is in the first byte of
-        * ucode_ver.
-        */
-       if (IWL_UCODE_SERIAL(mvm->fw->ucode_ver) < 41)
+       if (!iwl_mvm_sar_geo_support(mvm))
                return 0;
 
        ret = iwl_mvm_sar_get_wgds_table(mvm);
index 55cd49ccbf0b7a309286692cef45cc7bbddd4fa0..1c904b5226aa42d875ba503b725b33fec85e0ffd 100644 (file)
@@ -207,11 +207,11 @@ static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = {
        },
 };
 
-static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
-                              enum set_key_cmd cmd,
-                              struct ieee80211_vif *vif,
-                              struct ieee80211_sta *sta,
-                              struct ieee80211_key_conf *key);
+static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+                                enum set_key_cmd cmd,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_sta *sta,
+                                struct ieee80211_key_conf *key);
 
 void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
 {
@@ -474,7 +474,19 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
        ieee80211_hw_set(hw, BUFF_MMPDU_TXQ);
        ieee80211_hw_set(hw, STA_MMPDU_TXQ);
-       ieee80211_hw_set(hw, TX_AMSDU);
+       /*
+        * On older devices, enabling TX A-MSDU occasionally leads to
+        * something getting messed up, the command read from the FIFO
+        * gets out of sync and isn't a TX command, so that we have an
+        * assert EDC.
+        *
+        * It's not clear where the bug is, but since we didn't used to
+        * support A-MSDU until moving the mac80211 iTXQs, just leave it
+        * for older devices. We also don't see this issue on any newer
+        * devices.
+        */
+       if (mvm->cfg->device_family >= IWL_DEVICE_FAMILY_9000)
+               ieee80211_hw_set(hw, TX_AMSDU);
        ieee80211_hw_set(hw, TX_FRAG_LIST);
 
        if (iwl_mvm_has_tlc_offload(mvm)) {
@@ -2726,7 +2738,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
 
                mvmvif->ap_early_keys[i] = NULL;
 
-               ret = iwl_mvm_mac_set_key(hw, SET_KEY, vif, NULL, key);
+               ret = __iwl_mvm_mac_set_key(hw, SET_KEY, vif, NULL, key);
                if (ret)
                        goto out_quota_failed;
        }
@@ -3494,11 +3506,11 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
        return ret;
 }
 
-static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
-                              enum set_key_cmd cmd,
-                              struct ieee80211_vif *vif,
-                              struct ieee80211_sta *sta,
-                              struct ieee80211_key_conf *key)
+static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+                                enum set_key_cmd cmd,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_sta *sta,
+                                struct ieee80211_key_conf *key)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
@@ -3553,8 +3565,6 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
                        return -EOPNOTSUPP;
        }
 
-       mutex_lock(&mvm->mutex);
-
        switch (cmd) {
        case SET_KEY:
                if ((vif->type == NL80211_IFTYPE_ADHOC ||
@@ -3700,7 +3710,22 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
                ret = -EINVAL;
        }
 
+       return ret;
+}
+
+static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+                              enum set_key_cmd cmd,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta,
+                              struct ieee80211_key_conf *key)
+{
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       int ret;
+
+       mutex_lock(&mvm->mutex);
+       ret = __iwl_mvm_mac_set_key(hw, cmd, vif, sta, key);
        mutex_unlock(&mvm->mutex);
+
        return ret;
 }
 
@@ -5041,7 +5066,6 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
        u32 qmask = BIT(mvm->trans->num_rx_queues) - 1;
        int ret;
 
-       lockdep_assert_held(&mvm->mutex);
 
        if (!iwl_mvm_has_new_rx_api(mvm))
                return;
@@ -5052,13 +5076,15 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
                atomic_set(&mvm->queue_sync_counter,
                           mvm->trans->num_rx_queues);
 
-       ret = iwl_mvm_notify_rx_queue(mvm, qmask, (u8 *)notif, size);
+       ret = iwl_mvm_notify_rx_queue(mvm, qmask, (u8 *)notif,
+                                     size, !notif->sync);
        if (ret) {
                IWL_ERR(mvm, "Failed to trigger RX queues sync (%d)\n", ret);
                goto out;
        }
 
        if (notif->sync) {
+               lockdep_assert_held(&mvm->mutex);
                ret = wait_event_timeout(mvm->rx_sync_waitq,
                                         atomic_read(&mvm->queue_sync_counter) == 0 ||
                                         iwl_mvm_is_radio_killed(mvm),
index 48c77af54e9919017d4261a2ac80b10a41a900df..a263cc629d7551d05f8084e8770b1aec6ddfcae6 100644 (file)
@@ -1664,9 +1664,9 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
 void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
                              struct iwl_rx_cmd_buffer *rxb, int queue);
 int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
-                           const u8 *data, u32 count);
-void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
-                           int queue);
+                           const u8 *data, u32 count, bool async);
+void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi,
+                           struct iwl_rx_cmd_buffer *rxb, int queue);
 void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm,
                                   struct iwl_rx_cmd_buffer *rxb);
@@ -1813,7 +1813,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 #endif /* CONFIG_IWLWIFI_DEBUGFS */
 
 /* rate scaling */
-int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync);
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq);
 void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg);
 int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate);
 void rs_update_last_rssi(struct iwl_mvm *mvm,
index 719f793b3487ce28b949d9d4d80185503d2013b7..a9bb43a2f27b2c81e0a02e5e6ae5a7835a0563a2 100644 (file)
@@ -620,7 +620,7 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
        enum iwl_mcc_source src;
        char mcc[3];
        struct ieee80211_regdomain *regd;
-       u32 wgds_tbl_idx;
+       int wgds_tbl_idx;
 
        lockdep_assert_held(&mvm->mutex);
 
index d7d6f3398f86b4516198bc372261bca0b6ca9a1c..4888054dc3d87eb1c7f0a565dde24b1dec3bd305 100644 (file)
@@ -1088,7 +1088,7 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
                iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0);
        else if (unlikely(cmd == WIDE_ID(DATA_PATH_GROUP,
                                         RX_QUEUES_NOTIFICATION)))
-               iwl_mvm_rx_queue_notif(mvm, rxb, 0);
+               iwl_mvm_rx_queue_notif(mvm, napi, rxb, 0);
        else if (cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE))
                iwl_mvm_rx_frame_release(mvm, napi, rxb, 0);
        else if (cmd == WIDE_ID(DATA_PATH_GROUP, RX_NO_DATA_NOTIF))
@@ -1812,7 +1812,7 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode,
                iwl_mvm_rx_frame_release(mvm, napi, rxb, queue);
        else if (unlikely(cmd == WIDE_ID(DATA_PATH_GROUP,
                                         RX_QUEUES_NOTIFICATION)))
-               iwl_mvm_rx_queue_notif(mvm, rxb, queue);
+               iwl_mvm_rx_queue_notif(mvm, napi, rxb, queue);
        else if (likely(cmd == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD)))
                iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue);
 }
index 8c9069f28a589c78c0df05c8c36f6fea3e2fa328..d3f04acfbacb9fa360388110423391f6032ea2ca 100644 (file)
@@ -1197,239 +1197,6 @@ static u8 rs_get_tid(struct ieee80211_hdr *hdr)
        return tid;
 }
 
-void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                         int tid, struct ieee80211_tx_info *info, bool ndp)
-{
-       int legacy_success;
-       int retries;
-       int i;
-       struct iwl_lq_cmd *table;
-       u32 lq_hwrate;
-       struct rs_rate lq_rate, tx_resp_rate;
-       struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
-       u32 tlc_info = (uintptr_t)info->status.status_driver_data[0];
-       u8 reduced_txp = tlc_info & RS_DRV_DATA_TXP_MSK;
-       u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info);
-       u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1];
-       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
-       struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv;
-
-       /* Treat uninitialized rate scaling data same as non-existing. */
-       if (!lq_sta) {
-               IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n");
-               return;
-       } else if (!lq_sta->pers.drv) {
-               IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n");
-               return;
-       }
-
-       /* This packet was aggregated but doesn't carry status info */
-       if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
-           !(info->flags & IEEE80211_TX_STAT_AMPDU))
-               return;
-
-       if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band,
-                                   &tx_resp_rate)) {
-               WARN_ON_ONCE(1);
-               return;
-       }
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-       /* Disable last tx check if we are debugging with fixed rate but
-        * update tx stats */
-       if (lq_sta->pers.dbg_fixed_rate) {
-               int index = tx_resp_rate.index;
-               enum rs_column column;
-               int attempts, success;
-
-               column = rs_get_column_from_rate(&tx_resp_rate);
-               if (WARN_ONCE(column == RS_COLUMN_INVALID,
-                             "Can't map rate 0x%x to column",
-                             tx_resp_hwrate))
-                       return;
-
-               if (info->flags & IEEE80211_TX_STAT_AMPDU) {
-                       attempts = info->status.ampdu_len;
-                       success = info->status.ampdu_ack_len;
-               } else {
-                       attempts = info->status.rates[0].count;
-                       success = !!(info->flags & IEEE80211_TX_STAT_ACK);
-               }
-
-               lq_sta->pers.tx_stats[column][index].total += attempts;
-               lq_sta->pers.tx_stats[column][index].success += success;
-
-               IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n",
-                              tx_resp_hwrate, success, attempts);
-               return;
-       }
-#endif
-
-       if (time_after(jiffies,
-                      (unsigned long)(lq_sta->last_tx +
-                                      (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
-               IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
-               iwl_mvm_rs_rate_init(mvm, sta, info->band, true);
-               return;
-       }
-       lq_sta->last_tx = jiffies;
-
-       /* Ignore this Tx frame response if its initial rate doesn't match
-        * that of latest Link Quality command.  There may be stragglers
-        * from a previous Link Quality command, but we're no longer interested
-        * in those; they're either from the "active" mode while we're trying
-        * to check "search" mode, or a prior "search" mode after we've moved
-        * to a new "search" mode (which might become the new "active" mode).
-        */
-       table = &lq_sta->lq;
-       lq_hwrate = le32_to_cpu(table->rs_table[0]);
-       if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) {
-               WARN_ON_ONCE(1);
-               return;
-       }
-
-       /* Here we actually compare this rate to the latest LQ command */
-       if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) {
-               IWL_DEBUG_RATE(mvm,
-                              "tx resp color 0x%x does not match 0x%x\n",
-                              lq_color, LQ_FLAG_COLOR_GET(table->flags));
-
-               /*
-                * Since rates mis-match, the last LQ command may have failed.
-                * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
-                * ... driver.
-                */
-               lq_sta->missed_rate_counter++;
-               if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) {
-                       lq_sta->missed_rate_counter = 0;
-                       IWL_DEBUG_RATE(mvm,
-                                      "Too many rates mismatch. Send sync LQ. rs_state %d\n",
-                                      lq_sta->rs_state);
-                       iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
-               }
-               /* Regardless, ignore this status info for outdated rate */
-               return;
-       } else
-               /* Rate did match, so reset the missed_rate_counter */
-               lq_sta->missed_rate_counter = 0;
-
-       if (!lq_sta->search_better_tbl) {
-               curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-               other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
-       } else {
-               curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
-               other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-       }
-
-       if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) {
-               IWL_DEBUG_RATE(mvm,
-                              "Neither active nor search matches tx rate\n");
-               tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-               rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE");
-               tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
-               rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH");
-               rs_dump_rate(mvm, &lq_rate, "ACTUAL");
-
-               /*
-                * no matching table found, let's by-pass the data collection
-                * and continue to perform rate scale to find the rate table
-                */
-               rs_stay_in_table(lq_sta, true);
-               goto done;
-       }
-
-       /*
-        * Updating the frame history depends on whether packets were
-        * aggregated.
-        *
-        * For aggregation, all packets were transmitted at the same rate, the
-        * first index into rate scale table.
-        */
-       if (info->flags & IEEE80211_TX_STAT_AMPDU) {
-               rs_collect_tpc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index,
-                                   info->status.ampdu_len,
-                                   info->status.ampdu_ack_len,
-                                   reduced_txp);
-
-               /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat
-                * it as a single frame loss as we don't want the success ratio
-                * to dip too quickly because a BA wasn't received.
-                * For TPC, there's no need for this optimisation since we want
-                * to recover very quickly from a bad power reduction and,
-                * therefore we'd like the success ratio to get an immediate hit
-                * when failing to get a BA, so we'd switch back to a lower or
-                * zero power reduction. When FW transmits agg with a rate
-                * different from the initial rate, it will not use reduced txp
-                * and will send BA notification twice (one empty with reduced
-                * txp equal to the value from LQ and one with reduced txp 0).
-                * We need to update counters for each txp level accordingly.
-                */
-               if (info->status.ampdu_ack_len == 0)
-                       info->status.ampdu_len = 1;
-
-               rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl, tx_resp_rate.index,
-                                   info->status.ampdu_len,
-                                   info->status.ampdu_ack_len);
-
-               /* Update success/fail counts if not searching for new mode */
-               if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
-                       lq_sta->total_success += info->status.ampdu_ack_len;
-                       lq_sta->total_failed += (info->status.ampdu_len -
-                                       info->status.ampdu_ack_len);
-               }
-       } else {
-               /* For legacy, update frame history with for each Tx retry. */
-               retries = info->status.rates[0].count - 1;
-               /* HW doesn't send more than 15 retries */
-               retries = min(retries, 15);
-
-               /* The last transmission may have been successful */
-               legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
-               /* Collect data for each rate used during failed TX attempts */
-               for (i = 0; i <= retries; ++i) {
-                       lq_hwrate = le32_to_cpu(table->rs_table[i]);
-                       if (rs_rate_from_ucode_rate(lq_hwrate, info->band,
-                                                   &lq_rate)) {
-                               WARN_ON_ONCE(1);
-                               return;
-                       }
-
-                       /*
-                        * Only collect stats if retried rate is in the same RS
-                        * table as active/search.
-                        */
-                       if (rs_rate_column_match(&lq_rate, &curr_tbl->rate))
-                               tmp_tbl = curr_tbl;
-                       else if (rs_rate_column_match(&lq_rate,
-                                                     &other_tbl->rate))
-                               tmp_tbl = other_tbl;
-                       else
-                               continue;
-
-                       rs_collect_tpc_data(mvm, lq_sta, tmp_tbl,
-                                           tx_resp_rate.index, 1,
-                                           i < retries ? 0 : legacy_success,
-                                           reduced_txp);
-                       rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl,
-                                           tx_resp_rate.index, 1,
-                                           i < retries ? 0 : legacy_success);
-               }
-
-               /* Update success/fail counts if not searching for new mode */
-               if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
-                       lq_sta->total_success += legacy_success;
-                       lq_sta->total_failed += retries + (1 - legacy_success);
-               }
-       }
-       /* The last TX rate is cached in lq_sta; it's set in if/else above */
-       lq_sta->last_rate_n_flags = lq_hwrate;
-       IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
-done:
-       /* See if there's a better rate or modulation mode to try. */
-       if (sta->supp_rates[info->band])
-               rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp);
-}
-
 /*
  * mac80211 sends us Tx status
  */
@@ -1442,8 +1209,9 @@ static void rs_drv_mac80211_tx_status(void *mvm_r,
        struct iwl_op_mode *op_mode = mvm_r;
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
 
-       if (!iwl_mvm_sta_from_mac80211(sta)->vif)
+       if (!mvmsta->vif)
                return;
 
        if (!ieee80211_is_data(hdr->frame_control) ||
@@ -1584,6 +1352,18 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
        tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw);
 }
 
+/* rs uses two tables, one is active and the second is for searching better
+ * configuration. This function, according to the index of the currently
+ * active table returns the search table, which is located at the
+ * index complementary to 1 according to the active table (active = 1,
+ * search = 0 or active = 0, search = 1).
+ * Since lq_info is an arary of size 2, make sure index cannot be out of bounds.
+ */
+static inline u8 rs_search_tbl(u8 active_tbl)
+{
+       return (active_tbl ^ 1) & 1;
+}
+
 static s32 rs_get_best_rate(struct iwl_mvm *mvm,
                            struct iwl_lq_sta *lq_sta,
                            struct iwl_scale_tbl_info *tbl,     /* "search" */
@@ -1794,7 +1574,7 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm,
                               struct iwl_scale_tbl_info *tbl)
 {
        rs_fill_lq_cmd(mvm, sta, lq_sta, &tbl->rate);
-       iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
+       iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq);
 }
 
 static bool rs_tweak_rate_tbl(struct iwl_mvm *mvm,
@@ -1931,9 +1711,9 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
                               struct ieee80211_sta *sta,
                               enum rs_column col_id)
 {
-       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+       struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
        struct iwl_scale_tbl_info *search_tbl =
-                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+               &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
        struct rs_rate *rate = &search_tbl->rate;
        const struct rs_tx_column *column = &rs_tx_columns[col_id];
        const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column];
@@ -2341,7 +2121,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
        if (!lq_sta->search_better_tbl)
                active_tbl = lq_sta->active_tbl;
        else
-               active_tbl = 1 - lq_sta->active_tbl;
+               active_tbl = rs_search_tbl(lq_sta->active_tbl);
 
        tbl = &(lq_sta->lq_info[active_tbl]);
        rate = &tbl->rate;
@@ -2565,7 +2345,7 @@ lq_update:
                /* If new "search" mode was selected, set up in uCode table */
                if (lq_sta->search_better_tbl) {
                        /* Access the "search" table, clear its history. */
-                       tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+                       tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
                        rs_rate_scale_clear_tbl_windows(mvm, tbl);
 
                        /* Use new "search" start rate */
@@ -2896,7 +2676,7 @@ void rs_update_last_rssi(struct iwl_mvm *mvm,
 static void rs_initialize_lq(struct iwl_mvm *mvm,
                             struct ieee80211_sta *sta,
                             struct iwl_lq_sta *lq_sta,
-                            enum nl80211_band band, bool update)
+                            enum nl80211_band band)
 {
        struct iwl_scale_tbl_info *tbl;
        struct rs_rate *rate;
@@ -2908,7 +2688,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
        if (!lq_sta->search_better_tbl)
                active_tbl = lq_sta->active_tbl;
        else
-               active_tbl = 1 - lq_sta->active_tbl;
+               active_tbl = rs_search_tbl(lq_sta->active_tbl);
 
        tbl = &(lq_sta->lq_info[active_tbl]);
        rate = &tbl->rate;
@@ -2926,7 +2706,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
        rs_set_expected_tpt_table(lq_sta, tbl);
        rs_fill_lq_cmd(mvm, sta, lq_sta, rate);
        /* TODO restore station should remember the lq cmd */
-       iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, !update);
+       iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq);
 }
 
 static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
@@ -3175,7 +2955,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
  * Called after adding a new station to initialize rate scaling
  */
 static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                            enum nl80211_band band, bool update)
+                            enum nl80211_band band)
 {
        int i, j;
        struct ieee80211_hw *hw = mvm->hw;
@@ -3186,6 +2966,8 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        struct ieee80211_supported_band *sband;
        unsigned long supp; /* must be unsigned long for for_each_set_bit */
 
+       lockdep_assert_held(&mvmsta->lq_sta.rs_drv.pers.lock);
+
        /* clear all non-persistent lq data */
        memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
 
@@ -3255,7 +3037,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        iwl_mvm_reset_frame_stats(mvm);
 #endif
-       rs_initialize_lq(mvm, sta, lq_sta, band, update);
+       rs_initialize_lq(mvm, sta, lq_sta, band);
 }
 
 static void rs_drv_rate_update(void *mvm_r,
@@ -3278,6 +3060,258 @@ static void rs_drv_rate_update(void *mvm_r,
        iwl_mvm_rs_rate_init(mvm, sta, sband->band, true);
 }
 
+static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
+                                  struct ieee80211_sta *sta,
+                                  int tid, struct ieee80211_tx_info *info,
+                                  bool ndp)
+{
+       int legacy_success;
+       int retries;
+       int i;
+       struct iwl_lq_cmd *table;
+       u32 lq_hwrate;
+       struct rs_rate lq_rate, tx_resp_rate;
+       struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
+       u32 tlc_info = (uintptr_t)info->status.status_driver_data[0];
+       u8 reduced_txp = tlc_info & RS_DRV_DATA_TXP_MSK;
+       u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info);
+       u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1];
+       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv;
+
+       /* Treat uninitialized rate scaling data same as non-existing. */
+       if (!lq_sta) {
+               IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n");
+               return;
+       } else if (!lq_sta->pers.drv) {
+               IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n");
+               return;
+       }
+
+       /* This packet was aggregated but doesn't carry status info */
+       if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+           !(info->flags & IEEE80211_TX_STAT_AMPDU))
+               return;
+
+       if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band,
+                                   &tx_resp_rate)) {
+               WARN_ON_ONCE(1);
+               return;
+       }
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       /* Disable last tx check if we are debugging with fixed rate but
+        * update tx stats
+        */
+       if (lq_sta->pers.dbg_fixed_rate) {
+               int index = tx_resp_rate.index;
+               enum rs_column column;
+               int attempts, success;
+
+               column = rs_get_column_from_rate(&tx_resp_rate);
+               if (WARN_ONCE(column == RS_COLUMN_INVALID,
+                             "Can't map rate 0x%x to column",
+                             tx_resp_hwrate))
+                       return;
+
+               if (info->flags & IEEE80211_TX_STAT_AMPDU) {
+                       attempts = info->status.ampdu_len;
+                       success = info->status.ampdu_ack_len;
+               } else {
+                       attempts = info->status.rates[0].count;
+                       success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+               }
+
+               lq_sta->pers.tx_stats[column][index].total += attempts;
+               lq_sta->pers.tx_stats[column][index].success += success;
+
+               IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n",
+                              tx_resp_hwrate, success, attempts);
+               return;
+       }
+#endif
+
+       if (time_after(jiffies,
+                      (unsigned long)(lq_sta->last_tx +
+                                      (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
+               IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
+               /* reach here only in case of driver RS, call directly
+                * the unlocked version
+                */
+               rs_drv_rate_init(mvm, sta, info->band);
+               return;
+       }
+       lq_sta->last_tx = jiffies;
+
+       /* Ignore this Tx frame response if its initial rate doesn't match
+        * that of latest Link Quality command.  There may be stragglers
+        * from a previous Link Quality command, but we're no longer interested
+        * in those; they're either from the "active" mode while we're trying
+        * to check "search" mode, or a prior "search" mode after we've moved
+        * to a new "search" mode (which might become the new "active" mode).
+        */
+       table = &lq_sta->lq;
+       lq_hwrate = le32_to_cpu(table->rs_table[0]);
+       if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) {
+               WARN_ON_ONCE(1);
+               return;
+       }
+
+       /* Here we actually compare this rate to the latest LQ command */
+       if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) {
+               IWL_DEBUG_RATE(mvm,
+                              "tx resp color 0x%x does not match 0x%x\n",
+                              lq_color, LQ_FLAG_COLOR_GET(table->flags));
+
+               /* Since rates mis-match, the last LQ command may have failed.
+                * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
+                * ... driver.
+                */
+               lq_sta->missed_rate_counter++;
+               if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) {
+                       lq_sta->missed_rate_counter = 0;
+                       IWL_DEBUG_RATE(mvm,
+                                      "Too many rates mismatch. Send sync LQ. rs_state %d\n",
+                                      lq_sta->rs_state);
+                       iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq);
+               }
+               /* Regardless, ignore this status info for outdated rate */
+               return;
+       }
+
+       /* Rate did match, so reset the missed_rate_counter */
+       lq_sta->missed_rate_counter = 0;
+
+       if (!lq_sta->search_better_tbl) {
+               curr_tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+               other_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
+       } else {
+               curr_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
+               other_tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+       }
+
+       if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) {
+               IWL_DEBUG_RATE(mvm,
+                              "Neither active nor search matches tx rate\n");
+               tmp_tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+               rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE");
+               tmp_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
+               rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH");
+               rs_dump_rate(mvm, &lq_rate, "ACTUAL");
+
+               /* no matching table found, let's by-pass the data collection
+                * and continue to perform rate scale to find the rate table
+                */
+               rs_stay_in_table(lq_sta, true);
+               goto done;
+       }
+
+       /* Updating the frame history depends on whether packets were
+        * aggregated.
+        *
+        * For aggregation, all packets were transmitted at the same rate, the
+        * first index into rate scale table.
+        */
+       if (info->flags & IEEE80211_TX_STAT_AMPDU) {
+               rs_collect_tpc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index,
+                                   info->status.ampdu_len,
+                                   info->status.ampdu_ack_len,
+                                   reduced_txp);
+
+               /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat
+                * it as a single frame loss as we don't want the success ratio
+                * to dip too quickly because a BA wasn't received.
+                * For TPC, there's no need for this optimisation since we want
+                * to recover very quickly from a bad power reduction and,
+                * therefore we'd like the success ratio to get an immediate hit
+                * when failing to get a BA, so we'd switch back to a lower or
+                * zero power reduction. When FW transmits agg with a rate
+                * different from the initial rate, it will not use reduced txp
+                * and will send BA notification twice (one empty with reduced
+                * txp equal to the value from LQ and one with reduced txp 0).
+                * We need to update counters for each txp level accordingly.
+                */
+               if (info->status.ampdu_ack_len == 0)
+                       info->status.ampdu_len = 1;
+
+               rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl,
+                                   tx_resp_rate.index,
+                                   info->status.ampdu_len,
+                                   info->status.ampdu_ack_len);
+
+               /* Update success/fail counts if not searching for new mode */
+               if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
+                       lq_sta->total_success += info->status.ampdu_ack_len;
+                       lq_sta->total_failed += (info->status.ampdu_len -
+                                       info->status.ampdu_ack_len);
+               }
+       } else {
+               /* For legacy, update frame history with for each Tx retry. */
+               retries = info->status.rates[0].count - 1;
+               /* HW doesn't send more than 15 retries */
+               retries = min(retries, 15);
+
+               /* The last transmission may have been successful */
+               legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+               /* Collect data for each rate used during failed TX attempts */
+               for (i = 0; i <= retries; ++i) {
+                       lq_hwrate = le32_to_cpu(table->rs_table[i]);
+                       if (rs_rate_from_ucode_rate(lq_hwrate, info->band,
+                                                   &lq_rate)) {
+                               WARN_ON_ONCE(1);
+                               return;
+                       }
+
+                       /* Only collect stats if retried rate is in the same RS
+                        * table as active/search.
+                        */
+                       if (rs_rate_column_match(&lq_rate, &curr_tbl->rate))
+                               tmp_tbl = curr_tbl;
+                       else if (rs_rate_column_match(&lq_rate,
+                                                     &other_tbl->rate))
+                               tmp_tbl = other_tbl;
+                       else
+                               continue;
+
+                       rs_collect_tpc_data(mvm, lq_sta, tmp_tbl,
+                                           tx_resp_rate.index, 1,
+                                           i < retries ? 0 : legacy_success,
+                                           reduced_txp);
+                       rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl,
+                                           tx_resp_rate.index, 1,
+                                           i < retries ? 0 : legacy_success);
+               }
+
+               /* Update success/fail counts if not searching for new mode */
+               if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
+                       lq_sta->total_success += legacy_success;
+                       lq_sta->total_failed += retries + (1 - legacy_success);
+               }
+       }
+       /* The last TX rate is cached in lq_sta; it's set in if/else above */
+       lq_sta->last_rate_n_flags = lq_hwrate;
+       IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
+done:
+       /* See if there's a better rate or modulation mode to try. */
+       if (sta->supp_rates[info->band])
+               rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp);
+}
+
+void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+                         int tid, struct ieee80211_tx_info *info, bool ndp)
+{
+       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+       /* If it's locked we are in middle of init flow
+        * just wait for next tx status to update the lq_sta data
+        */
+       if (!spin_trylock(&mvmsta->lq_sta.rs_drv.pers.lock))
+               return;
+
+       __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp);
+       spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock);
+}
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
                                            struct iwl_lq_cmd *lq_cmd,
@@ -3569,7 +3603,7 @@ static void rs_set_lq_ss_params(struct iwl_mvm *mvm,
 
                bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED;
                bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params);
-               iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false);
+               iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd);
 
                ss_params |= LQ_SS_BFER_ALLOWED;
                IWL_DEBUG_RATE(mvm,
@@ -3735,7 +3769,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm,
 
        if (lq_sta->pers.dbg_fixed_rate) {
                rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL);
-               iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false);
+               iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq);
        }
 }
 
@@ -4132,10 +4166,15 @@ static const struct rate_control_ops rs_mvm_ops_drv = {
 void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                          enum nl80211_band band, bool update)
 {
-       if (iwl_mvm_has_tlc_offload(mvm))
+       if (iwl_mvm_has_tlc_offload(mvm)) {
                rs_fw_rate_init(mvm, sta, band, update);
-       else
-               rs_drv_rate_init(mvm, sta, band, update);
+       } else {
+               struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+               spin_lock(&mvmsta->lq_sta.rs_drv.pers.lock);
+               rs_drv_rate_init(mvm, sta, band);
+               spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock);
+       }
 }
 
 int iwl_mvm_rate_control_register(void)
@@ -4165,7 +4204,7 @@ static int rs_drv_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
                        lq->flags &= ~LQ_FLAG_USE_RTS_MSK;
        }
 
-       return iwl_mvm_send_lq_cmd(mvm, lq, false);
+       return iwl_mvm_send_lq_cmd(mvm, lq);
 }
 
 /**
index f7eb60dbaf202460eaca0cf8695171357073996a..428642e666587d14e7d6d3c7a9f8713c4a8d6713 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
  *
  * Contact Information:
  *  Intel Linux Wireless <linuxwifi@intel.com>
@@ -390,6 +390,7 @@ struct iwl_lq_sta {
                s8 last_rssi;
                struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
                struct iwl_mvm *drv;
+               spinlock_t lock; /* for races in reinit/update table */
        } pers;
 };
 
index 64f95050128770cae30a2871f1a3c717b95d7cf8..854edd7d7103b351fe69b23a085d3b2e6b9eb610 100644 (file)
@@ -463,20 +463,22 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue,
 }
 
 int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
-                           const u8 *data, u32 count)
+                           const u8 *data, u32 count, bool async)
 {
-       struct iwl_rxq_sync_cmd *cmd;
+       u8 buf[sizeof(struct iwl_rxq_sync_cmd) +
+              sizeof(struct iwl_mvm_rss_sync_notif)];
+       struct iwl_rxq_sync_cmd *cmd = (void *)buf;
        u32 data_size = sizeof(*cmd) + count;
        int ret;
 
-       /* should be DWORD aligned */
-       if (WARN_ON(count & 3 || count > IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE))
+       /*
+        * size must be a multiple of DWORD
+        * Ensure we don't overflow buf
+        */
+       if (WARN_ON(count & 3 ||
+                   count > sizeof(struct iwl_mvm_rss_sync_notif)))
                return -EINVAL;
 
-       cmd = kzalloc(data_size, GFP_KERNEL);
-       if (!cmd)
-               return -ENOMEM;
-
        cmd->rxq_mask = cpu_to_le32(rxq_mask);
        cmd->count =  cpu_to_le32(count);
        cmd->flags = 0;
@@ -485,9 +487,8 @@ int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
        ret = iwl_mvm_send_cmd_pdu(mvm,
                                   WIDE_ID(DATA_PATH_GROUP,
                                           TRIGGER_RX_QUEUES_NOTIF_CMD),
-                                  0, data_size, cmd);
+                                  async ? CMD_ASYNC : 0, data_size, cmd);
 
-       kfree(cmd);
        return ret;
 }
 
@@ -503,14 +504,31 @@ static bool iwl_mvm_is_sn_less(u16 sn1, u16 sn2, u16 buffer_size)
               !ieee80211_sn_less(sn1, sn2 - buffer_size);
 }
 
+static void iwl_mvm_sync_nssn(struct iwl_mvm *mvm, u8 baid, u16 nssn)
+{
+       struct iwl_mvm_rss_sync_notif notif = {
+               .metadata.type = IWL_MVM_RXQ_NSSN_SYNC,
+               .metadata.sync = 0,
+               .nssn_sync.baid = baid,
+               .nssn_sync.nssn = nssn,
+       };
+
+       iwl_mvm_sync_rx_queues_internal(mvm, (void *)&notif, sizeof(notif));
+}
+
 #define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10)
 
+enum iwl_mvm_release_flags {
+       IWL_MVM_RELEASE_SEND_RSS_SYNC = BIT(0),
+       IWL_MVM_RELEASE_FROM_RSS_SYNC = BIT(1),
+};
+
 static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
                                   struct ieee80211_sta *sta,
                                   struct napi_struct *napi,
                                   struct iwl_mvm_baid_data *baid_data,
                                   struct iwl_mvm_reorder_buffer *reorder_buf,
-                                  u16 nssn)
+                                  u16 nssn, u32 flags)
 {
        struct iwl_mvm_reorder_buf_entry *entries =
                &baid_data->entries[reorder_buf->queue *
@@ -519,6 +537,18 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
 
        lockdep_assert_held(&reorder_buf->lock);
 
+       /*
+        * We keep the NSSN not too far behind, if we are sync'ing it and it
+        * is more than 2048 ahead of us, it must be behind us. Discard it.
+        * This can happen if the queue that hit the 0 / 2048 seqno was lagging
+        * behind and this queue already processed packets. The next if
+        * would have caught cases where this queue would have processed less
+        * than 64 packets, but it may have processed more than 64 packets.
+        */
+       if ((flags & IWL_MVM_RELEASE_FROM_RSS_SYNC) &&
+           ieee80211_sn_less(nssn, ssn))
+               goto set_timer;
+
        /* ignore nssn smaller than head sn - this can happen due to timeout */
        if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size))
                goto set_timer;
@@ -529,6 +559,9 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
                struct sk_buff *skb;
 
                ssn = ieee80211_sn_inc(ssn);
+               if ((flags & IWL_MVM_RELEASE_SEND_RSS_SYNC) &&
+                   (ssn == 2048 || ssn == 0))
+                       iwl_mvm_sync_nssn(mvm, baid_data->baid, ssn);
 
                /*
                 * Empty the list. Will have more than one frame for A-MSDU.
@@ -615,7 +648,8 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t)
                             sta_id, sn);
                iwl_mvm_event_frame_timeout_callback(buf->mvm, mvmsta->vif,
                                                     sta, baid_data->tid);
-               iwl_mvm_release_frames(buf->mvm, sta, NULL, baid_data, buf, sn);
+               iwl_mvm_release_frames(buf->mvm, sta, NULL, baid_data,
+                                      buf, sn, IWL_MVM_RELEASE_SEND_RSS_SYNC);
                rcu_read_unlock();
        } else {
                /*
@@ -657,7 +691,8 @@ static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue,
        spin_lock_bh(&reorder_buf->lock);
        iwl_mvm_release_frames(mvm, sta, NULL, ba_data, reorder_buf,
                               ieee80211_sn_add(reorder_buf->head_sn,
-                                               reorder_buf->buf_size));
+                                               reorder_buf->buf_size),
+                              0);
        spin_unlock_bh(&reorder_buf->lock);
        del_timer_sync(&reorder_buf->reorder_timer);
 
@@ -665,8 +700,54 @@ out:
        rcu_read_unlock();
 }
 
-void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
-                           int queue)
+static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm,
+                                             struct napi_struct *napi,
+                                             u8 baid, u16 nssn, int queue,
+                                             u32 flags)
+{
+       struct ieee80211_sta *sta;
+       struct iwl_mvm_reorder_buffer *reorder_buf;
+       struct iwl_mvm_baid_data *ba_data;
+
+       IWL_DEBUG_HT(mvm, "Frame release notification for BAID %u, NSSN %d\n",
+                    baid, nssn);
+
+       if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID ||
+                        baid >= ARRAY_SIZE(mvm->baid_map)))
+               return;
+
+       rcu_read_lock();
+
+       ba_data = rcu_dereference(mvm->baid_map[baid]);
+       if (WARN_ON_ONCE(!ba_data))
+               goto out;
+
+       sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]);
+       if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta)))
+               goto out;
+
+       reorder_buf = &ba_data->reorder_buf[queue];
+
+       spin_lock_bh(&reorder_buf->lock);
+       iwl_mvm_release_frames(mvm, sta, napi, ba_data,
+                              reorder_buf, nssn, flags);
+       spin_unlock_bh(&reorder_buf->lock);
+
+out:
+       rcu_read_unlock();
+}
+
+static void iwl_mvm_nssn_sync(struct iwl_mvm *mvm,
+                             struct napi_struct *napi, int queue,
+                             const struct iwl_mvm_nssn_sync_data *data)
+{
+       iwl_mvm_release_frames_from_notif(mvm, napi, data->baid,
+                                         data->nssn, queue,
+                                         IWL_MVM_RELEASE_FROM_RSS_SYNC);
+}
+
+void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi,
+                           struct iwl_rx_cmd_buffer *rxb, int queue)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_rxq_sync_notification *notif;
@@ -687,6 +768,10 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        case IWL_MVM_RXQ_NOTIF_DEL_BA:
                iwl_mvm_del_ba(mvm, queue, (void *)internal_notif->data);
                break;
+       case IWL_MVM_RXQ_NSSN_SYNC:
+               iwl_mvm_nssn_sync(mvm, napi, queue,
+                                 (void *)internal_notif->data);
+               break;
        default:
                WARN_ONCE(1, "Invalid identifier %d", internal_notif->type);
        }
@@ -785,7 +870,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
        }
 
        if (ieee80211_is_back_req(hdr->frame_control)) {
-               iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, nssn);
+               iwl_mvm_release_frames(mvm, sta, napi, baid_data,
+                                      buffer, nssn, 0);
                goto drop;
        }
 
@@ -794,7 +880,10 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
         * If the SN is smaller than the NSSN it might need to first go into
         * the reorder buffer, in which case we just release up to it and the
         * rest of the function will take care of storing it and releasing up to
-        * the nssn
+        * the nssn.
+        * This should not happen. This queue has been lagging and it should
+        * have been updated by a IWL_MVM_RXQ_NSSN_SYNC notification. Be nice
+        * and update the other queues.
         */
        if (!iwl_mvm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size,
                                buffer->buf_size) ||
@@ -802,7 +891,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
                u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn;
 
                iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer,
-                                      min_sn);
+                                      min_sn, IWL_MVM_RELEASE_SEND_RSS_SYNC);
        }
 
        /* drop any oudated packets */
@@ -813,8 +902,23 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
        if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
                if (iwl_mvm_is_sn_less(buffer->head_sn, nssn,
                                       buffer->buf_size) &&
-                  (!amsdu || last_subframe))
+                  (!amsdu || last_subframe)) {
+                       /*
+                        * If we crossed the 2048 or 0 SN, notify all the
+                        * queues. This is done in order to avoid having a
+                        * head_sn that lags behind for too long. When that
+                        * happens, we can get to a situation where the head_sn
+                        * is within the interval [nssn - buf_size : nssn]
+                        * which will make us think that the nssn is a packet
+                        * that we already freed because of the reordering
+                        * buffer and we will ignore it. So maintain the
+                        * head_sn somewhat updated across all the queues:
+                        * when it crosses 0 and 2048.
+                        */
+                       if (sn == 2048 || sn == 0)
+                               iwl_mvm_sync_nssn(mvm, baid, sn);
                        buffer->head_sn = nssn;
+               }
                /* No need to update AMSDU last SN - we are moving the head */
                spin_unlock_bh(&buffer->lock);
                return false;
@@ -829,8 +933,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
         * while technically there is no hole and we can move forward.
         */
        if (!buffer->num_stored && sn == buffer->head_sn) {
-               if (!amsdu || last_subframe)
+               if (!amsdu || last_subframe) {
+                       if (sn == 2048 || sn == 0)
+                               iwl_mvm_sync_nssn(mvm, baid, sn);
                        buffer->head_sn = ieee80211_sn_inc(buffer->head_sn);
+               }
                /* No need to update AMSDU last SN - we are moving the head */
                spin_unlock_bh(&buffer->lock);
                return false;
@@ -875,7 +982,9 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
         * release notification with up to date NSSN.
         */
        if (!amsdu || last_subframe)
-               iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, nssn);
+               iwl_mvm_release_frames(mvm, sta, napi, baid_data,
+                                      buffer, nssn,
+                                      IWL_MVM_RELEASE_SEND_RSS_SYNC);
 
        spin_unlock_bh(&buffer->lock);
        return true;
@@ -1840,40 +1949,14 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
 out:
        rcu_read_unlock();
 }
+
 void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
                              struct iwl_rx_cmd_buffer *rxb, int queue)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_frame_release *release = (void *)pkt->data;
-       struct ieee80211_sta *sta;
-       struct iwl_mvm_reorder_buffer *reorder_buf;
-       struct iwl_mvm_baid_data *ba_data;
-
-       int baid = release->baid;
-
-       IWL_DEBUG_HT(mvm, "Frame release notification for BAID %u, NSSN %d\n",
-                    release->baid, le16_to_cpu(release->nssn));
 
-       if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID))
-               return;
-
-       rcu_read_lock();
-
-       ba_data = rcu_dereference(mvm->baid_map[baid]);
-       if (WARN_ON_ONCE(!ba_data))
-               goto out;
-
-       sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]);
-       if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta)))
-               goto out;
-
-       reorder_buf = &ba_data->reorder_buf[queue];
-
-       spin_lock_bh(&reorder_buf->lock);
-       iwl_mvm_release_frames(mvm, sta, napi, ba_data, reorder_buf,
-                              le16_to_cpu(release->nssn));
-       spin_unlock_bh(&reorder_buf->lock);
-
-out:
-       rcu_read_unlock();
+       iwl_mvm_release_frames_from_notif(mvm, napi, release->baid,
+                                         le16_to_cpu(release->nssn),
+                                         queue, 0);
 }
index f545a737a92dfa8321b83ce00748c1833ec7c854..10f18536dd0d288884aca8068eded9b1bc193dcb 100644 (file)
@@ -1684,6 +1684,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
         */
        if (iwl_mvm_has_tlc_offload(mvm))
                iwl_mvm_rs_add_sta(mvm, mvm_sta);
+       else
+               spin_lock_init(&mvm_sta->lq_sta.rs_drv.pers.lock);
 
        iwl_mvm_toggle_tx_ant(mvm, &mvm_sta->tx_ant);
 
@@ -2421,7 +2423,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 
 static void iwl_mvm_sync_rxq_del_ba(struct iwl_mvm *mvm, u8 baid)
 {
-       struct iwl_mvm_delba_notif notif = {
+       struct iwl_mvm_rss_sync_notif notif = {
                .metadata.type = IWL_MVM_RXQ_NOTIF_DEL_BA,
                .metadata.sync = 1,
                .delba.baid = baid,
@@ -2972,7 +2974,7 @@ out:
        IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
                     sta->addr, tid);
 
-       return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.rs_drv.lq, false);
+       return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.rs_drv.lq);
 }
 
 static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm,
index 4487cc3e07c1ebc6a223d9b0af387ea52db57b27..8d70093847cb1d8f1fcd3ada15f03f2c620597fa 100644 (file)
@@ -343,9 +343,17 @@ struct iwl_mvm_delba_data {
        u32 baid;
 } __packed;
 
-struct iwl_mvm_delba_notif {
+struct iwl_mvm_nssn_sync_data {
+       u32 baid;
+       u32 nssn;
+} __packed;
+
+struct iwl_mvm_rss_sync_notif {
        struct iwl_mvm_internal_rxq_notif metadata;
-       struct iwl_mvm_delba_data delba;
+       union {
+               struct iwl_mvm_delba_data delba;
+               struct iwl_mvm_nssn_sync_data nssn_sync;
+       };
 } __packed;
 
 /**
index a3e5d88f1c07cf5123f1d100ea117bda189c0938..6ac114a393ccf361cac64a891579de27623e6d7e 100644 (file)
@@ -831,6 +831,7 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
        unsigned int tcp_payload_len;
        unsigned int mss = skb_shinfo(skb)->gso_size;
        bool ipv4 = (skb->protocol == htons(ETH_P_IP));
+       bool qos = ieee80211_is_data_qos(hdr->frame_control);
        u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
 
        skb_shinfo(skb)->gso_size = num_subframes * mss;
@@ -864,7 +865,7 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
                if (tcp_payload_len > mss) {
                        skb_shinfo(tmp)->gso_size = mss;
                } else {
-                       if (ieee80211_is_data_qos(hdr->frame_control)) {
+                       if (qos) {
                                u8 *qc;
 
                                if (ipv4)
index 9ecd5f09615a64a34f220dcad8775568b022cde5..b8e20a01c1923b6de62f7a52bf4e8060ded1c221 100644 (file)
@@ -653,12 +653,12 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
  * this case to clear the state indicating that station creation is in
  * progress.
  */
-int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync)
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq)
 {
        struct iwl_host_cmd cmd = {
                .id = LQ_CMD,
                .len = { sizeof(struct iwl_lq_cmd), },
-               .flags = sync ? 0 : CMD_ASYNC,
+               .flags = CMD_ASYNC,
                .data = { lq, },
        };
 
index ea2a03d4bf55c66571cae63c4223625e9d920db7..de711c1160d316320bc8d92ec3f537e390bbd517 100644 (file)
@@ -604,10 +604,13 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)},
        {IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)},
        {IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)},
+       {IWL_PCI_DEVICE(0x2526, 0x6010, iwl9260_2ac_160_cfg)},
        {IWL_PCI_DEVICE(0x2526, 0x6014, iwl9260_2ac_160_cfg)},
        {IWL_PCI_DEVICE(0x2526, 0x8014, iwl9260_2ac_160_cfg)},
        {IWL_PCI_DEVICE(0x2526, 0x8010, iwl9260_2ac_160_cfg)},
        {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_160_cfg)},
+       {IWL_PCI_DEVICE(0x2526, 0xE010, iwl9260_2ac_160_cfg)},
+       {IWL_PCI_DEVICE(0x2526, 0xE014, iwl9260_2ac_160_cfg)},
        {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)},
        {IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)},
        {IWL_PCI_DEVICE(0x271B, 0x0210, iwl9160_2ac_cfg)},
index fa4245d0d4a8f848163c930126cd088f2f5c46b1..2f0ba7ef53b8616a4bf4581b49106cf0094739ad 100644 (file)
@@ -435,6 +435,8 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
                                         DMA_TO_DEVICE);
        }
 
+       meta->tbs = 0;
+
        if (trans->cfg->use_tfh) {
                struct iwl_tfh_tfd *tfd_fh = (void *)tfd;
 
index 519b4ee88c5c3af68141b6bb357917ca610a32af..772e54f0696fdf728254dbc966936a92ca4a209b 100644 (file)
@@ -3617,10 +3617,12 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb,
                hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
                                  cb->nlh->nlmsg_seq, &hwsim_genl_family,
                                  NLM_F_MULTI, HWSIM_CMD_GET_RADIO);
-               if (!hdr)
+               if (hdr) {
+                       genl_dump_check_consistent(cb, hdr);
+                       genlmsg_end(skb, hdr);
+               } else {
                        res = -EMSGSIZE;
-               genl_dump_check_consistent(cb, hdr);
-               genlmsg_end(skb, hdr);
+               }
        }
 
 done:
index 3e442c7f78827bf5ce91953af495a7a6cc73a977..095837fba300536c719285183061156f17082028 100644 (file)
@@ -124,6 +124,7 @@ enum {
 
 #define MWIFIEX_MAX_TOTAL_SCAN_TIME    (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
 
+#define WPA_GTK_OUI_OFFSET                             2
 #define RSN_GTK_OUI_OFFSET                             2
 
 #define MWIFIEX_OUI_NOT_PRESENT                        0
index 0d6d41727037a737ed224ca84b6bd370dc0a5b7b..21dda385f6c6816fed5732042b0b135c0e364b68 100644 (file)
@@ -181,7 +181,8 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
        u8 ret = MWIFIEX_OUI_NOT_PRESENT;
 
        if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) {
-               iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
+               iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data +
+                                           WPA_GTK_OUI_OFFSET);
                oui = &mwifiex_wpa_oui[cipher][0];
                ret = mwifiex_search_oui_in_ie(iebody, oui);
                if (ret)
index e65d027b91fafbbd752970cff0afdc9e8cfb0d7c..529be35ac1782a62e9f18b71905fa597ea52a222 100644 (file)
@@ -244,7 +244,7 @@ void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
        /* Reset possible fault of previous session */
        clear_bit(NFCMRVL_PHY_ERROR, &priv->flags);
 
-       if (priv->config.reset_n_io) {
+       if (gpio_is_valid(priv->config.reset_n_io)) {
                nfc_info(priv->dev, "reset the chip\n");
                gpio_set_value(priv->config.reset_n_io, 0);
                usleep_range(5000, 10000);
@@ -255,7 +255,7 @@ void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
 
 void nfcmrvl_chip_halt(struct nfcmrvl_private *priv)
 {
-       if (priv->config.reset_n_io)
+       if (gpio_is_valid(priv->config.reset_n_io))
                gpio_set_value(priv->config.reset_n_io, 0);
 }
 
index 9a22056e8d9eea921b59a588318be8c47b6b1046..e5a622ce4b9517d299170f20d35bde2bd5e003da 100644 (file)
@@ -26,7 +26,7 @@
 static unsigned int hci_muxed;
 static unsigned int flow_control;
 static unsigned int break_control;
-static unsigned int reset_n_io;
+static int reset_n_io = -EINVAL;
 
 /*
 ** NFCMRVL NCI OPS
@@ -231,5 +231,5 @@ MODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal.");
 module_param(hci_muxed, uint, 0);
 MODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one.");
 
-module_param(reset_n_io, uint, 0);
+module_param(reset_n_io, int, 0);
 MODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal.");
index 945cc903d8f1123fd63a13c42564a3dfe7465a12..888e298f610b8ed7140c85c5d0355d55007b6cfc 100644 (file)
@@ -305,6 +305,7 @@ static int nfcmrvl_probe(struct usb_interface *intf,
 
        /* No configuration for USB */
        memset(&config, 0, sizeof(config));
+       config.reset_n_io = -EINVAL;
 
        nfc_info(&udev->dev, "intf %p id %p\n", intf, id);
 
index c3e10b6ab3a4d45203a67e36af1cf2d193a39028..f25f1ec5f9e97a10aebc1b308180cb84beb4133e 100644 (file)
@@ -333,6 +333,8 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
 
                transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
                                            skb->len - 2, GFP_KERNEL);
+               if (!transaction)
+                       return -ENOMEM;
 
                transaction->aid_len = skb->data[1];
                memcpy(transaction->aid, &skb->data[2], transaction->aid_len);
index 06fc542fd19876d16c0a6e8e39de654340cc2b5a..6586378cacb05ed6b80bcc8c9c350010f7e88905 100644 (file)
@@ -317,6 +317,8 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
 
                transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
                                                   skb->len - 2, GFP_KERNEL);
+               if (!transaction)
+                       return -ENOMEM;
 
                transaction->aid_len = skb->data[1];
                memcpy(transaction->aid, &skb->data[2],
index 152053361862d4c5c8595ed4931d0bafd002bdd1..989506bd90b193bc696abf90096e0c4ae1a37efa 100644 (file)
 #define AXP803_DCDC5_1140mV_STEPS      35
 #define AXP803_DCDC5_1140mV_END                \
        (AXP803_DCDC5_1140mV_START + AXP803_DCDC5_1140mV_STEPS)
-#define AXP803_DCDC5_NUM_VOLTAGES      68
+#define AXP803_DCDC5_NUM_VOLTAGES      69
 
 #define AXP803_DCDC6_600mV_START       0x00
 #define AXP803_DCDC6_600mV_STEPS       50
 #define AXP803_DCDC6_600mV_END         \
        (AXP803_DCDC6_600mV_START + AXP803_DCDC6_600mV_STEPS)
 #define AXP803_DCDC6_1120mV_START      0x33
-#define AXP803_DCDC6_1120mV_STEPS      14
+#define AXP803_DCDC6_1120mV_STEPS      20
 #define AXP803_DCDC6_1120mV_END                \
        (AXP803_DCDC6_1120mV_START + AXP803_DCDC6_1120mV_STEPS)
 #define AXP803_DCDC6_NUM_VOLTAGES      72
 #define AXP806_DCDCA_600mV_END         \
        (AXP806_DCDCA_600mV_START + AXP806_DCDCA_600mV_STEPS)
 #define AXP806_DCDCA_1120mV_START      0x33
-#define AXP806_DCDCA_1120mV_STEPS      14
+#define AXP806_DCDCA_1120mV_STEPS      20
 #define AXP806_DCDCA_1120mV_END                \
        (AXP806_DCDCA_1120mV_START + AXP806_DCDCA_1120mV_STEPS)
 #define AXP806_DCDCA_NUM_VOLTAGES      72
@@ -774,8 +774,8 @@ static const struct regulator_linear_range axp806_dcdcd_ranges[] = {
                               AXP806_DCDCD_600mV_END,
                               20000),
        REGULATOR_LINEAR_RANGE(1600000,
-                              AXP806_DCDCD_600mV_START,
-                              AXP806_DCDCD_600mV_END,
+                              AXP806_DCDCD_1600mV_START,
+                              AXP806_DCDCD_1600mV_END,
                               100000),
 };
 
index 5d067f7c2116601a5ff558e194963a82a3869d9d..0c440c5e28327c80b596f0996c3ef6b122021a6d 100644 (file)
@@ -163,7 +163,7 @@ static int lp87565_regulator_probe(struct platform_device *pdev)
        struct lp87565 *lp87565 = dev_get_drvdata(pdev->dev.parent);
        struct regulator_config config = { };
        struct regulator_dev *rdev;
-       int i, min_idx = LP87565_BUCK_0, max_idx = LP87565_BUCK_3;
+       int i, min_idx, max_idx;
 
        platform_set_drvdata(pdev, lp87565);
 
@@ -182,9 +182,9 @@ static int lp87565_regulator_probe(struct platform_device *pdev)
                max_idx = LP87565_BUCK_3210;
                break;
        default:
-               dev_err(lp87565->dev, "Invalid lp config %d\n",
-                       lp87565->dev_type);
-               return -EINVAL;
+               min_idx = LP87565_BUCK_0;
+               max_idx = LP87565_BUCK_3;
+               break;
        }
 
        for (i = min_idx; i <= max_idx; i++) {
index 397918ebba550a5c120481052ba586db7cb9f055..9112faa6a9a0e12830e8f931e83fcd56070e1ac5 100644 (file)
@@ -416,8 +416,10 @@ device_node *regulator_of_get_init_node(struct device *dev,
                if (!name)
                        name = child->name;
 
-               if (!strcmp(desc->of_match, name))
+               if (!strcmp(desc->of_match, name)) {
+                       of_node_put(search);
                        return of_node_get(child);
+               }
        }
 
        of_node_put(search);
index 6f243a90c844d5078faeb442fb620e6ef37e750e..840b1b8ff3dcbf644eff61ad239d9917dcae1406 100644 (file)
@@ -834,7 +834,8 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
        bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
 
        /* handle all the 3-wire mode */
-       if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf))
+       if (spi->mode & SPI_3WIRE && tfr->rx_buf &&
+           tfr->rx_buf != ctlr->dummy_rx)
                cs |= BCM2835_SPI_CS_REN;
        else
                cs &= ~BCM2835_SPI_CS_REN;
index 41a49b93ca60e6979a8ffdebd871dda739695a63..448c00e4065b86cad66e61c0db103f6f604bde80 100644 (file)
@@ -206,7 +206,7 @@ static const struct fsl_qspi_devtype_data imx6sx_data = {
 };
 
 static const struct fsl_qspi_devtype_data imx7d_data = {
-       .rxfifo = SZ_512,
+       .rxfifo = SZ_128,
        .txfifo = SZ_512,
        .ahb_buf_size = SZ_1K,
        .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK,
index eca9d52ecf65c57d342ac4abcb4bd49e9f781972..9eb82150666e88e98b83ba336123ce88267eab5b 100644 (file)
@@ -410,6 +410,12 @@ static int spi_gpio_probe(struct platform_device *pdev)
 
        bb = &spi_gpio->bitbang;
        bb->master = master;
+       /*
+        * There is some additional business, apart from driving the CS GPIO
+        * line, that we need to do on selection. This makes the local
+        * callback for chipselect always get called.
+        */
+       master->flags |= SPI_MASTER_GPIO_SS;
        bb->chipselect = spi_gpio_chipselect;
        bb->set_line_direction = spi_gpio_set_direction;
 
index fc7ab4b2688023b215c273bb8c65cad13533f5f0..bb6a14d1ab0f929d6e4573573be92db15e631acc 100644 (file)
@@ -1457,6 +1457,14 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
        { PCI_VDEVICE(INTEL, 0x02aa), LPSS_CNL_SSP },
        { PCI_VDEVICE(INTEL, 0x02ab), LPSS_CNL_SSP },
        { PCI_VDEVICE(INTEL, 0x02fb), LPSS_CNL_SSP },
+       /* TGL-LP */
+       { PCI_VDEVICE(INTEL, 0xa0aa), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0xa0ab), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0xa0de), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0xa0df), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0xa0fb), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0xa0fd), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0xa0fe), LPSS_CNL_SSP },
        { },
 };
 
@@ -1831,14 +1839,16 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        status = devm_spi_register_controller(&pdev->dev, controller);
        if (status != 0) {
                dev_err(&pdev->dev, "problem registering spi controller\n");
-               goto out_error_clock_enabled;
+               goto out_error_pm_runtime_enabled;
        }
 
        return status;
 
-out_error_clock_enabled:
+out_error_pm_runtime_enabled:
        pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
+
+out_error_clock_enabled:
        clk_disable_unprepare(ssp->clk);
 
 out_error_dma_irq_alloc:
index 6e30949d9f7794a584c1503fe8dbf7a51d0e83b7..a7ec2d3dff9282bf6e8fbc2c29e2f8e0301efb39 100644 (file)
@@ -638,9 +638,6 @@ COMPATIBLE_IOCTL(PPPIOCDISCONN)
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
 COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
-/* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD)
-COMPATIBLE_IOCTL(PPPOEIOCDFWD)
 /* Big A */
 /* sparc only */
 /* Big Q for sound/OSS */
index d3a0fbfff2bb0931dddd8fd0d65ab544bc8f76b0..9fa4b3f88c397a790ce3d0d8a7042d5cea3107bd 100644 (file)
@@ -272,62 +272,6 @@ dim_update_sample_with_comps(u16 event_ctr, u64 packets, u64 bytes, u64 comps,
 
 /* Net DIM */
 
-/*
- * Net DIM profiles:
- *        There are different set of profiles for each CQ period mode.
- *        There are different set of profiles for RX/TX CQs.
- *        Each profile size must be of NET_DIM_PARAMS_NUM_PROFILES
- */
-#define NET_DIM_PARAMS_NUM_PROFILES 5
-#define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
-#define NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE 128
-#define NET_DIM_DEF_PROFILE_CQE 1
-#define NET_DIM_DEF_PROFILE_EQE 1
-
-#define NET_DIM_RX_EQE_PROFILES { \
-       {1,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
-       {8,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
-       {64,  NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
-       {128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
-       {256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
-}
-
-#define NET_DIM_RX_CQE_PROFILES { \
-       {2,  256},             \
-       {8,  128},             \
-       {16, 64},              \
-       {32, 64},              \
-       {64, 64}               \
-}
-
-#define NET_DIM_TX_EQE_PROFILES { \
-       {1,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
-       {8,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
-       {32,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
-       {64,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
-       {128, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}   \
-}
-
-#define NET_DIM_TX_CQE_PROFILES { \
-       {5,  128},  \
-       {8,  64},  \
-       {16, 32},  \
-       {32, 32},  \
-       {64, 32}   \
-}
-
-static const struct dim_cq_moder
-rx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
-       NET_DIM_RX_EQE_PROFILES,
-       NET_DIM_RX_CQE_PROFILES,
-};
-
-static const struct dim_cq_moder
-tx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
-       NET_DIM_TX_EQE_PROFILES,
-       NET_DIM_TX_CQE_PROFILES,
-};
-
 /**
  *     net_dim_get_rx_moderation - provide a CQ moderation object for the given RX profile
  *     @cq_period_mode: CQ period mode
index ff65d22cf336935c9406930496dc8a8f57a0cbd0..92c6e31fb008ee80073e310797e27d0e72d428c2 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <net/sch_generic.h>
 
+#include <asm/byteorder.h>
 #include <uapi/linux/filter.h>
 #include <uapi/linux/bpf.h>
 
@@ -747,6 +748,18 @@ bpf_ctx_narrow_access_ok(u32 off, u32 size, u32 size_default)
        return size <= size_default && (size & (size - 1)) == 0;
 }
 
+static inline u8
+bpf_ctx_narrow_load_shift(u32 off, u32 size, u32 size_default)
+{
+       u8 load_off = off & (size_default - 1);
+
+#ifdef __LITTLE_ENDIAN
+       return load_off * 8;
+#else
+       return (size_default - (load_off + size)) * 8;
+#endif
+}
+
 #define bpf_ctx_wide_access_ok(off, size, type, field)                 \
        (size == sizeof(__u64) &&                                       \
        off >= offsetof(type, field) &&                                 \
index 8b728750a62580c6ed05fe93fc5aada94e145ac1..69e813bcb947ef59c1fc23e541a938d5c179d197 100644 (file)
@@ -80,6 +80,9 @@ extern int register_pppox_proto(int proto_num, const struct pppox_proto *pp);
 extern void unregister_pppox_proto(int proto_num);
 extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */
 extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+extern int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+
+#define PPPOEIOCSFWD32    _IOW(0xB1 ,0, compat_size_t)
 
 /* PPPoX socket states */
 enum {
index b4f5403383fc9be106fad4cde572909df920c00c..9661416a9bb473da8bb329477b548a22fce4eaae 100644 (file)
@@ -41,11 +41,11 @@ struct rmnet_map_ul_csum_header {
        __be16 csum_start_offset;
 #if defined(__LITTLE_ENDIAN_BITFIELD)
        u16 csum_insert_offset:14;
-       u16 udp_ip4_ind:1;
+       u16 udp_ind:1;
        u16 csum_enabled:1;
 #elif defined (__BIG_ENDIAN_BITFIELD)
        u16 csum_enabled:1;
-       u16 udp_ip4_ind:1;
+       u16 udp_ind:1;
        u16 csum_insert_offset:14;
 #else
 #error "Please fix <asm/byteorder.h>"
index 04a569568eacb738bcc52a9389f96eb4fcafdd7f..f049af3f3cd838c85d87e02d5e13f5a39d1ffec0 100644 (file)
@@ -220,6 +220,7 @@ int mlx5_modify_rule_destination(struct mlx5_flow_handle *handler,
 
 struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging);
 void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter);
+u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter);
 void mlx5_fc_query_cached(struct mlx5_fc *counter,
                          u64 *bytes, u64 *packets, u64 *lastuse);
 int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter,
index b3d5752657d9893fbc83bdaf577d872ed9bde5a4..ec571fd7fcf89299e4ef17b17142fce13059de6e 100644 (file)
@@ -5975,10 +5975,12 @@ struct mlx5_ifc_modify_cq_in_bits {
 
        struct mlx5_ifc_cqc_bits cq_context;
 
-       u8         reserved_at_280[0x40];
+       u8         reserved_at_280[0x60];
 
        u8         cq_umem_valid[0x1];
-       u8         reserved_at_2c1[0x5bf];
+       u8         reserved_at_2e1[0x1f];
+
+       u8         reserved_at_300[0x580];
 
        u8         pas[0][0x40];
 };
index 50ced8aba9dbf6c2cd4a0a1ef1598bdd58822821..e4b3fb4bb77c7004d9164c6ba85f3be37eea741f 100644 (file)
@@ -354,7 +354,13 @@ static inline void sk_psock_restore_proto(struct sock *sk,
        sk->sk_write_space = psock->saved_write_space;
 
        if (psock->sk_proto) {
-               sk->sk_prot = psock->sk_proto;
+               struct inet_connection_sock *icsk = inet_csk(sk);
+               bool has_ulp = !!icsk->icsk_ulp_data;
+
+               if (has_ulp)
+                       tcp_update_ulp(sk, psock->sk_proto);
+               else
+                       sk->sk_prot = psock->sk_proto;
                psock->sk_proto = NULL;
        }
 }
index 45850a8391d95d50e608ca36d1dfb3554582b4f8..26e2ad2c702786781d326f01c7bb824775a82d37 100644 (file)
@@ -7320,6 +7320,21 @@ void cfg80211_pmsr_complete(struct wireless_dev *wdev,
                            struct cfg80211_pmsr_request *req,
                            gfp_t gfp);
 
+/**
+ * cfg80211_iftype_allowed - check whether the interface can be allowed
+ * @wiphy: the wiphy
+ * @iftype: interface type
+ * @is_4addr: use_4addr flag, must be '0' when check_swif is '1'
+ * @check_swif: check iftype against software interfaces
+ *
+ * Check whether the interface is allowed to operate; additionally, this API
+ * can be used to check iftype against the software interfaces when
+ * check_swif is '1'.
+ */
+bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
+                            bool is_4addr, u8 check_swif);
+
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
index 8b9ef366426256ee83943f9da05bd1c301ffbf23..cfdc7cb82cad02b12167a168d2cce13def02f0c0 100644 (file)
@@ -54,7 +54,7 @@ static inline u64 tcf_police_rate_bytes_ps(const struct tc_action *act)
        struct tcf_police *police = to_police(act);
        struct tcf_police_params *params;
 
-       params = rcu_dereference_bh(police->params);
+       params = rcu_dereference_bh_rtnl(police->params);
        return params->rate.rate_bytes_ps;
 }
 
@@ -63,7 +63,7 @@ static inline s64 tcf_police_tcfp_burst(const struct tc_action *act)
        struct tcf_police *police = to_police(act);
        struct tcf_police_params *params;
 
-       params = rcu_dereference_bh(police->params);
+       params = rcu_dereference_bh_rtnl(police->params);
        return params->tcfp_burst;
 }
 
index 0a559d4b6f0f019a872e2afad578fc3cd3d02b1b..b4fce0fae645690207be3b4cd289cf27f8578f03 100644 (file)
@@ -44,7 +44,7 @@ static inline int tcf_sample_trunc_size(const struct tc_action *a)
 static inline struct psample_group *
 tcf_sample_psample_group(const struct tc_action *a)
 {
-       return rcu_dereference(to_sample(a)->psample_group);
+       return rcu_dereference_rtnl(to_sample(a)->psample_group);
 }
 
 #endif /* __NET_TC_SAMPLE_H */
index e5cf514ba118e688ce3b3da66f696abd47e1d10f..81e8ade1e6e415779e1a18b39bd2695c9b871152 100644 (file)
@@ -2108,6 +2108,8 @@ struct tcp_ulp_ops {
 
        /* initialize ulp */
        int (*init)(struct sock *sk);
+       /* update ulp */
+       void (*update)(struct sock *sk, struct proto *p);
        /* cleanup ulp */
        void (*release)(struct sock *sk);
 
@@ -2119,6 +2121,7 @@ void tcp_unregister_ulp(struct tcp_ulp_ops *type);
 int tcp_set_ulp(struct sock *sk, const char *name);
 void tcp_get_available_ulp(char *buf, size_t len);
 void tcp_cleanup_ulp(struct sock *sk);
+void tcp_update_ulp(struct sock *sk, struct proto *p);
 
 #define MODULE_ALIAS_TCP_ULP(name)                             \
        __MODULE_INFO(alias, alias_userspace, name);            \
index 584609174fe007fbaea67da225363e2b91047c3b..41b2d41bb1b81a67731fc064c9dffa33b1c439e9 100644 (file)
@@ -107,9 +107,7 @@ struct tls_device {
 enum {
        TLS_BASE,
        TLS_SW,
-#ifdef CONFIG_TLS_DEVICE
        TLS_HW,
-#endif
        TLS_HW_RECORD,
        TLS_NUM_CONFIG,
 };
@@ -162,6 +160,7 @@ struct tls_sw_context_tx {
        int async_capable;
 
 #define BIT_TX_SCHEDULED       0
+#define BIT_TX_CLOSING         1
        unsigned long tx_bitmask;
 };
 
@@ -272,6 +271,8 @@ struct tls_context {
        unsigned long flags;
 
        /* cache cold stuff */
+       struct proto *sk_proto;
+
        void (*sk_destruct)(struct sock *sk);
        void (*sk_proto_close)(struct sock *sk, long timeout);
 
@@ -355,13 +356,17 @@ int tls_sk_attach(struct sock *sk, int optname, char __user *optval,
                  unsigned int optlen);
 
 int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx);
+void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx);
+void tls_sw_strparser_done(struct tls_context *tls_ctx);
 int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
 int tls_sw_sendpage(struct sock *sk, struct page *page,
                    int offset, size_t size, int flags);
-void tls_sw_close(struct sock *sk, long timeout);
-void tls_sw_free_resources_tx(struct sock *sk);
+void tls_sw_cancel_work_tx(struct tls_context *tls_ctx);
+void tls_sw_release_resources_tx(struct sock *sk);
+void tls_sw_free_ctx_tx(struct tls_context *tls_ctx);
 void tls_sw_free_resources_rx(struct sock *sk);
 void tls_sw_release_resources_rx(struct sock *sk);
+void tls_sw_free_ctx_rx(struct tls_context *tls_ctx);
 int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
                   int nonblock, int flags, int *addr_len);
 bool tls_sw_stream_read(const struct sock *sk);
index 2312f0ec07b2791ffaece0a95eebaefa727f14be..323f0dfc2a4e2403ca50b13fc46b74f4d44a779c 100644 (file)
@@ -1,4 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _UAPI_XT_CONNLABEL_H
+#define _UAPI_XT_CONNLABEL_H
+
 #include <linux/types.h>
 
 #define XT_CONNLABEL_MAXBIT 127
@@ -11,3 +15,5 @@ struct xt_connlabel_mtinfo {
        __u16 bit;
        __u16 options;
 };
+
+#endif /* _UAPI_XT_CONNLABEL_H */
index 8eb96021709c8c3ed15f53e7295a6c92dfe77010..c3409c8ec0ddd10de38c1a1e7742dff563ec8b71 100644 (file)
@@ -6,17 +6,24 @@
  * Desired design of maximum size and alignment (see RFC2553)
  */
 #define _K_SS_MAXSIZE  128     /* Implementation specific max size */
-#define _K_SS_ALIGNSIZE        (__alignof__ (struct sockaddr *))
-                               /* Implementation specific desired alignment */
 
 typedef unsigned short __kernel_sa_family_t;
 
+/*
+ * The definition uses anonymous union and struct in order to control the
+ * default alignment.
+ */
 struct __kernel_sockaddr_storage {
-       __kernel_sa_family_t    ss_family;              /* address family */
-       /* Following field(s) are implementation specific */
-       char            __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
+       union {
+               struct {
+                       __kernel_sa_family_t    ss_family; /* address family */
+                       /* Following field(s) are implementation specific */
+                       char __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
                                /* space to achieve desired size, */
                                /* _SS_MAXSIZE value minus size of ss_family */
-} __attribute__ ((aligned(_K_SS_ALIGNSIZE)));  /* force desired alignment */
+               };
+               void *__align; /* implementation specific desired alignment */
+       };
+};
 
 #endif /* _UAPI_LINUX_SOCKET_H */
index 5900cbb966b17adb04538e887b2f2eff658ba823..c84d83f86141f82913bd540be1fcd87bd04613f6 100644 (file)
@@ -8616,8 +8616,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
                }
 
                if (is_narrower_load && size < target_size) {
-                       u8 shift = (off & (size_default - 1)) * 8;
-
+                       u8 shift = bpf_ctx_narrow_load_shift(off, size,
+                                                            size_default);
                        if (ctx_field_size <= 4) {
                                if (shift)
                                        insn_buf[cnt++] = BPF_ALU32_IMM(BPF_RSH,
index 439d641ec79648439999bcb9a93a11cece9c4566..38045d6d05381ebb89d73369b0c60766505ef9be 100644 (file)
@@ -74,8 +74,8 @@ void dim_calc_stats(struct dim_sample *start, struct dim_sample *end,
                                        delta_us);
        curr_stats->cpms = DIV_ROUND_UP(ncomps * USEC_PER_MSEC, delta_us);
        if (curr_stats->epms != 0)
-               curr_stats->cpe_ratio =
-                               (curr_stats->cpms * 100) / curr_stats->epms;
+               curr_stats->cpe_ratio = DIV_ROUND_DOWN_ULL(
+                       curr_stats->cpms * 100, curr_stats->epms);
        else
                curr_stats->cpe_ratio = 0;
 
index 5bcc902c53888d8feb90957d0e90e5ad91e562fc..a4db51c2126633c35c3f0ee789022a3562596b80 100644 (file)
@@ -5,6 +5,62 @@
 
 #include <linux/dim.h>
 
+/*
+ * Net DIM profiles:
+ *        There are different set of profiles for each CQ period mode.
+ *        There are different set of profiles for RX/TX CQs.
+ *        Each profile size must be of NET_DIM_PARAMS_NUM_PROFILES
+ */
+#define NET_DIM_PARAMS_NUM_PROFILES 5
+#define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
+#define NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE 128
+#define NET_DIM_DEF_PROFILE_CQE 1
+#define NET_DIM_DEF_PROFILE_EQE 1
+
+#define NET_DIM_RX_EQE_PROFILES { \
+       {1,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+       {8,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+       {64,  NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+       {128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+       {256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+}
+
+#define NET_DIM_RX_CQE_PROFILES { \
+       {2,  256},             \
+       {8,  128},             \
+       {16, 64},              \
+       {32, 64},              \
+       {64, 64}               \
+}
+
+#define NET_DIM_TX_EQE_PROFILES { \
+       {1,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+       {8,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+       {32,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+       {64,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+       {128, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}   \
+}
+
+#define NET_DIM_TX_CQE_PROFILES { \
+       {5,  128},  \
+       {8,  64},  \
+       {16, 32},  \
+       {32, 32},  \
+       {64, 32}   \
+}
+
+static const struct dim_cq_moder
+rx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
+       NET_DIM_RX_EQE_PROFILES,
+       NET_DIM_RX_CQE_PROFILES,
+};
+
+static const struct dim_cq_moder
+tx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
+       NET_DIM_TX_EQE_PROFILES,
+       NET_DIM_TX_CQE_PROFILES,
+};
+
 struct dim_cq_moder
 net_dim_get_rx_moderation(u8 cq_period_mode, int ix)
 {
index d164f63a4345c5667e5190f92900d79d3d8806d8..8a8f9e5f264f2a70b246094fa7c31f1be8c0deef 100644 (file)
@@ -37,12 +37,15 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        int err;
 
        if (dev->priv_flags & IFF_EBRIDGE) {
+               err = br_vlan_bridge_event(dev, event, ptr);
+               if (err)
+                       return notifier_from_errno(err);
+
                if (event == NETDEV_REGISTER) {
                        /* register of bridge completed, add sysfs entries */
                        br_sysfs_addbr(dev);
                        return NOTIFY_DONE;
                }
-               br_vlan_bridge_event(dev, event, ptr);
        }
 
        /* not a port of a bridge */
index 3d8deac2353d045964c52981a1eaac96d6f23025..f8cac3702712028ef596ce994c7b872cc4e353d1 100644 (file)
@@ -1388,6 +1388,9 @@ br_multicast_leave_group(struct net_bridge *br,
                        if (!br_port_group_equal(p, port, src))
                                continue;
 
+                       if (p->flags & MDB_PG_FLAGS_PERMANENT)
+                               break;
+
                        rcu_assign_pointer(*pp, p->next);
                        hlist_del_init(&p->mglist);
                        del_timer(&p->timer);
index e8cf03b43b7d6c5225f6be08d285a2cbe0307fa2..646504db0220eaadf112a14a82a56f5223d264fa 100644 (file)
@@ -894,8 +894,8 @@ int nbp_get_num_vlan_infos(struct net_bridge_port *p, u32 filter_mask);
 void br_vlan_get_stats(const struct net_bridge_vlan *v,
                       struct br_vlan_stats *stats);
 void br_vlan_port_event(struct net_bridge_port *p, unsigned long event);
-void br_vlan_bridge_event(struct net_device *dev, unsigned long event,
-                         void *ptr);
+int br_vlan_bridge_event(struct net_device *dev, unsigned long event,
+                        void *ptr);
 
 static inline struct net_bridge_vlan_group *br_vlan_group(
                                        const struct net_bridge *br)
@@ -1085,9 +1085,10 @@ static inline void br_vlan_port_event(struct net_bridge_port *p,
 {
 }
 
-static inline void br_vlan_bridge_event(struct net_device *dev,
-                                       unsigned long event, void *ptr)
+static inline int br_vlan_bridge_event(struct net_device *dev,
+                                      unsigned long event, void *ptr)
 {
+       return 0;
 }
 #endif
 
index 021cc9f66804d6db567d7a139d6e68ab10798665..f5b2aeebbfe98d82a084c78be2747a14ebcbc938 100644 (file)
@@ -1053,7 +1053,6 @@ int br_vlan_init(struct net_bridge *br)
 {
        struct net_bridge_vlan_group *vg;
        int ret = -ENOMEM;
-       bool changed;
 
        vg = kzalloc(sizeof(*vg), GFP_KERNEL);
        if (!vg)
@@ -1068,17 +1067,10 @@ int br_vlan_init(struct net_bridge *br)
        br->vlan_proto = htons(ETH_P_8021Q);
        br->default_pvid = 1;
        rcu_assign_pointer(br->vlgrp, vg);
-       ret = br_vlan_add(br, 1,
-                         BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED |
-                         BRIDGE_VLAN_INFO_BRENTRY, &changed, NULL);
-       if (ret)
-               goto err_vlan_add;
 
 out:
        return ret;
 
-err_vlan_add:
-       vlan_tunnel_deinit(vg);
 err_tunnel_init:
        rhashtable_destroy(&vg->vlan_hash);
 err_rhtbl:
@@ -1464,13 +1456,23 @@ static void nbp_vlan_set_vlan_dev_state(struct net_bridge_port *p, u16 vid)
 }
 
 /* Must be protected by RTNL. */
-void br_vlan_bridge_event(struct net_device *dev, unsigned long event,
-                         void *ptr)
+int br_vlan_bridge_event(struct net_device *dev, unsigned long event, void *ptr)
 {
        struct netdev_notifier_changeupper_info *info;
-       struct net_bridge *br;
+       struct net_bridge *br = netdev_priv(dev);
+       bool changed;
+       int ret = 0;
 
        switch (event) {
+       case NETDEV_REGISTER:
+               ret = br_vlan_add(br, br->default_pvid,
+                                 BRIDGE_VLAN_INFO_PVID |
+                                 BRIDGE_VLAN_INFO_UNTAGGED |
+                                 BRIDGE_VLAN_INFO_BRENTRY, &changed, NULL);
+               break;
+       case NETDEV_UNREGISTER:
+               br_vlan_delete(br, br->default_pvid);
+               break;
        case NETDEV_CHANGEUPPER:
                info = ptr;
                br_vlan_upper_change(dev, info->upper_dev, info->linking);
@@ -1478,12 +1480,13 @@ void br_vlan_bridge_event(struct net_device *dev, unsigned long event,
 
        case NETDEV_CHANGE:
        case NETDEV_UP:
-               br = netdev_priv(dev);
                if (!br_opt_get(br, BROPT_VLAN_BRIDGE_BINDING))
-                       return;
+                       break;
                br_vlan_link_state_change(dev, br);
                break;
        }
+
+       return ret;
 }
 
 /* Must be protected by RTNL. */
index 963dfdc1482724c07ad95a0fc17750c90cbfc964..c8177a89f52c362e70e4bb617db78bb000613bd8 100644 (file)
@@ -1770,20 +1770,28 @@ static int compat_calc_entry(const struct ebt_entry *e,
        return 0;
 }
 
+static int ebt_compat_init_offsets(unsigned int number)
+{
+       if (number > INT_MAX)
+               return -EINVAL;
+
+       /* also count the base chain policies */
+       number += NF_BR_NUMHOOKS;
+
+       return xt_compat_init_offsets(NFPROTO_BRIDGE, number);
+}
 
 static int compat_table_info(const struct ebt_table_info *info,
                             struct compat_ebt_replace *newinfo)
 {
        unsigned int size = info->entries_size;
        const void *entries = info->entries;
+       int ret;
 
        newinfo->entries_size = size;
-       if (info->nentries) {
-               int ret = xt_compat_init_offsets(NFPROTO_BRIDGE,
-                                                info->nentries);
-               if (ret)
-                       return ret;
-       }
+       ret = ebt_compat_init_offsets(info->nentries);
+       if (ret)
+               return ret;
 
        return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info,
                                                        entries, newinfo);
@@ -2234,11 +2242,9 @@ static int compat_do_replace(struct net *net, void __user *user,
 
        xt_compat_lock(NFPROTO_BRIDGE);
 
-       if (tmp.nentries) {
-               ret = xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries);
-               if (ret < 0)
-                       goto out_unlock;
-       }
+       ret = ebt_compat_init_offsets(tmp.nentries);
+       if (ret < 0)
+               goto out_unlock;
 
        ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state);
        if (ret < 0)
@@ -2261,8 +2267,10 @@ static int compat_do_replace(struct net *net, void __user *user,
        state.buf_kern_len = size64;
 
        ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state);
-       if (WARN_ON(ret < 0))
+       if (WARN_ON(ret < 0)) {
+               vfree(entries_tmp);
                goto out_unlock;
+       }
 
        vfree(entries_tmp);
        tmp.entries_size = size64;
index bed66f536b34535c38e72cd5de4ea0fb6aaf2780..1804e867f7151c77284f15b3681e72728c73cc5b 100644 (file)
@@ -30,13 +30,9 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr,
        switch (priv->key) {
        case NFT_META_BRI_IIFNAME:
                br_dev = nft_meta_get_bridge(in);
-               if (!br_dev)
-                       goto err;
                break;
        case NFT_META_BRI_OIFNAME:
                br_dev = nft_meta_get_bridge(out);
-               if (!br_dev)
-                       goto err;
                break;
        case NFT_META_BRI_IIFPVID: {
                u16 p_pvid;
@@ -61,13 +57,11 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr,
                return;
        }
        default:
-               goto out;
+               return nft_meta_get_eval(expr, regs, pkt);
        }
 
-       strncpy((char *)dest, br_dev->name, IFNAMSIZ);
+       strncpy((char *)dest, br_dev ? br_dev->name : "", IFNAMSIZ);
        return;
-out:
-       return nft_meta_get_eval(expr, regs, pkt);
 err:
        regs->verdict.code = NFT_BREAK;
 }
index 5275ddf580bc7d64139e323eca15e276357bfdd1..72711053ebe66ce8231fbb79d9c37f682071be64 100644 (file)
@@ -1046,32 +1046,50 @@ static __init int cgw_module_init(void)
        pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n",
                max_hops);
 
-       register_pernet_subsys(&cangw_pernet_ops);
+       ret = register_pernet_subsys(&cangw_pernet_ops);
+       if (ret)
+               return ret;
+
+       ret = -ENOMEM;
        cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
                                      0, 0, NULL);
-
        if (!cgw_cache)
-               return -ENOMEM;
+               goto out_cache_create;
 
        /* set notifier */
        notifier.notifier_call = cgw_notifier;
-       register_netdevice_notifier(&notifier);
+       ret = register_netdevice_notifier(&notifier);
+       if (ret)
+               goto out_register_notifier;
 
        ret = rtnl_register_module(THIS_MODULE, PF_CAN, RTM_GETROUTE,
                                   NULL, cgw_dump_jobs, 0);
-       if (ret) {
-               unregister_netdevice_notifier(&notifier);
-               kmem_cache_destroy(cgw_cache);
-               return -ENOBUFS;
-       }
-
-       /* Only the first call to rtnl_register_module can fail */
-       rtnl_register_module(THIS_MODULE, PF_CAN, RTM_NEWROUTE,
-                            cgw_create_job, NULL, 0);
-       rtnl_register_module(THIS_MODULE, PF_CAN, RTM_DELROUTE,
-                            cgw_remove_job, NULL, 0);
+       if (ret)
+               goto out_rtnl_register1;
+
+       ret = rtnl_register_module(THIS_MODULE, PF_CAN, RTM_NEWROUTE,
+                                  cgw_create_job, NULL, 0);
+       if (ret)
+               goto out_rtnl_register2;
+       ret = rtnl_register_module(THIS_MODULE, PF_CAN, RTM_DELROUTE,
+                                  cgw_remove_job, NULL, 0);
+       if (ret)
+               goto out_rtnl_register3;
 
        return 0;
+
+out_rtnl_register3:
+       rtnl_unregister(PF_CAN, RTM_NEWROUTE);
+out_rtnl_register2:
+       rtnl_unregister(PF_CAN, RTM_GETROUTE);
+out_rtnl_register1:
+       unregister_netdevice_notifier(&notifier);
+out_register_notifier:
+       kmem_cache_destroy(cgw_cache);
+out_cache_create:
+       unregister_pernet_subsys(&cangw_pernet_ops);
+
+       return ret;
 }
 
 static __exit void cgw_module_exit(void)
index fc676b2610e3c1e7e236b62d4984647bc0e71916..0891f499c1bb7cdb85490a681b21895f2206bcba 100644 (file)
@@ -4374,12 +4374,17 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
 
        act = bpf_prog_run_xdp(xdp_prog, xdp);
 
+       /* check if bpf_xdp_adjust_head was used */
        off = xdp->data - orig_data;
-       if (off > 0)
-               __skb_pull(skb, off);
-       else if (off < 0)
-               __skb_push(skb, -off);
-       skb->mac_header += off;
+       if (off) {
+               if (off > 0)
+                       __skb_pull(skb, off);
+               else if (off < 0)
+                       __skb_push(skb, -off);
+
+               skb->mac_header += off;
+               skb_reset_network_header(skb);
+       }
 
        /* check if bpf_xdp_adjust_tail was used. it can only "shrink"
         * pckt.
@@ -9701,6 +9706,8 @@ static void __net_exit default_device_exit(struct net *net)
 
                /* Push remaining network devices to init_net */
                snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex);
+               if (__dev_get_by_name(&init_net, fb_name))
+                       snprintf(fb_name, IFNAMSIZ, "dev%%d");
                err = dev_change_net_namespace(dev, &init_net, fb_name);
                if (err) {
                        pr_emerg("%s: failed to move %s to init_net: %d\n",
index 4e2a79b2fd77f36ba2a31e9e43af1abc1207766e..7878f918b8c057b7b90ca0afcf2d5773cfb55e15 100644 (file)
@@ -7455,12 +7455,12 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type,
        case offsetof(struct __sk_buff, gso_segs):
                /* si->dst_reg = skb_shinfo(SKB); */
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
-               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, head),
-                                     si->dst_reg, si->src_reg,
-                                     offsetof(struct sk_buff, head));
                *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, end),
                                      BPF_REG_AX, si->src_reg,
                                      offsetof(struct sk_buff, end));
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, head),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_buff, head));
                *insn++ = BPF_ALU64_REG(BPF_ADD, si->dst_reg, BPF_REG_AX);
 #else
                *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, end),
index 93bffaad21354d4a255a973d03bc7bcdf9477432..6832eeb4b785464f873d073f5cd3b41fdf956034 100644 (file)
@@ -585,12 +585,12 @@ EXPORT_SYMBOL_GPL(sk_psock_destroy);
 
 void sk_psock_drop(struct sock *sk, struct sk_psock *psock)
 {
-       rcu_assign_sk_user_data(sk, NULL);
        sk_psock_cork_free(psock);
        sk_psock_zap_ingress(psock);
-       sk_psock_restore_proto(sk, psock);
 
        write_lock_bh(&sk->sk_callback_lock);
+       sk_psock_restore_proto(sk, psock);
+       rcu_assign_sk_user_data(sk, NULL);
        if (psock->progs.skb_parser)
                sk_psock_stop_strp(sk, psock);
        write_unlock_bh(&sk->sk_callback_lock);
index 52d4faeee18b0cecc8432ee71db16efb852b8644..1330a7442e5b1e54d80d0b675f7356742bcdfbec 100644 (file)
@@ -247,6 +247,8 @@ static void sock_map_free(struct bpf_map *map)
        raw_spin_unlock_bh(&stab->lock);
        rcu_read_unlock();
 
+       synchronize_rcu();
+
        bpf_map_area_free(stab->sks);
        kfree(stab);
 }
@@ -276,16 +278,20 @@ static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test,
                             struct sock **psk)
 {
        struct sock *sk;
+       int err = 0;
 
        raw_spin_lock_bh(&stab->lock);
        sk = *psk;
        if (!sk_test || sk_test == sk)
-               *psk = NULL;
+               sk = xchg(psk, NULL);
+
+       if (likely(sk))
+               sock_map_unref(sk, psk);
+       else
+               err = -EINVAL;
+
        raw_spin_unlock_bh(&stab->lock);
-       if (unlikely(!sk))
-               return -EINVAL;
-       sock_map_unref(sk, psk);
-       return 0;
+       return err;
 }
 
 static void sock_map_delete_from_link(struct bpf_map *map, struct sock *sk,
@@ -328,6 +334,7 @@ static int sock_map_update_common(struct bpf_map *map, u32 idx,
                                  struct sock *sk, u64 flags)
 {
        struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct sk_psock_link *link;
        struct sk_psock *psock;
        struct sock *osk;
@@ -338,6 +345,8 @@ static int sock_map_update_common(struct bpf_map *map, u32 idx,
                return -EINVAL;
        if (unlikely(idx >= map->max_entries))
                return -E2BIG;
+       if (unlikely(icsk->icsk_ulp_data))
+               return -EINVAL;
 
        link = sk_psock_init_link();
        if (!link)
index 26363d72d25b35377bf844466b10e2844cbb70f6..47ee88163a9daede6494af72025d2f86974d167b 100644 (file)
@@ -165,6 +165,7 @@ static struct sk_buff
                                            "Expected meta frame, is %12llx "
                                            "in the DSA master multicast filter?\n",
                                            SJA1105_META_DMAC);
+                       kfree_skb(sp->data->stampable_skb);
                }
 
                /* Hold a reference to avoid dsa_switch_rcv
@@ -211,17 +212,8 @@ static struct sk_buff
                 * for further processing up the network stack.
                 */
                kfree_skb(skb);
-
-               skb = skb_copy(stampable_skb, GFP_ATOMIC);
-               if (!skb) {
-                       dev_err_ratelimited(dp->ds->dev,
-                                           "Failed to copy stampable skb\n");
-                       spin_unlock(&sp->data->meta_lock);
-                       return NULL;
-               }
+               skb = stampable_skb;
                sja1105_transfer_meta(skb, meta);
-               /* The cached copy will be freed now */
-               skb_unref(stampable_skb);
 
                spin_unlock(&sp->data->meta_lock);
        }
index d666756be5f18404ce8e85a95e9f09636d5f2694..a999451345f9805a195915dc2c55a9db31a51002 100644 (file)
@@ -331,7 +331,7 @@ struct inet_frag_queue *inet_frag_find(struct fqdir *fqdir, void *key)
        prev = rhashtable_lookup(&fqdir->rhashtable, key, fqdir->f->rhash_params);
        if (!prev)
                fq = inet_frag_create(fqdir, key, &prev);
-       if (prev && !IS_ERR(prev)) {
+       if (!IS_ERR_OR_NULL(prev)) {
                fq = prev;
                if (!refcount_inc_not_zero(&fq->refcnt))
                        fq = NULL;
index 43adfc1641bacac2df882970e1eafca318896041..2f01cf6fa0deffb6f86a4db89b0aa8b951d0f352 100644 (file)
@@ -275,6 +275,9 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
        const struct iphdr  *tiph = &tunnel->parms.iph;
        u8 ipproto;
 
+       if (!pskb_inet_may_pull(skb))
+               goto tx_error;
+
        switch (skb->protocol) {
        case htons(ETH_P_IP):
                ipproto = IPPROTO_IPIP;
index 3d8a1d8354719378ef157e36dbe21c57af9a4b7c..4849edb62d52964c61ef2d0601c16baa662e196d 100644 (file)
@@ -96,6 +96,19 @@ void tcp_get_available_ulp(char *buf, size_t maxlen)
        rcu_read_unlock();
 }
 
+void tcp_update_ulp(struct sock *sk, struct proto *proto)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (!icsk->icsk_ulp_ops) {
+               sk->sk_prot = proto;
+               return;
+       }
+
+       if (icsk->icsk_ulp_ops->update)
+               icsk->icsk_ulp_ops->update(sk, proto);
+}
+
 void tcp_cleanup_ulp(struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
index c2049c72f3e533a7077674ca6dac43b527eb8b7f..dd2d0b96326074d3255eee91891938dc1d948483 100644 (file)
@@ -660,12 +660,13 @@ static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb,
                                    struct flowi6 *fl6, __u8 *dsfield,
                                    int *encap_limit)
 {
-       struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+       struct ipv6hdr *ipv6h;
        struct ip6_tnl *t = netdev_priv(dev);
        __u16 offset;
 
        offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
        /* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */
+       ipv6h = ipv6_hdr(skb);
 
        if (offset > 0) {
                struct ipv6_tlv_tnl_enc_lim *tel;
index 3134fbb65d7f268d2b8785b3feb622a36c2d15c3..754a484d35df6eb03b82593cbb66a78718e30326 100644 (file)
@@ -1278,12 +1278,11 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
+       dsfield = INET_ECN_encapsulate(dsfield, ipv4_get_dsfield(iph));
 
        if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
                return -1;
 
-       dsfield = INET_ECN_encapsulate(dsfield, ipv4_get_dsfield(iph));
-
        skb_set_inner_ipproto(skb, IPPROTO_IPIP);
 
        err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
@@ -1367,12 +1366,11 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
+       dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h));
 
        if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
                return -1;
 
-       dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h));
-
        skb_set_inner_ipproto(skb, IPPROTO_IPV6);
 
        err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
index e49fec767a10af5f6f03983f10cdf9d9f626ed3e..fd059e08785abb0d06320da870ffe8dd9499f8f9 100644 (file)
@@ -1951,7 +1951,7 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
                nexthop_for_each_fib6_nh(from->nh, fib6_nh_find_match, &arg);
 
                if (!arg.match)
-                       return;
+                       goto unlock;
                fib6_nh = arg.match;
        } else {
                fib6_nh = from->fib6_nh;
index 09e1694b6d341a5f1cf81e49643f9267ac4033c4..ebb62a4ebe30d3bd6347f72711b23655cddc00c5 100644 (file)
@@ -512,7 +512,9 @@ static void iucv_sock_close(struct sock *sk)
                        sk->sk_state = IUCV_DISCONN;
                        sk->sk_state_change(sk);
                }
-       case IUCV_DISCONN:   /* fall through */
+               /* fall through */
+
+       case IUCV_DISCONN:
                sk->sk_state = IUCV_CLOSING;
                sk->sk_state_change(sk);
 
@@ -525,8 +527,9 @@ static void iucv_sock_close(struct sock *sk)
                                        iucv_sock_in_state(sk, IUCV_CLOSED, 0),
                                        timeo);
                }
+               /* fall through */
 
-       case IUCV_CLOSING:   /* fall through */
+       case IUCV_CLOSING:
                sk->sk_state = IUCV_CLOSED;
                sk->sk_state_change(sk);
 
@@ -535,8 +538,9 @@ static void iucv_sock_close(struct sock *sk)
 
                skb_queue_purge(&iucv->send_skb_q);
                skb_queue_purge(&iucv->backlog_skb_q);
+               /* fall through */
 
-       default:   /* fall through */
+       default:
                iucv_sever_path(sk, 1);
        }
 
@@ -2247,10 +2251,10 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
                        kfree_skb(skb);
                        break;
                }
-               /* fall through and receive non-zero length data */
+               /* fall through and receive non-zero length data */
        case (AF_IUCV_FLAG_SHT):
                /* shutdown request */
-               /* fall through and receive zero length data */
+               /* fall through and receive zero length data */
        case 0:
                /* plain data frame */
                IUCV_SKB_CB(skb)->class = trans_hdr->iucv_hdr.class;
index 1d0e5904dedf0bd180f2cd56400ac0da2038c0dd..c54cb59593ef8133c74bd30b771eb020573a27e2 100644 (file)
@@ -1681,6 +1681,9 @@ static const struct proto_ops pppol2tp_ops = {
        .recvmsg        = pppol2tp_recvmsg,
        .mmap           = sock_no_mmap,
        .ioctl          = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = pppox_compat_ioctl,
+#endif
 };
 
 static const struct pppox_proto pppol2tp_proto = {
index 06aac0aaae646cda1f3bca4aab7363922225be58..8dc6580e17871c4f8095079b226d18e1a41d51a5 100644 (file)
@@ -1222,7 +1222,6 @@ static void ieee80211_if_setup(struct net_device *dev)
 static void ieee80211_if_setup_no_queue(struct net_device *dev)
 {
        ieee80211_if_setup(dev);
-       dev->features |= NETIF_F_LLTX;
        dev->priv_flags |= IFF_NO_QUEUE;
 }
 
index a99ad032530946fd8c5d82cfd799ba598284e10d..4c888dc9bd8133eb0025ae919aa98ab002904740 100644 (file)
@@ -2042,6 +2042,16 @@ ieee80211_sta_wmm_params(struct ieee80211_local *local,
                ieee80211_regulatory_limit_wmm_params(sdata, &params[ac], ac);
        }
 
+       /* WMM specification requires all 4 ACIs. */
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               if (params[ac].cw_min == 0) {
+                       sdata_info(sdata,
+                                  "AP has invalid WMM params (missing AC %d), using defaults\n",
+                                  ac);
+                       return false;
+               }
+       }
+
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
                mlme_dbg(sdata,
                         "WMM AC=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
index 1b224fa27367fbf4ce7cc7385eb27f8051081704..ad1e58184c4e4581dd111c506f0fe19a72aa6810 100644 (file)
@@ -3796,9 +3796,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
        }
 
        /* Always allow software iftypes */
-       if (local->hw.wiphy->software_iftypes & BIT(iftype) ||
-           (iftype == NL80211_IFTYPE_AP_VLAN &&
-            local->hw.wiphy->flags & WIPHY_FLAG_4ADDR_AP)) {
+       if (cfg80211_iftype_allowed(local->hw.wiphy, iftype, 0, 1)) {
                if (radar_detect)
                        return -EINVAL;
                return 0;
@@ -3833,7 +3831,8 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 
                if (sdata_iter == sdata ||
                    !ieee80211_sdata_running(sdata_iter) ||
-                   local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
+                   cfg80211_iftype_allowed(local->hw.wiphy,
+                                           wdev_iter->iftype, 0, 1))
                        continue;
 
                params.iftype_num[wdev_iter->iftype]++;
index ca7ac4a25ada2f1527175f03d204d90bedfea7ba..1d4e63326e68c1fe68d2e8542c8bbb4b29b2d859 100644 (file)
@@ -226,7 +226,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
 
        e.id = ip_to_id(map, ip);
 
-       if (opt->flags & IPSET_DIM_ONE_SRC)
+       if (opt->flags & IPSET_DIM_TWO_SRC)
                ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
        else
                ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
index 2e151856ad9992f1ec338f8fd6bed53b98c30be4..e64d5f9a89dd331e48ddf38af1c9978d2507a958 100644 (file)
@@ -1161,7 +1161,7 @@ static int ip_set_rename(struct net *net, struct sock *ctnl,
                return -ENOENT;
 
        write_lock_bh(&ip_set_ref_lock);
-       if (set->ref != 0) {
+       if (set->ref != 0 || set->ref_netlink != 0) {
                ret = -IPSET_ERR_REFERENCED;
                goto out;
        }
index faf59b6a998fecf50c191321d5605d5c5b460dc4..24d8f4df4230ca573098fbcdc83baadfd855e094 100644 (file)
@@ -89,15 +89,11 @@ hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb,
        struct hash_ipmac4_elem e = { .ip = 0, { .foo[0] = 0, .foo[1] = 0 } };
        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 
-        /* MAC can be src only */
-       if (!(opt->flags & IPSET_DIM_TWO_SRC))
-               return 0;
-
        if (skb_mac_header(skb) < skb->head ||
            (skb_mac_header(skb) + ETH_HLEN) > skb->data)
                return -EINVAL;
 
-       if (opt->flags & IPSET_DIM_ONE_SRC)
+       if (opt->flags & IPSET_DIM_TWO_SRC)
                ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
        else
                ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
index f1b1d948c07b431ea2bb6fe1ca5a024e4a1bc539..f69afb9ff3cbe04a5b36d9aef3964fb2e6962926 100644 (file)
@@ -60,24 +60,16 @@ void nft_meta_get_eval(const struct nft_expr *expr,
                *dest = skb->mark;
                break;
        case NFT_META_IIF:
-               if (in == NULL)
-                       goto err;
-               *dest = in->ifindex;
+               *dest = in ? in->ifindex : 0;
                break;
        case NFT_META_OIF:
-               if (out == NULL)
-                       goto err;
-               *dest = out->ifindex;
+               *dest = out ? out->ifindex : 0;
                break;
        case NFT_META_IIFNAME:
-               if (in == NULL)
-                       goto err;
-               strncpy((char *)dest, in->name, IFNAMSIZ);
+               strncpy((char *)dest, in ? in->name : "", IFNAMSIZ);
                break;
        case NFT_META_OIFNAME:
-               if (out == NULL)
-                       goto err;
-               strncpy((char *)dest, out->name, IFNAMSIZ);
+               strncpy((char *)dest, out ? out->name : "", IFNAMSIZ);
                break;
        case NFT_META_IIFTYPE:
                if (in == NULL)
index 96740d389377170b90a5d3d2dba3482bd293eb9a..c4f54ad2b98afb44002415ce1daf2afef646d8c0 100644 (file)
@@ -967,6 +967,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
 
        window = skb->data[20];
 
+       sock_hold(make);
        skb->sk             = make;
        skb->destructor     = sock_efree;
        make->sk_state      = TCP_ESTABLISHED;
index 892287d06c1768d3f16b029859f344c560984ff1..d01410e520979dd4a05336568f80dd6e0362bd93 100644 (file)
@@ -1047,7 +1047,7 @@ error:
 }
 
 /* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */
-static struct sw_flow_actions *get_flow_actions(struct net *net,
+static noinline_for_stack struct sw_flow_actions *get_flow_actions(struct net *net,
                                                const struct nlattr *a,
                                                const struct sw_flow_key *key,
                                                const struct sw_flow_mask *mask,
@@ -1081,12 +1081,13 @@ static struct sw_flow_actions *get_flow_actions(struct net *net,
  * we should not to return match object with dangling reference
  * to mask.
  * */
-static int ovs_nla_init_match_and_action(struct net *net,
-                                        struct sw_flow_match *match,
-                                        struct sw_flow_key *key,
-                                        struct nlattr **a,
-                                        struct sw_flow_actions **acts,
-                                        bool log)
+static noinline_for_stack int
+ovs_nla_init_match_and_action(struct net *net,
+                             struct sw_flow_match *match,
+                             struct sw_flow_key *key,
+                             struct nlattr **a,
+                             struct sw_flow_actions **acts,
+                             bool log)
 {
        struct sw_flow_mask mask;
        int error = 0;
index ff74c4bbb9fc883f4107432c11a47f3d6f840137..9986d6065c4d1f357f021700351866d0ebe4f8a2 100644 (file)
@@ -105,7 +105,8 @@ static int rds_rdma_cm_event_handler_cmn(struct rdma_cm_id *cm_id,
                break;
 
        case RDMA_CM_EVENT_ESTABLISHED:
-               trans->cm_connect_complete(conn, event);
+               if (conn)
+                       trans->cm_connect_complete(conn, event);
                break;
 
        case RDMA_CM_EVENT_REJECTED:
@@ -137,6 +138,8 @@ static int rds_rdma_cm_event_handler_cmn(struct rdma_cm_id *cm_id,
                break;
 
        case RDMA_CM_EVENT_DISCONNECTED:
+               if (!conn)
+                       break;
                rdsdebug("DISCONNECT event - dropping connection "
                         "%pI6c->%pI6c\n", &conn->c_laddr,
                         &conn->c_faddr);
index 80335b4ee4fd6c2b1ae39bed5b9089e35c292b84..822f45386e31169378157fa09530fa258ec6577d 100644 (file)
@@ -1061,6 +1061,7 @@ void rxrpc_destroy_all_peers(struct rxrpc_net *);
 struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *);
 struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *);
 void rxrpc_put_peer(struct rxrpc_peer *);
+void rxrpc_put_peer_locked(struct rxrpc_peer *);
 
 /*
  * proc.c
index 9f2f45c09e58353d11e1b8abc9345209a92dc726..7666ec72d37e5e5e8971ca288749738ba324c64a 100644 (file)
@@ -378,7 +378,7 @@ static void rxrpc_peer_keepalive_dispatch(struct rxrpc_net *rxnet,
                spin_lock_bh(&rxnet->peer_hash_lock);
                list_add_tail(&peer->keepalive_link,
                              &rxnet->peer_keepalive[slot & mask]);
-               rxrpc_put_peer(peer);
+               rxrpc_put_peer_locked(peer);
        }
 
        spin_unlock_bh(&rxnet->peer_hash_lock);
index 9d3ce81cf8ae899cd38c92a493b700d4d152f50a..9c3ac96f71cbf8202ccdeca3af388ad8a2ae08b3 100644 (file)
@@ -436,6 +436,24 @@ void rxrpc_put_peer(struct rxrpc_peer *peer)
        }
 }
 
+/*
+ * Drop a ref on a peer record where the caller already holds the
+ * peer_hash_lock.
+ */
+void rxrpc_put_peer_locked(struct rxrpc_peer *peer)
+{
+       const void *here = __builtin_return_address(0);
+       int n;
+
+       n = atomic_dec_return(&peer->usage);
+       trace_rxrpc_peer(peer, rxrpc_peer_put, n, here);
+       if (n == 0) {
+               hash_del_rcu(&peer->hash_link);
+               list_del_init(&peer->keepalive_link);
+               kfree_rcu(peer, rcu);
+       }
+}
+
 /*
  * Make sure all peer records have been discarded.
  */
index 5d3f33ce6d4100070dd348edc2018167fce921d3..bae14438f86918a8ccf1e2df82071d3a9dba7f18 100644 (file)
@@ -226,6 +226,7 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
                        rxrpc_set_call_completion(call,
                                                  RXRPC_CALL_LOCAL_ERROR,
                                                  0, ret);
+                       rxrpc_notify_socket(call);
                        goto out;
                }
                _debug("need instant resend %d", ret);
index 8126b26f125e019e3b5a16b632e2f7414498bfe4..fd1f7e799e23e04337eaee35aef5dfb03d43563e 100644 (file)
@@ -285,6 +285,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
        struct tcf_bpf *prog;
        bool is_bpf, is_ebpf;
        int ret, res = 0;
+       u32 index;
 
        if (!nla)
                return -EINVAL;
@@ -298,13 +299,13 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
                return -EINVAL;
 
        parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
-
-       ret = tcf_idr_check_alloc(tn, &parm->index, act, bind);
+       index = parm->index;
+       ret = tcf_idr_check_alloc(tn, &index, act, bind);
        if (!ret) {
-               ret = tcf_idr_create(tn, parm->index, est, act,
+               ret = tcf_idr_create(tn, index, est, act,
                                     &act_bpf_ops, bind, true);
                if (ret < 0) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
 
index ce36b0f7e1dc15379319858d5e5891d3417ca061..32ac04d77a455a845e61d89ec9d646d3e886b155 100644 (file)
@@ -103,6 +103,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
        struct tcf_connmark_info *ci;
        struct tc_connmark *parm;
        int ret = 0, err;
+       u32 index;
 
        if (!nla)
                return -EINVAL;
@@ -116,13 +117,13 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
                return -EINVAL;
 
        parm = nla_data(tb[TCA_CONNMARK_PARMS]);
-
-       ret = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       ret = tcf_idr_check_alloc(tn, &index, a, bind);
        if (!ret) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_connmark_ops, bind, false);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
 
index 621fb22ce2a9297f6cab5fd1d675cc2fdd63aa73..9b9288267a545627474a9909018f6a3e9f625930 100644 (file)
@@ -52,6 +52,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
        struct tc_csum *parm;
        struct tcf_csum *p;
        int ret = 0, err;
+       u32 index;
 
        if (nla == NULL)
                return -EINVAL;
@@ -64,13 +65,13 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
        if (tb[TCA_CSUM_PARMS] == NULL)
                return -EINVAL;
        parm = nla_data(tb[TCA_CSUM_PARMS]);
-
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (!err) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_csum_ops, bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
                ret = ACT_P_CREATED;
index b501ce0cf11675c04c7840cb1d8d0b3ad5029498..33a1a7406e87feb2735f9acde1b9a76f7304bec5 100644 (file)
@@ -666,6 +666,7 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
        struct tc_ct *parm;
        struct tcf_ct *c;
        int err, res = 0;
+       u32 index;
 
        if (!nla) {
                NL_SET_ERR_MSG_MOD(extack, "Ct requires attributes to be passed");
@@ -681,16 +682,16 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
                return -EINVAL;
        }
        parm = nla_data(tb[TCA_CT_PARMS]);
-
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
 
        if (!err) {
-               err = tcf_idr_create(tn, parm->index, est, a,
+               err = tcf_idr_create(tn, index, est, a,
                                     &act_ct_ops, bind, true);
                if (err) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return err;
                }
                res = ACT_P_CREATED;
index 10eb2bb998617b38a71764aa307f024a7436f018..06ef74b74911cea631af5f12d8dba6fb9c13cf46 100644 (file)
@@ -157,10 +157,10 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
                           struct netlink_ext_ack *extack)
 {
        struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
+       u32 dscpmask = 0, dscpstatemask, index;
        struct nlattr *tb[TCA_CTINFO_MAX + 1];
        struct tcf_ctinfo_params *cp_new;
        struct tcf_chain *goto_ch = NULL;
-       u32 dscpmask = 0, dscpstatemask;
        struct tc_ctinfo *actparm;
        struct tcf_ctinfo *ci;
        u8 dscpmaskshift;
@@ -206,12 +206,13 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
        }
 
        /* done the validation:now to the actual action allocation */
-       err = tcf_idr_check_alloc(tn, &actparm->index, a, bind);
+       index = actparm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (!err) {
-               ret = tcf_idr_create(tn, actparm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_ctinfo_ops, bind, false);
                if (ret) {
-                       tcf_idr_cleanup(tn, actparm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
                ret = ACT_P_CREATED;
index b2380c5284e6f5fbcdbb6a5f9a8e9f6b0ddc7394..8f0140c6ca58b6b0c6645f48b4f093c21c471dd6 100644 (file)
@@ -61,6 +61,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
        struct tc_gact *parm;
        struct tcf_gact *gact;
        int ret = 0;
+       u32 index;
        int err;
 #ifdef CONFIG_GACT_PROB
        struct tc_gact_p *p_parm = NULL;
@@ -77,6 +78,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
        if (tb[TCA_GACT_PARMS] == NULL)
                return -EINVAL;
        parm = nla_data(tb[TCA_GACT_PARMS]);
+       index = parm->index;
 
 #ifndef CONFIG_GACT_PROB
        if (tb[TCA_GACT_PROB] != NULL)
@@ -94,12 +96,12 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
        }
 #endif
 
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (!err) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_gact_ops, bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
                ret = ACT_P_CREATED;
index 41d5398dd2f2ee79bc9fc203df86846bdce0f3a7..92ee853d43e6c5f71d4ed635cc0043eb761358a9 100644 (file)
@@ -479,8 +479,14 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
        u8 *saddr = NULL;
        bool exists = false;
        int ret = 0;
+       u32 index;
        int err;
 
+       if (!nla) {
+               NL_SET_ERR_MSG_MOD(extack, "IFE requires attributes to be passed");
+               return -EINVAL;
+       }
+
        err = nla_parse_nested_deprecated(tb, TCA_IFE_MAX, nla, ife_policy,
                                          NULL);
        if (err < 0)
@@ -502,7 +508,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
        if (!p)
                return -ENOMEM;
 
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0) {
                kfree(p);
                return err;
@@ -514,10 +521,10 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
        }
 
        if (!exists) {
-               ret = tcf_idr_create(tn, parm->index, est, a, &act_ife_ops,
+               ret = tcf_idr_create(tn, index, est, a, &act_ife_ops,
                                     bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        kfree(p);
                        return ret;
                }
index 055faa298c8e90f5c9029735fa411d06308f5d10..be3f88dfc37eb735a7f76728c525fad88d22c83a 100644 (file)
@@ -104,6 +104,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
        struct net_device *dev;
        bool exists = false;
        int ret, err;
+       u32 index;
 
        if (!nla) {
                NL_SET_ERR_MSG_MOD(extack, "Mirred requires attributes to be passed");
@@ -118,8 +119,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                return -EINVAL;
        }
        parm = nla_data(tb[TCA_MIRRED_PARMS]);
-
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
        exists = err;
@@ -136,21 +137,21 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                if (exists)
                        tcf_idr_release(*a, bind);
                else
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                NL_SET_ERR_MSG_MOD(extack, "Unknown mirred option");
                return -EINVAL;
        }
 
        if (!exists) {
                if (!parm->ifindex) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist");
                        return -EINVAL;
                }
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_mirred_ops, bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
                ret = ACT_P_CREATED;
index ca2597ce4ac9d9296e7c76ec2d9851310bf38004..0f299e3b618cbae1f4794cd8e7230437d974ead9 100644 (file)
@@ -138,6 +138,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
        struct tcf_mpls *m;
        int ret = 0, err;
        u8 mpls_ttl = 0;
+       u32 index;
 
        if (!nla) {
                NL_SET_ERR_MSG_MOD(extack, "Missing netlink attributes");
@@ -153,6 +154,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
                return -EINVAL;
        }
        parm = nla_data(tb[TCA_MPLS_PARMS]);
+       index = parm->index;
 
        /* Verify parameters against action type. */
        switch (parm->m_action) {
@@ -209,7 +211,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
                return -EINVAL;
        }
 
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
        exists = err;
@@ -217,10 +219,10 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
                return 0;
 
        if (!exists) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_mpls_ops, bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
 
index 45923ebb7a4fa3c103111b128274058ea088bee5..7b858c11b1b5ffd34f57706ee5631229b45f65a3 100644 (file)
@@ -44,6 +44,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        struct tc_nat *parm;
        int ret = 0, err;
        struct tcf_nat *p;
+       u32 index;
 
        if (nla == NULL)
                return -EINVAL;
@@ -56,13 +57,13 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        if (tb[TCA_NAT_PARMS] == NULL)
                return -EINVAL;
        parm = nla_data(tb[TCA_NAT_PARMS]);
-
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (!err) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_nat_ops, bind, false);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
                ret = ACT_P_CREATED;
index 45e9d6bfddb3df539d9b76e7cc72e8e5e6b71e8a..17360c6faeaac184a59ef82fa2e909885b83fa84 100644 (file)
@@ -149,6 +149,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
        struct tcf_pedit *p;
        int ret = 0, err;
        int ksize;
+       u32 index;
 
        if (!nla) {
                NL_SET_ERR_MSG_MOD(extack, "Pedit requires attributes to be passed");
@@ -179,18 +180,19 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
        if (IS_ERR(keys_ex))
                return PTR_ERR(keys_ex);
 
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (!err) {
                if (!parm->nkeys) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed");
                        ret = -EINVAL;
                        goto out_free;
                }
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_pedit_ops, bind, false);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        goto out_free;
                }
                ret = ACT_P_CREATED;
index a065f62fa79c04e10442d870e6bb29523d216f36..49cec3e64a4d5b15b781151715347cccff1833ca 100644 (file)
@@ -57,6 +57,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
        struct tc_action_net *tn = net_generic(net, police_net_id);
        struct tcf_police_params *new;
        bool exists = false;
+       u32 index;
 
        if (nla == NULL)
                return -EINVAL;
@@ -73,7 +74,8 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
                return -EINVAL;
 
        parm = nla_data(tb[TCA_POLICE_TBF]);
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
        exists = err;
@@ -81,10 +83,10 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
                return 0;
 
        if (!exists) {
-               ret = tcf_idr_create(tn, parm->index, NULL, a,
+               ret = tcf_idr_create(tn, index, NULL, a,
                                     &act_police_ops, bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
                ret = ACT_P_CREATED;
index 274d7a0c0e25c91186b5513715f7b87534d6476d..595308d60133d4428d385d34429d692af3f8c747 100644 (file)
@@ -41,8 +41,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
        struct tc_action_net *tn = net_generic(net, sample_net_id);
        struct nlattr *tb[TCA_SAMPLE_MAX + 1];
        struct psample_group *psample_group;
+       u32 psample_group_num, rate, index;
        struct tcf_chain *goto_ch = NULL;
-       u32 psample_group_num, rate;
        struct tc_sample *parm;
        struct tcf_sample *s;
        bool exists = false;
@@ -59,8 +59,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
                return -EINVAL;
 
        parm = nla_data(tb[TCA_SAMPLE_PARMS]);
-
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
        exists = err;
@@ -68,10 +68,10 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
                return 0;
 
        if (!exists) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_sample_ops, bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
                ret = ACT_P_CREATED;
index f28ddbabff7604373bd9374fa283c07f9b3c01ed..33aefa25b545e4032c0058b633aaaf74a88cf70e 100644 (file)
@@ -95,6 +95,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
        struct tcf_defact *d;
        bool exists = false;
        int ret = 0, err;
+       u32 index;
 
        if (nla == NULL)
                return -EINVAL;
@@ -108,7 +109,8 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
                return -EINVAL;
 
        parm = nla_data(tb[TCA_DEF_PARMS]);
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
        exists = err;
@@ -119,15 +121,15 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
                if (exists)
                        tcf_idr_release(*a, bind);
                else
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                return -EINVAL;
        }
 
        if (!exists) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_simp_ops, bind, false);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
 
index 215a06705cef71d501faa5ecb3a97fbb2f51bfe7..b100870f02a6d802ef0877d5dde19380a25130d5 100644 (file)
@@ -99,6 +99,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
        u16 *queue_mapping = NULL, *ptype = NULL;
        bool exists = false;
        int ret = 0, err;
+       u32 index;
 
        if (nla == NULL)
                return -EINVAL;
@@ -146,8 +147,8 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
        }
 
        parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
-
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
        exists = err;
@@ -158,15 +159,15 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
                if (exists)
                        tcf_idr_release(*a, bind);
                else
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                return -EINVAL;
        }
 
        if (!exists) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_skbedit_ops, bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
 
index 4f07706eff07ec7790c3bee295b893f1f2e6f720..7da3518e18efb709f81d9435d6fe66411b8a270a 100644 (file)
@@ -87,12 +87,12 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
        struct tcf_skbmod_params *p, *p_old;
        struct tcf_chain *goto_ch = NULL;
        struct tc_skbmod *parm;
+       u32 lflags = 0, index;
        struct tcf_skbmod *d;
        bool exists = false;
        u8 *daddr = NULL;
        u8 *saddr = NULL;
        u16 eth_type = 0;
-       u32 lflags = 0;
        int ret = 0, err;
 
        if (!nla)
@@ -122,10 +122,11 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
        }
 
        parm = nla_data(tb[TCA_SKBMOD_PARMS]);
+       index = parm->index;
        if (parm->flags & SKBMOD_F_SWAPMAC)
                lflags = SKBMOD_F_SWAPMAC;
 
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
        exists = err;
@@ -136,15 +137,15 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
                if (exists)
                        tcf_idr_release(*a, bind);
                else
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                return -EINVAL;
        }
 
        if (!exists) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_skbmod_ops, bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
 
index 10dffda1d5cc4d9d0236efaf713502a6367c1f92..6d0debdc9b972631ee2f53a1745e8fe0d8d5d126 100644 (file)
@@ -225,6 +225,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
        __be16 flags = 0;
        u8 tos, ttl;
        int ret = 0;
+       u32 index;
        int err;
 
        if (!nla) {
@@ -245,7 +246,8 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
        }
 
        parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]);
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
        exists = err;
@@ -345,7 +347,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
        }
 
        if (!exists) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_tunnel_key_ops, bind, true);
                if (ret) {
                        NL_SET_ERR_MSG(extack, "Cannot create TC IDR");
@@ -403,7 +405,7 @@ err_out:
        if (exists)
                tcf_idr_release(*a, bind);
        else
-               tcf_idr_cleanup(tn, parm->index);
+               tcf_idr_cleanup(tn, index);
        return ret;
 }
 
index 9269d350fb8aa0ae525cd89fa8d855b9be280731..a3c9eea1ee8ac720311a8c88994a08a4a01d2bcb 100644 (file)
@@ -116,6 +116,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
        u8 push_prio = 0;
        bool exists = false;
        int ret = 0, err;
+       u32 index;
 
        if (!nla)
                return -EINVAL;
@@ -128,7 +129,8 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
        if (!tb[TCA_VLAN_PARMS])
                return -EINVAL;
        parm = nla_data(tb[TCA_VLAN_PARMS]);
-       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       index = parm->index;
+       err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0)
                return err;
        exists = err;
@@ -144,7 +146,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
                        if (exists)
                                tcf_idr_release(*a, bind);
                        else
-                               tcf_idr_cleanup(tn, parm->index);
+                               tcf_idr_cleanup(tn, index);
                        return -EINVAL;
                }
                push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
@@ -152,7 +154,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
                        if (exists)
                                tcf_idr_release(*a, bind);
                        else
-                               tcf_idr_cleanup(tn, parm->index);
+                               tcf_idr_cleanup(tn, index);
                        return -ERANGE;
                }
 
@@ -166,7 +168,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
                                if (exists)
                                        tcf_idr_release(*a, bind);
                                else
-                                       tcf_idr_cleanup(tn, parm->index);
+                                       tcf_idr_cleanup(tn, index);
                                return -EPROTONOSUPPORT;
                        }
                } else {
@@ -180,16 +182,16 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
                if (exists)
                        tcf_idr_release(*a, bind);
                else
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                return -EINVAL;
        }
        action = parm->v_action;
 
        if (!exists) {
-               ret = tcf_idr_create(tn, parm->index, est, a,
+               ret = tcf_idr_create(tn, index, est, a,
                                     &act_vlan_ops, bind, true);
                if (ret) {
-                       tcf_idr_cleanup(tn, parm->index);
+                       tcf_idr_cleanup(tn, index);
                        return ret;
                }
 
@@ -306,6 +308,14 @@ static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index)
        return tcf_idr_search(tn, a, index);
 }
 
+static size_t tcf_vlan_get_fill_size(const struct tc_action *act)
+{
+       return nla_total_size(sizeof(struct tc_vlan))
+               + nla_total_size(sizeof(u16)) /* TCA_VLAN_PUSH_VLAN_ID */
+               + nla_total_size(sizeof(u16)) /* TCA_VLAN_PUSH_VLAN_PROTOCOL */
+               + nla_total_size(sizeof(u8)); /* TCA_VLAN_PUSH_VLAN_PRIORITY */
+}
+
 static struct tc_action_ops act_vlan_ops = {
        .kind           =       "vlan",
        .id             =       TCA_ID_VLAN,
@@ -315,6 +325,7 @@ static struct tc_action_ops act_vlan_ops = {
        .init           =       tcf_vlan_init,
        .cleanup        =       tcf_vlan_cleanup,
        .walk           =       tcf_vlan_walker,
+       .get_fill_size  =       tcf_vlan_get_fill_size,
        .lookup         =       tcf_vlan_search,
        .size           =       sizeof(struct tcf_vlan),
 };
index 25ef172c23dfa31d05729c76a58ade3bb4967d5e..30169b3adbbb064c51b6006755d56446570f974c 100644 (file)
@@ -71,10 +71,10 @@ static struct sk_buff *dequeue_func(struct codel_vars *vars, void *ctx)
        struct Qdisc *sch = ctx;
        struct sk_buff *skb = __qdisc_dequeue_head(&sch->q);
 
-       if (skb)
+       if (skb) {
                sch->qstats.backlog -= qdisc_pkt_len(skb);
-
-       prefetch(&skb->end); /* we'll need skb_shinfo() */
+               prefetch(&skb->end); /* we'll need skb_shinfo() */
+       }
        return skb;
 }
 
index aa80cda3658116b94081f4700c28b8cb03fd2de6..9d1f83b10c0a6c5ab0ca2736c8a9f8491e44c310 100644 (file)
@@ -985,7 +985,7 @@ static int sctp_setsockopt_bindx(struct sock *sk,
                return -EINVAL;
 
        kaddrs = memdup_user(addrs, addrs_size);
-       if (unlikely(IS_ERR(kaddrs)))
+       if (IS_ERR(kaddrs))
                return PTR_ERR(kaddrs);
 
        /* Walk through the addrs buffer and count the number of addresses. */
@@ -1315,7 +1315,7 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
                return -EINVAL;
 
        kaddrs = memdup_user(addrs, addrs_size);
-       if (unlikely(IS_ERR(kaddrs)))
+       if (IS_ERR(kaddrs))
                return PTR_ERR(kaddrs);
 
        /* Allow security module to validate connectx addresses. */
index 302e355f2ebc39c49ebbe7d617cbc488f66f83c6..5b932583e4076feacb786d315bc4d6181fd9a17b 100644 (file)
@@ -263,7 +263,7 @@ static int smc_bind(struct socket *sock, struct sockaddr *uaddr,
 
        /* Check if socket is already active */
        rc = -EINVAL;
-       if (sk->sk_state != SMC_INIT)
+       if (sk->sk_state != SMC_INIT || smc->connect_nonblock)
                goto out_rel;
 
        smc->clcsock->sk->sk_reuse = sk->sk_reuse;
@@ -1390,7 +1390,8 @@ static int smc_listen(struct socket *sock, int backlog)
        lock_sock(sk);
 
        rc = -EINVAL;
-       if ((sk->sk_state != SMC_INIT) && (sk->sk_state != SMC_LISTEN))
+       if ((sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) ||
+           smc->connect_nonblock)
                goto out;
 
        rc = 0;
@@ -1518,7 +1519,7 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
                goto out;
 
        if (msg->msg_flags & MSG_FASTOPEN) {
-               if (sk->sk_state == SMC_INIT) {
+               if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) {
                        smc_switch_to_fallback(smc);
                        smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP;
                } else {
@@ -1732,14 +1733,18 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
                }
                break;
        case TCP_NODELAY:
-               if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) {
+               if (sk->sk_state != SMC_INIT &&
+                   sk->sk_state != SMC_LISTEN &&
+                   sk->sk_state != SMC_CLOSED) {
                        if (val && !smc->use_fallback)
                                mod_delayed_work(system_wq, &smc->conn.tx_work,
                                                 0);
                }
                break;
        case TCP_CORK:
-               if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) {
+               if (sk->sk_state != SMC_INIT &&
+                   sk->sk_state != SMC_LISTEN &&
+                   sk->sk_state != SMC_CLOSED) {
                        if (!val && !smc->use_fallback)
                                mod_delayed_work(system_wq, &smc->conn.tx_work,
                                                 0);
index d86030ef1232a33af7e2da036bc5592c4d5c0021..e135d4e11231995c952d4adbe69d7b42a63adc27 100644 (file)
@@ -55,6 +55,7 @@ struct tipc_nl_compat_msg {
        int rep_type;
        int rep_size;
        int req_type;
+       int req_size;
        struct net *net;
        struct sk_buff *rep;
        struct tlv_desc *req;
@@ -257,7 +258,8 @@ static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
        int err;
        struct sk_buff *arg;
 
-       if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
+       if (msg->req_type && (!msg->req_size ||
+                             !TLV_CHECK_TYPE(msg->req, msg->req_type)))
                return -EINVAL;
 
        msg->rep = tipc_tlv_alloc(msg->rep_size);
@@ -354,7 +356,8 @@ static int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
 {
        int err;
 
-       if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
+       if (msg->req_type && (!msg->req_size ||
+                             !TLV_CHECK_TYPE(msg->req, msg->req_type)))
                return -EINVAL;
 
        err = __tipc_nl_compat_doit(cmd, msg);
@@ -1278,8 +1281,8 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
                goto send;
        }
 
-       len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
-       if (!len || !TLV_OK(msg.req, len)) {
+       msg.req_size = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
+       if (msg.req_size && !TLV_OK(msg.req, msg.req_size)) {
                msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
                err = -EOPNOTSUPP;
                goto send;
index dd8537f988c4004a5c50e004f1654db5c4e548b6..83ae41d7e5548077778c805e6c3367cdbf674313 100644 (file)
@@ -485,9 +485,8 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
                tsk_set_unreturnable(tsk, true);
                if (sock->type == SOCK_DGRAM)
                        tsk_set_unreliable(tsk, true);
-               __skb_queue_head_init(&tsk->mc_method.deferredq);
        }
-
+       __skb_queue_head_init(&tsk->mc_method.deferredq);
        trace_tipc_sk_create(sk, NULL, TIPC_DUMP_NONE, " ");
        return 0;
 }
index 4674e57e66b0533fc5faf5ae930c0aad85eb8b77..9cbbae606ced4a12469151a523c11d3d3cfa7d7b 100644 (file)
@@ -261,24 +261,9 @@ void tls_ctx_free(struct tls_context *ctx)
        kfree(ctx);
 }
 
-static void tls_sk_proto_close(struct sock *sk, long timeout)
+static void tls_sk_proto_cleanup(struct sock *sk,
+                                struct tls_context *ctx, long timeo)
 {
-       struct tls_context *ctx = tls_get_ctx(sk);
-       long timeo = sock_sndtimeo(sk, 0);
-       void (*sk_proto_close)(struct sock *sk, long timeout);
-       bool free_ctx = false;
-
-       lock_sock(sk);
-       sk_proto_close = ctx->sk_proto_close;
-
-       if (ctx->tx_conf == TLS_HW_RECORD && ctx->rx_conf == TLS_HW_RECORD)
-               goto skip_tx_cleanup;
-
-       if (ctx->tx_conf == TLS_BASE && ctx->rx_conf == TLS_BASE) {
-               free_ctx = true;
-               goto skip_tx_cleanup;
-       }
-
        if (unlikely(sk->sk_write_pending) &&
            !wait_on_pending_writer(sk, &timeo))
                tls_handle_open_record(sk, 0);
@@ -287,7 +272,7 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
        if (ctx->tx_conf == TLS_SW) {
                kfree(ctx->tx.rec_seq);
                kfree(ctx->tx.iv);
-               tls_sw_free_resources_tx(sk);
+               tls_sw_release_resources_tx(sk);
 #ifdef CONFIG_TLS_DEVICE
        } else if (ctx->tx_conf == TLS_HW) {
                tls_device_free_resources_tx(sk);
@@ -295,26 +280,44 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
        }
 
        if (ctx->rx_conf == TLS_SW)
-               tls_sw_free_resources_rx(sk);
+               tls_sw_release_resources_rx(sk);
 
 #ifdef CONFIG_TLS_DEVICE
        if (ctx->rx_conf == TLS_HW)
                tls_device_offload_cleanup_rx(sk);
-
-       if (ctx->tx_conf != TLS_HW && ctx->rx_conf != TLS_HW) {
-#else
-       {
 #endif
-               tls_ctx_free(ctx);
-               ctx = NULL;
-       }
+}
 
-skip_tx_cleanup:
+static void tls_sk_proto_close(struct sock *sk, long timeout)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct tls_context *ctx = tls_get_ctx(sk);
+       long timeo = sock_sndtimeo(sk, 0);
+       bool free_ctx;
+
+       if (ctx->tx_conf == TLS_SW)
+               tls_sw_cancel_work_tx(ctx);
+
+       lock_sock(sk);
+       free_ctx = ctx->tx_conf != TLS_HW && ctx->rx_conf != TLS_HW;
+
+       if (ctx->tx_conf != TLS_BASE || ctx->rx_conf != TLS_BASE)
+               tls_sk_proto_cleanup(sk, ctx, timeo);
+
+       write_lock_bh(&sk->sk_callback_lock);
+       if (free_ctx)
+               icsk->icsk_ulp_data = NULL;
+       sk->sk_prot = ctx->sk_proto;
+       write_unlock_bh(&sk->sk_callback_lock);
        release_sock(sk);
-       sk_proto_close(sk, timeout);
-       /* free ctx for TLS_HW_RECORD, used by tcp_set_state
-        * for sk->sk_prot->unhash [tls_hw_unhash]
-        */
+       if (ctx->tx_conf == TLS_SW)
+               tls_sw_free_ctx_tx(ctx);
+       if (ctx->rx_conf == TLS_SW || ctx->rx_conf == TLS_HW)
+               tls_sw_strparser_done(ctx);
+       if (ctx->rx_conf == TLS_SW)
+               tls_sw_free_ctx_rx(ctx);
+       ctx->sk_proto_close(sk, timeout);
+
        if (free_ctx)
                tls_ctx_free(ctx);
 }
@@ -526,6 +529,8 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
                {
 #endif
                        rc = tls_set_sw_offload(sk, ctx, 1);
+                       if (rc)
+                               goto err_crypto_info;
                        conf = TLS_SW;
                }
        } else {
@@ -537,13 +542,13 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
                {
 #endif
                        rc = tls_set_sw_offload(sk, ctx, 0);
+                       if (rc)
+                               goto err_crypto_info;
                        conf = TLS_SW;
                }
+               tls_sw_strparser_arm(sk, ctx);
        }
 
-       if (rc)
-               goto err_crypto_info;
-
        if (tx)
                ctx->tx_conf = conf;
        else
@@ -607,6 +612,7 @@ static struct tls_context *create_ctx(struct sock *sk)
        ctx->setsockopt = sk->sk_prot->setsockopt;
        ctx->getsockopt = sk->sk_prot->getsockopt;
        ctx->sk_proto_close = sk->sk_prot->close;
+       ctx->unhash = sk->sk_prot->unhash;
        return ctx;
 }
 
@@ -764,7 +770,6 @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
        prot[TLS_HW_RECORD][TLS_HW_RECORD] = *base;
        prot[TLS_HW_RECORD][TLS_HW_RECORD].hash         = tls_hw_hash;
        prot[TLS_HW_RECORD][TLS_HW_RECORD].unhash       = tls_hw_unhash;
-       prot[TLS_HW_RECORD][TLS_HW_RECORD].close        = tls_sk_proto_close;
 }
 
 static int tls_init(struct sock *sk)
@@ -773,7 +778,7 @@ static int tls_init(struct sock *sk)
        int rc = 0;
 
        if (tls_hw_prot(sk))
-               goto out;
+               return 0;
 
        /* The TLS ulp is currently supported only for TCP sockets
         * in ESTABLISHED state.
@@ -784,21 +789,38 @@ static int tls_init(struct sock *sk)
        if (sk->sk_state != TCP_ESTABLISHED)
                return -ENOTSUPP;
 
+       tls_build_proto(sk);
+
        /* allocate tls context */
+       write_lock_bh(&sk->sk_callback_lock);
        ctx = create_ctx(sk);
        if (!ctx) {
                rc = -ENOMEM;
                goto out;
        }
 
-       tls_build_proto(sk);
        ctx->tx_conf = TLS_BASE;
        ctx->rx_conf = TLS_BASE;
+       ctx->sk_proto = sk->sk_prot;
        update_sk_prot(sk, ctx);
 out:
+       write_unlock_bh(&sk->sk_callback_lock);
        return rc;
 }
 
+static void tls_update(struct sock *sk, struct proto *p)
+{
+       struct tls_context *ctx;
+
+       ctx = tls_get_ctx(sk);
+       if (likely(ctx)) {
+               ctx->sk_proto_close = p->close;
+               ctx->sk_proto = p;
+       } else {
+               sk->sk_prot = p;
+       }
+}
+
 void tls_register_device(struct tls_device *device)
 {
        spin_lock_bh(&device_spinlock);
@@ -819,6 +841,7 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
        .name                   = "tls",
        .owner                  = THIS_MODULE,
        .init                   = tls_init,
+       .update                 = tls_update,
 };
 
 static int __init tls_register(void)
index 53b4ad94e74ab0aecb964ce0ed482c9277654d47..91d21b048a9b245804ba800d7e9dbc1b5c07a868 100644 (file)
@@ -2054,7 +2054,16 @@ static void tls_data_ready(struct sock *sk)
        }
 }
 
-void tls_sw_free_resources_tx(struct sock *sk)
+void tls_sw_cancel_work_tx(struct tls_context *tls_ctx)
+{
+       struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
+
+       set_bit(BIT_TX_CLOSING, &ctx->tx_bitmask);
+       set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask);
+       cancel_delayed_work_sync(&ctx->tx_work.work);
+}
+
+void tls_sw_release_resources_tx(struct sock *sk)
 {
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
@@ -2065,11 +2074,6 @@ void tls_sw_free_resources_tx(struct sock *sk)
        if (atomic_read(&ctx->encrypt_pending))
                crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
 
-       release_sock(sk);
-       cancel_delayed_work_sync(&ctx->tx_work.work);
-       lock_sock(sk);
-
-       /* Tx whatever records we can transmit and abandon the rest */
        tls_tx_records(sk, -1);
 
        /* Free up un-sent records in tx_list. First, free
@@ -2092,6 +2096,11 @@ void tls_sw_free_resources_tx(struct sock *sk)
 
        crypto_free_aead(ctx->aead_send);
        tls_free_open_rec(sk);
+}
+
+void tls_sw_free_ctx_tx(struct tls_context *tls_ctx)
+{
+       struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
 
        kfree(ctx);
 }
@@ -2110,25 +2119,40 @@ void tls_sw_release_resources_rx(struct sock *sk)
                skb_queue_purge(&ctx->rx_list);
                crypto_free_aead(ctx->aead_recv);
                strp_stop(&ctx->strp);
-               write_lock_bh(&sk->sk_callback_lock);
-               sk->sk_data_ready = ctx->saved_data_ready;
-               write_unlock_bh(&sk->sk_callback_lock);
-               release_sock(sk);
-               strp_done(&ctx->strp);
-               lock_sock(sk);
+               /* If tls_sw_strparser_arm() was not called (cleanup paths)
+                * we still want to strp_stop(), but sk->sk_data_ready was
+                * never swapped.
+                */
+               if (ctx->saved_data_ready) {
+                       write_lock_bh(&sk->sk_callback_lock);
+                       sk->sk_data_ready = ctx->saved_data_ready;
+                       write_unlock_bh(&sk->sk_callback_lock);
+               }
        }
 }
 
-void tls_sw_free_resources_rx(struct sock *sk)
+void tls_sw_strparser_done(struct tls_context *tls_ctx)
 {
-       struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx);
 
-       tls_sw_release_resources_rx(sk);
+       strp_done(&ctx->strp);
+}
+
+void tls_sw_free_ctx_rx(struct tls_context *tls_ctx)
+{
+       struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx);
 
        kfree(ctx);
 }
 
+void tls_sw_free_resources_rx(struct sock *sk)
+{
+       struct tls_context *tls_ctx = tls_get_ctx(sk);
+
+       tls_sw_release_resources_rx(sk);
+       tls_sw_free_ctx_rx(tls_ctx);
+}
+
 /* The work handler to transmitt the encrypted records in tx_list */
 static void tx_work_handler(struct work_struct *work)
 {
@@ -2137,11 +2161,17 @@ static void tx_work_handler(struct work_struct *work)
                                               struct tx_work, work);
        struct sock *sk = tx_work->sk;
        struct tls_context *tls_ctx = tls_get_ctx(sk);
-       struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
+       struct tls_sw_context_tx *ctx;
 
-       if (!test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
+       if (unlikely(!tls_ctx))
                return;
 
+       ctx = tls_sw_ctx_tx(tls_ctx);
+       if (test_bit(BIT_TX_CLOSING, &ctx->tx_bitmask))
+               return;
+
+       if (!test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
+               return;
        lock_sock(sk);
        tls_tx_records(sk, -1);
        release_sock(sk);
@@ -2160,6 +2190,18 @@ void tls_sw_write_space(struct sock *sk, struct tls_context *ctx)
        }
 }
 
+void tls_sw_strparser_arm(struct sock *sk, struct tls_context *tls_ctx)
+{
+       struct tls_sw_context_rx *rx_ctx = tls_sw_ctx_rx(tls_ctx);
+
+       write_lock_bh(&sk->sk_callback_lock);
+       rx_ctx->saved_data_ready = sk->sk_data_ready;
+       sk->sk_data_ready = tls_data_ready;
+       write_unlock_bh(&sk->sk_callback_lock);
+
+       strp_check_rcv(&rx_ctx->strp);
+}
+
 int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
 {
        struct tls_context *tls_ctx = tls_get_ctx(sk);
@@ -2357,13 +2399,6 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
                cb.parse_msg = tls_read_size;
 
                strp_init(&sw_ctx_rx->strp, sk, &cb);
-
-               write_lock_bh(&sk->sk_callback_lock);
-               sw_ctx_rx->saved_data_ready = sk->sk_data_ready;
-               sk->sk_data_ready = tls_data_ready;
-               write_unlock_bh(&sk->sk_callback_lock);
-
-               strp_check_rcv(&sw_ctx_rx->strp);
        }
 
        goto out;
index f2084e3f7aa4f2157fc7a76dbdfbb31a46c8edb8..9d864ebeb7b32acaca6c207279b829e09ac6c60b 100644 (file)
@@ -312,6 +312,11 @@ static void hvs_close_connection(struct vmbus_channel *chan)
        lock_sock(sk);
        hvs_do_close_lock_held(vsock_sk(sk), true);
        release_sock(sk);
+
+       /* Release the refcnt for the channel that's opened in
+        * hvs_open_connection().
+        */
+       sock_put(sk);
 }
 
 static void hvs_open_connection(struct vmbus_channel *chan)
@@ -407,6 +412,9 @@ static void hvs_open_connection(struct vmbus_channel *chan)
        }
 
        set_per_channel_state(chan, conn_from_host ? new : sk);
+
+       /* This reference will be dropped by hvs_close_connection(). */
+       sock_hold(conn_from_host ? new : sk);
        vmbus_set_chn_rescind_callback(chan, hvs_close_connection);
 
        /* Set the pending send size to max packet size to always get
index 45d9afcff6d5f060c0f60fecd15a7acb42731fc2..32b3c719fdfce2487321d29a10b03c0cebad17f8 100644 (file)
@@ -1410,10 +1410,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                }
                break;
        case NETDEV_PRE_UP:
-               if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)) &&
-                   !(wdev->iftype == NL80211_IFTYPE_AP_VLAN &&
-                     rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP &&
-                     wdev->use_4addr))
+               if (!cfg80211_iftype_allowed(wdev->wiphy, wdev->iftype,
+                                            wdev->use_4addr, 0))
                        return notifier_from_errno(-EOPNOTSUPP);
 
                if (rfkill_blocked(rdev->rfkill))
index fc83dd179c1a8b64b622a0646840fe70a06c3b2f..fd05ae1437a9f4aaca9a8d2f07f00565cff7817f 100644 (file)
@@ -3484,9 +3484,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
-       if (!(rdev->wiphy.interface_modes & (1 << type)) &&
-           !(type == NL80211_IFTYPE_AP_VLAN && params.use_4addr &&
-             rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP))
+       if (!cfg80211_iftype_allowed(&rdev->wiphy, type, params.use_4addr, 0))
                return -EOPNOTSUPP;
 
        err = nl80211_parse_mon_options(rdev, type, info, &params);
index 1c39d6a2e85011aff8a4991473fdec387c93bdac..d0e35b7b9e3502790cb6812f12824ff3826e7610 100644 (file)
@@ -1697,7 +1697,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
        for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
                num_interfaces += params->iftype_num[iftype];
                if (params->iftype_num[iftype] > 0 &&
-                   !(wiphy->software_iftypes & BIT(iftype)))
+                   !cfg80211_iftype_allowed(wiphy, iftype, 0, 1))
                        used_iftypes |= BIT(iftype);
        }
 
@@ -1719,7 +1719,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
                        return -ENOMEM;
 
                for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
-                       if (wiphy->software_iftypes & BIT(iftype))
+                       if (cfg80211_iftype_allowed(wiphy, iftype, 0, 1))
                                continue;
                        for (j = 0; j < c->n_limits; j++) {
                                all_iftypes |= limits[j].types;
@@ -2072,3 +2072,26 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
        return max_vht_nss;
 }
 EXPORT_SYMBOL(ieee80211_get_vht_max_nss);
+
+bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
+                            bool is_4addr, u8 check_swif)
+
+{
+       bool is_vlan = iftype == NL80211_IFTYPE_AP_VLAN;
+
+       switch (check_swif) {
+       case 0:
+               if (is_vlan && is_4addr)
+                       return wiphy->flags & WIPHY_FLAG_4ADDR_AP;
+               return wiphy->interface_modes & BIT(iftype);
+       case 1:
+               if (!(wiphy->software_iftypes & BIT(iftype)) && is_vlan)
+                       return wiphy->flags & WIPHY_FLAG_4ADDR_AP;
+               return wiphy->software_iftypes & BIT(iftype);
+       default:
+               break;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL(cfg80211_iftype_allowed);
index 467224feb43b0fa56b5720aa0ff693ad42ce6b32..d821107f55f90ff5c823d4ff1c19432268132a84 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
 /* Copyright (c) 2018 Facebook */
 
+#include <endian.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -419,9 +420,9 @@ done:
 
 static bool btf_check_endianness(const GElf_Ehdr *ehdr)
 {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#if __BYTE_ORDER == __LITTLE_ENDIAN
        return ehdr->e_ident[EI_DATA] == ELFDATA2LSB;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#elif __BYTE_ORDER == __BIG_ENDIAN
        return ehdr->e_ident[EI_DATA] == ELFDATA2MSB;
 #else
 # error "Unrecognized __BYTE_ORDER__"
index 794dd5064ae8a01d9628c3baade0605a24fa4f44..2586b6cb8f34f2ce30e382f3ddd60687f9971ecc 100644 (file)
@@ -20,6 +20,7 @@
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
+#include <endian.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <asm/unistd.h>
@@ -612,10 +613,10 @@ errout:
 
 static int bpf_object__check_endianness(struct bpf_object *obj)
 {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#if __BYTE_ORDER == __LITTLE_ENDIAN
        if (obj->efile.ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
                return 0;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#elif __BYTE_ORDER == __BIG_ENDIAN
        if (obj->efile.ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
                return 0;
 #else
@@ -1377,8 +1378,13 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj)
                if (!has_datasec && kind == BTF_KIND_VAR) {
                        /* replace VAR with INT */
                        t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0);
-                       t->size = sizeof(int);
-                       *(int *)(t+1) = BTF_INT_ENC(0, 0, 32);
+                       /*
+                        * using size = 1 is the safest choice, 4 will be too
+                        * big and cause kernel BTF validation failure if
+                        * original variable took less than 4 bytes
+                        */
+                       t->size = 1;
+                       *(int *)(t+1) = BTF_INT_ENC(0, 0, 8);
                } else if (!has_datasec && kind == BTF_KIND_DATASEC) {
                        /* replace DATASEC with STRUCT */
                        struct btf_var_secinfo *v = (void *)(t + 1);
@@ -1500,6 +1506,12 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
                           BTF_ELF_SEC, err);
                btf__free(obj->btf);
                obj->btf = NULL;
+               /* btf_ext can't exist without btf, so free it as well */
+               if (obj->btf_ext) {
+                       btf_ext__free(obj->btf_ext);
+                       obj->btf_ext = NULL;
+               }
+
                if (bpf_object__is_btf_mandatory(obj))
                        return err;
        }
@@ -4507,13 +4519,13 @@ struct perf_buffer *perf_buffer__new(int map_fd, size_t page_cnt,
                                     const struct perf_buffer_opts *opts)
 {
        struct perf_buffer_params p = {};
-       struct perf_event_attr attr = {
-               .config = PERF_COUNT_SW_BPF_OUTPUT,
-               .type = PERF_TYPE_SOFTWARE,
-               .sample_type = PERF_SAMPLE_RAW,
-               .sample_period = 1,
-               .wakeup_events = 1,
-       };
+       struct perf_event_attr attr = { 0, };
+
+       attr.config = PERF_COUNT_SW_BPF_OUTPUT,
+       attr.type = PERF_TYPE_SOFTWARE;
+       attr.sample_type = PERF_SAMPLE_RAW;
+       attr.sample_period = 1;
+       attr.wakeup_events = 1;
 
        p.attr = &attr;
        p.sample_cb = opts ? opts->sample_cb : NULL;
index 5007b5d4fd2c51186a554fb03893dcabd7bef381..680e63066cf39c7f3bd06cdf645b05065060728e 100644 (file)
@@ -317,17 +317,16 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
 
 static int xsk_get_max_queues(struct xsk_socket *xsk)
 {
-       struct ethtool_channels channels;
-       struct ifreq ifr;
+       struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
+       struct ifreq ifr = {};
        int fd, err, ret;
 
        fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (fd < 0)
                return -errno;
 
-       channels.cmd = ETHTOOL_GCHANNELS;
        ifr.ifr_data = (void *)&channels;
-       strncpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1);
+       memcpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1);
        ifr.ifr_name[IFNAMSIZ - 1] = '\0';
        err = ioctl(fd, SIOCETHTOOL, &ifr);
        if (err && errno != EOPNOTSUPP) {
@@ -335,7 +334,7 @@ static int xsk_get_max_queues(struct xsk_socket *xsk)
                goto out;
        }
 
-       if (channels.max_combined == 0 || errno == EOPNOTSUPP)
+       if (err || channels.max_combined == 0)
                /* If the device says it has no channels, then all traffic
                 * is sent to a single stream, so max queues = 1.
                 */
@@ -517,7 +516,7 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
                err = -errno;
                goto out_socket;
        }
-       strncpy(xsk->ifname, ifname, IFNAMSIZ - 1);
+       memcpy(xsk->ifname, ifname, IFNAMSIZ - 1);
        xsk->ifname[IFNAMSIZ - 1] = '\0';
 
        err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
index 11c9c62c33620790f6ff72cba3369721f13fdc4e..c085964e1d05a2d85e589be8565b025e9dda4665 100644 (file)
@@ -57,7 +57,8 @@ TEST_PROGS := test_kmod.sh \
        test_lirc_mode2.sh \
        test_skb_cgroup_id.sh \
        test_flow_dissector.sh \
-       test_xdp_vlan.sh \
+       test_xdp_vlan_mode_generic.sh \
+       test_xdp_vlan_mode_native.sh \
        test_lwt_ip_encap.sh \
        test_tcp_check_syncookie.sh \
        test_tc_tunnel.sh \
index 5aeaa284fc47493decf0fc55b31de7c8a734ac6d..a680628204108b41d0c046a5371cec9f2cfedc0b 100644 (file)
@@ -41,8 +41,7 @@ int sendmsg_v6_prog(struct bpf_sock_addr *ctx)
        }
 
        /* Rewrite destination. */
-       if ((ctx->user_ip6[0] & 0xFFFF) == bpf_htons(0xFACE) &&
-            ctx->user_ip6[0] >> 16 == bpf_htons(0xB00C)) {
+       if (ctx->user_ip6[0] == bpf_htonl(0xFACEB00C)) {
                ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0);
                ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1);
                ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2);
index 51a3a31d1aac47b0e95e27b9ce3cc28d29b94d09..bb8b0da91686f0e14105b7c22bb40a7e762f937f 100755 (executable)
@@ -1,6 +1,14 @@
 #!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Author: Jesper Dangaard Brouer <hawk@kernel.org>
 
-TESTNAME=xdp_vlan
+# Allow wrapper scripts to name test
+if [ -z "$TESTNAME" ]; then
+    TESTNAME=xdp_vlan
+fi
+
+# Default XDP mode
+XDP_MODE=xdpgeneric
 
 usage() {
   echo "Testing XDP + TC eBPF VLAN manipulations: $TESTNAME"
@@ -9,9 +17,23 @@ usage() {
   echo "  -v | --verbose : Verbose"
   echo "  --flush        : Flush before starting (e.g. after --interactive)"
   echo "  --interactive  : Keep netns setup running after test-run"
+  echo "  --mode=XXX     : Choose XDP mode (xdp | xdpgeneric | xdpdrv)"
   echo ""
 }
 
+valid_xdp_mode()
+{
+       local mode=$1
+
+       case "$mode" in
+               xdpgeneric | xdpdrv | xdp)
+                       return 0
+                       ;;
+               *)
+                       return 1
+       esac
+}
+
 cleanup()
 {
        local status=$?
@@ -37,7 +59,7 @@ cleanup()
 
 # Using external program "getopt" to get --long-options
 OPTIONS=$(getopt -o hvfi: \
-    --long verbose,flush,help,interactive,debug -- "$@")
+    --long verbose,flush,help,interactive,debug,mode: -- "$@")
 if (( $? != 0 )); then
     usage
     echo "selftests: $TESTNAME [FAILED] Error calling getopt, unknown option?"
@@ -60,6 +82,11 @@ while true; do
                cleanup
                shift
                ;;
+           --mode )
+               shift
+               XDP_MODE=$1
+               shift
+               ;;
            -- )
                shift
                break
@@ -81,8 +108,14 @@ if [ "$EUID" -ne 0 ]; then
        exit 1
 fi
 
-ip link set dev lo xdp off 2>/dev/null > /dev/null
-if [ $? -ne 0 ];then
+valid_xdp_mode $XDP_MODE
+if [ $? -ne 0 ]; then
+       echo "selftests: $TESTNAME [FAILED] unknown XDP mode ($XDP_MODE)"
+       exit 1
+fi
+
+ip link set dev lo xdpgeneric off 2>/dev/null > /dev/null
+if [ $? -ne 0 ]; then
        echo "selftests: $TESTNAME [SKIP] need ip xdp support"
        exit 0
 fi
@@ -155,7 +188,7 @@ ip netns exec ns2 ip link set lo up
 # At this point, the hosts cannot reach each-other,
 # because ns2 are using VLAN tags on the packets.
 
-ip netns exec ns2 sh -c 'ping -W 1 -c 1 100.64.41.1 || echo "Okay ping fails"'
+ip netns exec ns2 sh -c 'ping -W 1 -c 1 100.64.41.1 || echo "Success: First ping must fail"'
 
 
 # Now we can use the test_xdp_vlan.c program to pop/push these VLAN tags
@@ -166,7 +199,7 @@ export FILE=test_xdp_vlan.o
 
 # First test: Remove VLAN by setting VLAN ID 0, using "xdp_vlan_change"
 export XDP_PROG=xdp_vlan_change
-ip netns exec ns1 ip link set $DEVNS1 xdp object $FILE section $XDP_PROG
+ip netns exec ns1 ip link set $DEVNS1 $XDP_MODE object $FILE section $XDP_PROG
 
 # In ns1: egress use TC to add back VLAN tag 4011
 #  (del cmd)
@@ -177,8 +210,8 @@ ip netns exec ns1 tc filter add dev $DEVNS1 egress \
   prio 1 handle 1 bpf da obj $FILE sec tc_vlan_push
 
 # Now the namespaces can reach each-other, test with ping:
-ip netns exec ns2 ping -W 2 -c 3 $IPADDR1
-ip netns exec ns1 ping -W 2 -c 3 $IPADDR2
+ip netns exec ns2 ping -i 0.2 -W 2 -c 2 $IPADDR1
+ip netns exec ns1 ping -i 0.2 -W 2 -c 2 $IPADDR2
 
 # Second test: Replace xdp prog, that fully remove vlan header
 #
@@ -187,9 +220,9 @@ ip netns exec ns1 ping -W 2 -c 3 $IPADDR2
 # ETH_P_8021Q indication, and this cause overwriting of our changes.
 #
 export XDP_PROG=xdp_vlan_remove_outer2
-ip netns exec ns1 ip link set $DEVNS1 xdp off
-ip netns exec ns1 ip link set $DEVNS1 xdp object $FILE section $XDP_PROG
+ip netns exec ns1 ip link set $DEVNS1 $XDP_MODE off
+ip netns exec ns1 ip link set $DEVNS1 $XDP_MODE object $FILE section $XDP_PROG
 
 # Now the namespaces should still be able reach each-other, test with ping:
-ip netns exec ns2 ping -W 2 -c 3 $IPADDR1
-ip netns exec ns1 ping -W 2 -c 3 $IPADDR2
+ip netns exec ns2 ping -i 0.2 -W 2 -c 2 $IPADDR1
+ip netns exec ns1 ping -i 0.2 -W 2 -c 2 $IPADDR2
diff --git a/tools/testing/selftests/bpf/test_xdp_vlan_mode_generic.sh b/tools/testing/selftests/bpf/test_xdp_vlan_mode_generic.sh
new file mode 100755 (executable)
index 0000000..c515326
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# Exit on failure
+set -e
+
+# Wrapper script to test generic-XDP
+export TESTNAME=xdp_vlan_mode_generic
+./test_xdp_vlan.sh --mode=xdpgeneric
diff --git a/tools/testing/selftests/bpf/test_xdp_vlan_mode_native.sh b/tools/testing/selftests/bpf/test_xdp_vlan_mode_native.sh
new file mode 100755 (executable)
index 0000000..5cf7ce1
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# Exit on failure
+set -e
+
+# Wrapper script to test native-XDP
+export TESTNAME=xdp_vlan_mode_native
+./test_xdp_vlan.sh --mode=xdpdrv
index b0fda2877119c4af08277bd0f329f238c193313c..d438193804b212ffa80c94be47e8c1aca392181e 100644 (file)
        .result = ACCEPT,
        .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
 },
+{
+       "read gso_segs from CGROUP_SKB",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
+                   offsetof(struct __sk_buff, gso_segs)),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+},
 {
        "write gso_segs from CGROUP_SKB",
        .insns = {
index ec15c4f6af552d57a5584e18abb7cb9bb17cc90f..0ac49d91a26023c3eb10804f4cf77fc004b4d080 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef __KSELFTEST_H
 #define __KSELFTEST_H
 
+#include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdarg.h>
@@ -81,58 +82,68 @@ static inline void ksft_print_cnts(void)
 
 static inline void ksft_print_msg(const char *msg, ...)
 {
+       int saved_errno = errno;
        va_list args;
 
        va_start(args, msg);
        printf("# ");
+       errno = saved_errno;
        vprintf(msg, args);
        va_end(args);
 }
 
 static inline void ksft_test_result_pass(const char *msg, ...)
 {
+       int saved_errno = errno;
        va_list args;
 
        ksft_cnt.ksft_pass++;
 
        va_start(args, msg);
        printf("ok %d ", ksft_test_num());
+       errno = saved_errno;
        vprintf(msg, args);
        va_end(args);
 }
 
 static inline void ksft_test_result_fail(const char *msg, ...)
 {
+       int saved_errno = errno;
        va_list args;
 
        ksft_cnt.ksft_fail++;
 
        va_start(args, msg);
        printf("not ok %d ", ksft_test_num());
+       errno = saved_errno;
        vprintf(msg, args);
        va_end(args);
 }
 
 static inline void ksft_test_result_skip(const char *msg, ...)
 {
+       int saved_errno = errno;
        va_list args;
 
        ksft_cnt.ksft_xskip++;
 
        va_start(args, msg);
        printf("not ok %d # SKIP ", ksft_test_num());
+       errno = saved_errno;
        vprintf(msg, args);
        va_end(args);
 }
 
 static inline void ksft_test_result_error(const char *msg, ...)
 {
+       int saved_errno = errno;
        va_list args;
 
        ksft_cnt.ksft_error++;
 
        va_start(args, msg);
        printf("not ok %d # error ", ksft_test_num());
+       errno = saved_errno;
        vprintf(msg, args);
        va_end(args);
 }
@@ -152,10 +163,12 @@ static inline int ksft_exit_fail(void)
 
 static inline int ksft_exit_fail_msg(const char *msg, ...)
 {
+       int saved_errno = errno;
        va_list args;
 
        va_start(args, msg);
        printf("Bail out! ");
+       errno = saved_errno;
        vprintf(msg, args);
        va_end(args);
 
@@ -178,10 +191,12 @@ static inline int ksft_exit_xpass(void)
 static inline int ksft_exit_skip(const char *msg, ...)
 {
        if (msg) {
+               int saved_errno = errno;
                va_list args;
 
                va_start(args, msg);
                printf("not ok %d # SKIP ", 1 + ksft_test_num());
+               errno = saved_errno;
                vprintf(msg, args);
                va_end(args);
        } else {
index edcfeace465509a3f17c6d7eb381b5da97ffeebc..79b0affd21fbddf6d6075a216b536592f6fc3305 100644 (file)
@@ -29,13 +29,27 @@ function die() {
        exit 1
 }
 
-# set_dynamic_debug() - setup kernel dynamic debug
-#      TODO - push and pop this config?
+function push_dynamic_debug() {
+        DYNAMIC_DEBUG=$(grep '^kernel/livepatch' /sys/kernel/debug/dynamic_debug/control | \
+                awk -F'[: ]' '{print "file " $1 " line " $2 " " $4}')
+}
+
+function pop_dynamic_debug() {
+       if [[ -n "$DYNAMIC_DEBUG" ]]; then
+               echo -n "$DYNAMIC_DEBUG" > /sys/kernel/debug/dynamic_debug/control
+       fi
+}
+
+# set_dynamic_debug() - save the current dynamic debug config and tweak
+#                      it for the self-tests.  Set a script exit trap
+#                      that restores the original config.
 function set_dynamic_debug() {
-       cat << EOF > /sys/kernel/debug/dynamic_debug/control
-file kernel/livepatch/* +p
-func klp_try_switch_task -p
-EOF
+        push_dynamic_debug
+        trap pop_dynamic_debug EXIT INT TERM HUP
+        cat <<-EOF > /sys/kernel/debug/dynamic_debug/control
+               file kernel/livepatch/* +p
+               func klp_try_switch_task -p
+               EOF
 }
 
 # loop_until(cmd) - loop a command until it is successful or $MAX_RETRIES,
index 4ce0bc1612f5495444d72f678d6368d54e6a10c1..c7cced739c34bcada309cae1ce7607af04637887 100644 (file)
@@ -17,7 +17,7 @@ tcp_inq
 tls
 txring_overwrite
 ip_defrag
+ipv6_flowlabel
+ipv6_flowlabel_mgr
 so_txtime
-flowlabel
-flowlabel_mgr
 tcp_fastopen_backup_key
index cca2baa03fb81b12f393a1df566dbe0494cabe27..a8d8e8b3dc819f3abc90060eaa0d312632c2145f 100755 (executable)
@@ -93,18 +93,10 @@ sw1_create()
        ip route add vrf v$ol1 192.0.2.16/28 \
           nexthop dev g1a \
           nexthop dev g1b
-
-       tc qdisc add dev $ul1 clsact
-       tc filter add dev $ul1 egress pref 111 prot ipv4 \
-          flower dst_ip 192.0.2.66 action pass
-       tc filter add dev $ul1 egress pref 222 prot ipv4 \
-          flower dst_ip 192.0.2.82 action pass
 }
 
 sw1_destroy()
 {
-       tc qdisc del dev $ul1 clsact
-
        ip route del vrf v$ol1 192.0.2.16/28
 
        ip route del vrf v$ol1 192.0.2.82/32 via 192.0.2.146
@@ -139,10 +131,18 @@ sw2_create()
        ip route add vrf v$ol2 192.0.2.0/28 \
           nexthop dev g2a \
           nexthop dev g2b
+
+       tc qdisc add dev $ul2 clsact
+       tc filter add dev $ul2 ingress pref 111 prot 802.1Q \
+          flower vlan_id 111 action pass
+       tc filter add dev $ul2 ingress pref 222 prot 802.1Q \
+          flower vlan_id 222 action pass
 }
 
 sw2_destroy()
 {
+       tc qdisc del dev $ul2 clsact
+
        ip route del vrf v$ol2 192.0.2.0/28
 
        ip route del vrf v$ol2 192.0.2.81/32 via 192.0.2.145
@@ -187,12 +187,16 @@ setup_prepare()
        sw1_create
        sw2_create
        h2_create
+
+       forwarding_enable
 }
 
 cleanup()
 {
        pre_cleanup
 
+       forwarding_restore
+
        h2_destroy
        sw2_destroy
        sw1_destroy
@@ -211,15 +215,15 @@ multipath4_test()
           nexthop dev g1a weight $weight1 \
           nexthop dev g1b weight $weight2
 
-       local t0_111=$(tc_rule_stats_get $ul1 111 egress)
-       local t0_222=$(tc_rule_stats_get $ul1 222 egress)
+       local t0_111=$(tc_rule_stats_get $ul2 111 ingress)
+       local t0_222=$(tc_rule_stats_get $ul2 222 ingress)
 
        ip vrf exec v$h1 \
           $MZ $h1 -q -p 64 -A 192.0.2.1 -B 192.0.2.18 \
               -d 1msec -t udp "sp=1024,dp=0-32768"
 
-       local t1_111=$(tc_rule_stats_get $ul1 111 egress)
-       local t1_222=$(tc_rule_stats_get $ul1 222 egress)
+       local t1_111=$(tc_rule_stats_get $ul2 111 ingress)
+       local t1_222=$(tc_rule_stats_get $ul2 222 ingress)
 
        local d111=$((t1_111 - t0_111))
        local d222=$((t1_222 - t0_222))
index 090fff9dbc48f11a28ccba2444e80a3ac806a683..4c285b6e1db8c1713b70e6be5092b780bb5e0d6a 100644 (file)
 #define TLS_PAYLOAD_MAX_LEN 16384
 #define SOL_TLS 282
 
+#ifndef ENOTSUPP
+#define ENOTSUPP 524
+#endif
+
+FIXTURE(tls_basic)
+{
+       int fd, cfd;
+       bool notls;
+};
+
+FIXTURE_SETUP(tls_basic)
+{
+       struct sockaddr_in addr;
+       socklen_t len;
+       int sfd, ret;
+
+       self->notls = false;
+       len = sizeof(addr);
+
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = htonl(INADDR_ANY);
+       addr.sin_port = 0;
+
+       self->fd = socket(AF_INET, SOCK_STREAM, 0);
+       sfd = socket(AF_INET, SOCK_STREAM, 0);
+
+       ret = bind(sfd, &addr, sizeof(addr));
+       ASSERT_EQ(ret, 0);
+       ret = listen(sfd, 10);
+       ASSERT_EQ(ret, 0);
+
+       ret = getsockname(sfd, &addr, &len);
+       ASSERT_EQ(ret, 0);
+
+       ret = connect(self->fd, &addr, sizeof(addr));
+       ASSERT_EQ(ret, 0);
+
+       self->cfd = accept(sfd, &addr, &len);
+       ASSERT_GE(self->cfd, 0);
+
+       close(sfd);
+
+       ret = setsockopt(self->fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
+       if (ret != 0) {
+               ASSERT_EQ(errno, ENOENT);
+               self->notls = true;
+               printf("Failure setting TCP_ULP, testing without tls\n");
+               return;
+       }
+
+       ret = setsockopt(self->cfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
+       ASSERT_EQ(ret, 0);
+}
+
+FIXTURE_TEARDOWN(tls_basic)
+{
+       close(self->fd);
+       close(self->cfd);
+}
+
+/* Send some data through with ULP but no keys */
+TEST_F(tls_basic, base_base)
+{
+       char const *test_str = "test_read";
+       int send_len = 10;
+       char buf[10];
+
+       ASSERT_EQ(strlen(test_str) + 1, send_len);
+
+       EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+       EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
+       EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+};
+
 FIXTURE(tls)
 {
        int fd, cfd;
@@ -165,6 +239,16 @@ TEST_F(tls, msg_more)
        EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
 }
 
+TEST_F(tls, msg_more_unsent)
+{
+       char const *test_str = "test_read";
+       int send_len = 10;
+       char buf[10];
+
+       EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len);
+       EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1);
+}
+
 TEST_F(tls, sendmsg_single)
 {
        struct msghdr msg;
@@ -610,6 +694,42 @@ TEST_F(tls, recv_lowat)
        EXPECT_EQ(memcmp(send_mem, recv_mem + 10, 5), 0);
 }
 
+TEST_F(tls, bidir)
+{
+       char const *test_str = "test_read";
+       int send_len = 10;
+       char buf[10];
+       int ret;
+
+       if (!self->notls) {
+               struct tls12_crypto_info_aes_gcm_128 tls12;
+
+               memset(&tls12, 0, sizeof(tls12));
+               tls12.info.version = TLS_1_3_VERSION;
+               tls12.info.cipher_type = TLS_CIPHER_AES_GCM_128;
+
+               ret = setsockopt(self->fd, SOL_TLS, TLS_RX, &tls12,
+                                sizeof(tls12));
+               ASSERT_EQ(ret, 0);
+
+               ret = setsockopt(self->cfd, SOL_TLS, TLS_TX, &tls12,
+                                sizeof(tls12));
+               ASSERT_EQ(ret, 0);
+       }
+
+       ASSERT_EQ(strlen(test_str) + 1, send_len);
+
+       EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+       EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
+       EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+
+       memset(buf, 0, sizeof(buf));
+
+       EXPECT_EQ(send(self->cfd, test_str, send_len, 0), send_len);
+       EXPECT_NE(recv(self->fd, buf, send_len, 0), -1);
+       EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+};
+
 TEST_F(tls, pollin)
 {
        char const *test_str = "test_poll";
@@ -837,6 +957,109 @@ TEST_F(tls, control_msg)
        EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
 }
 
+TEST_F(tls, shutdown)
+{
+       char const *test_str = "test_read";
+       int send_len = 10;
+       char buf[10];
+
+       ASSERT_EQ(strlen(test_str) + 1, send_len);
+
+       EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+       EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
+       EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+
+       shutdown(self->fd, SHUT_RDWR);
+       shutdown(self->cfd, SHUT_RDWR);
+}
+
+TEST_F(tls, shutdown_unsent)
+{
+       char const *test_str = "test_read";
+       int send_len = 10;
+
+       EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len);
+
+       shutdown(self->fd, SHUT_RDWR);
+       shutdown(self->cfd, SHUT_RDWR);
+}
+
+TEST_F(tls, shutdown_reuse)
+{
+       struct sockaddr_in addr;
+       int ret;
+
+       shutdown(self->fd, SHUT_RDWR);
+       shutdown(self->cfd, SHUT_RDWR);
+       close(self->cfd);
+
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = htonl(INADDR_ANY);
+       addr.sin_port = 0;
+
+       ret = bind(self->fd, &addr, sizeof(addr));
+       EXPECT_EQ(ret, 0);
+       ret = listen(self->fd, 10);
+       EXPECT_EQ(ret, -1);
+       EXPECT_EQ(errno, EINVAL);
+
+       ret = connect(self->fd, &addr, sizeof(addr));
+       EXPECT_EQ(ret, -1);
+       EXPECT_EQ(errno, EISCONN);
+}
+
+TEST(non_established) {
+       struct tls12_crypto_info_aes_gcm_256 tls12;
+       struct sockaddr_in addr;
+       int sfd, ret, fd;
+       socklen_t len;
+
+       len = sizeof(addr);
+
+       memset(&tls12, 0, sizeof(tls12));
+       tls12.info.version = TLS_1_2_VERSION;
+       tls12.info.cipher_type = TLS_CIPHER_AES_GCM_256;
+
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = htonl(INADDR_ANY);
+       addr.sin_port = 0;
+
+       fd = socket(AF_INET, SOCK_STREAM, 0);
+       sfd = socket(AF_INET, SOCK_STREAM, 0);
+
+       ret = bind(sfd, &addr, sizeof(addr));
+       ASSERT_EQ(ret, 0);
+       ret = listen(sfd, 10);
+       ASSERT_EQ(ret, 0);
+
+       ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
+       EXPECT_EQ(ret, -1);
+       /* TLS ULP not supported */
+       if (errno == ENOENT)
+               return;
+       EXPECT_EQ(errno, ENOTSUPP);
+
+       ret = setsockopt(sfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
+       EXPECT_EQ(ret, -1);
+       EXPECT_EQ(errno, ENOTSUPP);
+
+       ret = getsockname(sfd, &addr, &len);
+       ASSERT_EQ(ret, 0);
+
+       ret = connect(fd, &addr, sizeof(addr));
+       ASSERT_EQ(ret, 0);
+
+       ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
+       ASSERT_EQ(ret, 0);
+
+       ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
+       EXPECT_EQ(ret, -1);
+       EXPECT_EQ(errno, EEXIST);
+
+       close(fd);
+       close(sfd);
+}
+
 TEST(keysizes) {
        struct tls12_crypto_info_aes_gcm_256 tls12;
        struct sockaddr_in addr;
index cc7c7d75800809115bc22d62dbcd4c646a7f35d3..6503b1ce091f824dabbc3f25ddef6059cc6bce1f 100644 (file)
         "teardown": [
             "$TC actions flush action vlan"
         ]
+    },
+    {
+        "id": "294e",
+        "name": "Add batch of 32 vlan push actions with cookie",
+        "category": [
+            "actions",
+            "vlan"
+        ],
+        "setup": [
+            [
+                "$TC actions flush action vlan",
+                0,
+                1,
+                255
+            ]
+        ],
+        "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan push protocol 802.1q id 4094 priority 7 pipe index \\$i cookie aabbccddeeff112233445566778800a1 \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"",
+        "expExitCode": "0",
+        "verifyCmd": "$TC actions list action vlan",
+        "matchPattern": "^[ \t]+index [0-9]+ ref",
+        "matchCount": "32",
+        "teardown": [
+            "$TC actions flush action vlan"
+        ]
+    },
+    {
+        "id": "56f7",
+        "name": "Delete batch of 32 vlan push actions",
+        "category": [
+            "actions",
+            "vlan"
+        ],
+        "setup": [
+            [
+                "$TC actions flush action vlan",
+                0,
+                1,
+                255
+            ],
+            "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan push protocol 802.1q id 4094 priority 7 pipe index \\$i \\\"; args=\\\"\\$args\\$cmd\\\"; done && $TC actions add \\$args\""
+        ],
+        "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions del \\$args\"",
+        "expExitCode": "0",
+        "verifyCmd": "$TC actions list action vlan",
+        "matchPattern": "^[ \t]+index [0-9]+ ref",
+        "matchCount": "0",
+        "teardown": []
+    },
+    {
+        "id": "759f",
+        "name": "Add batch of 32 vlan pop actions with cookie",
+        "category": [
+            "actions",
+            "vlan"
+        ],
+        "setup": [
+            [
+                "$TC actions flush action vlan",
+                0,
+                1,
+                255
+            ]
+        ],
+        "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan pop continue index \\$i cookie aabbccddeeff112233445566778800a1 \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"",
+        "expExitCode": "0",
+        "verifyCmd": "$TC actions list action vlan",
+        "matchPattern": "^[ \t]+index [0-9]+ ref",
+        "matchCount": "32",
+        "teardown": [
+            "$TC actions flush action vlan"
+        ]
+    },
+    {
+        "id": "c84a",
+        "name": "Delete batch of 32 vlan pop actions",
+        "category": [
+            "actions",
+            "vlan"
+        ],
+        "setup": [
+            [
+                "$TC actions flush action vlan",
+                0,
+                1,
+                255
+            ],
+            "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan pop index \\$i \\\"; args=\\\"\\$args\\$cmd\\\"; done && $TC actions add \\$args\""
+        ],
+        "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions del \\$args\"",
+        "expExitCode": "0",
+        "verifyCmd": "$TC actions list action vlan",
+        "matchPattern": "^[ \t]+index [0-9]+ ref",
+        "matchCount": "0",
+        "teardown": []
     }
 ]