Merge tag 'v5.3-rc6' into perf/core, to pick up fixes
authorIngo Molnar <mingo@kernel.org>
Mon, 26 Aug 2019 09:59:57 +0000 (11:59 +0200)
committerIngo Molnar <mingo@kernel.org>
Mon, 26 Aug 2019 09:59:57 +0000 (11:59 +0200)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
305 files changed:
Documentation/PCI/index.rst
Documentation/PCI/pciebus-howto.rst [new file with mode: 0644]
Documentation/PCI/picebus-howto.rst [deleted file]
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/sysctl/net.rst
Documentation/networking/tls-offload.rst
Documentation/networking/tuntap.txt
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/mach-rpc/riscpc.c
arch/arm/mm/Kconfig
arch/mips/include/asm/octeon/cvmx-sli-defs.h
arch/parisc/include/asm/pgtable.h
arch/um/include/shared/timer-internal.h
arch/um/kernel/process.c
arch/um/kernel/time.c
arch/x86/boot/compressed/pgtable_64.c
arch/x86/events/core.c
arch/x86/include/asm/bootparam_utils.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/nospec-branch.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/cpu/amd.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/svm.c
arch/x86/net/bpf_jit_comp.c
arch/x86/power/cpu.c
drivers/auxdisplay/ht16k33.c
drivers/block/drbd/drbd_main.c
drivers/bluetooth/btqca.c
drivers/bluetooth/btqca.h
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_qca.c
drivers/clk/clk.c
drivers/clk/samsung/clk-exynos5-subcmu.c
drivers/clk/samsung/clk-exynos5-subcmu.h
drivers/clk/samsung/clk-exynos5250.c
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/socfpga/clk-periph-s10.c
drivers/dma/fsldma.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/nv.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
drivers/gpu/drm/amd/powerplay/smu_v11_0.c
drivers/gpu/drm/arm/display/komeda/komeda_dev.c
drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
drivers/gpu/drm/arm/display/komeda/komeda_kms.c
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/mediatek/mtk_drm_drv.c
drivers/gpu/drm/mediatek/mtk_drm_drv.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/rcar-du/rcar_lvds.c
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/intel-ish-hid/ipc/hw-ish.h
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hid/wacom_wac.c
drivers/hv/channel.c
drivers/hv/hyperv_vmbus.h
drivers/infiniband/core/cma.c
drivers/infiniband/core/counters.c
drivers/infiniband/core/nldev.c
drivers/infiniband/core/restrack.c
drivers/infiniband/core/umem.c
drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
drivers/infiniband/hw/hfi1/fault.c
drivers/infiniband/hw/hfi1/tid_rdma.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mem.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/mlx5/odp.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/sw/siw/siw.h
drivers/infiniband/sw/siw/siw_cm.c
drivers/infiniband/sw/siw/siw_cq.c
drivers/infiniband/sw/siw/siw_mem.c
drivers/infiniband/sw/siw/siw_mem.h
drivers/infiniband/sw/siw/siw_qp.c
drivers/infiniband/sw/siw/siw_qp_rx.c
drivers/infiniband/sw/siw/siw_qp_tx.c
drivers/infiniband/sw/siw/siw_verbs.c
drivers/input/serio/hyperv-keyboard.c
drivers/iommu/dma-iommu.c
drivers/md/dm-bufio.c
drivers/md/dm-dust.c
drivers/md/dm-integrity.c
drivers/md/dm-kcopyd.c
drivers/md/dm-raid.c
drivers/md/dm-table.c
drivers/md/dm-zoned-metadata.c
drivers/md/dm-zoned-reclaim.c
drivers/md/dm-zoned-target.c
drivers/md/dm-zoned.h
drivers/md/persistent-data/dm-btree.c
drivers/md/persistent-data/dm-space-map-metadata.c
drivers/mtd/maps/sa1100-flash.c
drivers/net/bonding/bond_main.c
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h
drivers/net/ethernet/cavium/common/cavium_ptp.c
drivers/net/ethernet/cavium/liquidio/request_manager.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
drivers/net/ethernet/ezchip/nps_enet.h
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
drivers/net/ethernet/mscc/ocelot_flower.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/ethernet/netronome/nfp/flower/qos_conf.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
drivers/net/ethernet/toshiba/tc35815.c
drivers/net/ethernet/tundra/tsi108_eth.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/netdevsim/dev.c
drivers/net/netdevsim/fib.c
drivers/net/netdevsim/netdev.c
drivers/net/netdevsim/netdevsim.h
drivers/net/phy/at803x.c
drivers/net/phy/phy-c45.c
drivers/net/phy/phy_device.c
drivers/net/team/team.c
drivers/net/usb/cx82310_eth.c
drivers/net/usb/kalmia.c
drivers/net/usb/lan78xx.c
drivers/net/wimax/i2400m/fw.c
drivers/net/xen-netback/netback.c
drivers/nvme/host/core.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/pci/quirks.c
drivers/platform/chrome/cros_ec_ishtp.c
drivers/power/supply/ab8500_charger.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/scsi/libsas/sas_discover.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/ufs/ufshcd.c
drivers/target/target_core_user.c
drivers/video/fbdev/acornfb.c
drivers/watchdog/wdt285.c
fs/afs/cell.c
fs/afs/dir.c
fs/afs/yfsclient.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/inode.c
fs/ceph/locks.c
fs/ceph/snap.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cifs/connect.c
fs/io_uring.c
fs/nfsd/nfscache.c
fs/nfsd/nfsctl.c
fs/read_write.c
fs/ubifs/budget.c
fs/ubifs/orphan.c
fs/ubifs/super.c
fs/userfaultfd.c
fs/xfs/xfs_ioctl32.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_pnfs.c
fs/xfs/xfs_reflink.c
include/linux/ceph/buffer.h
include/linux/dma-contiguous.h
include/linux/gpio.h
include/linux/key.h
include/linux/mlx5/device.h
include/linux/mlx5/mlx5_ifc.h
include/linux/signal.h
include/linux/skbuff.h
include/linux/socket.h
include/linux/timekeeper_internal.h
include/net/bluetooth/hci_core.h
include/net/inet_frag.h
include/net/net_namespace.h
include/net/netfilter/nf_tables.h
include/net/netfilter/nf_tables_offload.h
include/net/netlink.h
include/net/pkt_cls.h
include/net/sock.h
include/rdma/restrack.h
include/trace/events/rxrpc.h
include/uapi/linux/bpf.h
include/uapi/linux/jffs2.h
kernel/dma/contiguous.c
kernel/dma/direct.c
kernel/irq/irqdesc.c
kernel/kprobes.c
kernel/module.c
kernel/sched/core.c
kernel/sched/psi.c
kernel/signal.c
kernel/time/timekeeping.c
kernel/time/vsyscall.c
mm/huge_memory.c
mm/kasan/common.c
mm/memcontrol.c
mm/page_alloc.c
mm/z3fold.c
mm/zsmalloc.c
net/batman-adv/multicast.c
net/bluetooth/hci_core.c
net/bluetooth/hci_debugfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/ceph/osd_client.c
net/core/sock.c
net/core/sock_diag.c
net/dsa/switch.c
net/ieee802154/6lowpan/reassembly.c
net/ipv4/inet_fragment.c
net/ipv4/ip_fragment.c
net/ipv4/tcp.c
net/ipv4/tcp_bpf.c
net/ipv4/tcp_output.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_flow_table_ip.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_offload.c
net/netfilter/nft_flow_offload.c
net/packet/af_packet.c
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/call_event.c
net/rxrpc/input.c
net/rxrpc/local_object.c
net/rxrpc/output.c
net/rxrpc/recvmsg.c
net/sched/act_skbedit.c
net/sched/sch_taprio.c
net/sctp/sm_sideeffect.c
net/sctp/stream.c
net/tipc/addr.c
net/tipc/link.c
net/tipc/msg.h
net/tls/tls_device.c
net/tls/tls_main.c
tools/bpf/bpftool/common.c
tools/hv/hv_kvp_daemon.c
tools/include/uapi/linux/bpf.h
tools/lib/bpf/libbpf.c
tools/testing/selftests/bpf/verifier/loops1.c
tools/testing/selftests/kvm/include/evmcs.h
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/lib/x86_64/vmx.c
tools/testing/selftests/kvm/x86_64/evmcs_test.c
tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c
tools/testing/selftests/kvm/x86_64/platform_info_test.c
tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
tools/testing/selftests/net/tcp_fastopen_backup_key.sh
tools/testing/selftests/netfilter/nft_flowtable.sh
tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json
virt/kvm/arm/mmio.c
virt/kvm/arm/vgic/vgic-init.c

index f4c6121..6768305 100644 (file)
@@ -9,7 +9,7 @@ Linux PCI Bus Subsystem
    :numbered:
 
    pci
-   picebus-howto
+   pciebus-howto
    pci-iov-howto
    msi-howto
    acpi-info
diff --git a/Documentation/PCI/pciebus-howto.rst b/Documentation/PCI/pciebus-howto.rst
new file mode 100644 (file)
index 0000000..f882ff6
--- /dev/null
@@ -0,0 +1,220 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+
+===========================================
+The PCI Express Port Bus Driver Guide HOWTO
+===========================================
+
+:Author: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004
+:Copyright: |copy| 2004 Intel Corporation
+
+About this guide
+================
+
+This guide describes the basics of the PCI Express Port Bus driver
+and provides information on how to enable the service drivers to
+register/unregister with the PCI Express Port Bus Driver.
+
+
+What is the PCI Express Port Bus Driver
+=======================================
+
+A PCI Express Port is a logical PCI-PCI Bridge structure. There
+are two types of PCI Express Port: the Root Port and the Switch
+Port. The Root Port originates a PCI Express link from a PCI Express
+Root Complex and the Switch Port connects PCI Express links to
+internal logical PCI buses. The Switch Port, which has its secondary
+bus representing the switch's internal routing logic, is called the
+switch's Upstream Port. The switch's Downstream Port is bridging from
+switch's internal routing bus to a bus representing the downstream
+PCI Express link from the PCI Express Switch.
+
+A PCI Express Port can provide up to four distinct functions,
+referred to in this document as services, depending on its port type.
+PCI Express Port's services include native hotplug support (HP),
+power management event support (PME), advanced error reporting
+support (AER), and virtual channel support (VC). These services may
+be handled by a single complex driver or be individually distributed
+and handled by corresponding service drivers.
+
+Why use the PCI Express Port Bus Driver?
+========================================
+
+In existing Linux kernels, the Linux Device Driver Model allows a
+physical device to be handled by only a single driver. The PCI
+Express Port is a PCI-PCI Bridge device with multiple distinct
+services. To maintain a clean and simple solution each service
+may have its own software service driver. In this case several
+service drivers will compete for a single PCI-PCI Bridge device.
+For example, if the PCI Express Root Port native hotplug service
+driver is loaded first, it claims a PCI-PCI Bridge Root Port. The
+kernel therefore does not load other service drivers for that Root
+Port. In other words, it is impossible to have multiple service
+drivers load and run on a PCI-PCI Bridge device simultaneously
+using the current driver model.
+
+To enable multiple service drivers running simultaneously requires
+having a PCI Express Port Bus driver, which manages all populated
+PCI Express Ports and distributes all provided service requests
+to the corresponding service drivers as required. Some key
+advantages of using the PCI Express Port Bus driver are listed below:
+
+  - Allow multiple service drivers to run simultaneously on
+    a PCI-PCI Bridge Port device.
+
+  - Allow service drivers implemented in an independent
+    staged approach.
+
+  - Allow one service driver to run on multiple PCI-PCI Bridge
+    Port devices.
+
+  - Manage and distribute resources of a PCI-PCI Bridge Port
+    device to requested service drivers.
+
+Configuring the PCI Express Port Bus Driver vs. Service Drivers
+===============================================================
+
+Including the PCI Express Port Bus Driver Support into the Kernel
+-----------------------------------------------------------------
+
+Including the PCI Express Port Bus driver depends on whether the PCI
+Express support is included in the kernel config. The kernel will
+automatically include the PCI Express Port Bus driver as a kernel
+driver when the PCI Express support is enabled in the kernel.
+
+Enabling Service Driver Support
+-------------------------------
+
+PCI device drivers are implemented based on Linux Device Driver Model.
+All service drivers are PCI device drivers. As discussed above, it is
+impossible to load any service driver once the kernel has loaded the
+PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver
+Model requires some minimal changes on existing service drivers that
+imposes no impact on the functionality of existing service drivers.
+
+A service driver is required to use the two APIs shown below to
+register its service with the PCI Express Port Bus driver (see
+section 5.2.1 & 5.2.2). It is important that a service driver
+initializes the pcie_port_service_driver data structure, included in
+header file /include/linux/pcieport_if.h, before calling these APIs.
+Failure to do so will result an identity mismatch, which prevents
+the PCI Express Port Bus driver from loading a service driver.
+
+pcie_port_service_register
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+::
+
+  int pcie_port_service_register(struct pcie_port_service_driver *new)
+
+This API replaces the Linux Driver Model's pci_register_driver API. A
+service driver should always calls pcie_port_service_register at
+module init. Note that after service driver being loaded, calls
+such as pci_enable_device(dev) and pci_set_master(dev) are no longer
+necessary since these calls are executed by the PCI Port Bus driver.
+
+pcie_port_service_unregister
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+::
+
+  void pcie_port_service_unregister(struct pcie_port_service_driver *new)
+
+pcie_port_service_unregister replaces the Linux Driver Model's
+pci_unregister_driver. It's always called by service driver when a
+module exits.
+
+Sample Code
+~~~~~~~~~~~
+
+Below is sample service driver code to initialize the port service
+driver data structure.
+::
+
+  static struct pcie_port_service_id service_id[] = { {
+    .vendor = PCI_ANY_ID,
+    .device = PCI_ANY_ID,
+    .port_type = PCIE_RC_PORT,
+    .service_type = PCIE_PORT_SERVICE_AER,
+    }, { /* end: all zeroes */ }
+  };
+
+  static struct pcie_port_service_driver root_aerdrv = {
+    .name              = (char *)device_name,
+    .id_table  = &service_id[0],
+
+    .probe             = aerdrv_load,
+    .remove            = aerdrv_unload,
+
+    .suspend   = aerdrv_suspend,
+    .resume            = aerdrv_resume,
+  };
+
+Below is a sample code for registering/unregistering a service
+driver.
+::
+
+  static int __init aerdrv_service_init(void)
+  {
+    int retval = 0;
+
+    retval = pcie_port_service_register(&root_aerdrv);
+    if (!retval) {
+      /*
+      * FIX ME
+      */
+    }
+    return retval;
+  }
+
+  static void __exit aerdrv_service_exit(void)
+  {
+    pcie_port_service_unregister(&root_aerdrv);
+  }
+
+  module_init(aerdrv_service_init);
+  module_exit(aerdrv_service_exit);
+
+Possible Resource Conflicts
+===========================
+
+Since all service drivers of a PCI-PCI Bridge Port device are
+allowed to run simultaneously, below lists a few of possible resource
+conflicts with proposed solutions.
+
+MSI and MSI-X Vector Resource
+-----------------------------
+
+Once MSI or MSI-X interrupts are enabled on a device, it stays in this
+mode until they are disabled again.  Since service drivers of the same
+PCI-PCI Bridge port share the same physical device, if an individual
+service driver enables or disables MSI/MSI-X mode it may result
+unpredictable behavior.
+
+To avoid this situation all service drivers are not permitted to
+switch interrupt mode on its device. The PCI Express Port Bus driver
+is responsible for determining the interrupt mode and this should be
+transparent to service drivers. Service drivers need to know only
+the vector IRQ assigned to the field irq of struct pcie_device, which
+is passed in when the PCI Express Port Bus driver probes each service
+driver. Service drivers should use (struct pcie_device*)dev->irq to
+call request_irq/free_irq. In addition, the interrupt mode is stored
+in the field interrupt_mode of struct pcie_device.
+
+PCI Memory/IO Mapped Regions
+----------------------------
+
+Service drivers for PCI Express Power Management (PME), Advanced
+Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access
+PCI configuration space on the PCI Express port. In all cases the
+registers accessed are independent of each other. This patch assumes
+that all service drivers will be well behaved and not overwrite
+other service driver's configuration settings.
+
+PCI Config Registers
+--------------------
+
+Each service driver runs its PCI config operations on its own
+capability structure except the PCI Express capability structure, in
+which Root Control register and Device Control register are shared
+between PME and AER. This patch assumes that all service drivers
+will be well behaved and not overwrite other service driver's
+configuration settings.
diff --git a/Documentation/PCI/picebus-howto.rst b/Documentation/PCI/picebus-howto.rst
deleted file mode 100644 (file)
index f882ff6..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-===========================================
-The PCI Express Port Bus Driver Guide HOWTO
-===========================================
-
-:Author: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004
-:Copyright: |copy| 2004 Intel Corporation
-
-About this guide
-================
-
-This guide describes the basics of the PCI Express Port Bus driver
-and provides information on how to enable the service drivers to
-register/unregister with the PCI Express Port Bus Driver.
-
-
-What is the PCI Express Port Bus Driver
-=======================================
-
-A PCI Express Port is a logical PCI-PCI Bridge structure. There
-are two types of PCI Express Port: the Root Port and the Switch
-Port. The Root Port originates a PCI Express link from a PCI Express
-Root Complex and the Switch Port connects PCI Express links to
-internal logical PCI buses. The Switch Port, which has its secondary
-bus representing the switch's internal routing logic, is called the
-switch's Upstream Port. The switch's Downstream Port is bridging from
-switch's internal routing bus to a bus representing the downstream
-PCI Express link from the PCI Express Switch.
-
-A PCI Express Port can provide up to four distinct functions,
-referred to in this document as services, depending on its port type.
-PCI Express Port's services include native hotplug support (HP),
-power management event support (PME), advanced error reporting
-support (AER), and virtual channel support (VC). These services may
-be handled by a single complex driver or be individually distributed
-and handled by corresponding service drivers.
-
-Why use the PCI Express Port Bus Driver?
-========================================
-
-In existing Linux kernels, the Linux Device Driver Model allows a
-physical device to be handled by only a single driver. The PCI
-Express Port is a PCI-PCI Bridge device with multiple distinct
-services. To maintain a clean and simple solution each service
-may have its own software service driver. In this case several
-service drivers will compete for a single PCI-PCI Bridge device.
-For example, if the PCI Express Root Port native hotplug service
-driver is loaded first, it claims a PCI-PCI Bridge Root Port. The
-kernel therefore does not load other service drivers for that Root
-Port. In other words, it is impossible to have multiple service
-drivers load and run on a PCI-PCI Bridge device simultaneously
-using the current driver model.
-
-To enable multiple service drivers running simultaneously requires
-having a PCI Express Port Bus driver, which manages all populated
-PCI Express Ports and distributes all provided service requests
-to the corresponding service drivers as required. Some key
-advantages of using the PCI Express Port Bus driver are listed below:
-
-  - Allow multiple service drivers to run simultaneously on
-    a PCI-PCI Bridge Port device.
-
-  - Allow service drivers implemented in an independent
-    staged approach.
-
-  - Allow one service driver to run on multiple PCI-PCI Bridge
-    Port devices.
-
-  - Manage and distribute resources of a PCI-PCI Bridge Port
-    device to requested service drivers.
-
-Configuring the PCI Express Port Bus Driver vs. Service Drivers
-===============================================================
-
-Including the PCI Express Port Bus Driver Support into the Kernel
------------------------------------------------------------------
-
-Including the PCI Express Port Bus driver depends on whether the PCI
-Express support is included in the kernel config. The kernel will
-automatically include the PCI Express Port Bus driver as a kernel
-driver when the PCI Express support is enabled in the kernel.
-
-Enabling Service Driver Support
--------------------------------
-
-PCI device drivers are implemented based on Linux Device Driver Model.
-All service drivers are PCI device drivers. As discussed above, it is
-impossible to load any service driver once the kernel has loaded the
-PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver
-Model requires some minimal changes on existing service drivers that
-imposes no impact on the functionality of existing service drivers.
-
-A service driver is required to use the two APIs shown below to
-register its service with the PCI Express Port Bus driver (see
-section 5.2.1 & 5.2.2). It is important that a service driver
-initializes the pcie_port_service_driver data structure, included in
-header file /include/linux/pcieport_if.h, before calling these APIs.
-Failure to do so will result an identity mismatch, which prevents
-the PCI Express Port Bus driver from loading a service driver.
-
-pcie_port_service_register
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-::
-
-  int pcie_port_service_register(struct pcie_port_service_driver *new)
-
-This API replaces the Linux Driver Model's pci_register_driver API. A
-service driver should always calls pcie_port_service_register at
-module init. Note that after service driver being loaded, calls
-such as pci_enable_device(dev) and pci_set_master(dev) are no longer
-necessary since these calls are executed by the PCI Port Bus driver.
-
-pcie_port_service_unregister
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-::
-
-  void pcie_port_service_unregister(struct pcie_port_service_driver *new)
-
-pcie_port_service_unregister replaces the Linux Driver Model's
-pci_unregister_driver. It's always called by service driver when a
-module exits.
-
-Sample Code
-~~~~~~~~~~~
-
-Below is sample service driver code to initialize the port service
-driver data structure.
-::
-
-  static struct pcie_port_service_id service_id[] = { {
-    .vendor = PCI_ANY_ID,
-    .device = PCI_ANY_ID,
-    .port_type = PCIE_RC_PORT,
-    .service_type = PCIE_PORT_SERVICE_AER,
-    }, { /* end: all zeroes */ }
-  };
-
-  static struct pcie_port_service_driver root_aerdrv = {
-    .name              = (char *)device_name,
-    .id_table  = &service_id[0],
-
-    .probe             = aerdrv_load,
-    .remove            = aerdrv_unload,
-
-    .suspend   = aerdrv_suspend,
-    .resume            = aerdrv_resume,
-  };
-
-Below is a sample code for registering/unregistering a service
-driver.
-::
-
-  static int __init aerdrv_service_init(void)
-  {
-    int retval = 0;
-
-    retval = pcie_port_service_register(&root_aerdrv);
-    if (!retval) {
-      /*
-      * FIX ME
-      */
-    }
-    return retval;
-  }
-
-  static void __exit aerdrv_service_exit(void)
-  {
-    pcie_port_service_unregister(&root_aerdrv);
-  }
-
-  module_init(aerdrv_service_init);
-  module_exit(aerdrv_service_exit);
-
-Possible Resource Conflicts
-===========================
-
-Since all service drivers of a PCI-PCI Bridge Port device are
-allowed to run simultaneously, below lists a few of possible resource
-conflicts with proposed solutions.
-
-MSI and MSI-X Vector Resource
------------------------------
-
-Once MSI or MSI-X interrupts are enabled on a device, it stays in this
-mode until they are disabled again.  Since service drivers of the same
-PCI-PCI Bridge port share the same physical device, if an individual
-service driver enables or disables MSI/MSI-X mode it may result
-unpredictable behavior.
-
-To avoid this situation all service drivers are not permitted to
-switch interrupt mode on its device. The PCI Express Port Bus driver
-is responsible for determining the interrupt mode and this should be
-transparent to service drivers. Service drivers need to know only
-the vector IRQ assigned to the field irq of struct pcie_device, which
-is passed in when the PCI Express Port Bus driver probes each service
-driver. Service drivers should use (struct pcie_device*)dev->irq to
-call request_irq/free_irq. In addition, the interrupt mode is stored
-in the field interrupt_mode of struct pcie_device.
-
-PCI Memory/IO Mapped Regions
-----------------------------
-
-Service drivers for PCI Express Power Management (PME), Advanced
-Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access
-PCI configuration space on the PCI Express port. In all cases the
-registers accessed are independent of each other. This patch assumes
-that all service drivers will be well behaved and not overwrite
-other service driver's configuration settings.
-
-PCI Config Registers
---------------------
-
-Each service driver runs its PCI config operations on its own
-capability structure except the PCI Express capability structure, in
-which Root Control register and Device Control register are shared
-between PME and AER. This patch assumes that all service drivers
-will be well behaved and not overwrite other service driver's
-configuration settings.
index 47d981a..4c19719 100644 (file)
                        Run specified binary instead of /init from the ramdisk,
                        used for early userspace startup. See initrd.
 
+       rdrand=         [X86]
+                       force - Override the decision by the kernel to hide the
+                               advertisement of RDRAND support (this affects
+                               certain AMD processors because of buggy BIOS
+                               support, specifically around the suspend/resume
+                               path).
+
        rdt=            [HW,X86,RDT]
                        Turn on/off individual RDT features. List is:
                        cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, l2cdp,
index a7d44e7..287b987 100644 (file)
@@ -39,7 +39,6 @@ Table : Subdirectories in /proc/sys/net
  802       E802 protocol         ax25       AX25
  ethernet  Ethernet protocol     rose       X.25 PLP layer
  ipv4      IP version 4          x25        X.25 protocol
- ipx       IPX                   token-ring IBM token ring
  bridge    Bridging              decnet     DEC net
  ipv6      IP version 6          tipc       TIPC
  ========= =================== = ========== ==================
@@ -401,33 +400,7 @@ interface.
 (network) that the route leads to, the router (may be directly connected), the
 route flags, and the device the route is using.
 
-
-5. IPX
-------
-
-The IPX protocol has no tunable values in proc/sys/net.
-
-The IPX  protocol  does,  however,  provide  proc/net/ipx. This lists each IPX
-socket giving  the  local  and  remote  addresses  in  Novell  format (that is
-network:node:port). In  accordance  with  the  strange  Novell  tradition,
-everything but the port is in hex. Not_Connected is displayed for sockets that
-are not  tied to a specific remote address. The Tx and Rx queue sizes indicate
-the number  of  bytes  pending  for  transmission  and  reception.  The  state
-indicates the  state  the  socket  is  in and the uid is the owning uid of the
-socket.
-
-The /proc/net/ipx_interface  file lists all IPX interfaces. For each interface
-it gives  the network number, the node number, and indicates if the network is
-the primary  network.  It  also  indicates  which  device  it  is bound to (or
-Internal for  internal  networks)  and  the  Frame  Type if appropriate. Linux
-supports 802.3,  802.2,  802.2  SNAP  and DIX (Blue Book) ethernet framing for
-IPX.
-
-The /proc/net/ipx_route  table  holds  a list of IPX routes. For each route it
-gives the  destination  network, the router node (or Directly) and the network
-address of the router (or Connected) for internal networks.
-
-6. TIPC
+5. TIPC
 -------
 
 tipc_rmem
index b70b70d..0dd3f74 100644 (file)
@@ -506,21 +506,3 @@ Drivers should ignore the changes to TLS the device feature flags.
 These flags will be acted upon accordingly by the core ``ktls`` code.
 TLS device feature flags only control adding of new TLS connection
 offloads, old connections will remain active after flags are cleared.
-
-Known bugs
-==========
-
-skb_orphan() leaks clear text
------------------------------
-
-Currently drivers depend on the :c:member:`sk` member of
-:c:type:`struct sk_buff <sk_buff>` to identify segments requiring
-encryption. Any operation which removes or does not preserve the socket
-association such as :c:func:`skb_orphan` or :c:func:`skb_clone`
-will cause the driver to miss the packets and lead to clear text leaks.
-
-Redirects leak clear text
--------------------------
-
-In the RX direction, if segment has already been decrypted by the device
-and it gets redirected or mirrored - clear text will be transmitted out.
index 949d5dc..0104830 100644 (file)
@@ -204,8 +204,8 @@ Ethernet device, which instead of receiving packets from a physical
 media, receives them from user space program and instead of sending 
 packets via physical media sends them to the user space program. 
 
-Let's say that you configured IPX on the tap0, then whenever 
-the kernel sends an IPX packet to tap0, it is passed to the application
+Let's say that you configured IPv6 on the tap0, then whenever
+the kernel sends an IPv6 packet to tap0, it is passed to the application
 (VTun for example). The application encrypts, compresses and sends it to 
 the other side over TCP or UDP. The application on the other side decompresses
 and decrypts the data received and writes the packet to the TAP device, 
index 43604d6..9cbcf16 100644 (file)
@@ -183,7 +183,7 @@ M:  Realtek linux nic maintainers <nic_swsd@realtek.com>
 M:     Heiner Kallweit <hkallweit1@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ethernet/realtek/r8169.c
+F:     drivers/net/ethernet/realtek/r8169*
 
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
@@ -6065,7 +6065,7 @@ M:        Florian Fainelli <f.fainelli@gmail.com>
 M:     Heiner Kallweit <hkallweit1@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     Documentation/ABI/testing/sysfs-bus-mdio
+F:     Documentation/ABI/testing/sysfs-class-net-phydev
 F:     Documentation/devicetree/bindings/net/ethernet-phy.yaml
 F:     Documentation/devicetree/bindings/net/mdio*
 F:     Documentation/networking/phy.rst
@@ -8832,14 +8832,6 @@ F:       virt/kvm/*
 F:     tools/kvm/
 F:     tools/testing/selftests/kvm/
 
-KERNEL VIRTUAL MACHINE FOR AMD-V (KVM/amd)
-M:     Joerg Roedel <joro@8bytes.org>
-L:     kvm@vger.kernel.org
-W:     http://www.linux-kvm.org/
-S:     Maintained
-F:     arch/x86/include/asm/svm.h
-F:     arch/x86/kvm/svm.c
-
 KERNEL VIRTUAL MACHINE FOR ARM/ARM64 (KVM/arm, KVM/arm64)
 M:     Marc Zyngier <maz@kernel.org>
 R:     James Morse <james.morse@arm.com>
@@ -8882,7 +8874,7 @@ M:        Christian Borntraeger <borntraeger@de.ibm.com>
 M:     Janosch Frank <frankja@linux.ibm.com>
 R:     David Hildenbrand <david@redhat.com>
 R:     Cornelia Huck <cohuck@redhat.com>
-L:     linux-s390@vger.kernel.org
+L:     kvm@vger.kernel.org
 W:     http://www.ibm.com/developerworks/linux/linux390/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
 S:     Supported
@@ -8897,6 +8889,11 @@ F:       tools/testing/selftests/kvm/*/s390x/
 KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86)
 M:     Paolo Bonzini <pbonzini@redhat.com>
 M:     Radim Krčmář <rkrcmar@redhat.com>
+R:     Sean Christopherson <sean.j.christopherson@intel.com>
+R:     Vitaly Kuznetsov <vkuznets@redhat.com>
+R:     Wanpeng Li <wanpengli@tencent.com>
+R:     Jim Mattson <jmattson@google.com>
+R:     Joerg Roedel <joro@8bytes.org>
 L:     kvm@vger.kernel.org
 W:     http://www.linux-kvm.org
 T:     git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
@@ -8904,8 +8901,12 @@ S:       Supported
 F:     arch/x86/kvm/
 F:     arch/x86/kvm/*/
 F:     arch/x86/include/uapi/asm/kvm*
+F:     arch/x86/include/uapi/asm/vmx.h
+F:     arch/x86/include/uapi/asm/svm.h
 F:     arch/x86/include/asm/kvm*
 F:     arch/x86/include/asm/pvclock-abi.h
+F:     arch/x86/include/asm/svm.h
+F:     arch/x86/include/asm/vmx.h
 F:     arch/x86/kernel/kvm.c
 F:     arch/x86/kernel/kvmclock.c
 
@@ -14882,9 +14883,9 @@ F:      include/linux/arm_sdei.h
 F:     include/uapi/linux/arm_sdei.h
 
 SOFTWARE RAID (Multiple Disks) SUPPORT
-M:     Shaohua Li <shli@kernel.org>
+M:     Song Liu <song@kernel.org>
 L:     linux-raid@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shli/md.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/song/md.git
 S:     Supported
 F:     drivers/md/Makefile
 F:     drivers/md/Kconfig
index 9fa1861..f125625 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 3
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc6
 NAME = Bobtail Squid
 
 # *DOCUMENTATION*
index 33b0057..2436021 100644 (file)
@@ -7,6 +7,8 @@ config ARM
        select ARCH_HAS_BINFMT_FLAT
        select ARCH_HAS_DEBUG_VIRTUAL if MMU
        select ARCH_HAS_DEVMEM_IS_ALLOWED
+       select ARCH_HAS_DMA_COHERENT_TO_PFN if SWIOTLB
+       select ARCH_HAS_DMA_MMAP_PGPROT if SWIOTLB
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_KEEPINITRD
@@ -18,6 +20,8 @@ config ARM
        select ARCH_HAS_SET_MEMORY
        select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL
        select ARCH_HAS_STRICT_MODULE_RWX if MMU
+       select ARCH_HAS_SYNC_DMA_FOR_DEVICE if SWIOTLB
+       select ARCH_HAS_SYNC_DMA_FOR_CPU if SWIOTLB
        select ARCH_HAS_TEARDOWN_DMA_OPS if MMU
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_HAVE_CUSTOM_GPIO_H
index 0ce56ad..ea2c842 100644 (file)
@@ -46,6 +46,7 @@ static int __init parse_tag_acorn(const struct tag *tag)
        switch (tag->u.acorn.vram_pages) {
        case 512:
                vram_size += PAGE_SIZE * 256;
+               /* Fall through - ??? */
        case 256:
                vram_size += PAGE_SIZE * 256;
        default:
index c54cd7e..c1222c0 100644 (file)
@@ -664,10 +664,6 @@ config ARM_LPAE
                !CPU_32v4 && !CPU_32v3
        select PHYS_ADDR_T_64BIT
        select SWIOTLB
-       select ARCH_HAS_DMA_COHERENT_TO_PFN
-       select ARCH_HAS_DMA_MMAP_PGPROT
-       select ARCH_HAS_SYNC_DMA_FOR_DEVICE
-       select ARCH_HAS_SYNC_DMA_FOR_CPU
        help
          Say Y if you have an ARMv7 processor supporting the LPAE page
          table format and you would like to access memory beyond the
index 52cf96e..cbc7cda 100644 (file)
@@ -46,6 +46,7 @@ static inline uint64_t CVMX_SLI_PCIE_MSI_RCV_FUNC(void)
        case OCTEON_CN78XX & OCTEON_FAMILY_MASK:
                if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X))
                        return 0x0000000000003CB0ull;
+               /* Else, fall through */
        default:
                return 0x0000000000023CB0ull;
        }
index a39b079..6d58c17 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _PARISC_PGTABLE_H
 #define _PARISC_PGTABLE_H
 
+#include <asm/page.h>
 #include <asm-generic/4level-fixup.h>
 
 #include <asm/fixmap.h>
@@ -98,8 +99,6 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 
 #endif /* !__ASSEMBLY__ */
 
-#include <asm/page.h>
-
 #define pte_ERROR(e) \
        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
index 8574338..9991ec2 100644 (file)
@@ -34,10 +34,13 @@ static inline void time_travel_set_time(unsigned long long ns)
        time_travel_time = ns;
 }
 
-static inline void time_travel_set_timer(enum time_travel_timer_mode mode,
-                                        unsigned long long expiry)
+static inline void time_travel_set_timer_mode(enum time_travel_timer_mode mode)
 {
        time_travel_timer_mode = mode;
+}
+
+static inline void time_travel_set_timer_expiry(unsigned long long expiry)
+{
        time_travel_timer_expiry = expiry;
 }
 #else
@@ -50,8 +53,11 @@ static inline void time_travel_set_time(unsigned long long ns)
 {
 }
 
-static inline void time_travel_set_timer(enum time_travel_timer_mode mode,
-                                        unsigned long long expiry)
+static inline void time_travel_set_timer_mode(enum time_travel_timer_mode mode)
+{
+}
+
+static inline void time_travel_set_timer_expiry(unsigned long long expiry)
 {
 }
 
index 67c0d1a..6bede78 100644 (file)
@@ -213,7 +213,7 @@ static void time_travel_sleep(unsigned long long duration)
        if (time_travel_timer_mode != TT_TMR_DISABLED ||
            time_travel_timer_expiry < next) {
                if (time_travel_timer_mode == TT_TMR_ONESHOT)
-                       time_travel_set_timer(TT_TMR_DISABLED, 0);
+                       time_travel_set_timer_mode(TT_TMR_DISABLED);
                /*
                 * time_travel_time will be adjusted in the timer
                 * IRQ handler so it works even when the signal
index 6a051b0..2347572 100644 (file)
@@ -50,7 +50,7 @@ void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
 static int itimer_shutdown(struct clock_event_device *evt)
 {
        if (time_travel_mode != TT_MODE_OFF)
-               time_travel_set_timer(TT_TMR_DISABLED, 0);
+               time_travel_set_timer_mode(TT_TMR_DISABLED);
 
        if (time_travel_mode != TT_MODE_INFCPU)
                os_timer_disable();
@@ -62,9 +62,10 @@ static int itimer_set_periodic(struct clock_event_device *evt)
 {
        unsigned long long interval = NSEC_PER_SEC / HZ;
 
-       if (time_travel_mode != TT_MODE_OFF)
-               time_travel_set_timer(TT_TMR_PERIODIC,
-                                     time_travel_time + interval);
+       if (time_travel_mode != TT_MODE_OFF) {
+               time_travel_set_timer_mode(TT_TMR_PERIODIC);
+               time_travel_set_timer_expiry(time_travel_time + interval);
+       }
 
        if (time_travel_mode != TT_MODE_INFCPU)
                os_timer_set_interval(interval);
@@ -77,9 +78,10 @@ static int itimer_next_event(unsigned long delta,
 {
        delta += 1;
 
-       if (time_travel_mode != TT_MODE_OFF)
-               time_travel_set_timer(TT_TMR_ONESHOT,
-                                     time_travel_time + delta);
+       if (time_travel_mode != TT_MODE_OFF) {
+               time_travel_set_timer_mode(TT_TMR_ONESHOT);
+               time_travel_set_timer_expiry(time_travel_time + delta);
+       }
 
        if (time_travel_mode != TT_MODE_INFCPU)
                return os_timer_one_shot(delta);
index 5f2d030..2faddeb 100644 (file)
@@ -72,6 +72,8 @@ static unsigned long find_trampoline_placement(void)
 
        /* Find the first usable memory region under bios_start. */
        for (i = boot_params->e820_entries - 1; i >= 0; i--) {
+               unsigned long new;
+
                entry = &boot_params->e820_table[i];
 
                /* Skip all entries above bios_start. */
@@ -84,15 +86,20 @@ static unsigned long find_trampoline_placement(void)
 
                /* Adjust bios_start to the end of the entry if needed. */
                if (bios_start > entry->addr + entry->size)
-                       bios_start = entry->addr + entry->size;
+                       new = entry->addr + entry->size;
 
                /* Keep bios_start page-aligned. */
-               bios_start = round_down(bios_start, PAGE_SIZE);
+               new = round_down(new, PAGE_SIZE);
 
                /* Skip the entry if it's too small. */
-               if (bios_start - TRAMPOLINE_32BIT_SIZE < entry->addr)
+               if (new - TRAMPOLINE_32BIT_SIZE < entry->addr)
                        continue;
 
+               /* Protect against underflow. */
+               if (new - TRAMPOLINE_32BIT_SIZE > bios_start)
+                       break;
+
+               bios_start = new;
                break;
        }
 
index 81b005e..325959d 100644 (file)
@@ -1236,7 +1236,7 @@ void x86_pmu_enable_event(struct perf_event *event)
  * Add a single event to the PMU.
  *
  * The event is added to the group of enabled events
- * but only if it can be scehduled with existing events.
+ * but only if it can be scheduled with existing events.
  */
 static int x86_pmu_add(struct perf_event *event, int flags)
 {
index f5e90a8..9e5f3c7 100644 (file)
@@ -59,7 +59,6 @@ static void sanitize_boot_params(struct boot_params *boot_params)
                        BOOT_PARAM_PRESERVE(apm_bios_info),
                        BOOT_PARAM_PRESERVE(tboot_addr),
                        BOOT_PARAM_PRESERVE(ist_info),
-                       BOOT_PARAM_PRESERVE(acpi_rsdp_addr),
                        BOOT_PARAM_PRESERVE(hd0_info),
                        BOOT_PARAM_PRESERVE(hd1_info),
                        BOOT_PARAM_PRESERVE(sys_desc_table),
@@ -71,6 +70,7 @@ static void sanitize_boot_params(struct boot_params *boot_params)
                        BOOT_PARAM_PRESERVE(eddbuf_entries),
                        BOOT_PARAM_PRESERVE(edd_mbr_sig_buf_entries),
                        BOOT_PARAM_PRESERVE(edd_mbr_sig_buffer),
+                       BOOT_PARAM_PRESERVE(hdr),
                        BOOT_PARAM_PRESERVE(e820_table),
                        BOOT_PARAM_PRESERVE(eddbuf),
                };
index 0278aa6..fe7c205 100644 (file)
  * While adding a new CPUID for a new microarchitecture, add a new
  * group to keep logically sorted out in chronological order. Within
  * that group keep the CPUID for the variants sorted by model number.
+ *
+ * The defined symbol names have the following form:
+ *     INTEL_FAM6{OPTFAMILY}_{MICROARCH}{OPTDIFF}
+ * where:
+ * OPTFAMILY   Describes the family of CPUs that this belongs to. Default
+ *             is assumed to be "_CORE" (and should be omitted). Other values
+ *             currently in use are _ATOM and _XEON_PHI
+ * MICROARCH   Is the code name for the micro-architecture for this core.
+ *             N.B. Not the platform name.
+ * OPTDIFF     If needed, a short string to differentiate by market segment.
+ *             Exact strings here will vary over time. _DESKTOP, _MOBILE, and
+ *             _X (short for Xeon server) should be used when they are
+ *             appropriate.
+ *
+ * The #define line may optionally include a comment including platform names.
  */
 
 #define INTEL_FAM6_CORE_YONAH          0x0E
index 6b4fc27..271d837 100644 (file)
 #define MSR_AMD64_PATCH_LEVEL          0x0000008b
 #define MSR_AMD64_TSC_RATIO            0xc0000104
 #define MSR_AMD64_NB_CFG               0xc001001f
+#define MSR_AMD64_CPUID_FN_1           0xc0011004
 #define MSR_AMD64_PATCH_LOADER         0xc0010020
 #define MSR_AMD64_OSVW_ID_LENGTH       0xc0010140
 #define MSR_AMD64_OSVW_STATUS          0xc0010141
index 109f974..80bc209 100644 (file)
        "       lfence;\n"                                      \
        "       jmp    902b;\n"                                 \
        "       .align 16\n"                                    \
-       "903:   addl   $4, %%esp;\n"                            \
+       "903:   lea    4(%%esp), %%esp;\n"                      \
        "       pushl  %[thunk_target];\n"                      \
        "       ret;\n"                                         \
        "       .align 16\n"                                    \
index f529136..aa5495d 100644 (file)
@@ -722,7 +722,7 @@ static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2;
 static __initdata unsigned long lapic_cal_j1, lapic_cal_j2;
 
 /*
- * Temporary interrupt handler.
+ * Temporary interrupt handler and polled calibration function.
  */
 static void __init lapic_cal_handler(struct clock_event_device *dev)
 {
@@ -851,7 +851,8 @@ bool __init apic_needs_pit(void)
 static int __init calibrate_APIC_clock(void)
 {
        struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
-       void (*real_handler)(struct clock_event_device *dev);
+       u64 tsc_perj = 0, tsc_start = 0;
+       unsigned long jif_start;
        unsigned long deltaj;
        long delta, deltatsc;
        int pm_referenced = 0;
@@ -878,28 +879,64 @@ static int __init calibrate_APIC_clock(void)
        apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
                    "calibrating APIC timer ...\n");
 
+       /*
+        * There are platforms w/o global clockevent devices. Instead of
+        * making the calibration conditional on that, use a polling based
+        * approach everywhere.
+        */
        local_irq_disable();
 
-       /* Replace the global interrupt handler */
-       real_handler = global_clock_event->event_handler;
-       global_clock_event->event_handler = lapic_cal_handler;
-
        /*
         * Setup the APIC counter to maximum. There is no way the lapic
         * can underflow in the 100ms detection time frame
         */
        __setup_APIC_LVTT(0xffffffff, 0, 0);
 
-       /* Let the interrupts run */
+       /*
+        * Methods to terminate the calibration loop:
+        *  1) Global clockevent if available (jiffies)
+        *  2) TSC if available and frequency is known
+        */
+       jif_start = READ_ONCE(jiffies);
+
+       if (tsc_khz) {
+               tsc_start = rdtsc();
+               tsc_perj = div_u64((u64)tsc_khz * 1000, HZ);
+       }
+
+       /*
+        * Enable interrupts so the tick can fire, if a global
+        * clockevent device is available
+        */
        local_irq_enable();
 
-       while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
-               cpu_relax();
+       while (lapic_cal_loops <= LAPIC_CAL_LOOPS) {
+               /* Wait for a tick to elapse */
+               while (1) {
+                       if (tsc_khz) {
+                               u64 tsc_now = rdtsc();
+                               if ((tsc_now - tsc_start) >= tsc_perj) {
+                                       tsc_start += tsc_perj;
+                                       break;
+                               }
+                       } else {
+                               unsigned long jif_now = READ_ONCE(jiffies);
 
-       local_irq_disable();
+                               if (time_after(jif_now, jif_start)) {
+                                       jif_start = jif_now;
+                                       break;
+                               }
+                       }
+                       cpu_relax();
+               }
 
-       /* Restore the real event handler */
-       global_clock_event->event_handler = real_handler;
+               /* Invoke the calibration routine */
+               local_irq_disable();
+               lapic_cal_handler(NULL);
+               local_irq_enable();
+       }
+
+       local_irq_disable();
 
        /* Build delta t1-t2 as apic timer counts down */
        delta = lapic_cal_t1 - lapic_cal_t2;
@@ -943,10 +980,11 @@ static int __init calibrate_APIC_clock(void)
        levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
 
        /*
-        * PM timer calibration failed or not turned on
-        * so lets try APIC timer based calibration
+        * PM timer calibration failed or not turned on so lets try APIC
+        * timer based calibration, if a global clockevent device is
+        * available.
         */
-       if (!pm_referenced) {
+       if (!pm_referenced && global_clock_event) {
                apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
 
                /*
index 8d4e504..68c363c 100644 (file)
@@ -804,6 +804,64 @@ static void init_amd_ln(struct cpuinfo_x86 *c)
        msr_set_bit(MSR_AMD64_DE_CFG, 31);
 }
 
+static bool rdrand_force;
+
+static int __init rdrand_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       if (!strcmp(str, "force"))
+               rdrand_force = true;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+early_param("rdrand", rdrand_cmdline);
+
+static void clear_rdrand_cpuid_bit(struct cpuinfo_x86 *c)
+{
+       /*
+        * Saving of the MSR used to hide the RDRAND support during
+        * suspend/resume is done by arch/x86/power/cpu.c, which is
+        * dependent on CONFIG_PM_SLEEP.
+        */
+       if (!IS_ENABLED(CONFIG_PM_SLEEP))
+               return;
+
+       /*
+        * The nordrand option can clear X86_FEATURE_RDRAND, so check for
+        * RDRAND support using the CPUID function directly.
+        */
+       if (!(cpuid_ecx(1) & BIT(30)) || rdrand_force)
+               return;
+
+       msr_clear_bit(MSR_AMD64_CPUID_FN_1, 62);
+
+       /*
+        * Verify that the CPUID change has occurred in case the kernel is
+        * running virtualized and the hypervisor doesn't support the MSR.
+        */
+       if (cpuid_ecx(1) & BIT(30)) {
+               pr_info_once("BIOS may not properly restore RDRAND after suspend, but hypervisor does not support hiding RDRAND via CPUID.\n");
+               return;
+       }
+
+       clear_cpu_cap(c, X86_FEATURE_RDRAND);
+       pr_info_once("BIOS may not properly restore RDRAND after suspend, hiding RDRAND via CPUID. Use rdrand=force to reenable.\n");
+}
+
+static void init_amd_jg(struct cpuinfo_x86 *c)
+{
+       /*
+        * Some BIOS implementations do not restore proper RDRAND support
+        * across suspend and resume. Check on whether to hide the RDRAND
+        * instruction support via CPUID.
+        */
+       clear_rdrand_cpuid_bit(c);
+}
+
 static void init_amd_bd(struct cpuinfo_x86 *c)
 {
        u64 value;
@@ -818,6 +876,13 @@ static void init_amd_bd(struct cpuinfo_x86 *c)
                        wrmsrl_safe(MSR_F15H_IC_CFG, value);
                }
        }
+
+       /*
+        * Some BIOS implementations do not restore proper RDRAND support
+        * across suspend and resume. Check on whether to hide the RDRAND
+        * instruction support via CPUID.
+        */
+       clear_rdrand_cpuid_bit(c);
 }
 
 static void init_amd_zn(struct cpuinfo_x86 *c)
@@ -860,6 +925,7 @@ static void init_amd(struct cpuinfo_x86 *c)
        case 0x10: init_amd_gh(c); break;
        case 0x12: init_amd_ln(c); break;
        case 0x15: init_amd_bd(c); break;
+       case 0x16: init_amd_jg(c); break;
        case 0x17: init_amd_zn(c); break;
        }
 
index 685d17c..e904ff0 100644 (file)
@@ -216,6 +216,9 @@ static void recalculate_apic_map(struct kvm *kvm)
                if (!apic_x2apic_mode(apic) && !new->phys_map[xapic_id])
                        new->phys_map[xapic_id] = apic;
 
+               if (!kvm_apic_sw_enabled(apic))
+                       continue;
+
                ldr = kvm_lapic_get_reg(apic, APIC_LDR);
 
                if (apic_x2apic_mode(apic)) {
@@ -258,6 +261,8 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
                        static_key_slow_dec_deferred(&apic_sw_disabled);
                else
                        static_key_slow_inc(&apic_sw_disabled.key);
+
+               recalculate_apic_map(apic->vcpu->kvm);
        }
 }
 
index 24843cf..218b277 100644 (file)
@@ -5653,38 +5653,7 @@ static void kvm_mmu_invalidate_zap_pages_in_memslot(struct kvm *kvm,
                        struct kvm_memory_slot *slot,
                        struct kvm_page_track_notifier_node *node)
 {
-       struct kvm_mmu_page *sp;
-       LIST_HEAD(invalid_list);
-       unsigned long i;
-       bool flush;
-       gfn_t gfn;
-
-       spin_lock(&kvm->mmu_lock);
-
-       if (list_empty(&kvm->arch.active_mmu_pages))
-               goto out_unlock;
-
-       flush = slot_handle_all_level(kvm, slot, kvm_zap_rmapp, false);
-
-       for (i = 0; i < slot->npages; i++) {
-               gfn = slot->base_gfn + i;
-
-               for_each_valid_sp(kvm, sp, gfn) {
-                       if (sp->gfn != gfn)
-                               continue;
-
-                       kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
-               }
-               if (need_resched() || spin_needbreak(&kvm->mmu_lock)) {
-                       kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, flush);
-                       flush = false;
-                       cond_resched_lock(&kvm->mmu_lock);
-               }
-       }
-       kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, flush);
-
-out_unlock:
-       spin_unlock(&kvm->mmu_lock);
+       kvm_mmu_zap_all(kvm);
 }
 
 void kvm_mmu_init_vm(struct kvm *kvm)
index d685491..e3d3b21 100644 (file)
@@ -1714,7 +1714,6 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu)
        if (!entry)
                return -EINVAL;
 
-       new_entry = READ_ONCE(*entry);
        new_entry = __sme_set((page_to_phys(svm->avic_backing_page) &
                              AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK) |
                              AVIC_PHYSICAL_ID_ENTRY_VALID_MASK);
index eaaed5b..991549a 100644 (file)
@@ -390,8 +390,9 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
 
        emit_prologue(&prog, bpf_prog->aux->stack_depth,
                      bpf_prog_was_classic(bpf_prog));
+       addrs[0] = prog - temp;
 
-       for (i = 0; i < insn_cnt; i++, insn++) {
+       for (i = 1; i <= insn_cnt; i++, insn++) {
                const s32 imm32 = insn->imm;
                u32 dst_reg = insn->dst_reg;
                u32 src_reg = insn->src_reg;
@@ -1105,7 +1106,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
                extra_pass = true;
                goto skip_init_addrs;
        }
-       addrs = kmalloc_array(prog->len, sizeof(*addrs), GFP_KERNEL);
+       addrs = kmalloc_array(prog->len + 1, sizeof(*addrs), GFP_KERNEL);
        if (!addrs) {
                prog = orig_prog;
                goto out_addrs;
@@ -1115,7 +1116,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
         * Before first pass, make a rough estimation of addrs[]
         * each BPF instruction is translated to less than 64 bytes
         */
-       for (proglen = 0, i = 0; i < prog->len; i++) {
+       for (proglen = 0, i = 0; i <= prog->len; i++) {
                proglen += 64;
                addrs[i] = proglen;
        }
@@ -1180,7 +1181,7 @@ out_image:
 
        if (!image || !prog->is_func || extra_pass) {
                if (image)
-                       bpf_prog_fill_jited_linfo(prog, addrs);
+                       bpf_prog_fill_jited_linfo(prog, addrs + 1);
 out_addrs:
                kfree(addrs);
                kfree(jit_data);
index 24b079e..c9ef6a7 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/smp.h>
 #include <linux/perf_event.h>
 #include <linux/tboot.h>
+#include <linux/dmi.h>
 
 #include <asm/pgtable.h>
 #include <asm/proto.h>
@@ -23,7 +24,7 @@
 #include <asm/debugreg.h>
 #include <asm/cpu.h>
 #include <asm/mmu_context.h>
-#include <linux/dmi.h>
+#include <asm/cpu_device_id.h>
 
 #ifdef CONFIG_X86_32
 __visible unsigned long saved_context_ebx;
@@ -397,15 +398,14 @@ static int __init bsp_pm_check_init(void)
 
 core_initcall(bsp_pm_check_init);
 
-static int msr_init_context(const u32 *msr_id, const int total_num)
+static int msr_build_context(const u32 *msr_id, const int num)
 {
-       int i = 0;
+       struct saved_msrs *saved_msrs = &saved_context.saved_msrs;
        struct saved_msr *msr_array;
+       int total_num;
+       int i, j;
 
-       if (saved_context.saved_msrs.array || saved_context.saved_msrs.num > 0) {
-               pr_err("x86/pm: MSR quirk already applied, please check your DMI match table.\n");
-               return -EINVAL;
-       }
+       total_num = saved_msrs->num + num;
 
        msr_array = kmalloc_array(total_num, sizeof(struct saved_msr), GFP_KERNEL);
        if (!msr_array) {
@@ -413,19 +413,30 @@ static int msr_init_context(const u32 *msr_id, const int total_num)
                return -ENOMEM;
        }
 
-       for (i = 0; i < total_num; i++) {
-               msr_array[i].info.msr_no        = msr_id[i];
+       if (saved_msrs->array) {
+               /*
+                * Multiple callbacks can invoke this function, so copy any
+                * MSR save requests from previous invocations.
+                */
+               memcpy(msr_array, saved_msrs->array,
+                      sizeof(struct saved_msr) * saved_msrs->num);
+
+               kfree(saved_msrs->array);
+       }
+
+       for (i = saved_msrs->num, j = 0; i < total_num; i++, j++) {
+               msr_array[i].info.msr_no        = msr_id[j];
                msr_array[i].valid              = false;
                msr_array[i].info.reg.q         = 0;
        }
-       saved_context.saved_msrs.num    = total_num;
-       saved_context.saved_msrs.array  = msr_array;
+       saved_msrs->num   = total_num;
+       saved_msrs->array = msr_array;
 
        return 0;
 }
 
 /*
- * The following section is a quirk framework for problematic BIOSen:
+ * The following sections are a quirk framework for problematic BIOSen:
  * Sometimes MSRs are modified by the BIOSen after suspended to
  * RAM, this might cause unexpected behavior after wakeup.
  * Thus we save/restore these specified MSRs across suspend/resume
@@ -440,7 +451,7 @@ static int msr_initialize_bdw(const struct dmi_system_id *d)
        u32 bdw_msr_id[] = { MSR_IA32_THERM_CONTROL };
 
        pr_info("x86/pm: %s detected, MSR saving is needed during suspending.\n", d->ident);
-       return msr_init_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
+       return msr_build_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
 }
 
 static const struct dmi_system_id msr_save_dmi_table[] = {
@@ -455,9 +466,58 @@ static const struct dmi_system_id msr_save_dmi_table[] = {
        {}
 };
 
+static int msr_save_cpuid_features(const struct x86_cpu_id *c)
+{
+       u32 cpuid_msr_id[] = {
+               MSR_AMD64_CPUID_FN_1,
+       };
+
+       pr_info("x86/pm: family %#hx cpu detected, MSR saving is needed during suspending.\n",
+               c->family);
+
+       return msr_build_context(cpuid_msr_id, ARRAY_SIZE(cpuid_msr_id));
+}
+
+static const struct x86_cpu_id msr_save_cpu_table[] = {
+       {
+               .vendor = X86_VENDOR_AMD,
+               .family = 0x15,
+               .model = X86_MODEL_ANY,
+               .feature = X86_FEATURE_ANY,
+               .driver_data = (kernel_ulong_t)msr_save_cpuid_features,
+       },
+       {
+               .vendor = X86_VENDOR_AMD,
+               .family = 0x16,
+               .model = X86_MODEL_ANY,
+               .feature = X86_FEATURE_ANY,
+               .driver_data = (kernel_ulong_t)msr_save_cpuid_features,
+       },
+       {}
+};
+
+typedef int (*pm_cpu_match_t)(const struct x86_cpu_id *);
+static int pm_cpu_check(const struct x86_cpu_id *c)
+{
+       const struct x86_cpu_id *m;
+       int ret = 0;
+
+       m = x86_match_cpu(msr_save_cpu_table);
+       if (m) {
+               pm_cpu_match_t fn;
+
+               fn = (pm_cpu_match_t)m->driver_data;
+               ret = fn(m);
+       }
+
+       return ret;
+}
+
 static int pm_check_save_msr(void)
 {
        dmi_check_system(msr_save_dmi_table);
+       pm_cpu_check(msr_save_cpu_table);
+
        return 0;
 }
 
index 9c0bb77..a2fcde5 100644 (file)
@@ -74,7 +74,7 @@ struct ht16k33_priv {
        struct ht16k33_fbdev fbdev;
 };
 
-static struct fb_fix_screeninfo ht16k33_fb_fix = {
+static const struct fb_fix_screeninfo ht16k33_fb_fix = {
        .id             = DRIVER_NAME,
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_MONO10,
@@ -85,7 +85,7 @@ static struct fb_fix_screeninfo ht16k33_fb_fix = {
        .accel          = FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo ht16k33_fb_var = {
+static const struct fb_var_screeninfo ht16k33_fb_var = {
        .xres = HT16K33_MATRIX_LED_MAX_ROWS,
        .yres = HT16K33_MATRIX_LED_MAX_COLS,
        .xres_virtual = HT16K33_MATRIX_LED_MAX_ROWS,
index 9bd4ddd..5b24876 100644 (file)
@@ -322,6 +322,8 @@ static int drbd_thread_setup(void *arg)
                 thi->name[0],
                 resource->name);
 
+       allow_kernel_signal(DRBD_SIGKILL);
+       allow_kernel_signal(SIGXCPU);
 restart:
        retval = thi->function(thi);
 
index 8b33128..0875470 100644 (file)
@@ -99,6 +99,27 @@ static int qca_send_reset(struct hci_dev *hdev)
        return 0;
 }
 
+int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
+{
+       struct sk_buff *skb;
+       int err;
+
+       bt_dev_dbg(hdev, "QCA pre shutdown cmd");
+
+       skb = __hci_cmd_sync(hdev, QCA_PRE_SHUTDOWN_CMD, 0,
+                               NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               err = PTR_ERR(skb);
+               bt_dev_err(hdev, "QCA preshutdown_cmd failed (%d)", err);
+               return err;
+       }
+
+       kfree_skb(skb);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd);
+
 static void qca_tlv_check_data(struct rome_config *config,
                                const struct firmware *fw)
 {
@@ -119,6 +140,7 @@ static void qca_tlv_check_data(struct rome_config *config,
        BT_DBG("Length\t\t : %d bytes", length);
 
        config->dnld_mode = ROME_SKIP_EVT_NONE;
+       config->dnld_type = ROME_SKIP_EVT_NONE;
 
        switch (config->type) {
        case TLV_TYPE_PATCH:
@@ -268,7 +290,7 @@ static int qca_inject_cmd_complete_event(struct hci_dev *hdev)
 
        evt = skb_put(skb, sizeof(*evt));
        evt->ncmd = 1;
-       evt->opcode = QCA_HCI_CC_OPCODE;
+       evt->opcode = cpu_to_le16(QCA_HCI_CC_OPCODE);
 
        skb_put_u8(skb, QCA_HCI_CC_SUCCESS);
 
@@ -323,7 +345,7 @@ static int qca_download_firmware(struct hci_dev *hdev,
         */
        if (config->dnld_type == ROME_SKIP_EVT_VSE_CC ||
            config->dnld_type == ROME_SKIP_EVT_VSE)
-               return qca_inject_cmd_complete_event(hdev);
+               ret = qca_inject_cmd_complete_event(hdev);
 
 out:
        release_firmware(fw);
@@ -388,6 +410,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
                return err;
        }
 
+       /* Give the controller some time to get ready to receive the NVM */
+       msleep(10);
+
        /* Download NVM configuration */
        config.type = TLV_TYPE_NVM;
        if (firmware_name)
index 6a291a7..69c5315 100644 (file)
@@ -13,6 +13,7 @@
 #define EDL_PATCH_TLV_REQ_CMD          (0x1E)
 #define EDL_NVM_ACCESS_SET_REQ_CMD     (0x01)
 #define MAX_SIZE_PER_TLV_SEGMENT       (243)
+#define QCA_PRE_SHUTDOWN_CMD           (0xFC08)
 
 #define EDL_CMD_REQ_RES_EVT            (0x00)
 #define EDL_PATCH_VER_RES_EVT          (0x19)
@@ -135,6 +136,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
                   const char *firmware_name);
 int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version);
 int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
+int qca_send_pre_shutdown_cmd(struct hci_dev *hdev);
 static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
 {
        return soc_type == QCA_WCN3990 || soc_type == QCA_WCN3998;
@@ -167,4 +169,9 @@ static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
 {
        return false;
 }
+
+static inline int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
+{
+       return -EOPNOTSUPP;
+}
 #endif
index 3876fee..5cf0734 100644 (file)
@@ -2762,8 +2762,10 @@ static int btusb_mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
        fw_size = fw->size;
 
        /* The size of patch header is 30 bytes, should be skip */
-       if (fw_size < 30)
+       if (fw_size < 30) {
+               err = -EINVAL;
                goto err_release_fw;
+       }
 
        fw_size -= 30;
        fw_ptr += 30;
index 82a0a36..9a970fd 100644 (file)
@@ -705,7 +705,7 @@ static void device_want_to_sleep(struct hci_uart *hu)
        unsigned long flags;
        struct qca_data *qca = hu->priv;
 
-       BT_DBG("hu %p want to sleep", hu);
+       BT_DBG("hu %p want to sleep in %d state", hu, qca->rx_ibs_state);
 
        spin_lock_irqsave(&qca->hci_ibs_lock, flags);
 
@@ -720,7 +720,7 @@ static void device_want_to_sleep(struct hci_uart *hu)
                break;
 
        case HCI_IBS_RX_ASLEEP:
-               /* Fall through */
+               break;
 
        default:
                /* Any other state is illegal */
@@ -912,7 +912,7 @@ static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
                if (hdr->evt == HCI_EV_VENDOR)
                        complete(&qca->drop_ev_comp);
 
-               kfree(skb);
+               kfree_skb(skb);
 
                return 0;
        }
@@ -1386,6 +1386,9 @@ static int qca_power_off(struct hci_dev *hdev)
 {
        struct hci_uart *hu = hci_get_drvdata(hdev);
 
+       /* Perform pre shutdown command */
+       qca_send_pre_shutdown_cmd(hdev);
+
        qca_power_shutdown(hu);
        return 0;
 }
index c099070..1c46bab 100644 (file)
@@ -324,6 +324,25 @@ static struct clk_core *clk_core_lookup(const char *name)
        return NULL;
 }
 
+#ifdef CONFIG_OF
+static int of_parse_clkspec(const struct device_node *np, int index,
+                           const char *name, struct of_phandle_args *out_args);
+static struct clk_hw *
+of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec);
+#else
+static inline int of_parse_clkspec(const struct device_node *np, int index,
+                                  const char *name,
+                                  struct of_phandle_args *out_args)
+{
+       return -ENOENT;
+}
+static inline struct clk_hw *
+of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec)
+{
+       return ERR_PTR(-ENOENT);
+}
+#endif
+
 /**
  * clk_core_get - Find the clk_core parent of a clk
  * @core: clk to find parent of
@@ -355,8 +374,9 @@ static struct clk_core *clk_core_lookup(const char *name)
  *      };
  *
  * Returns: -ENOENT when the provider can't be found or the clk doesn't
- * exist in the provider. -EINVAL when the name can't be found. NULL when the
- * provider knows about the clk but it isn't provided on this system.
+ * exist in the provider or the name can't be found in the DT node or
+ * in a clkdev lookup. NULL when the provider knows about the clk but it
+ * isn't provided on this system.
  * A valid clk_core pointer when the clk can be found in the provider.
  */
 static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
@@ -367,17 +387,19 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
        struct device *dev = core->dev;
        const char *dev_id = dev ? dev_name(dev) : NULL;
        struct device_node *np = core->of_node;
+       struct of_phandle_args clkspec;
 
-       if (np && (name || index >= 0))
-               hw = of_clk_get_hw(np, index, name);
-
-       /*
-        * If the DT search above couldn't find the provider or the provider
-        * didn't know about this clk, fallback to looking up via clkdev based
-        * clk_lookups
-        */
-       if (PTR_ERR(hw) == -ENOENT && name)
+       if (np && (name || index >= 0) &&
+           !of_parse_clkspec(np, index, name, &clkspec)) {
+               hw = of_clk_get_hw_from_clkspec(&clkspec);
+               of_node_put(clkspec.np);
+       } else if (name) {
+               /*
+                * If the DT search above couldn't find the provider fallback to
+                * looking up via clkdev based clk_lookups.
+                */
                hw = clk_find_hw(dev_id, name);
+       }
 
        if (IS_ERR(hw))
                return ERR_CAST(hw);
@@ -401,7 +423,7 @@ static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
                        parent = ERR_PTR(-EPROBE_DEFER);
        } else {
                parent = clk_core_get(core, index);
-               if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT)
+               if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT && entry->name)
                        parent = clk_core_lookup(entry->name);
        }
 
@@ -1632,7 +1654,8 @@ static int clk_fetch_parent_index(struct clk_core *core,
                        break;
 
                /* Fallback to comparing globally unique names */
-               if (!strcmp(parent->name, core->parents[i].name))
+               if (core->parents[i].name &&
+                   !strcmp(parent->name, core->parents[i].name))
                        break;
        }
 
index 91db789..65c82d9 100644 (file)
@@ -14,7 +14,7 @@
 #include "clk-exynos5-subcmu.h"
 
 static struct samsung_clk_provider *ctx;
-static const struct exynos5_subcmu_info *cmu;
+static const struct exynos5_subcmu_info **cmu;
 static int nr_cmus;
 
 static void exynos5_subcmu_clk_save(void __iomem *base,
@@ -56,17 +56,17 @@ static void exynos5_subcmu_defer_gate(struct samsung_clk_provider *ctx,
  * when OF-core populates all device-tree nodes.
  */
 void exynos5_subcmus_init(struct samsung_clk_provider *_ctx, int _nr_cmus,
-                         const struct exynos5_subcmu_info *_cmu)
+                         const struct exynos5_subcmu_info **_cmu)
 {
        ctx = _ctx;
        cmu = _cmu;
        nr_cmus = _nr_cmus;
 
        for (; _nr_cmus--; _cmu++) {
-               exynos5_subcmu_defer_gate(ctx, _cmu->gate_clks,
-                                         _cmu->nr_gate_clks);
-               exynos5_subcmu_clk_save(ctx->reg_base, _cmu->suspend_regs,
-                                       _cmu->nr_suspend_regs);
+               exynos5_subcmu_defer_gate(ctx, (*_cmu)->gate_clks,
+                                         (*_cmu)->nr_gate_clks);
+               exynos5_subcmu_clk_save(ctx->reg_base, (*_cmu)->suspend_regs,
+                                       (*_cmu)->nr_suspend_regs);
        }
 }
 
@@ -163,9 +163,9 @@ static int __init exynos5_clk_probe(struct platform_device *pdev)
                if (of_property_read_string(np, "label", &name) < 0)
                        continue;
                for (i = 0; i < nr_cmus; i++)
-                       if (strcmp(cmu[i].pd_name, name) == 0)
+                       if (strcmp(cmu[i]->pd_name, name) == 0)
                                exynos5_clk_register_subcmu(&pdev->dev,
-                                                           &cmu[i], np);
+                                                           cmu[i], np);
        }
        return 0;
 }
index 755ee8a..9ae5356 100644 (file)
@@ -21,6 +21,6 @@ struct exynos5_subcmu_info {
 };
 
 void exynos5_subcmus_init(struct samsung_clk_provider *ctx, int nr_cmus,
-                         const struct exynos5_subcmu_info *cmu);
+                         const struct exynos5_subcmu_info **cmu);
 
 #endif
index f2b8968..931c70a 100644 (file)
@@ -681,6 +681,10 @@ static const struct exynos5_subcmu_info exynos5250_disp_subcmu = {
        .pd_name        = "DISP1",
 };
 
+static const struct exynos5_subcmu_info *exynos5250_subcmus[] = {
+       &exynos5250_disp_subcmu,
+};
+
 static const struct samsung_pll_rate_table vpll_24mhz_tbl[] __initconst = {
        /* sorted in descending order */
        /* PLL_36XX_RATE(rate, m, p, s, k) */
@@ -843,7 +847,8 @@ static void __init exynos5250_clk_init(struct device_node *np)
 
        samsung_clk_sleep_init(reg_base, exynos5250_clk_regs,
                               ARRAY_SIZE(exynos5250_clk_regs));
-       exynos5_subcmus_init(ctx, 1, &exynos5250_disp_subcmu);
+       exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5250_subcmus),
+                            exynos5250_subcmus);
 
        samsung_clk_of_add_provider(np, ctx);
 
index 01bca5a..7670cc5 100644 (file)
@@ -534,8 +534,6 @@ static const struct samsung_gate_clock exynos5800_gate_clks[] __initconst = {
                                GATE_BUS_TOP, 24, 0, 0),
        GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler",
                                GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0),
-       GATE(CLK_MAU_EPLL, "mau_epll", "mout_user_mau_epll",
-                       SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0),
 };
 
 static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = {
@@ -577,8 +575,13 @@ static const struct samsung_div_clock exynos5420_div_clks[] __initconst = {
 
 static const struct samsung_gate_clock exynos5420_gate_clks[] __initconst = {
        GATE(CLK_SECKEY, "seckey", "aclk66_psgen", GATE_BUS_PERIS1, 1, 0, 0),
+       /* Maudio Block */
        GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
                        SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_MAUDIO0, "sclk_maudio0", "dout_maudio0",
+               GATE_TOP_SCLK_MAU, 0, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_MAUPCM0, "sclk_maupcm0", "dout_maupcm0",
+               GATE_TOP_SCLK_MAU, 1, CLK_SET_RATE_PARENT, 0),
 };
 
 static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
@@ -890,9 +893,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = {
        /* GSCL Block */
        DIV(0, "dout_gscl_blk_333", "aclk333_432_gscl", DIV2_RATIO0, 6, 2),
 
-       /* MSCL Block */
-       DIV(0, "dout_mscl_blk", "aclk400_mscl", DIV2_RATIO0, 28, 2),
-
        /* PSGEN */
        DIV(0, "dout_gen_blk", "mout_user_aclk266", DIV2_RATIO0, 8, 1),
        DIV(0, "dout_jpg_blk", "aclk166", DIV2_RATIO0, 20, 1),
@@ -1017,12 +1017,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
        GATE(CLK_SCLK_DP1, "sclk_dp1", "dout_dp1",
                        GATE_TOP_SCLK_DISP1, 20, CLK_SET_RATE_PARENT, 0),
 
-       /* Maudio Block */
-       GATE(CLK_SCLK_MAUDIO0, "sclk_maudio0", "dout_maudio0",
-               GATE_TOP_SCLK_MAU, 0, CLK_SET_RATE_PARENT, 0),
-       GATE(CLK_SCLK_MAUPCM0, "sclk_maupcm0", "dout_maupcm0",
-               GATE_TOP_SCLK_MAU, 1, CLK_SET_RATE_PARENT, 0),
-
        /* FSYS Block */
        GATE(CLK_TSI, "tsi", "aclk200_fsys", GATE_BUS_FSYS0, 0, 0, 0),
        GATE(CLK_PDMA0, "pdma0", "aclk200_fsys", GATE_BUS_FSYS0, 1, 0, 0),
@@ -1162,17 +1156,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
        GATE(CLK_FIMC_LITE3, "fimc_lite3", "aclk333_432_gscl",
                        GATE_IP_GSCL1, 17, 0, 0),
 
-       /* MSCL Block */
-       GATE(CLK_MSCL0, "mscl0", "aclk400_mscl", GATE_IP_MSCL, 0, 0, 0),
-       GATE(CLK_MSCL1, "mscl1", "aclk400_mscl", GATE_IP_MSCL, 1, 0, 0),
-       GATE(CLK_MSCL2, "mscl2", "aclk400_mscl", GATE_IP_MSCL, 2, 0, 0),
-       GATE(CLK_SMMU_MSCL0, "smmu_mscl0", "dout_mscl_blk",
-                       GATE_IP_MSCL, 8, 0, 0),
-       GATE(CLK_SMMU_MSCL1, "smmu_mscl1", "dout_mscl_blk",
-                       GATE_IP_MSCL, 9, 0, 0),
-       GATE(CLK_SMMU_MSCL2, "smmu_mscl2", "dout_mscl_blk",
-                       GATE_IP_MSCL, 10, 0, 0),
-
        /* ISP */
        GATE(CLK_SCLK_UART_ISP, "sclk_uart_isp", "dout_uart_isp",
                        GATE_TOP_SCLK_ISP, 0, CLK_SET_RATE_PARENT, 0),
@@ -1281,32 +1264,103 @@ static struct exynos5_subcmu_reg_dump exynos5x_mfc_suspend_regs[] = {
        { DIV4_RATIO, 0, 0x3 },                 /* DIV dout_mfc_blk */
 };
 
-static const struct exynos5_subcmu_info exynos5x_subcmus[] = {
-       {
-               .div_clks       = exynos5x_disp_div_clks,
-               .nr_div_clks    = ARRAY_SIZE(exynos5x_disp_div_clks),
-               .gate_clks      = exynos5x_disp_gate_clks,
-               .nr_gate_clks   = ARRAY_SIZE(exynos5x_disp_gate_clks),
-               .suspend_regs   = exynos5x_disp_suspend_regs,
-               .nr_suspend_regs = ARRAY_SIZE(exynos5x_disp_suspend_regs),
-               .pd_name        = "DISP",
-       }, {
-               .div_clks       = exynos5x_gsc_div_clks,
-               .nr_div_clks    = ARRAY_SIZE(exynos5x_gsc_div_clks),
-               .gate_clks      = exynos5x_gsc_gate_clks,
-               .nr_gate_clks   = ARRAY_SIZE(exynos5x_gsc_gate_clks),
-               .suspend_regs   = exynos5x_gsc_suspend_regs,
-               .nr_suspend_regs = ARRAY_SIZE(exynos5x_gsc_suspend_regs),
-               .pd_name        = "GSC",
-       }, {
-               .div_clks       = exynos5x_mfc_div_clks,
-               .nr_div_clks    = ARRAY_SIZE(exynos5x_mfc_div_clks),
-               .gate_clks      = exynos5x_mfc_gate_clks,
-               .nr_gate_clks   = ARRAY_SIZE(exynos5x_mfc_gate_clks),
-               .suspend_regs   = exynos5x_mfc_suspend_regs,
-               .nr_suspend_regs = ARRAY_SIZE(exynos5x_mfc_suspend_regs),
-               .pd_name        = "MFC",
-       },
+static const struct samsung_gate_clock exynos5x_mscl_gate_clks[] __initconst = {
+       /* MSCL Block */
+       GATE(CLK_MSCL0, "mscl0", "aclk400_mscl", GATE_IP_MSCL, 0, 0, 0),
+       GATE(CLK_MSCL1, "mscl1", "aclk400_mscl", GATE_IP_MSCL, 1, 0, 0),
+       GATE(CLK_MSCL2, "mscl2", "aclk400_mscl", GATE_IP_MSCL, 2, 0, 0),
+       GATE(CLK_SMMU_MSCL0, "smmu_mscl0", "dout_mscl_blk",
+                       GATE_IP_MSCL, 8, 0, 0),
+       GATE(CLK_SMMU_MSCL1, "smmu_mscl1", "dout_mscl_blk",
+                       GATE_IP_MSCL, 9, 0, 0),
+       GATE(CLK_SMMU_MSCL2, "smmu_mscl2", "dout_mscl_blk",
+                       GATE_IP_MSCL, 10, 0, 0),
+};
+
+static const struct samsung_div_clock exynos5x_mscl_div_clks[] __initconst = {
+       DIV(0, "dout_mscl_blk", "aclk400_mscl", DIV2_RATIO0, 28, 2),
+};
+
+static struct exynos5_subcmu_reg_dump exynos5x_mscl_suspend_regs[] = {
+       { GATE_IP_MSCL, 0xffffffff, 0xffffffff }, /* MSCL gates */
+       { SRC_TOP3, 0, BIT(4) },                /* MUX mout_user_aclk400_mscl */
+       { DIV2_RATIO0, 0, 0x30000000 },         /* DIV dout_mscl_blk */
+};
+
+static const struct samsung_gate_clock exynos5800_mau_gate_clks[] __initconst = {
+       GATE(CLK_MAU_EPLL, "mau_epll", "mout_user_mau_epll",
+                       SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_MAUDIO0, "sclk_maudio0", "dout_maudio0",
+               GATE_TOP_SCLK_MAU, 0, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_MAUPCM0, "sclk_maupcm0", "dout_maupcm0",
+               GATE_TOP_SCLK_MAU, 1, CLK_SET_RATE_PARENT, 0),
+};
+
+static struct exynos5_subcmu_reg_dump exynos5800_mau_suspend_regs[] = {
+       { SRC_TOP9, 0, BIT(8) },        /* MUX mout_user_mau_epll */
+};
+
+static const struct exynos5_subcmu_info exynos5x_disp_subcmu = {
+       .div_clks       = exynos5x_disp_div_clks,
+       .nr_div_clks    = ARRAY_SIZE(exynos5x_disp_div_clks),
+       .gate_clks      = exynos5x_disp_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5x_disp_gate_clks),
+       .suspend_regs   = exynos5x_disp_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5x_disp_suspend_regs),
+       .pd_name        = "DISP",
+};
+
+static const struct exynos5_subcmu_info exynos5x_gsc_subcmu = {
+       .div_clks       = exynos5x_gsc_div_clks,
+       .nr_div_clks    = ARRAY_SIZE(exynos5x_gsc_div_clks),
+       .gate_clks      = exynos5x_gsc_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5x_gsc_gate_clks),
+       .suspend_regs   = exynos5x_gsc_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5x_gsc_suspend_regs),
+       .pd_name        = "GSC",
+};
+
+static const struct exynos5_subcmu_info exynos5x_mfc_subcmu = {
+       .div_clks       = exynos5x_mfc_div_clks,
+       .nr_div_clks    = ARRAY_SIZE(exynos5x_mfc_div_clks),
+       .gate_clks      = exynos5x_mfc_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5x_mfc_gate_clks),
+       .suspend_regs   = exynos5x_mfc_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5x_mfc_suspend_regs),
+       .pd_name        = "MFC",
+};
+
+static const struct exynos5_subcmu_info exynos5x_mscl_subcmu = {
+       .div_clks       = exynos5x_mscl_div_clks,
+       .nr_div_clks    = ARRAY_SIZE(exynos5x_mscl_div_clks),
+       .gate_clks      = exynos5x_mscl_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5x_mscl_gate_clks),
+       .suspend_regs   = exynos5x_mscl_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5x_mscl_suspend_regs),
+       .pd_name        = "MSC",
+};
+
+static const struct exynos5_subcmu_info exynos5800_mau_subcmu = {
+       .gate_clks      = exynos5800_mau_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5800_mau_gate_clks),
+       .suspend_regs   = exynos5800_mau_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5800_mau_suspend_regs),
+       .pd_name        = "MAU",
+};
+
+static const struct exynos5_subcmu_info *exynos5x_subcmus[] = {
+       &exynos5x_disp_subcmu,
+       &exynos5x_gsc_subcmu,
+       &exynos5x_mfc_subcmu,
+       &exynos5x_mscl_subcmu,
+};
+
+static const struct exynos5_subcmu_info *exynos5800_subcmus[] = {
+       &exynos5x_disp_subcmu,
+       &exynos5x_gsc_subcmu,
+       &exynos5x_mfc_subcmu,
+       &exynos5x_mscl_subcmu,
+       &exynos5800_mau_subcmu,
 };
 
 static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __initconst = {
@@ -1539,11 +1593,17 @@ static void __init exynos5x_clk_init(struct device_node *np,
        samsung_clk_extended_sleep_init(reg_base,
                exynos5x_clk_regs, ARRAY_SIZE(exynos5x_clk_regs),
                exynos5420_set_clksrc, ARRAY_SIZE(exynos5420_set_clksrc));
-       if (soc == EXYNOS5800)
+
+       if (soc == EXYNOS5800) {
                samsung_clk_sleep_init(reg_base, exynos5800_clk_regs,
                                       ARRAY_SIZE(exynos5800_clk_regs));
-       exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5x_subcmus),
-                            exynos5x_subcmus);
+
+               exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5800_subcmus),
+                                    exynos5800_subcmus);
+       } else {
+               exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5x_subcmus),
+                                    exynos5x_subcmus);
+       }
 
        samsung_clk_of_add_provider(np, ctx);
 }
index 5c50e72..1a191ee 100644 (file)
@@ -38,7 +38,7 @@ static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,
        if (socfpgaclk->fixed_div) {
                div = socfpgaclk->fixed_div;
        } else {
-               if (!socfpgaclk->bypass_reg)
+               if (socfpgaclk->hw.reg)
                        div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1);
        }
 
index 23e0a35..ad72b3f 100644 (file)
@@ -1163,6 +1163,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
        switch (chan->feature & FSL_DMA_IP_MASK) {
        case FSL_DMA_IP_85XX:
                chan->toggle_ext_pause = fsl_chan_toggle_ext_pause;
+               /* Fall through */
        case FSL_DMA_IP_83XX:
                chan->toggle_ext_start = fsl_chan_toggle_ext_start;
                chan->set_src_loop_size = fsl_chan_set_src_loop_size;
index 567fb98..9762dd6 100644 (file)
@@ -363,7 +363,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
        /* Special handling for SPI GPIOs if used */
        if (IS_ERR(desc))
                desc = of_find_spi_gpio(dev, con_id, &of_flags);
-       if (IS_ERR(desc)) {
+       if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER) {
                /* This quirk looks up flags and all */
                desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
                if (!IS_ERR(desc))
index f497003..cca7490 100644 (file)
@@ -1091,9 +1091,11 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
                        lineinfo.flags |= GPIOLINE_FLAG_ACTIVE_LOW;
                if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
-                       lineinfo.flags |= GPIOLINE_FLAG_OPEN_DRAIN;
+                       lineinfo.flags |= (GPIOLINE_FLAG_OPEN_DRAIN |
+                                          GPIOLINE_FLAG_IS_OUT);
                if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
-                       lineinfo.flags |= GPIOLINE_FLAG_OPEN_SOURCE;
+                       lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
+                                          GPIOLINE_FLAG_IS_OUT);
 
                if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
                        return -EFAULT;
@@ -1371,21 +1373,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        if (status)
                goto err_remove_from_list;
 
-       status = gpiochip_irqchip_init_valid_mask(chip);
-       if (status)
-               goto err_remove_from_list;
-
        status = gpiochip_alloc_valid_mask(chip);
        if (status)
-               goto err_remove_irqchip_mask;
-
-       status = gpiochip_add_irqchip(chip, lock_key, request_key);
-       if (status)
-               goto err_free_gpiochip_mask;
+               goto err_remove_from_list;
 
        status = of_gpiochip_add(chip);
        if (status)
-               goto err_remove_chip;
+               goto err_free_gpiochip_mask;
 
        status = gpiochip_init_valid_mask(chip);
        if (status)
@@ -1411,6 +1405,14 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        machine_gpiochip_add(chip);
 
+       status = gpiochip_irqchip_init_valid_mask(chip);
+       if (status)
+               goto err_remove_acpi_chip;
+
+       status = gpiochip_add_irqchip(chip, lock_key, request_key);
+       if (status)
+               goto err_remove_irqchip_mask;
+
        /*
         * By first adding the chardev, and then adding the device,
         * we get a device node entry in sysfs under
@@ -1422,21 +1424,21 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        if (gpiolib_initialized) {
                status = gpiochip_setup_dev(gdev);
                if (status)
-                       goto err_remove_acpi_chip;
+                       goto err_remove_irqchip;
        }
        return 0;
 
+err_remove_irqchip:
+       gpiochip_irqchip_remove(chip);
+err_remove_irqchip_mask:
+       gpiochip_irqchip_free_valid_mask(chip);
 err_remove_acpi_chip:
        acpi_gpiochip_remove(chip);
 err_remove_of_chip:
        gpiochip_free_hogs(chip);
        of_gpiochip_remove(chip);
-err_remove_chip:
-       gpiochip_irqchip_remove(chip);
 err_free_gpiochip_mask:
        gpiochip_free_valid_mask(chip);
-err_remove_irqchip_mask:
-       gpiochip_irqchip_free_valid_mask(chip);
 err_remove_from_list:
        spin_lock_irqsave(&gpio_lock, flags);
        list_del(&gdev->list);
index 4e4094f..8b26c97 100644 (file)
@@ -1143,6 +1143,9 @@ static int amdgpu_cs_process_syncobj_out_dep(struct amdgpu_cs_parser *p,
        num_deps = chunk->length_dw * 4 /
                sizeof(struct drm_amdgpu_cs_chunk_sem);
 
+       if (p->post_deps)
+               return -EINVAL;
+
        p->post_deps = kmalloc_array(num_deps, sizeof(*p->post_deps),
                                     GFP_KERNEL);
        p->num_post_deps = 0;
@@ -1166,8 +1169,7 @@ static int amdgpu_cs_process_syncobj_out_dep(struct amdgpu_cs_parser *p,
 
 
 static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p,
-                                                     struct amdgpu_cs_chunk
-                                                     *chunk)
+                                                     struct amdgpu_cs_chunk *chunk)
 {
        struct drm_amdgpu_cs_chunk_syncobj *syncobj_deps;
        unsigned num_deps;
@@ -1177,6 +1179,9 @@ static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p
        num_deps = chunk->length_dw * 4 /
                sizeof(struct drm_amdgpu_cs_chunk_syncobj);
 
+       if (p->post_deps)
+               return -EINVAL;
+
        p->post_deps = kmalloc_array(num_deps, sizeof(*p->post_deps),
                                     GFP_KERNEL);
        p->num_post_deps = 0;
index 04b8ac4..4ea67f9 100644 (file)
@@ -604,6 +604,10 @@ static void gfx_v9_0_check_if_need_gfxoff(struct amdgpu_device *adev)
                    (adev->gfx.rlc_feature_version < 1) ||
                    !adev->gfx.rlc.is_rlc_v2_1)
                        adev->pm.pp_feature &= ~PP_GFXOFF_MASK;
+               if (adev->pm.pp_feature & PP_GFXOFF_MASK)
+                       adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
+                               AMD_PG_SUPPORT_CP |
+                               AMD_PG_SUPPORT_RLC_SMU_HS;
                break;
        default:
                break;
index 662612f..9922bce 100644 (file)
@@ -552,7 +552,6 @@ static int nv_common_early_init(void *handle)
                        AMD_CG_SUPPORT_BIF_LS;
                adev->pg_flags = AMD_PG_SUPPORT_VCN |
                        AMD_PG_SUPPORT_VCN_DPG |
-                       AMD_PG_SUPPORT_MMHUB |
                        AMD_PG_SUPPORT_ATHUB;
                adev->external_rev_id = adev->rev_id + 0x1;
                break;
index 2326541..04fbf05 100644 (file)
@@ -992,11 +992,6 @@ static int soc15_common_early_init(void *handle)
 
                        adev->pg_flags = AMD_PG_SUPPORT_SDMA | AMD_PG_SUPPORT_VCN;
                }
-
-               if (adev->pm.pp_feature & PP_GFXOFF_MASK)
-                       adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
-                               AMD_PG_SUPPORT_CP |
-                               AMD_PG_SUPPORT_RLC_SMU_HS;
                break;
        default:
                /* FIXME: not supported yet */
index 4a29f72..45be7a2 100644 (file)
@@ -3131,13 +3131,25 @@ static enum dc_color_depth
 convert_color_depth_from_display_info(const struct drm_connector *connector,
                                      const struct drm_connector_state *state)
 {
-       uint32_t bpc = connector->display_info.bpc;
+       uint8_t bpc = (uint8_t)connector->display_info.bpc;
+
+       /* Assume 8 bpc by default if no bpc is specified. */
+       bpc = bpc ? bpc : 8;
 
        if (!state)
                state = connector->state;
 
        if (state) {
-               bpc = state->max_bpc;
+               /*
+                * Cap display bpc based on the user requested value.
+                *
+                * The value for state->max_bpc may not correctly updated
+                * depending on when the connector gets added to the state
+                * or if this was called outside of atomic check, so it
+                * can't be used directly.
+                */
+               bpc = min(bpc, state->max_requested_bpc);
+
                /* Round down to the nearest even number. */
                bpc = bpc - (bpc & 1);
        }
index a0f52c8..a78b2e2 100644 (file)
@@ -907,8 +907,6 @@ struct smu_funcs
        ((smu)->funcs->register_irq_handler ? (smu)->funcs->register_irq_handler(smu) : 0)
 #define smu_set_azalia_d3_pme(smu) \
        ((smu)->funcs->set_azalia_d3_pme ? (smu)->funcs->set_azalia_d3_pme((smu)) : 0)
-#define smu_get_uclk_dpm_states(smu, clocks_in_khz, num_states) \
-       ((smu)->ppt_funcs->get_uclk_dpm_states ? (smu)->ppt_funcs->get_uclk_dpm_states((smu), (clocks_in_khz), (num_states)) : 0)
 #define smu_get_max_sustainable_clocks_by_dc(smu, max_clocks) \
        ((smu)->funcs->get_max_sustainable_clocks_by_dc ? (smu)->funcs->get_max_sustainable_clocks_by_dc((smu), (max_clocks)) : 0)
 #define smu_get_uclk_dpm_states(smu, clocks_in_khz, num_states) \
index 5fde5cf..5309796 100644 (file)
@@ -326,7 +326,8 @@ static int smu_v11_0_setup_pptable(struct smu_context *smu)
        struct amdgpu_device *adev = smu->adev;
        const struct smc_firmware_header_v1_0 *hdr;
        int ret, index;
-       uint32_t size;
+       uint32_t size = 0;
+       uint16_t atom_table_size;
        uint8_t frev, crev;
        void *table;
        uint16_t version_major, version_minor;
@@ -354,10 +355,11 @@ static int smu_v11_0_setup_pptable(struct smu_context *smu)
                index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
                                                    powerplayinfo);
 
-               ret = smu_get_atom_data_table(smu, index, (uint16_t *)&size, &frev, &crev,
+               ret = smu_get_atom_data_table(smu, index, &atom_table_size, &frev, &crev,
                                              (uint8_t **)&table);
                if (ret)
                        return ret;
+               size = atom_table_size;
        }
 
        if (!smu->smu_table.power_play_table)
index 5a11898..a0eabc1 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/iommu.h>
 #include <linux/of_device.h>
 #include <linux/of_graph.h>
+#include <linux/of_reserved_mem.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #ifdef CONFIG_DEBUG_FS
@@ -143,6 +144,12 @@ static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
                return mdev->irq;
        }
 
+       /* Get the optional framebuffer memory resource */
+       ret = of_reserved_mem_device_init(dev);
+       if (ret && ret != -ENODEV)
+               return ret;
+       ret = 0;
+
        for_each_available_child_of_node(np, child) {
                if (of_node_cmp(child->name, "pipeline") == 0) {
                        ret = komeda_parse_pipe_dt(mdev, child);
@@ -289,6 +296,8 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
 
        mdev->n_pipelines = 0;
 
+       of_reserved_mem_device_release(dev);
+
        if (funcs && funcs->cleanup)
                funcs->cleanup(mdev);
 
index cd4d9f5..c9a1edb 100644 (file)
@@ -35,6 +35,25 @@ komeda_get_format_caps(struct komeda_format_caps_table *table,
        return NULL;
 }
 
+u32 komeda_get_afbc_format_bpp(const struct drm_format_info *info, u64 modifier)
+{
+       u32 bpp;
+
+       switch (info->format) {
+       case DRM_FORMAT_YUV420_8BIT:
+               bpp = 12;
+               break;
+       case DRM_FORMAT_YUV420_10BIT:
+               bpp = 15;
+               break;
+       default:
+               bpp = info->cpp[0] * 8;
+               break;
+       }
+
+       return bpp;
+}
+
 /* Two assumptions
  * 1. RGB always has YTR
  * 2. Tiled RGB always has SC
index 3631910..32273cf 100644 (file)
@@ -97,6 +97,9 @@ const struct komeda_format_caps *
 komeda_get_format_caps(struct komeda_format_caps_table *table,
                       u32 fourcc, u64 modifier);
 
+u32 komeda_get_afbc_format_bpp(const struct drm_format_info *info,
+                              u64 modifier);
+
 u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
                                  u32 layer_type, u32 *n_fmts);
 
index 3b0a70e..1b01a62 100644 (file)
@@ -43,7 +43,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
        struct drm_framebuffer *fb = &kfb->base;
        const struct drm_format_info *info = fb->format;
        struct drm_gem_object *obj;
-       u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks;
+       u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
        u64 min_size;
 
        obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
@@ -88,8 +88,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
        kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
                                    alignment_header);
 
+       bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
        kfb->afbc_size = kfb->offset_payload + n_blocks *
-                        ALIGN(info->cpp[0] * AFBC_SUPERBLK_PIXELS,
+                        ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
                               AFBC_SUPERBLK_ALIGNMENT);
        min_size = kfb->afbc_size + fb->offsets[0];
        if (min_size > obj->size) {
index 419a8b0..d50e75f 100644 (file)
@@ -15,6 +15,7 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_irq.h>
 #include <drm/drm_vblank.h>
+#include <drm/drm_probe_helper.h>
 
 #include "komeda_dev.h"
 #include "komeda_framebuffer.h"
@@ -315,6 +316,8 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
 
        drm->irq_enabled = true;
 
+       drm_kms_helper_poll_init(drm);
+
        err = drm_dev_register(drm, 0);
        if (err)
                goto cleanup_mode_config;
@@ -322,6 +325,7 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
        return kms;
 
 cleanup_mode_config:
+       drm_kms_helper_poll_fini(drm);
        drm->irq_enabled = false;
        drm_mode_config_cleanup(drm);
        komeda_kms_cleanup_private_objs(kms);
@@ -338,6 +342,7 @@ void komeda_kms_detach(struct komeda_kms_dev *kms)
        drm->irq_enabled = false;
        mdev->funcs->disable_irq(mdev);
        drm_dev_unregister(drm);
+       drm_kms_helper_poll_fini(drm);
        component_unbind_all(mdev->dev, drm);
        komeda_kms_cleanup_private_objs(kms);
        drm_mode_config_cleanup(drm);
index 7925a17..1cb1fa7 100644 (file)
@@ -1465,8 +1465,8 @@ static void ddi_dotclock_get(struct intel_crtc_state *pipe_config)
        else if (intel_crtc_has_dp_encoder(pipe_config))
                dotclock = intel_dotclock_calculate(pipe_config->port_clock,
                                                    &pipe_config->dp_m_n);
-       else if (pipe_config->has_hdmi_sink && pipe_config->pipe_bpp == 36)
-               dotclock = pipe_config->port_clock * 2 / 3;
+       else if (pipe_config->has_hdmi_sink && pipe_config->pipe_bpp > 24)
+               dotclock = pipe_config->port_clock * 24 / pipe_config->pipe_bpp;
        else
                dotclock = pipe_config->port_clock;
 
index 1d58f7e..f119798 100644 (file)
@@ -829,7 +829,7 @@ struct intel_crtc_state {
 
        /*
         * Frequence the dpll for the port should run at. Differs from the
-        * adjusted dotclock e.g. for DP or 12bpc hdmi mode. This is also
+        * adjusted dotclock e.g. for DP or 10/12bpc hdmi mode. This is also
         * already multiplied by pixel_multiplier.
         */
        int port_clock;
index 95fdbd0..945bc20 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
 
 #include "mtk_drm_crtc.h"
 #include "mtk_drm_ddp.h"
@@ -213,6 +214,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)
        struct mtk_drm_private *private = drm->dev_private;
        struct platform_device *pdev;
        struct device_node *np;
+       struct device *dma_dev;
        int ret;
 
        if (!iommu_present(&platform_bus_type))
@@ -275,7 +277,29 @@ static int mtk_drm_kms_init(struct drm_device *drm)
                goto err_component_unbind;
        }
 
-       private->dma_dev = &pdev->dev;
+       dma_dev = &pdev->dev;
+       private->dma_dev = dma_dev;
+
+       /*
+        * Configure the DMA segment size to make sure we get contiguous IOVA
+        * when importing PRIME buffers.
+        */
+       if (!dma_dev->dma_parms) {
+               private->dma_parms_allocated = true;
+               dma_dev->dma_parms =
+                       devm_kzalloc(drm->dev, sizeof(*dma_dev->dma_parms),
+                                    GFP_KERNEL);
+       }
+       if (!dma_dev->dma_parms) {
+               ret = -ENOMEM;
+               goto err_component_unbind;
+       }
+
+       ret = dma_set_max_seg_size(dma_dev, (unsigned int)DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(dma_dev, "Failed to set DMA segment size\n");
+               goto err_unset_dma_parms;
+       }
 
        /*
         * We don't use the drm_irq_install() helpers provided by the DRM
@@ -285,13 +309,16 @@ static int mtk_drm_kms_init(struct drm_device *drm)
        drm->irq_enabled = true;
        ret = drm_vblank_init(drm, MAX_CRTC);
        if (ret < 0)
-               goto err_component_unbind;
+               goto err_unset_dma_parms;
 
        drm_kms_helper_poll_init(drm);
        drm_mode_config_reset(drm);
 
        return 0;
 
+err_unset_dma_parms:
+       if (private->dma_parms_allocated)
+               dma_dev->dma_parms = NULL;
 err_component_unbind:
        component_unbind_all(drm->dev, drm);
 err_config_cleanup:
@@ -302,9 +329,14 @@ err_config_cleanup:
 
 static void mtk_drm_kms_deinit(struct drm_device *drm)
 {
+       struct mtk_drm_private *private = drm->dev_private;
+
        drm_kms_helper_poll_fini(drm);
        drm_atomic_helper_shutdown(drm);
 
+       if (private->dma_parms_allocated)
+               private->dma_dev->dma_parms = NULL;
+
        component_unbind_all(drm->dev, drm);
        drm_mode_config_cleanup(drm);
 }
@@ -320,6 +352,18 @@ static const struct file_operations mtk_drm_fops = {
        .compat_ioctl = drm_compat_ioctl,
 };
 
+/*
+ * We need to override this because the device used to import the memory is
+ * not dev->dev, as drm_gem_prime_import() expects.
+ */
+struct drm_gem_object *mtk_drm_gem_prime_import(struct drm_device *dev,
+                                               struct dma_buf *dma_buf)
+{
+       struct mtk_drm_private *private = dev->dev_private;
+
+       return drm_gem_prime_import_dev(dev, dma_buf, private->dma_dev);
+}
+
 static struct drm_driver mtk_drm_driver = {
        .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
                           DRIVER_ATOMIC,
@@ -331,7 +375,7 @@ static struct drm_driver mtk_drm_driver = {
        .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
        .gem_prime_export = drm_gem_prime_export,
-       .gem_prime_import = drm_gem_prime_import,
+       .gem_prime_import = mtk_drm_gem_prime_import,
        .gem_prime_get_sg_table = mtk_gem_prime_get_sg_table,
        .gem_prime_import_sg_table = mtk_gem_prime_import_sg_table,
        .gem_prime_mmap = mtk_drm_gem_mmap_buf,
@@ -524,12 +568,15 @@ static int mtk_drm_probe(struct platform_device *pdev)
                        comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
                        if (!comp) {
                                ret = -ENOMEM;
+                               of_node_put(node);
                                goto err_node;
                        }
 
                        ret = mtk_ddp_comp_init(dev, node, comp, comp_id, NULL);
-                       if (ret)
+                       if (ret) {
+                               of_node_put(node);
                                goto err_node;
+                       }
 
                        private->ddp_comp[comp_id] = comp;
                }
index 598ff3e..e03fea1 100644 (file)
@@ -51,6 +51,8 @@ struct mtk_drm_private {
        } commit;
 
        struct drm_atomic_state *suspend_state;
+
+       bool dma_parms_allocated;
 };
 
 extern struct platform_driver mtk_ddp_driver;
index b4e7404..a11637b 100644 (file)
@@ -40,8 +40,7 @@ nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                u8 *ptr = msg->buf;
 
                while (remaining) {
-                       u8 cnt = (remaining > 16) ? 16 : remaining;
-                       u8 cmd;
+                       u8 cnt, retries, cmd;
 
                        if (msg->flags & I2C_M_RD)
                                cmd = 1;
@@ -51,10 +50,19 @@ nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        if (mcnt || remaining > 16)
                                cmd |= 4; /* MOT */
 
-                       ret = aux->func->xfer(aux, true, cmd, msg->addr, ptr, &cnt);
-                       if (ret < 0) {
-                               nvkm_i2c_aux_release(aux);
-                               return ret;
+                       for (retries = 0, cnt = 0;
+                            retries < 32 && !cnt;
+                            retries++) {
+                               cnt = min_t(u8, remaining, 16);
+                               ret = aux->func->xfer(aux, true, cmd,
+                                                     msg->addr, ptr, &cnt);
+                               if (ret < 0)
+                                       goto out;
+                       }
+                       if (!cnt) {
+                               AUX_TRACE(aux, "no data after 32 retries");
+                               ret = -EIO;
+                               goto out;
                        }
 
                        ptr += cnt;
@@ -64,8 +72,10 @@ nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                msg++;
        }
 
+       ret = num;
+out:
        nvkm_i2c_aux_release(aux);
-       return num;
+       return ret;
 }
 
 static u32
index 288c59d..1bad0a2 100644 (file)
@@ -669,7 +669,7 @@ static int pdev_probe(struct platform_device *pdev)
        if (omapdss_is_initialized() == false)
                return -EPROBE_DEFER;
 
-       ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
        if (ret) {
                dev_err(&pdev->dev, "Failed to set the DMA mask\n");
                return ret;
index 1c62578..082d02c 100644 (file)
@@ -673,10 +673,8 @@ static int rcar_lvds_parse_dt_companion(struct rcar_lvds *lvds)
 
        /* Locate the companion LVDS encoder for dual-link operation, if any. */
        companion = of_parse_phandle(dev->of_node, "renesas,companion", 0);
-       if (!companion) {
-               dev_err(dev, "Companion LVDS encoder not found\n");
-               return -ENXIO;
-       }
+       if (!companion)
+               return 0;
 
        /*
         * Sanity check: the companion encoder must have the same compatible
index 64c43ee..df0cc8f 100644 (file)
@@ -314,6 +314,7 @@ static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon,
                /* R and B components are only 5 bits deep */
                val |= SUN4I_TCON0_FRM_CTL_MODE_R;
                val |= SUN4I_TCON0_FRM_CTL_MODE_B;
+               /* Fall through */
        case MEDIA_BUS_FMT_RGB666_1X18:
        case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
                /* Fall through: enable dithering */
index a1fc8b5..b889ad3 100644 (file)
@@ -993,6 +993,7 @@ static ssize_t sun6i_dsi_transfer(struct mipi_dsi_host *host,
                        ret = sun6i_dsi_dcs_read(dsi, msg);
                        break;
                }
+               /* Else, fall through */
 
        default:
                ret = -EINVAL;
index 2310c96..db1b55d 100644 (file)
@@ -1153,8 +1153,6 @@ static unsigned int cp2112_gpio_irq_startup(struct irq_data *d)
 
        INIT_DELAYED_WORK(&dev->gpio_poll_worker, cp2112_gpio_poll_callback);
 
-       cp2112_gpio_direction_input(gc, d->hwirq);
-
        if (!dev->gpio_poll) {
                dev->gpio_poll = true;
                schedule_delayed_work(&dev->gpio_poll_worker, 0);
@@ -1204,6 +1202,12 @@ static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
                return PTR_ERR(dev->desc[pin]);
        }
 
+       ret = cp2112_gpio_direction_input(&dev->gc, pin);
+       if (ret < 0) {
+               dev_err(dev->gc.parent, "Failed to set GPIO to input dir\n");
+               goto err_desc;
+       }
+
        ret = gpiochip_lock_as_irq(&dev->gc, pin);
        if (ret) {
                dev_err(dev->gc.parent, "Failed to lock GPIO as interrupt\n");
index 21268c9..0179f7e 100644 (file)
@@ -3749,30 +3749,8 @@ static const struct hid_device_id hidpp_devices[] = {
 
        { L27MHZ_DEVICE(HID_ANY_ID) },
 
-       { /* 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 */
index 1065692..5792a10 100644 (file)
@@ -24,6 +24,7 @@
 #define ICL_MOBILE_DEVICE_ID   0x34FC
 #define SPT_H_DEVICE_ID                0xA135
 #define CML_LP_DEVICE_ID       0x02FC
+#define EHL_Ax_DEVICE_ID       0x4BB3
 
 #define        REVISION_ID_CHT_A0      0x6
 #define        REVISION_ID_CHT_Ax_SI   0x0
index aa80b4d..279567b 100644 (file)
@@ -33,6 +33,7 @@ static const struct pci_device_id ish_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ICL_MOBILE_DEVICE_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_H_DEVICE_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CML_LP_DEVICE_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, EHL_Ax_DEVICE_ID)},
        {0, }
 };
 MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
index 7a8ddc9..1713235 100644 (file)
@@ -846,6 +846,8 @@ static int wacom_intuos_general(struct wacom_wac *wacom)
                y >>= 1;
                distance >>= 1;
        }
+       if (features->type == INTUOSHT2)
+               distance = features->distance_max - distance;
        input_report_abs(input, ABS_X, x);
        input_report_abs(input, ABS_Y, y);
        input_report_abs(input, ABS_DISTANCE, distance);
@@ -1059,7 +1061,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
        input_report_key(input, BTN_BASE2, (data[11] & 0x02));
 
        if (data[12] & 0x80)
-               input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
+               input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f) - 1);
        else
                input_report_abs(input, ABS_WHEEL, 0);
 
@@ -1290,7 +1292,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
                }
                if (wacom->tool[0]) {
                        input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
-                       if (wacom->features.type == INTUOSP2_BT) {
+                       if (wacom->features.type == INTUOSP2_BT ||
+                           wacom->features.type == INTUOSP2S_BT) {
                                input_report_abs(pen_input, ABS_DISTANCE,
                                                 range ? frame[13] : wacom->features.distance_max);
                        } else {
index 5f9505a..23f358c 100644 (file)
@@ -26,7 +26,7 @@
 
 static unsigned long virt_to_hvpfn(void *addr)
 {
-       unsigned long paddr;
+       phys_addr_t paddr;
 
        if (is_vmalloc_addr(addr))
                paddr = page_to_phys(vmalloc_to_page(addr)) +
index 362e70e..fb16a62 100644 (file)
@@ -146,8 +146,6 @@ struct hv_context {
         */
        u64 guestid;
 
-       void *tsc_page;
-
        struct hv_per_cpu_context __percpu *cpu_context;
 
        /*
index 19f1730..a68d0cc 100644 (file)
@@ -4724,10 +4724,14 @@ static int __init cma_init(void)
        if (ret)
                goto err;
 
-       cma_configfs_init();
+       ret = cma_configfs_init();
+       if (ret)
+               goto err_ib;
 
        return 0;
 
+err_ib:
+       ib_unregister_client(&cma_client);
 err:
        unregister_netdevice_notifier(&cma_nb);
        ib_sa_unregister_client(&sa_client);
index b798907..af8c85d 100644 (file)
@@ -149,13 +149,11 @@ static bool auto_mode_match(struct ib_qp *qp, struct rdma_counter *counter,
        struct auto_mode_param *param = &counter->mode.param;
        bool match = true;
 
-       if (rdma_is_kernel_res(&counter->res) != rdma_is_kernel_res(&qp->res))
+       if (!rdma_is_visible_in_pid_ns(&qp->res))
                return false;
 
-       /* Ensure that counter belong to right PID */
-       if (!rdma_is_kernel_res(&counter->res) &&
-           !rdma_is_kernel_res(&qp->res) &&
-           (task_pid_vnr(counter->res.task) != current->pid))
+       /* Ensure that counter belongs to the right PID */
+       if (task_pid_nr(counter->res.task) != task_pid_nr(qp->res.task))
                return false;
 
        if (auto_mask & RDMA_COUNTER_MASK_QP_TYPE)
@@ -424,7 +422,7 @@ static struct ib_qp *rdma_counter_get_qp(struct ib_device *dev, u32 qp_num)
        return qp;
 
 err:
-       rdma_restrack_put(&qp->res);
+       rdma_restrack_put(res);
        return NULL;
 }
 
index 87d40d1..020c269 100644 (file)
@@ -382,8 +382,7 @@ static int fill_res_info(struct sk_buff *msg, struct ib_device *device)
        for (i = 0; i < RDMA_RESTRACK_MAX; i++) {
                if (!names[i])
                        continue;
-               curr = rdma_restrack_count(device, i,
-                                          task_active_pid_ns(current));
+               curr = rdma_restrack_count(device, i);
                ret = fill_res_info_entry(msg, names[i], curr);
                if (ret)
                        goto err;
index bddff42..a07665f 100644 (file)
@@ -107,10 +107,8 @@ void rdma_restrack_clean(struct ib_device *dev)
  * rdma_restrack_count() - the current usage of specific object
  * @dev:  IB device
  * @type: actual type of object to operate
- * @ns:   PID namespace
  */
-int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
-                       struct pid_namespace *ns)
+int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type)
 {
        struct rdma_restrack_root *rt = &dev->res[type];
        struct rdma_restrack_entry *e;
@@ -119,10 +117,9 @@ int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
 
        xa_lock(&rt->xa);
        xas_for_each(&xas, e, U32_MAX) {
-               if (ns == &init_pid_ns ||
-                   (!rdma_is_kernel_res(e) &&
-                    ns == task_active_pid_ns(e->task)))
-                       cnt++;
+               if (!rdma_is_visible_in_pid_ns(e))
+                       continue;
+               cnt++;
        }
        xa_unlock(&rt->xa);
        return cnt;
@@ -360,5 +357,7 @@ bool rdma_is_visible_in_pid_ns(struct rdma_restrack_entry *res)
         */
        if (rdma_is_kernel_res(res))
                return task_active_pid_ns(current) == &init_pid_ns;
-       return task_active_pid_ns(current) == task_active_pid_ns(res->task);
+
+       /* PID 0 means that resource is not found in current namespace */
+       return task_pid_vnr(res->task);
 }
index 08da840..5655366 100644 (file)
@@ -379,14 +379,9 @@ EXPORT_SYMBOL(ib_umem_release);
 
 int ib_umem_page_count(struct ib_umem *umem)
 {
-       int i;
-       int n;
+       int i, n = 0;
        struct scatterlist *sg;
 
-       if (umem->is_odp)
-               return ib_umem_num_pages(umem);
-
-       n = 0;
        for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i)
                n += sg_dma_len(sg) >> PAGE_SHIFT;
 
index 48b04d2..60c8f76 100644 (file)
@@ -136,6 +136,13 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req,
                spin_unlock_irqrestore(&cmdq->lock, flags);
                return -EBUSY;
        }
+
+       size = req->cmd_size;
+       /* change the cmd_size to the number of 16byte cmdq unit.
+        * req->cmd_size is modified here
+        */
+       bnxt_qplib_set_cmd_slots(req);
+
        memset(resp, 0, sizeof(*resp));
        crsqe->resp = (struct creq_qp_event *)resp;
        crsqe->resp->cookie = req->cookie;
@@ -150,7 +157,6 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req,
 
        cmdq_ptr = (struct bnxt_qplib_cmdqe **)cmdq->pbl_ptr;
        preq = (u8 *)req;
-       size = req->cmd_size * BNXT_QPLIB_CMDQE_UNITS;
        do {
                /* Locate the next cmdq slot */
                sw_prod = HWQ_CMP(cmdq->prod, cmdq);
index 2138533..dfeadc1 100644 (file)
@@ -55,9 +55,7 @@
        do {                                                            \
                memset(&(req), 0, sizeof((req)));                       \
                (req).opcode = CMDQ_BASE_OPCODE_##CMD;                  \
-               (req).cmd_size = (sizeof((req)) +                       \
-                               BNXT_QPLIB_CMDQE_UNITS - 1) /           \
-                               BNXT_QPLIB_CMDQE_UNITS;                 \
+               (req).cmd_size = sizeof((req));                         \
                (req).flags = cpu_to_le16(cmd_flags);                   \
        } while (0)
 
@@ -95,6 +93,13 @@ static inline u32 bnxt_qplib_cmdqe_cnt_per_pg(u32 depth)
                 BNXT_QPLIB_CMDQE_UNITS);
 }
 
+/* Set the cmd_size to a factor of CMDQE unit */
+static inline void bnxt_qplib_set_cmd_slots(struct cmdq_base *req)
+{
+       req->cmd_size = (req->cmd_size + BNXT_QPLIB_CMDQE_UNITS - 1) /
+                        BNXT_QPLIB_CMDQE_UNITS;
+}
+
 #define MAX_CMDQ_IDX(depth)            ((depth) - 1)
 
 static inline u32 bnxt_qplib_max_cmdq_idx_per_pg(u32 depth)
index 93613e5..986c121 100644 (file)
@@ -141,12 +141,14 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf,
        if (!data)
                return -ENOMEM;
        copy = min(len, datalen - 1);
-       if (copy_from_user(data, buf, copy))
-               return -EFAULT;
+       if (copy_from_user(data, buf, copy)) {
+               ret = -EFAULT;
+               goto free_data;
+       }
 
        ret = debugfs_file_get(file->f_path.dentry);
        if (unlikely(ret))
-               return ret;
+               goto free_data;
        ptr = data;
        token = ptr;
        for (ptr = data; *ptr; ptr = end + 1, token = ptr) {
@@ -195,6 +197,7 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf,
        ret = len;
 
        debugfs_file_put(file->f_path.dentry);
+free_data:
        kfree(data);
        return ret;
 }
@@ -214,7 +217,7 @@ static ssize_t fault_opcodes_read(struct file *file, char __user *buf,
                return -ENOMEM;
        ret = debugfs_file_get(file->f_path.dentry);
        if (unlikely(ret))
-               return ret;
+               goto free_data;
        bit = find_first_bit(fault->opcodes, bitsize);
        while (bit < bitsize) {
                zero = find_next_zero_bit(fault->opcodes, bitsize, bit);
@@ -232,6 +235,7 @@ static ssize_t fault_opcodes_read(struct file *file, char __user *buf,
        data[size - 1] = '\n';
        data[size] = '\0';
        ret = simple_read_from_buffer(buf, len, pos, data, size);
+free_data:
        kfree(data);
        return ret;
 }
index 996fc29..6141f4e 100644 (file)
@@ -2574,18 +2574,9 @@ void hfi1_kern_read_tid_flow_free(struct rvt_qp *qp)
        hfi1_kern_clear_hw_flow(priv->rcd, qp);
 }
 
-static bool tid_rdma_tid_err(struct hfi1_ctxtdata *rcd,
-                            struct hfi1_packet *packet, u8 rcv_type,
-                            u8 opcode)
+static bool tid_rdma_tid_err(struct hfi1_packet *packet, u8 rcv_type)
 {
        struct rvt_qp *qp = packet->qp;
-       struct hfi1_qp_priv *qpriv = qp->priv;
-       u32 ipsn;
-       struct ib_other_headers *ohdr = packet->ohdr;
-       struct rvt_ack_entry *e;
-       struct tid_rdma_request *req;
-       struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
-       u32 i;
 
        if (rcv_type >= RHF_RCV_TYPE_IB)
                goto done;
@@ -2602,41 +2593,9 @@ static bool tid_rdma_tid_err(struct hfi1_ctxtdata *rcd,
        if (rcv_type == RHF_RCV_TYPE_EAGER) {
                hfi1_restart_rc(qp, qp->s_last_psn + 1, 1);
                hfi1_schedule_send(qp);
-               goto done_unlock;
-       }
-
-       /*
-        * For TID READ response, error out QP after freeing the tid
-        * resources.
-        */
-       if (opcode == TID_OP(READ_RESP)) {
-               ipsn = mask_psn(be32_to_cpu(ohdr->u.tid_rdma.r_rsp.verbs_psn));
-               if (cmp_psn(ipsn, qp->s_last_psn) > 0 &&
-                   cmp_psn(ipsn, qp->s_psn) < 0) {
-                       hfi1_kern_read_tid_flow_free(qp);
-                       spin_unlock(&qp->s_lock);
-                       rvt_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
-                       goto done;
-               }
-               goto done_unlock;
-       }
-
-       /*
-        * Error out the qp for TID RDMA WRITE
-        */
-       hfi1_kern_clear_hw_flow(qpriv->rcd, qp);
-       for (i = 0; i < rvt_max_atomic(rdi); i++) {
-               e = &qp->s_ack_queue[i];
-               if (e->opcode == TID_OP(WRITE_REQ)) {
-                       req = ack_to_tid_req(e);
-                       hfi1_kern_exp_rcv_clear_all(req);
-               }
        }
-       spin_unlock(&qp->s_lock);
-       rvt_rc_error(qp, IB_WC_LOC_LEN_ERR);
-       goto done;
 
-done_unlock:
+       /* Since no payload is delivered, just drop the packet */
        spin_unlock(&qp->s_lock);
 done:
        return true;
@@ -2687,12 +2646,12 @@ static bool handle_read_kdeth_eflags(struct hfi1_ctxtdata *rcd,
        u32 fpsn;
 
        lockdep_assert_held(&qp->r_lock);
+       spin_lock(&qp->s_lock);
        /* If the psn is out of valid range, drop the packet */
        if (cmp_psn(ibpsn, qp->s_last_psn) < 0 ||
            cmp_psn(ibpsn, qp->s_psn) > 0)
-               return ret;
+               goto s_unlock;
 
-       spin_lock(&qp->s_lock);
        /*
         * Note that NAKs implicitly ACK outstanding SEND and RDMA write
         * requests and implicitly NAK RDMA read and atomic requests issued
@@ -2740,9 +2699,12 @@ static bool handle_read_kdeth_eflags(struct hfi1_ctxtdata *rcd,
 
                wqe = do_rc_completion(qp, wqe, ibp);
                if (qp->s_acked == qp->s_tail)
-                       break;
+                       goto s_unlock;
        }
 
+       if (qp->s_acked == qp->s_tail)
+               goto s_unlock;
+
        /* Handle the eflags for the request */
        if (wqe->wr.opcode != IB_WR_TID_RDMA_READ)
                goto s_unlock;
@@ -2922,7 +2884,7 @@ bool hfi1_handle_kdeth_eflags(struct hfi1_ctxtdata *rcd,
                if (lnh == HFI1_LRH_GRH)
                        goto r_unlock;
 
-               if (tid_rdma_tid_err(rcd, packet, rcv_type, opcode))
+               if (tid_rdma_tid_err(packet, rcv_type))
                        goto r_unlock;
        }
 
@@ -2942,8 +2904,15 @@ bool hfi1_handle_kdeth_eflags(struct hfi1_ctxtdata *rcd,
         */
        spin_lock(&qp->s_lock);
        qpriv = qp->priv;
+       if (qpriv->r_tid_tail == HFI1_QP_WQE_INVALID ||
+           qpriv->r_tid_tail == qpriv->r_tid_head)
+               goto unlock;
        e = &qp->s_ack_queue[qpriv->r_tid_tail];
+       if (e->opcode != TID_OP(WRITE_REQ))
+               goto unlock;
        req = ack_to_tid_req(e);
+       if (req->comp_seg == req->cur_seg)
+               goto unlock;
        flow = &req->flows[req->clear_tail];
        trace_hfi1_eflags_err_write(qp, rcv_type, rte, psn);
        trace_hfi1_rsp_handle_kdeth_eflags(qp, psn);
@@ -4509,7 +4478,7 @@ void hfi1_rc_rcv_tid_rdma_ack(struct hfi1_packet *packet)
        struct rvt_swqe *wqe;
        struct tid_rdma_request *req;
        struct tid_rdma_flow *flow;
-       u32 aeth, psn, req_psn, ack_psn, resync_psn, ack_kpsn;
+       u32 aeth, psn, req_psn, ack_psn, flpsn, resync_psn, ack_kpsn;
        unsigned long flags;
        u16 fidx;
 
@@ -4538,6 +4507,9 @@ void hfi1_rc_rcv_tid_rdma_ack(struct hfi1_packet *packet)
                ack_kpsn--;
        }
 
+       if (unlikely(qp->s_acked == qp->s_tail))
+               goto ack_op_err;
+
        wqe = rvt_get_swqe_ptr(qp, qp->s_acked);
 
        if (wqe->wr.opcode != IB_WR_TID_RDMA_WRITE)
@@ -4550,7 +4522,8 @@ void hfi1_rc_rcv_tid_rdma_ack(struct hfi1_packet *packet)
        trace_hfi1_tid_flow_rcv_tid_ack(qp, req->acked_tail, flow);
 
        /* Drop stale ACK/NAK */
-       if (cmp_psn(psn, full_flow_psn(flow, flow->flow_state.spsn)) < 0)
+       if (cmp_psn(psn, full_flow_psn(flow, flow->flow_state.spsn)) < 0 ||
+           cmp_psn(req_psn, flow->flow_state.resp_ib_psn) < 0)
                goto ack_op_err;
 
        while (cmp_psn(ack_kpsn,
@@ -4712,7 +4685,12 @@ done:
                switch ((aeth >> IB_AETH_CREDIT_SHIFT) &
                        IB_AETH_CREDIT_MASK) {
                case 0: /* PSN sequence error */
+                       if (!req->flows)
+                               break;
                        flow = &req->flows[req->acked_tail];
+                       flpsn = full_flow_psn(flow, flow->flow_state.lpsn);
+                       if (cmp_psn(psn, flpsn) > 0)
+                               break;
                        trace_hfi1_tid_flow_rcv_tid_ack(qp, req->acked_tail,
                                                        flow);
                        req->r_ack_psn = mask_psn(be32_to_cpu(ohdr->bth[2]));
index 68c9514..5707911 100644 (file)
@@ -1677,8 +1677,6 @@ tx_err:
                                    tx_buf_size, DMA_TO_DEVICE);
                kfree(tun_qp->tx_ring[i].buf.addr);
        }
-       kfree(tun_qp->tx_ring);
-       tun_qp->tx_ring = NULL;
        i = MLX4_NUM_TUNNEL_BUFS;
 err:
        while (i > 0) {
@@ -1687,6 +1685,8 @@ err:
                                    rx_buf_size, DMA_FROM_DEVICE);
                kfree(tun_qp->ring[i].addr);
        }
+       kfree(tun_qp->tx_ring);
+       tun_qp->tx_ring = NULL;
        kfree(tun_qp->ring);
        tun_qp->ring = NULL;
        return -ENOMEM;
index e12a440..0569bca 100644 (file)
@@ -1023,7 +1023,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
        props->timestamp_mask = 0x7FFFFFFFFFFFFFFFULL;
 
        if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
-               if (MLX5_CAP_GEN(mdev, pg))
+               if (dev->odp_caps.general_caps & IB_ODP_SUPPORT)
                        props->device_cap_flags |= IB_DEVICE_ON_DEMAND_PAGING;
                props->odp_caps = dev->odp_caps;
        }
@@ -6139,6 +6139,8 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
                dev->port[i].roce.last_port_state = IB_PORT_DOWN;
        }
 
+       mlx5_ib_internal_fill_odp_caps(dev);
+
        err = mlx5_ib_init_multiport_master(dev);
        if (err)
                return err;
@@ -6563,8 +6565,6 @@ static void mlx5_ib_stage_dev_res_cleanup(struct mlx5_ib_dev *dev)
 
 static int mlx5_ib_stage_odp_init(struct mlx5_ib_dev *dev)
 {
-       mlx5_ib_internal_fill_odp_caps(dev);
-
        return mlx5_ib_odp_init_one(dev);
 }
 
index fe1a76d..a40e0ab 100644 (file)
@@ -57,9 +57,10 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr,
        int entry;
 
        if (umem->is_odp) {
-               unsigned int page_shift = to_ib_umem_odp(umem)->page_shift;
+               struct ib_umem_odp *odp = to_ib_umem_odp(umem);
+               unsigned int page_shift = odp->page_shift;
 
-               *ncont = ib_umem_page_count(umem);
+               *ncont = ib_umem_odp_num_pages(odp);
                *count = *ncont << (page_shift - PAGE_SHIFT);
                *shift = page_shift;
                if (order)
index f6a5345..9ae587b 100644 (file)
@@ -1475,4 +1475,18 @@ int bfregn_to_uar_index(struct mlx5_ib_dev *dev,
                        bool dyn_bfreg);
 
 int mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter);
+
+static inline bool mlx5_ib_can_use_umr(struct mlx5_ib_dev *dev,
+                                      bool do_modify_atomic)
+{
+       if (MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled))
+               return false;
+
+       if (do_modify_atomic &&
+           MLX5_CAP_GEN(dev->mdev, atomic) &&
+           MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled))
+               return false;
+
+       return true;
+}
 #endif /* MLX5_IB_H */
index b74fad0..3401f5f 100644 (file)
@@ -1293,9 +1293,7 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
        if (err < 0)
                return ERR_PTR(err);
 
-       use_umr = !MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled) &&
-                 (!MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled) ||
-                  !MLX5_CAP_GEN(dev->mdev, atomic));
+       use_umr = mlx5_ib_can_use_umr(dev, true);
 
        if (order <= mr_cache_max_order(dev) && use_umr) {
                mr = alloc_mr_from_cache(pd, umem, virt_addr, length, ncont,
@@ -1448,7 +1446,8 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
                        goto err;
        }
 
-       if (flags & IB_MR_REREG_TRANS && !use_umr_mtt_update(mr, addr, len)) {
+       if (!mlx5_ib_can_use_umr(dev, true) ||
+           (flags & IB_MR_REREG_TRANS && !use_umr_mtt_update(mr, addr, len))) {
                /*
                 * UMR can't be used - MKey needs to be replaced.
                 */
index 1d257d1..0a59912 100644 (file)
@@ -301,7 +301,8 @@ void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev)
 
        memset(caps, 0, sizeof(*caps));
 
-       if (!MLX5_CAP_GEN(dev->mdev, pg))
+       if (!MLX5_CAP_GEN(dev->mdev, pg) ||
+           !mlx5_ib_can_use_umr(dev, true))
                return;
 
        caps->general_caps = IB_ODP_SUPPORT;
@@ -355,7 +356,8 @@ void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev)
 
        if (MLX5_CAP_GEN(dev->mdev, fixed_buffer_size) &&
            MLX5_CAP_GEN(dev->mdev, null_mkey) &&
-           MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset))
+           MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset) &&
+           !MLX5_CAP_GEN(dev->mdev, umr_indirect_mkey_disabled))
                caps->general_caps |= IB_ODP_SUPPORT_IMPLICIT;
 
        return;
@@ -1622,8 +1624,10 @@ int mlx5_ib_odp_init_one(struct mlx5_ib_dev *dev)
 {
        int ret = 0;
 
-       if (dev->odp_caps.general_caps & IB_ODP_SUPPORT)
-               ib_set_device_ops(&dev->ib_dev, &mlx5_ib_dev_odp_ops);
+       if (!(dev->odp_caps.general_caps & IB_ODP_SUPPORT))
+               return ret;
+
+       ib_set_device_ops(&dev->ib_dev, &mlx5_ib_dev_odp_ops);
 
        if (dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT) {
                ret = mlx5_cmd_null_mkey(dev->mdev, &dev->null_mkey);
@@ -1633,9 +1637,6 @@ int mlx5_ib_odp_init_one(struct mlx5_ib_dev *dev)
                }
        }
 
-       if (!MLX5_CAP_GEN(dev->mdev, pg))
-               return ret;
-
        ret = mlx5_ib_create_pf_eq(dev, &dev->odp_pf_eq);
 
        return ret;
@@ -1643,7 +1644,7 @@ int mlx5_ib_odp_init_one(struct mlx5_ib_dev *dev)
 
 void mlx5_ib_odp_cleanup_one(struct mlx5_ib_dev *dev)
 {
-       if (!MLX5_CAP_GEN(dev->mdev, pg))
+       if (!(dev->odp_caps.general_caps & IB_ODP_SUPPORT))
                return;
 
        mlx5_ib_destroy_pf_eq(dev, &dev->odp_pf_eq);
index 379328b..72869ff 100644 (file)
@@ -4162,7 +4162,7 @@ static u64 get_xlt_octo(u64 bytes)
               MLX5_IB_UMR_OCTOWORD;
 }
 
-static __be64 frwr_mkey_mask(void)
+static __be64 frwr_mkey_mask(bool atomic)
 {
        u64 result;
 
@@ -4175,10 +4175,12 @@ static __be64 frwr_mkey_mask(void)
                MLX5_MKEY_MASK_LW               |
                MLX5_MKEY_MASK_RR               |
                MLX5_MKEY_MASK_RW               |
-               MLX5_MKEY_MASK_A                |
                MLX5_MKEY_MASK_SMALL_FENCE      |
                MLX5_MKEY_MASK_FREE;
 
+       if (atomic)
+               result |= MLX5_MKEY_MASK_A;
+
        return cpu_to_be64(result);
 }
 
@@ -4204,7 +4206,7 @@ static __be64 sig_mkey_mask(void)
 }
 
 static void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr,
-                           struct mlx5_ib_mr *mr, u8 flags)
+                           struct mlx5_ib_mr *mr, u8 flags, bool atomic)
 {
        int size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size;
 
@@ -4212,7 +4214,7 @@ static void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr,
 
        umr->flags = flags;
        umr->xlt_octowords = cpu_to_be16(get_xlt_octo(size));
-       umr->mkey_mask = frwr_mkey_mask();
+       umr->mkey_mask = frwr_mkey_mask(atomic);
 }
 
 static void set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr)
@@ -4811,10 +4813,22 @@ static int set_reg_wr(struct mlx5_ib_qp *qp,
 {
        struct mlx5_ib_mr *mr = to_mmr(wr->mr);
        struct mlx5_ib_pd *pd = to_mpd(qp->ibqp.pd);
+       struct mlx5_ib_dev *dev = to_mdev(pd->ibpd.device);
        int mr_list_size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size;
        bool umr_inline = mr_list_size <= MLX5_IB_SQ_UMR_INLINE_THRESHOLD;
+       bool atomic = wr->access & IB_ACCESS_REMOTE_ATOMIC;
        u8 flags = 0;
 
+       if (!mlx5_ib_can_use_umr(dev, atomic)) {
+               mlx5_ib_warn(to_mdev(qp->ibqp.device),
+                            "Fast update of %s for MR is disabled\n",
+                            (MLX5_CAP_GEN(dev->mdev,
+                                          umr_modify_entity_size_disabled)) ?
+                                    "entity size" :
+                                    "atomic access");
+               return -EINVAL;
+       }
+
        if (unlikely(wr->wr.send_flags & IB_SEND_INLINE)) {
                mlx5_ib_warn(to_mdev(qp->ibqp.device),
                             "Invalid IB_SEND_INLINE send flag\n");
@@ -4826,7 +4840,7 @@ static int set_reg_wr(struct mlx5_ib_qp *qp,
        if (umr_inline)
                flags |= MLX5_UMR_INLINE;
 
-       set_reg_umr_seg(*seg, mr, flags);
+       set_reg_umr_seg(*seg, mr, flags, atomic);
        *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
        *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
        handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
index 77b1aab..dba4535 100644 (file)
@@ -138,9 +138,9 @@ struct siw_umem {
 };
 
 struct siw_pble {
-       u64 addr; /* Address of assigned user buffer */
-       u64 size; /* Size of this entry */
-       u64 pbl_off; /* Total offset from start of PBL */
+       dma_addr_t addr; /* Address of assigned buffer */
+       unsigned int size; /* Size of this entry */
+       unsigned long pbl_off; /* Total offset from start of PBL */
 };
 
 struct siw_pbl {
@@ -734,7 +734,7 @@ static inline void siw_crc_skb(struct siw_rx_stream *srx, unsigned int len)
                  "MEM[0x%08x] %s: " fmt, mem->stag, __func__, ##__VA_ARGS__)
 
 #define siw_dbg_cep(cep, fmt, ...)                                             \
-       ibdev_dbg(&cep->sdev->base_dev, "CEP[0x%p] %s: " fmt,                  \
+       ibdev_dbg(&cep->sdev->base_dev, "CEP[0x%pK] %s: " fmt,                  \
                  cep, __func__, ##__VA_ARGS__)
 
 void siw_cq_flush(struct siw_cq *cq);
index 9ce8a1b..1db5ad3 100644 (file)
@@ -355,8 +355,8 @@ static int siw_cm_upcall(struct siw_cep *cep, enum iw_cm_event_type reason,
                getname_local(cep->sock, &event.local_addr);
                getname_peer(cep->sock, &event.remote_addr);
        }
-       siw_dbg_cep(cep, "[QP %u]: id 0x%p, reason=%d, status=%d\n",
-                   cep->qp ? qp_id(cep->qp) : -1, id, reason, status);
+       siw_dbg_cep(cep, "[QP %u]: reason=%d, status=%d\n",
+                   cep->qp ? qp_id(cep->qp) : UINT_MAX, reason, status);
 
        return id->event_handler(id, &event);
 }
@@ -947,8 +947,6 @@ static void siw_accept_newconn(struct siw_cep *cep)
        siw_cep_get(new_cep);
        new_s->sk->sk_user_data = new_cep;
 
-       siw_dbg_cep(cep, "listen socket 0x%p, new 0x%p\n", s, new_s);
-
        if (siw_tcp_nagle == false) {
                int val = 1;
 
@@ -1011,7 +1009,8 @@ static void siw_cm_work_handler(struct work_struct *w)
        cep = work->cep;
 
        siw_dbg_cep(cep, "[QP %u]: work type: %d, state %d\n",
-                   cep->qp ? qp_id(cep->qp) : -1, work->type, cep->state);
+                   cep->qp ? qp_id(cep->qp) : UINT_MAX,
+                   work->type, cep->state);
 
        siw_cep_set_inuse(cep);
 
@@ -1145,9 +1144,9 @@ static void siw_cm_work_handler(struct work_struct *w)
        }
        if (release_cep) {
                siw_dbg_cep(cep,
-                           "release: timer=%s, QP[%u], id 0x%p\n",
+                           "release: timer=%s, QP[%u]\n",
                            cep->mpa_timer ? "y" : "n",
-                           cep->qp ? qp_id(cep->qp) : -1, cep->cm_id);
+                           cep->qp ? qp_id(cep->qp) : UINT_MAX);
 
                siw_cancel_mpatimer(cep);
 
@@ -1211,8 +1210,8 @@ int siw_cm_queue_work(struct siw_cep *cep, enum siw_work_type type)
                else
                        delay = MPAREP_TIMEOUT;
        }
-       siw_dbg_cep(cep, "[QP %u]: work type: %d, work 0x%p, timeout %lu\n",
-                   cep->qp ? qp_id(cep->qp) : -1, type, work, delay);
+       siw_dbg_cep(cep, "[QP %u]: work type: %d, timeout %lu\n",
+                   cep->qp ? qp_id(cep->qp) : -1, type, delay);
 
        queue_delayed_work(siw_cm_wq, &work->work, delay);
 
@@ -1376,16 +1375,16 @@ int siw_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        }
        if (v4)
                siw_dbg_qp(qp,
-                          "id 0x%p, pd_len %d, laddr %pI4 %d, raddr %pI4 %d\n",
-                          id, pd_len,
+                          "pd_len %d, laddr %pI4 %d, raddr %pI4 %d\n",
+                          pd_len,
                           &((struct sockaddr_in *)(laddr))->sin_addr,
                           ntohs(((struct sockaddr_in *)(laddr))->sin_port),
                           &((struct sockaddr_in *)(raddr))->sin_addr,
                           ntohs(((struct sockaddr_in *)(raddr))->sin_port));
        else
                siw_dbg_qp(qp,
-                          "id 0x%p, pd_len %d, laddr %pI6 %d, raddr %pI6 %d\n",
-                          id, pd_len,
+                          "pd_len %d, laddr %pI6 %d, raddr %pI6 %d\n",
+                          pd_len,
                           &((struct sockaddr_in6 *)(laddr))->sin6_addr,
                           ntohs(((struct sockaddr_in6 *)(laddr))->sin6_port),
                           &((struct sockaddr_in6 *)(raddr))->sin6_addr,
@@ -1508,14 +1507,13 @@ int siw_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        if (rv >= 0) {
                rv = siw_cm_queue_work(cep, SIW_CM_WORK_MPATIMEOUT);
                if (!rv) {
-                       siw_dbg_cep(cep, "id 0x%p, [QP %u]: exit\n", id,
-                                   qp_id(qp));
+                       siw_dbg_cep(cep, "[QP %u]: exit\n", qp_id(qp));
                        siw_cep_set_free(cep);
                        return 0;
                }
        }
 error:
-       siw_dbg_qp(qp, "failed: %d\n", rv);
+       siw_dbg(id->device, "failed: %d\n", rv);
 
        if (cep) {
                siw_socket_disassoc(s);
@@ -1540,7 +1538,8 @@ error:
        } else if (s) {
                sock_release(s);
        }
-       siw_qp_put(qp);
+       if (qp)
+               siw_qp_put(qp);
 
        return rv;
 }
@@ -1580,7 +1579,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        siw_cancel_mpatimer(cep);
 
        if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) {
-               siw_dbg_cep(cep, "id 0x%p: out of state\n", id);
+               siw_dbg_cep(cep, "out of state\n");
 
                siw_cep_set_free(cep);
                siw_cep_put(cep);
@@ -1601,7 +1600,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
                up_write(&qp->state_lock);
                goto error;
        }
-       siw_dbg_cep(cep, "id 0x%p\n", id);
+       siw_dbg_cep(cep, "[QP %d]\n", params->qpn);
 
        if (try_gso && cep->mpa.hdr.params.bits & MPA_RR_FLAG_GSO_EXP) {
                siw_dbg_cep(cep, "peer allows GSO on TX\n");
@@ -1611,8 +1610,8 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
            params->ird > sdev->attrs.max_ird) {
                siw_dbg_cep(
                        cep,
-                       "id 0x%p, [QP %u]: ord %d (max %d), ird %d (max %d)\n",
-                       id, qp_id(qp), params->ord, sdev->attrs.max_ord,
+                       "[QP %u]: ord %d (max %d), ird %d (max %d)\n",
+                       qp_id(qp), params->ord, sdev->attrs.max_ord,
                        params->ird, sdev->attrs.max_ird);
                rv = -EINVAL;
                up_write(&qp->state_lock);
@@ -1624,8 +1623,8 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        if (params->private_data_len > max_priv_data) {
                siw_dbg_cep(
                        cep,
-                       "id 0x%p, [QP %u]: private data length: %d (max %d)\n",
-                       id, qp_id(qp), params->private_data_len, max_priv_data);
+                       "[QP %u]: private data length: %d (max %d)\n",
+                       qp_id(qp), params->private_data_len, max_priv_data);
                rv = -EINVAL;
                up_write(&qp->state_lock);
                goto error;
@@ -1679,7 +1678,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
                qp_attrs.flags = SIW_MPA_CRC;
        qp_attrs.state = SIW_QP_STATE_RTS;
 
-       siw_dbg_cep(cep, "id 0x%p, [QP%u]: moving to rts\n", id, qp_id(qp));
+       siw_dbg_cep(cep, "[QP%u]: moving to rts\n", qp_id(qp));
 
        /* Associate QP with CEP */
        siw_cep_get(cep);
@@ -1700,8 +1699,8 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        if (rv)
                goto error;
 
-       siw_dbg_cep(cep, "id 0x%p, [QP %u]: send mpa reply, %d byte pdata\n",
-                   id, qp_id(qp), params->private_data_len);
+       siw_dbg_cep(cep, "[QP %u]: send mpa reply, %d byte pdata\n",
+                   qp_id(qp), params->private_data_len);
 
        rv = siw_send_mpareqrep(cep, params->private_data,
                                params->private_data_len);
@@ -1759,14 +1758,14 @@ int siw_reject(struct iw_cm_id *id, const void *pdata, u8 pd_len)
        siw_cancel_mpatimer(cep);
 
        if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) {
-               siw_dbg_cep(cep, "id 0x%p: out of state\n", id);
+               siw_dbg_cep(cep, "out of state\n");
 
                siw_cep_set_free(cep);
                siw_cep_put(cep); /* put last reference */
 
                return -ECONNRESET;
        }
-       siw_dbg_cep(cep, "id 0x%p, cep->state %d, pd_len %d\n", id, cep->state,
+       siw_dbg_cep(cep, "cep->state %d, pd_len %d\n", cep->state,
                    pd_len);
 
        if (__mpa_rr_revision(cep->mpa.hdr.params.bits) >= MPA_REVISION_1) {
@@ -1804,14 +1803,14 @@ static int siw_listen_address(struct iw_cm_id *id, int backlog,
        rv = kernel_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&s_val,
                               sizeof(s_val));
        if (rv) {
-               siw_dbg(id->device, "id 0x%p: setsockopt error: %d\n", id, rv);
+               siw_dbg(id->device, "setsockopt error: %d\n", rv);
                goto error;
        }
        rv = s->ops->bind(s, laddr, addr_family == AF_INET ?
                                    sizeof(struct sockaddr_in) :
                                    sizeof(struct sockaddr_in6));
        if (rv) {
-               siw_dbg(id->device, "id 0x%p: socket bind error: %d\n", id, rv);
+               siw_dbg(id->device, "socket bind error: %d\n", rv);
                goto error;
        }
        cep = siw_cep_alloc(sdev);
@@ -1824,13 +1823,13 @@ static int siw_listen_address(struct iw_cm_id *id, int backlog,
        rv = siw_cm_alloc_work(cep, backlog);
        if (rv) {
                siw_dbg(id->device,
-                       "id 0x%p: alloc_work error %d, backlog %d\n", id,
+                       "alloc_work error %d, backlog %d\n",
                        rv, backlog);
                goto error;
        }
        rv = s->ops->listen(s, backlog);
        if (rv) {
-               siw_dbg(id->device, "id 0x%p: listen error %d\n", id, rv);
+               siw_dbg(id->device, "listen error %d\n", rv);
                goto error;
        }
        cep->cm_id = id;
@@ -1914,8 +1913,7 @@ static void siw_drop_listeners(struct iw_cm_id *id)
 
                list_del(p);
 
-               siw_dbg_cep(cep, "id 0x%p: drop cep, state %d\n", id,
-                           cep->state);
+               siw_dbg_cep(cep, "drop cep, state %d\n", cep->state);
 
                siw_cep_set_inuse(cep);
 
@@ -1952,7 +1950,7 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
        struct net_device *dev = to_siw_dev(id->device)->netdev;
        int rv = 0, listeners = 0;
 
-       siw_dbg(id->device, "id 0x%p: backlog %d\n", id, backlog);
+       siw_dbg(id->device, "backlog %d\n", backlog);
 
        /*
         * For each attached address of the interface, create a
@@ -1968,8 +1966,8 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
                s_raddr = (struct sockaddr_in *)&id->remote_addr;
 
                siw_dbg(id->device,
-                       "id 0x%p: laddr %pI4:%d, raddr %pI4:%d\n",
-                       id, &s_laddr.sin_addr, ntohs(s_laddr.sin_port),
+                       "laddr %pI4:%d, raddr %pI4:%d\n",
+                       &s_laddr.sin_addr, ntohs(s_laddr.sin_port),
                        &s_raddr->sin_addr, ntohs(s_raddr->sin_port));
 
                rtnl_lock();
@@ -1994,8 +1992,8 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
                        *s_raddr = &to_sockaddr_in6(id->remote_addr);
 
                siw_dbg(id->device,
-                       "id 0x%p: laddr %pI6:%d, raddr %pI6:%d\n",
-                       id, &s_laddr->sin6_addr, ntohs(s_laddr->sin6_port),
+                       "laddr %pI6:%d, raddr %pI6:%d\n",
+                       &s_laddr->sin6_addr, ntohs(s_laddr->sin6_port),
                        &s_raddr->sin6_addr, ntohs(s_raddr->sin6_port));
 
                read_lock_bh(&in6_dev->lock);
@@ -2028,17 +2026,15 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
        else if (!rv)
                rv = -EINVAL;
 
-       siw_dbg(id->device, "id 0x%p: %s\n", id, rv ? "FAIL" : "OK");
+       siw_dbg(id->device, "%s\n", rv ? "FAIL" : "OK");
 
        return rv;
 }
 
 int siw_destroy_listen(struct iw_cm_id *id)
 {
-       siw_dbg(id->device, "id 0x%p\n", id);
-
        if (!id->provider_data) {
-               siw_dbg(id->device, "id 0x%p: no cep(s)\n", id);
+               siw_dbg(id->device, "no cep(s)\n");
                return 0;
        }
        siw_drop_listeners(id);
index e381ae9..d8db3be 100644 (file)
@@ -71,9 +71,10 @@ int siw_reap_cqe(struct siw_cq *cq, struct ib_wc *wc)
                                wc->wc_flags = IB_WC_WITH_INVALIDATE;
                        }
                        wc->qp = cqe->base_qp;
-                       siw_dbg_cq(cq, "idx %u, type %d, flags %2x, id 0x%p\n",
+                       siw_dbg_cq(cq,
+                                  "idx %u, type %d, flags %2x, id 0x%pK\n",
                                   cq->cq_get % cq->num_cqe, cqe->opcode,
-                                  cqe->flags, (void *)cqe->id);
+                                  cqe->flags, (void *)(uintptr_t)cqe->id);
                }
                WRITE_ONCE(cqe->flags, 0);
                cq->cq_get++;
index 67171c8..87a5603 100644 (file)
@@ -197,12 +197,12 @@ int siw_check_mem(struct ib_pd *pd, struct siw_mem *mem, u64 addr,
         */
        if (addr < mem->va || addr + len > mem->va + mem->len) {
                siw_dbg_pd(pd, "MEM interval len %d\n", len);
-               siw_dbg_pd(pd, "[0x%016llx, 0x%016llx] out of bounds\n",
-                          (unsigned long long)addr,
-                          (unsigned long long)(addr + len));
-               siw_dbg_pd(pd, "[0x%016llx, 0x%016llx] STag=0x%08x\n",
-                          (unsigned long long)mem->va,
-                          (unsigned long long)(mem->va + mem->len),
+               siw_dbg_pd(pd, "[0x%pK, 0x%pK] out of bounds\n",
+                          (void *)(uintptr_t)addr,
+                          (void *)(uintptr_t)(addr + len));
+               siw_dbg_pd(pd, "[0x%pK, 0x%pK] STag=0x%08x\n",
+                          (void *)(uintptr_t)mem->va,
+                          (void *)(uintptr_t)(mem->va + mem->len),
                           mem->stag);
 
                return -E_BASE_BOUNDS;
@@ -330,7 +330,7 @@ out:
  * Optionally, provides remaining len within current element, and
  * current PBL index for later resume at same element.
  */
-u64 siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx)
+dma_addr_t siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx)
 {
        int i = idx ? *idx : 0;
 
index f43daf2..db138c8 100644 (file)
@@ -9,7 +9,7 @@
 struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable);
 void siw_umem_release(struct siw_umem *umem, bool dirty);
 struct siw_pbl *siw_pbl_alloc(u32 num_buf);
-u64 siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx);
+dma_addr_t siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx);
 struct siw_mem *siw_mem_id2obj(struct siw_device *sdev, int stag_index);
 int siw_mem_add(struct siw_device *sdev, struct siw_mem *m);
 int siw_invalidate_stag(struct ib_pd *pd, u32 stag);
index 0990307..430314c 100644 (file)
@@ -949,7 +949,7 @@ skip_irq:
                                rv = -EINVAL;
                                goto out;
                        }
-                       wqe->sqe.sge[0].laddr = (u64)&wqe->sqe.sge[1];
+                       wqe->sqe.sge[0].laddr = (uintptr_t)&wqe->sqe.sge[1];
                        wqe->sqe.sge[0].lkey = 0;
                        wqe->sqe.num_sge = 1;
                }
index f87657a..c0a8872 100644 (file)
@@ -38,9 +38,10 @@ static int siw_rx_umem(struct siw_rx_stream *srx, struct siw_umem *umem,
 
                p = siw_get_upage(umem, dest_addr);
                if (unlikely(!p)) {
-                       pr_warn("siw: %s: [QP %u]: bogus addr: %p, %p\n",
+                       pr_warn("siw: %s: [QP %u]: bogus addr: %pK, %pK\n",
                                __func__, qp_id(rx_qp(srx)),
-                               (void *)dest_addr, (void *)umem->fp_addr);
+                               (void *)(uintptr_t)dest_addr,
+                               (void *)(uintptr_t)umem->fp_addr);
                        /* siw internal error */
                        srx->skb_copied += copied;
                        srx->skb_new -= copied;
@@ -50,7 +51,7 @@ static int siw_rx_umem(struct siw_rx_stream *srx, struct siw_umem *umem,
                pg_off = dest_addr & ~PAGE_MASK;
                bytes = min(len, (int)PAGE_SIZE - pg_off);
 
-               siw_dbg_qp(rx_qp(srx), "page %p, bytes=%u\n", p, bytes);
+               siw_dbg_qp(rx_qp(srx), "page %pK, bytes=%u\n", p, bytes);
 
                dest = kmap_atomic(p);
                rv = skb_copy_bits(srx->skb, srx->skb_offset, dest + pg_off,
@@ -104,11 +105,11 @@ static int siw_rx_kva(struct siw_rx_stream *srx, void *kva, int len)
 {
        int rv;
 
-       siw_dbg_qp(rx_qp(srx), "kva: 0x%p, len: %u\n", kva, len);
+       siw_dbg_qp(rx_qp(srx), "kva: 0x%pK, len: %u\n", kva, len);
 
        rv = skb_copy_bits(srx->skb, srx->skb_offset, kva, len);
        if (unlikely(rv)) {
-               pr_warn("siw: [QP %u]: %s, len %d, kva 0x%p, rv %d\n",
+               pr_warn("siw: [QP %u]: %s, len %d, kva 0x%pK, rv %d\n",
                        qp_id(rx_qp(srx)), __func__, len, kva, rv);
 
                return rv;
@@ -132,7 +133,7 @@ static int siw_rx_pbl(struct siw_rx_stream *srx, int *pbl_idx,
 
        while (len) {
                int bytes;
-               u64 buf_addr =
+               dma_addr_t buf_addr =
                        siw_pbl_get_buffer(pbl, offset, &bytes, pbl_idx);
                if (!buf_addr)
                        break;
@@ -485,8 +486,8 @@ int siw_proc_send(struct siw_qp *qp)
                mem_p = *mem;
                if (mem_p->mem_obj == NULL)
                        rv = siw_rx_kva(srx,
-                                       (void *)(sge->laddr + frx->sge_off),
-                                       sge_bytes);
+                               (void *)(uintptr_t)(sge->laddr + frx->sge_off),
+                               sge_bytes);
                else if (!mem_p->is_pbl)
                        rv = siw_rx_umem(srx, mem_p->umem,
                                         sge->laddr + frx->sge_off, sge_bytes);
@@ -598,8 +599,8 @@ int siw_proc_write(struct siw_qp *qp)
 
        if (mem->mem_obj == NULL)
                rv = siw_rx_kva(srx,
-                               (void *)(srx->ddp_to + srx->fpdu_part_rcvd),
-                               bytes);
+                       (void *)(uintptr_t)(srx->ddp_to + srx->fpdu_part_rcvd),
+                       bytes);
        else if (!mem->is_pbl)
                rv = siw_rx_umem(srx, mem->umem,
                                 srx->ddp_to + srx->fpdu_part_rcvd, bytes);
@@ -841,8 +842,9 @@ int siw_proc_rresp(struct siw_qp *qp)
        bytes = min(srx->fpdu_part_rem, srx->skb_new);
 
        if (mem_p->mem_obj == NULL)
-               rv = siw_rx_kva(srx, (void *)(sge->laddr + wqe->processed),
-                               bytes);
+               rv = siw_rx_kva(srx,
+                       (void *)(uintptr_t)(sge->laddr + wqe->processed),
+                       bytes);
        else if (!mem_p->is_pbl)
                rv = siw_rx_umem(srx, mem_p->umem, sge->laddr + wqe->processed,
                                 bytes);
index 43020d2..438a291 100644 (file)
@@ -26,7 +26,7 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx)
 {
        struct siw_pbl *pbl = mem->pbl;
        u64 offset = addr - mem->va;
-       u64 paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx);
+       dma_addr_t paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx);
 
        if (paddr)
                return virt_to_page(paddr);
@@ -37,7 +37,7 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx)
 /*
  * Copy short payload at provided destination payload address
  */
-static int siw_try_1seg(struct siw_iwarp_tx *c_tx, u64 paddr)
+static int siw_try_1seg(struct siw_iwarp_tx *c_tx, void *paddr)
 {
        struct siw_wqe *wqe = &c_tx->wqe_active;
        struct siw_sge *sge = &wqe->sqe.sge[0];
@@ -50,16 +50,16 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, u64 paddr)
                return 0;
 
        if (tx_flags(wqe) & SIW_WQE_INLINE) {
-               memcpy((void *)paddr, &wqe->sqe.sge[1], bytes);
+               memcpy(paddr, &wqe->sqe.sge[1], bytes);
        } else {
                struct siw_mem *mem = wqe->mem[0];
 
                if (!mem->mem_obj) {
                        /* Kernel client using kva */
-                       memcpy((void *)paddr, (void *)sge->laddr, bytes);
+                       memcpy(paddr,
+                              (const void *)(uintptr_t)sge->laddr, bytes);
                } else if (c_tx->in_syscall) {
-                       if (copy_from_user((void *)paddr,
-                                          (const void __user *)sge->laddr,
+                       if (copy_from_user(paddr, u64_to_user_ptr(sge->laddr),
                                           bytes))
                                return -EFAULT;
                } else {
@@ -79,12 +79,12 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, u64 paddr)
                        buffer = kmap_atomic(p);
 
                        if (likely(PAGE_SIZE - off >= bytes)) {
-                               memcpy((void *)paddr, buffer + off, bytes);
+                               memcpy(paddr, buffer + off, bytes);
                                kunmap_atomic(buffer);
                        } else {
                                unsigned long part = bytes - (PAGE_SIZE - off);
 
-                               memcpy((void *)paddr, buffer + off, part);
+                               memcpy(paddr, buffer + off, part);
                                kunmap_atomic(buffer);
 
                                if (!mem->is_pbl)
@@ -98,7 +98,7 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, u64 paddr)
                                        return -EFAULT;
 
                                buffer = kmap_atomic(p);
-                               memcpy((void *)(paddr + part), buffer,
+                               memcpy(paddr + part, buffer,
                                       bytes - part);
                                kunmap_atomic(buffer);
                        }
@@ -166,7 +166,7 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
                c_tx->ctrl_len = sizeof(struct iwarp_send);
 
                crc = (char *)&c_tx->pkt.send_pkt.crc;
-               data = siw_try_1seg(c_tx, (u64)crc);
+               data = siw_try_1seg(c_tx, crc);
                break;
 
        case SIW_OP_SEND_REMOTE_INV:
@@ -189,7 +189,7 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
                c_tx->ctrl_len = sizeof(struct iwarp_send_inv);
 
                crc = (char *)&c_tx->pkt.send_pkt.crc;
-               data = siw_try_1seg(c_tx, (u64)crc);
+               data = siw_try_1seg(c_tx, crc);
                break;
 
        case SIW_OP_WRITE:
@@ -201,7 +201,7 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
                c_tx->ctrl_len = sizeof(struct iwarp_rdma_write);
 
                crc = (char *)&c_tx->pkt.write_pkt.crc;
-               data = siw_try_1seg(c_tx, (u64)crc);
+               data = siw_try_1seg(c_tx, crc);
                break;
 
        case SIW_OP_READ_RESPONSE:
@@ -216,7 +216,7 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
                c_tx->ctrl_len = sizeof(struct iwarp_rdma_rresp);
 
                crc = (char *)&c_tx->pkt.write_pkt.crc;
-               data = siw_try_1seg(c_tx, (u64)crc);
+               data = siw_try_1seg(c_tx, crc);
                break;
 
        default:
@@ -398,15 +398,13 @@ static int siw_0copy_tx(struct socket *s, struct page **page,
 
 #define MAX_TRAILER (MPA_CRC_SIZE + 4)
 
-static void siw_unmap_pages(struct page **pages, int hdr_len, int num_maps)
+static void siw_unmap_pages(struct page **pp, unsigned long kmap_mask)
 {
-       if (hdr_len) {
-               ++pages;
-               --num_maps;
-       }
-       while (num_maps-- > 0) {
-               kunmap(*pages);
-               pages++;
+       while (kmap_mask) {
+               if (kmap_mask & BIT(0))
+                       kunmap(*pp);
+               pp++;
+               kmap_mask >>= 1;
        }
 }
 
@@ -437,6 +435,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
        unsigned int data_len = c_tx->bytes_unsent, hdr_len = 0, trl_len = 0,
                     sge_off = c_tx->sge_off, sge_idx = c_tx->sge_idx,
                     pbl_idx = c_tx->pbl_idx;
+       unsigned long kmap_mask = 0L;
 
        if (c_tx->state == SIW_SEND_HDR) {
                if (c_tx->use_sendpage) {
@@ -463,8 +462,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
 
                if (!(tx_flags(wqe) & SIW_WQE_INLINE)) {
                        mem = wqe->mem[sge_idx];
-                       if (!mem->mem_obj)
-                               is_kva = 1;
+                       is_kva = mem->mem_obj == NULL ? 1 : 0;
                } else {
                        is_kva = 1;
                }
@@ -473,7 +471,8 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
                         * tx from kernel virtual address: either inline data
                         * or memory region with assigned kernel buffer
                         */
-                       iov[seg].iov_base = (void *)(sge->laddr + sge_off);
+                       iov[seg].iov_base =
+                               (void *)(uintptr_t)(sge->laddr + sge_off);
                        iov[seg].iov_len = sge_len;
 
                        if (do_crc)
@@ -500,12 +499,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
                                        p = siw_get_upage(mem->umem,
                                                          sge->laddr + sge_off);
                                if (unlikely(!p)) {
-                                       if (hdr_len)
-                                               seg--;
-                                       if (!c_tx->use_sendpage && seg) {
-                                               siw_unmap_pages(page_array,
-                                                               hdr_len, seg);
-                                       }
+                                       siw_unmap_pages(page_array, kmap_mask);
                                        wqe->processed -= c_tx->bytes_unsent;
                                        rv = -EFAULT;
                                        goto done_crc;
@@ -515,6 +509,10 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
                                if (!c_tx->use_sendpage) {
                                        iov[seg].iov_base = kmap(p) + fp_off;
                                        iov[seg].iov_len = plen;
+
+                                       /* Remember for later kunmap() */
+                                       kmap_mask |= BIT(seg);
+
                                        if (do_crc)
                                                crypto_shash_update(
                                                        c_tx->mpa_crc_hd,
@@ -526,13 +524,13 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
                                                page_address(p) + fp_off,
                                                plen);
                        } else {
-                               u64 pa = ((sge->laddr + sge_off) & PAGE_MASK);
+                               u64 va = sge->laddr + sge_off;
 
-                               page_array[seg] = virt_to_page(pa);
+                               page_array[seg] = virt_to_page(va & PAGE_MASK);
                                if (do_crc)
                                        crypto_shash_update(
                                                c_tx->mpa_crc_hd,
-                                               (void *)(sge->laddr + sge_off),
+                                               (void *)(uintptr_t)va,
                                                plen);
                        }
 
@@ -543,10 +541,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
 
                        if (++seg > (int)MAX_ARRAY) {
                                siw_dbg_qp(tx_qp(c_tx), "to many fragments\n");
-                               if (!is_kva && !c_tx->use_sendpage) {
-                                       siw_unmap_pages(page_array, hdr_len,
-                                                       seg - 1);
-                               }
+                               siw_unmap_pages(page_array, kmap_mask);
                                wqe->processed -= c_tx->bytes_unsent;
                                rv = -EMSGSIZE;
                                goto done_crc;
@@ -597,8 +592,7 @@ sge_done:
        } else {
                rv = kernel_sendmsg(s, &msg, iov, seg + 1,
                                    hdr_len + data_len + trl_len);
-               if (!is_kva)
-                       siw_unmap_pages(page_array, hdr_len, seg);
+               siw_unmap_pages(page_array, kmap_mask);
        }
        if (rv < (int)hdr_len) {
                /* Not even complete hdr pushed or negative rv */
@@ -829,7 +823,8 @@ static int siw_qp_sq_proc_tx(struct siw_qp *qp, struct siw_wqe *wqe)
                                        rv = -EINVAL;
                                        goto tx_error;
                                }
-                               wqe->sqe.sge[0].laddr = (u64)&wqe->sqe.sge[1];
+                               wqe->sqe.sge[0].laddr =
+                                       (u64)(uintptr_t)&wqe->sqe.sge[1];
                        }
                }
                wqe->wr_status = SIW_WR_INPROGRESS;
@@ -924,7 +919,7 @@ tx_error:
 
 static int siw_fastreg_mr(struct ib_pd *pd, struct siw_sqe *sqe)
 {
-       struct ib_mr *base_mr = (struct ib_mr *)sqe->base_mr;
+       struct ib_mr *base_mr = (struct ib_mr *)(uintptr_t)sqe->base_mr;
        struct siw_device *sdev = to_siw_dev(pd->device);
        struct siw_mem *mem = siw_mem_id2obj(sdev, sqe->rkey  >> 8);
        int rv = 0;
@@ -954,8 +949,7 @@ static int siw_fastreg_mr(struct ib_pd *pd, struct siw_sqe *sqe)
        mem->stag = sqe->rkey;
        mem->perms = sqe->access;
 
-       siw_dbg_mem(mem, "STag now valid, MR va: 0x%016llx -> 0x%016llx\n",
-                   mem->va, base_mr->iova);
+       siw_dbg_mem(mem, "STag 0x%08x now valid\n", sqe->rkey);
        mem->va = base_mr->iova;
        mem->stag_valid = 1;
 out:
index e7f3a23..da52c90 100644 (file)
@@ -424,8 +424,7 @@ struct ib_qp *siw_create_qp(struct ib_pd *pd,
                 */
                qp->srq = to_siw_srq(attrs->srq);
                qp->attrs.rq_size = 0;
-               siw_dbg(base_dev, "QP [%u]: [SRQ 0x%p] attached\n",
-                       qp->qp_num, qp->srq);
+               siw_dbg(base_dev, "QP [%u]: SRQ attached\n", qp->qp_num);
        } else if (num_rqe) {
                if (qp->kernel_verbs)
                        qp->recvq = vzalloc(num_rqe * sizeof(struct siw_rqe));
@@ -610,7 +609,7 @@ int siw_destroy_qp(struct ib_qp *base_qp, struct ib_udata *udata)
                                          base_ucontext);
        struct siw_qp_attrs qp_attrs;
 
-       siw_dbg_qp(qp, "state %d, cep 0x%p\n", qp->attrs.state, qp->cep);
+       siw_dbg_qp(qp, "state %d\n", qp->attrs.state);
 
        /*
         * Mark QP as in process of destruction to prevent from
@@ -662,7 +661,7 @@ static int siw_copy_inline_sgl(const struct ib_send_wr *core_wr,
        void *kbuf = &sqe->sge[1];
        int num_sge = core_wr->num_sge, bytes = 0;
 
-       sqe->sge[0].laddr = (u64)kbuf;
+       sqe->sge[0].laddr = (uintptr_t)kbuf;
        sqe->sge[0].lkey = 0;
 
        while (num_sge--) {
@@ -825,7 +824,7 @@ int siw_post_send(struct ib_qp *base_qp, const struct ib_send_wr *wr,
                        break;
 
                case IB_WR_REG_MR:
-                       sqe->base_mr = (uint64_t)reg_wr(wr)->mr;
+                       sqe->base_mr = (uintptr_t)reg_wr(wr)->mr;
                        sqe->rkey = reg_wr(wr)->key;
                        sqe->access = reg_wr(wr)->access & IWARP_ACCESS_MASK;
                        sqe->opcode = SIW_OP_REG_MR;
@@ -842,8 +841,9 @@ int siw_post_send(struct ib_qp *base_qp, const struct ib_send_wr *wr,
                        rv = -EINVAL;
                        break;
                }
-               siw_dbg_qp(qp, "opcode %d, flags 0x%x, wr_id 0x%p\n",
-                          sqe->opcode, sqe->flags, (void *)sqe->id);
+               siw_dbg_qp(qp, "opcode %d, flags 0x%x, wr_id 0x%pK\n",
+                          sqe->opcode, sqe->flags,
+                          (void *)(uintptr_t)sqe->id);
 
                if (unlikely(rv < 0))
                        break;
@@ -1205,8 +1205,8 @@ struct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
        unsigned long mem_limit = rlimit(RLIMIT_MEMLOCK);
        int rv;
 
-       siw_dbg_pd(pd, "start: 0x%016llx, va: 0x%016llx, len: %llu\n",
-                  (unsigned long long)start, (unsigned long long)rnic_va,
+       siw_dbg_pd(pd, "start: 0x%pK, va: 0x%pK, len: %llu\n",
+                  (void *)(uintptr_t)start, (void *)(uintptr_t)rnic_va,
                   (unsigned long long)len);
 
        if (atomic_inc_return(&sdev->num_mr) > SIW_MAX_MR) {
@@ -1363,7 +1363,7 @@ int siw_map_mr_sg(struct ib_mr *base_mr, struct scatterlist *sl, int num_sle,
        struct siw_mem *mem = mr->mem;
        struct siw_pbl *pbl = mem->pbl;
        struct siw_pble *pble;
-       u64 pbl_size;
+       unsigned long pbl_size;
        int i, rv;
 
        if (!pbl) {
@@ -1402,16 +1402,18 @@ int siw_map_mr_sg(struct ib_mr *base_mr, struct scatterlist *sl, int num_sle,
                        pbl_size += sg_dma_len(slp);
                }
                siw_dbg_mem(mem,
-                       "sge[%d], size %llu, addr 0x%016llx, total %llu\n",
-                       i, pble->size, pble->addr, pbl_size);
+                       "sge[%d], size %u, addr 0x%p, total %lu\n",
+                       i, pble->size, (void *)(uintptr_t)pble->addr,
+                       pbl_size);
        }
        rv = ib_sg_to_pages(base_mr, sl, num_sle, sg_off, siw_set_pbl_page);
        if (rv > 0) {
                mem->len = base_mr->length;
                mem->va = base_mr->iova;
                siw_dbg_mem(mem,
-                       "%llu bytes, start 0x%016llx, %u SLE to %u entries\n",
-                       mem->len, mem->va, num_sle, pbl->num_buf);
+                       "%llu bytes, start 0x%pK, %u SLE to %u entries\n",
+                       mem->len, (void *)(uintptr_t)mem->va, num_sle,
+                       pbl->num_buf);
        }
        return rv;
 }
@@ -1529,7 +1531,7 @@ int siw_create_srq(struct ib_srq *base_srq,
        }
        spin_lock_init(&srq->lock);
 
-       siw_dbg_pd(base_srq->pd, "[SRQ 0x%p]: success\n", srq);
+       siw_dbg_pd(base_srq->pd, "[SRQ]: success\n");
 
        return 0;
 
@@ -1650,8 +1652,7 @@ int siw_post_srq_recv(struct ib_srq *base_srq, const struct ib_recv_wr *wr,
 
        if (unlikely(!srq->kernel_verbs)) {
                siw_dbg_pd(base_srq->pd,
-                          "[SRQ 0x%p]: no kernel post_recv for mapped srq\n",
-                          srq);
+                          "[SRQ]: no kernel post_recv for mapped srq\n");
                rv = -EINVAL;
                goto out;
        }
@@ -1673,8 +1674,7 @@ int siw_post_srq_recv(struct ib_srq *base_srq, const struct ib_recv_wr *wr,
                }
                if (unlikely(wr->num_sge > srq->max_sge)) {
                        siw_dbg_pd(base_srq->pd,
-                                  "[SRQ 0x%p]: too many sge's: %d\n", srq,
-                                  wr->num_sge);
+                                  "[SRQ]: too many sge's: %d\n", wr->num_sge);
                        rv = -EINVAL;
                        break;
                }
@@ -1693,7 +1693,7 @@ int siw_post_srq_recv(struct ib_srq *base_srq, const struct ib_recv_wr *wr,
        spin_unlock_irqrestore(&srq->lock, flags);
 out:
        if (unlikely(rv < 0)) {
-               siw_dbg_pd(base_srq->pd, "[SRQ 0x%p]: error %d\n", srq, rv);
+               siw_dbg_pd(base_srq->pd, "[SRQ]: error %d\n", rv);
                *bad_wr = wr;
        }
        return rv;
index 88ae7c2..e486a8a 100644 (file)
@@ -237,40 +237,17 @@ static void hv_kbd_handle_received_packet(struct hv_device *hv_dev,
 
 static void hv_kbd_on_channel_callback(void *context)
 {
+       struct vmpacket_descriptor *desc;
        struct hv_device *hv_dev = context;
-       void *buffer;
-       int bufferlen = 0x100; /* Start with sensible size */
        u32 bytes_recvd;
        u64 req_id;
-       int error;
 
-       buffer = kmalloc(bufferlen, GFP_ATOMIC);
-       if (!buffer)
-               return;
-
-       while (1) {
-               error = vmbus_recvpacket_raw(hv_dev->channel, buffer, bufferlen,
-                                            &bytes_recvd, &req_id);
-               switch (error) {
-               case 0:
-                       if (bytes_recvd == 0) {
-                               kfree(buffer);
-                               return;
-                       }
-
-                       hv_kbd_handle_received_packet(hv_dev, buffer,
-                                                     bytes_recvd, req_id);
-                       break;
+       foreach_vmbus_pkt(desc, hv_dev->channel) {
+               bytes_recvd = desc->len8 * 8;
+               req_id = desc->trans_id;
 
-               case -ENOBUFS:
-                       kfree(buffer);
-                       /* Handle large packet */
-                       bufferlen = bytes_recvd;
-                       buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
-                       if (!buffer)
-                               return;
-                       break;
-               }
+               hv_kbd_handle_received_packet(hv_dev, desc, bytes_recvd,
+                                             req_id);
        }
 }
 
index d991d40..f68a62c 100644 (file)
@@ -965,10 +965,13 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size,
 {
        bool coherent = dev_is_dma_coherent(dev);
        size_t alloc_size = PAGE_ALIGN(size);
+       int node = dev_to_node(dev);
        struct page *page = NULL;
        void *cpu_addr;
 
        page = dma_alloc_contiguous(dev, alloc_size, gfp);
+       if (!page)
+               page = alloc_pages_node(node, gfp, get_order(alloc_size));
        if (!page)
                return NULL;
 
index b6b5acc..2a48ea3 100644 (file)
@@ -1599,7 +1599,9 @@ dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
        unsigned long freed;
 
        c = container_of(shrink, struct dm_bufio_client, shrinker);
-       if (!dm_bufio_trylock(c))
+       if (sc->gfp_mask & __GFP_FS)
+               dm_bufio_lock(c);
+       else if (!dm_bufio_trylock(c))
                return SHRINK_STOP;
 
        freed  = __scan(c, sc->nr_to_scan, sc->gfp_mask);
index 845f376..8288887 100644 (file)
@@ -25,6 +25,7 @@ struct dust_device {
        unsigned long long badblock_count;
        spinlock_t dust_lock;
        unsigned int blksz;
+       int sect_per_block_shift;
        unsigned int sect_per_block;
        sector_t start;
        bool fail_read_on_bb:1;
@@ -79,7 +80,7 @@ static int dust_remove_block(struct dust_device *dd, unsigned long long block)
        unsigned long flags;
 
        spin_lock_irqsave(&dd->dust_lock, flags);
-       bblock = dust_rb_search(&dd->badblocklist, block * dd->sect_per_block);
+       bblock = dust_rb_search(&dd->badblocklist, block);
 
        if (bblock == NULL) {
                if (!dd->quiet_mode) {
@@ -113,7 +114,7 @@ static int dust_add_block(struct dust_device *dd, unsigned long long block)
        }
 
        spin_lock_irqsave(&dd->dust_lock, flags);
-       bblock->bb = block * dd->sect_per_block;
+       bblock->bb = block;
        if (!dust_rb_insert(&dd->badblocklist, bblock)) {
                if (!dd->quiet_mode) {
                        DMERR("%s: block %llu already in badblocklist",
@@ -138,7 +139,7 @@ static int dust_query_block(struct dust_device *dd, unsigned long long block)
        unsigned long flags;
 
        spin_lock_irqsave(&dd->dust_lock, flags);
-       bblock = dust_rb_search(&dd->badblocklist, block * dd->sect_per_block);
+       bblock = dust_rb_search(&dd->badblocklist, block);
        if (bblock != NULL)
                DMINFO("%s: block %llu found in badblocklist", __func__, block);
        else
@@ -165,6 +166,7 @@ static int dust_map_read(struct dust_device *dd, sector_t thisblock,
        int ret = DM_MAPIO_REMAPPED;
 
        if (fail_read_on_bb) {
+               thisblock >>= dd->sect_per_block_shift;
                spin_lock_irqsave(&dd->dust_lock, flags);
                ret = __dust_map_read(dd, thisblock);
                spin_unlock_irqrestore(&dd->dust_lock, flags);
@@ -195,6 +197,7 @@ static int dust_map_write(struct dust_device *dd, sector_t thisblock,
        unsigned long flags;
 
        if (fail_read_on_bb) {
+               thisblock >>= dd->sect_per_block_shift;
                spin_lock_irqsave(&dd->dust_lock, flags);
                __dust_map_write(dd, thisblock);
                spin_unlock_irqrestore(&dd->dust_lock, flags);
@@ -331,6 +334,8 @@ static int dust_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        dd->blksz = blksz;
        dd->start = tmp;
 
+       dd->sect_per_block_shift = __ffs(sect_per_block);
+
        /*
         * Whether to fail a read on a "bad" block.
         * Defaults to false; enabled later by message.
index b1b0de4..9118ab8 100644 (file)
@@ -1943,7 +1943,22 @@ offload_to_thread:
                        queue_work(ic->wait_wq, &dio->work);
                        return;
                }
+               if (journal_read_pos != NOT_FOUND)
+                       dio->range.n_sectors = ic->sectors_per_block;
                wait_and_add_new_range(ic, &dio->range);
+               /*
+                * wait_and_add_new_range drops the spinlock, so the journal
+                * may have been changed arbitrarily. We need to recheck.
+                * To simplify the code, we restrict I/O size to just one block.
+                */
+               if (journal_read_pos != NOT_FOUND) {
+                       sector_t next_sector;
+                       unsigned new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
+                       if (unlikely(new_pos != journal_read_pos)) {
+                               remove_range_unlocked(ic, &dio->range);
+                               goto retry;
+                       }
+               }
        }
        spin_unlock_irq(&ic->endio_wait.lock);
 
index df2011d..1bbe4a3 100644 (file)
@@ -566,8 +566,10 @@ static int run_io_job(struct kcopyd_job *job)
         * no point in continuing.
         */
        if (test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags) &&
-           job->master_job->write_err)
+           job->master_job->write_err) {
+               job->write_err = job->master_job->write_err;
                return -EIO;
+       }
 
        io_job_start(job->kc->throttle);
 
@@ -619,6 +621,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
                        else
                                job->read_err = 1;
                        push(&kc->complete_jobs, job);
+                       wake(kc);
                        break;
                }
 
index 8a60a4a..1f933dd 100644 (file)
@@ -3194,7 +3194,7 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                          */
                        r = rs_prepare_reshape(rs);
                        if (r)
-                               return r;
+                               goto bad;
 
                        /* Reshaping ain't recovery, so disable recovery */
                        rs_setup_recovery(rs, MaxSector);
index 7b6c3ee..8820931 100644 (file)
@@ -1342,7 +1342,7 @@ void dm_table_event(struct dm_table *t)
 }
 EXPORT_SYMBOL(dm_table_event);
 
-sector_t dm_table_get_size(struct dm_table *t)
+inline sector_t dm_table_get_size(struct dm_table *t)
 {
        return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0;
 }
@@ -1367,6 +1367,9 @@ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector)
        unsigned int l, n = 0, k = 0;
        sector_t *node;
 
+       if (unlikely(sector >= dm_table_get_size(t)))
+               return &t->targets[t->num_targets];
+
        for (l = 0; l < t->depth; l++) {
                n = get_child(n, k);
                node = get_node(t, l, n);
index 8545dce..595a731 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2017 Western Digital Corporation or its affiliates.
  *
@@ -34,7 +35,7 @@
  *    (1) Super block (1 block)
  *    (2) Chunk mapping table (nr_map_blocks)
  *    (3) Bitmap blocks (nr_bitmap_blocks)
- * All metadata blocks are stored in conventional zones, starting from the
+ * All metadata blocks are stored in conventional zones, starting from
  * the first conventional zone found on disk.
  */
 struct dmz_super {
@@ -233,7 +234,7 @@ void dmz_unlock_map(struct dmz_metadata *zmd)
  * Lock/unlock metadata access. This is a "read" lock on a semaphore
  * that prevents metadata flush from running while metadata are being
  * modified. The actual metadata write mutual exclusion is achieved with
- * the map lock and zone styate management (active and reclaim state are
+ * the map lock and zone state management (active and reclaim state are
  * mutually exclusive).
  */
 void dmz_lock_metadata(struct dmz_metadata *zmd)
@@ -402,15 +403,18 @@ static struct dmz_mblock *dmz_get_mblock_slow(struct dmz_metadata *zmd,
        sector_t block = zmd->sb[zmd->mblk_primary].block + mblk_no;
        struct bio *bio;
 
+       if (dmz_bdev_is_dying(zmd->dev))
+               return ERR_PTR(-EIO);
+
        /* Get a new block and a BIO to read it */
        mblk = dmz_alloc_mblock(zmd, mblk_no);
        if (!mblk)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        bio = bio_alloc(GFP_NOIO, 1);
        if (!bio) {
                dmz_free_mblock(zmd, mblk);
-               return NULL;
+               return ERR_PTR(-ENOMEM);
        }
 
        spin_lock(&zmd->mblk_lock);
@@ -541,8 +545,8 @@ static struct dmz_mblock *dmz_get_mblock(struct dmz_metadata *zmd,
        if (!mblk) {
                /* Cache miss: read the block from disk */
                mblk = dmz_get_mblock_slow(zmd, mblk_no);
-               if (!mblk)
-                       return ERR_PTR(-ENOMEM);
+               if (IS_ERR(mblk))
+                       return mblk;
        }
 
        /* Wait for on-going read I/O and check for error */
@@ -570,16 +574,19 @@ static void dmz_dirty_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk)
 /*
  * Issue a metadata block write BIO.
  */
-static void dmz_write_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk,
-                            unsigned int set)
+static int dmz_write_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk,
+                           unsigned int set)
 {
        sector_t block = zmd->sb[set].block + mblk->no;
        struct bio *bio;
 
+       if (dmz_bdev_is_dying(zmd->dev))
+               return -EIO;
+
        bio = bio_alloc(GFP_NOIO, 1);
        if (!bio) {
                set_bit(DMZ_META_ERROR, &mblk->state);
-               return;
+               return -ENOMEM;
        }
 
        set_bit(DMZ_META_WRITING, &mblk->state);
@@ -591,6 +598,8 @@ static void dmz_write_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk,
        bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_META | REQ_PRIO);
        bio_add_page(bio, mblk->page, DMZ_BLOCK_SIZE, 0);
        submit_bio(bio);
+
+       return 0;
 }
 
 /*
@@ -602,6 +611,9 @@ static int dmz_rdwr_block(struct dmz_metadata *zmd, int op, sector_t block,
        struct bio *bio;
        int ret;
 
+       if (dmz_bdev_is_dying(zmd->dev))
+               return -EIO;
+
        bio = bio_alloc(GFP_NOIO, 1);
        if (!bio)
                return -ENOMEM;
@@ -659,22 +671,29 @@ static int dmz_write_dirty_mblocks(struct dmz_metadata *zmd,
 {
        struct dmz_mblock *mblk;
        struct blk_plug plug;
-       int ret = 0;
+       int ret = 0, nr_mblks_submitted = 0;
 
        /* Issue writes */
        blk_start_plug(&plug);
-       list_for_each_entry(mblk, write_list, link)
-               dmz_write_mblock(zmd, mblk, set);
+       list_for_each_entry(mblk, write_list, link) {
+               ret = dmz_write_mblock(zmd, mblk, set);
+               if (ret)
+                       break;
+               nr_mblks_submitted++;
+       }
        blk_finish_plug(&plug);
 
        /* Wait for completion */
        list_for_each_entry(mblk, write_list, link) {
+               if (!nr_mblks_submitted)
+                       break;
                wait_on_bit_io(&mblk->state, DMZ_META_WRITING,
                               TASK_UNINTERRUPTIBLE);
                if (test_bit(DMZ_META_ERROR, &mblk->state)) {
                        clear_bit(DMZ_META_ERROR, &mblk->state);
                        ret = -EIO;
                }
+               nr_mblks_submitted--;
        }
 
        /* Flush drive cache (this will also sync data) */
@@ -736,6 +755,11 @@ int dmz_flush_metadata(struct dmz_metadata *zmd)
         */
        dmz_lock_flush(zmd);
 
+       if (dmz_bdev_is_dying(zmd->dev)) {
+               ret = -EIO;
+               goto out;
+       }
+
        /* Get dirty blocks */
        spin_lock(&zmd->mblk_lock);
        list_splice_init(&zmd->mblk_dirty_list, &write_list);
@@ -1542,7 +1566,7 @@ static struct dm_zone *dmz_get_rnd_zone_for_reclaim(struct dmz_metadata *zmd)
        struct dm_zone *zone;
 
        if (list_empty(&zmd->map_rnd_list))
-               return NULL;
+               return ERR_PTR(-EBUSY);
 
        list_for_each_entry(zone, &zmd->map_rnd_list, link) {
                if (dmz_is_buf(zone))
@@ -1553,7 +1577,7 @@ static struct dm_zone *dmz_get_rnd_zone_for_reclaim(struct dmz_metadata *zmd)
                        return dzone;
        }
 
-       return NULL;
+       return ERR_PTR(-EBUSY);
 }
 
 /*
@@ -1564,7 +1588,7 @@ static struct dm_zone *dmz_get_seq_zone_for_reclaim(struct dmz_metadata *zmd)
        struct dm_zone *zone;
 
        if (list_empty(&zmd->map_seq_list))
-               return NULL;
+               return ERR_PTR(-EBUSY);
 
        list_for_each_entry(zone, &zmd->map_seq_list, link) {
                if (!zone->bzone)
@@ -1573,7 +1597,7 @@ static struct dm_zone *dmz_get_seq_zone_for_reclaim(struct dmz_metadata *zmd)
                        return zone;
        }
 
-       return NULL;
+       return ERR_PTR(-EBUSY);
 }
 
 /*
@@ -1628,9 +1652,13 @@ again:
                if (op != REQ_OP_WRITE)
                        goto out;
 
-               /* Alloate a random zone */
+               /* Allocate a random zone */
                dzone = dmz_alloc_zone(zmd, DMZ_ALLOC_RND);
                if (!dzone) {
+                       if (dmz_bdev_is_dying(zmd->dev)) {
+                               dzone = ERR_PTR(-EIO);
+                               goto out;
+                       }
                        dmz_wait_for_free_zones(zmd);
                        goto again;
                }
@@ -1725,9 +1753,13 @@ again:
        if (bzone)
                goto out;
 
-       /* Alloate a random zone */
+       /* Allocate a random zone */
        bzone = dmz_alloc_zone(zmd, DMZ_ALLOC_RND);
        if (!bzone) {
+               if (dmz_bdev_is_dying(zmd->dev)) {
+                       bzone = ERR_PTR(-EIO);
+                       goto out;
+               }
                dmz_wait_for_free_zones(zmd);
                goto again;
        }
index edf4b95..d240d7c 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2017 Western Digital Corporation or its affiliates.
  *
@@ -37,7 +38,7 @@ enum {
 /*
  * Number of seconds of target BIO inactivity to consider the target idle.
  */
-#define DMZ_IDLE_PERIOD                (10UL * HZ)
+#define DMZ_IDLE_PERIOD                        (10UL * HZ)
 
 /*
  * Percentage of unmapped (free) random zones below which reclaim starts
@@ -134,6 +135,9 @@ static int dmz_reclaim_copy(struct dmz_reclaim *zrc,
                set_bit(DM_KCOPYD_WRITE_SEQ, &flags);
 
        while (block < end_block) {
+               if (dev->flags & DMZ_BDEV_DYING)
+                       return -EIO;
+
                /* Get a valid region from the source zone */
                ret = dmz_first_valid_block(zmd, src_zone, &block);
                if (ret <= 0)
@@ -215,7 +219,7 @@ static int dmz_reclaim_buf(struct dmz_reclaim *zrc, struct dm_zone *dzone)
 
        dmz_unlock_flush(zmd);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -259,7 +263,7 @@ static int dmz_reclaim_seq_data(struct dmz_reclaim *zrc, struct dm_zone *dzone)
 
        dmz_unlock_flush(zmd);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -312,7 +316,7 @@ static int dmz_reclaim_rnd_data(struct dmz_reclaim *zrc, struct dm_zone *dzone)
 
        dmz_unlock_flush(zmd);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -334,7 +338,7 @@ static void dmz_reclaim_empty(struct dmz_reclaim *zrc, struct dm_zone *dzone)
 /*
  * Find a candidate zone for reclaim and process it.
  */
-static void dmz_reclaim(struct dmz_reclaim *zrc)
+static int dmz_do_reclaim(struct dmz_reclaim *zrc)
 {
        struct dmz_metadata *zmd = zrc->metadata;
        struct dm_zone *dzone;
@@ -344,8 +348,8 @@ static void dmz_reclaim(struct dmz_reclaim *zrc)
 
        /* Get a data zone */
        dzone = dmz_get_zone_for_reclaim(zmd);
-       if (!dzone)
-               return;
+       if (IS_ERR(dzone))
+               return PTR_ERR(dzone);
 
        start = jiffies;
 
@@ -391,13 +395,20 @@ static void dmz_reclaim(struct dmz_reclaim *zrc)
 out:
        if (ret) {
                dmz_unlock_zone_reclaim(dzone);
-               return;
+               return ret;
        }
 
-       (void) dmz_flush_metadata(zrc->metadata);
+       ret = dmz_flush_metadata(zrc->metadata);
+       if (ret) {
+               dmz_dev_debug(zrc->dev,
+                             "Metadata flush for zone %u failed, err %d\n",
+                             dmz_id(zmd, rzone), ret);
+               return ret;
+       }
 
        dmz_dev_debug(zrc->dev, "Reclaimed zone %u in %u ms",
                      dmz_id(zmd, rzone), jiffies_to_msecs(jiffies - start));
+       return 0;
 }
 
 /*
@@ -427,7 +438,7 @@ static bool dmz_should_reclaim(struct dmz_reclaim *zrc)
                return false;
 
        /*
-        * If the percentage of unmappped random zones is low,
+        * If the percentage of unmapped random zones is low,
         * reclaim even if the target is busy.
         */
        return p_unmap_rnd <= DMZ_RECLAIM_LOW_UNMAP_RND;
@@ -442,6 +453,10 @@ static void dmz_reclaim_work(struct work_struct *work)
        struct dmz_metadata *zmd = zrc->metadata;
        unsigned int nr_rnd, nr_unmap_rnd;
        unsigned int p_unmap_rnd;
+       int ret;
+
+       if (dmz_bdev_is_dying(zrc->dev))
+               return;
 
        if (!dmz_should_reclaim(zrc)) {
                mod_delayed_work(zrc->wq, &zrc->work, DMZ_IDLE_PERIOD);
@@ -471,7 +486,17 @@ static void dmz_reclaim_work(struct work_struct *work)
                      (dmz_target_idle(zrc) ? "Idle" : "Busy"),
                      p_unmap_rnd, nr_unmap_rnd, nr_rnd);
 
-       dmz_reclaim(zrc);
+       ret = dmz_do_reclaim(zrc);
+       if (ret) {
+               dmz_dev_debug(zrc->dev, "Reclaim error %d\n", ret);
+               if (ret == -EIO)
+                       /*
+                        * LLD might be performing some error handling sequence
+                        * at the underlying device. To not interfere, do not
+                        * attempt to schedule the next reclaim run immediately.
+                        */
+                       return;
+       }
 
        dmz_schedule_reclaim(zrc);
 }
index 51d029b..31478fe 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2017 Western Digital Corporation or its affiliates.
  *
@@ -133,6 +134,8 @@ static int dmz_submit_bio(struct dmz_target *dmz, struct dm_zone *zone,
 
        refcount_inc(&bioctx->ref);
        generic_make_request(clone);
+       if (clone->bi_status == BLK_STS_IOERR)
+               return -EIO;
 
        if (bio_op(bio) == REQ_OP_WRITE && dmz_is_seq(zone))
                zone->wp_block += nr_blocks;
@@ -277,8 +280,8 @@ static int dmz_handle_buffered_write(struct dmz_target *dmz,
 
        /* Get the buffer zone. One will be allocated if needed */
        bzone = dmz_get_chunk_buffer(zmd, zone);
-       if (!bzone)
-               return -ENOSPC;
+       if (IS_ERR(bzone))
+               return PTR_ERR(bzone);
 
        if (dmz_is_readonly(bzone))
                return -EROFS;
@@ -389,6 +392,11 @@ static void dmz_handle_bio(struct dmz_target *dmz, struct dm_chunk_work *cw,
 
        dmz_lock_metadata(zmd);
 
+       if (dmz->dev->flags & DMZ_BDEV_DYING) {
+               ret = -EIO;
+               goto out;
+       }
+
        /*
         * Get the data zone mapping the chunk. There may be no
         * mapping for read and discard. If a mapping is obtained,
@@ -493,6 +501,8 @@ static void dmz_flush_work(struct work_struct *work)
 
        /* Flush dirty metadata blocks */
        ret = dmz_flush_metadata(dmz->metadata);
+       if (ret)
+               dmz_dev_debug(dmz->dev, "Metadata flush failed, rc=%d\n", ret);
 
        /* Process queued flush requests */
        while (1) {
@@ -513,22 +523,24 @@ static void dmz_flush_work(struct work_struct *work)
  * Get a chunk work and start it to process a new BIO.
  * If the BIO chunk has no work yet, create one.
  */
-static void dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
+static int dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
 {
        unsigned int chunk = dmz_bio_chunk(dmz->dev, bio);
        struct dm_chunk_work *cw;
+       int ret = 0;
 
        mutex_lock(&dmz->chunk_lock);
 
        /* Get the BIO chunk work. If one is not active yet, create one */
        cw = radix_tree_lookup(&dmz->chunk_rxtree, chunk);
        if (!cw) {
-               int ret;
 
                /* Create a new chunk work */
                cw = kmalloc(sizeof(struct dm_chunk_work), GFP_NOIO);
-               if (!cw)
+               if (unlikely(!cw)) {
+                       ret = -ENOMEM;
                        goto out;
+               }
 
                INIT_WORK(&cw->work, dmz_chunk_work);
                refcount_set(&cw->refcount, 0);
@@ -539,7 +551,6 @@ static void dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
                ret = radix_tree_insert(&dmz->chunk_rxtree, chunk, cw);
                if (unlikely(ret)) {
                        kfree(cw);
-                       cw = NULL;
                        goto out;
                }
        }
@@ -547,10 +558,38 @@ static void dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
        bio_list_add(&cw->bio_list, bio);
        dmz_get_chunk_work(cw);
 
+       dmz_reclaim_bio_acc(dmz->reclaim);
        if (queue_work(dmz->chunk_wq, &cw->work))
                dmz_get_chunk_work(cw);
 out:
        mutex_unlock(&dmz->chunk_lock);
+       return ret;
+}
+
+/*
+ * Check the backing device availability. If it's on the way out,
+ * start failing I/O. Reclaim and metadata components also call this
+ * function to cleanly abort operation in the event of such failure.
+ */
+bool dmz_bdev_is_dying(struct dmz_dev *dmz_dev)
+{
+       struct gendisk *disk;
+
+       if (!(dmz_dev->flags & DMZ_BDEV_DYING)) {
+               disk = dmz_dev->bdev->bd_disk;
+               if (blk_queue_dying(bdev_get_queue(dmz_dev->bdev))) {
+                       dmz_dev_warn(dmz_dev, "Backing device queue dying");
+                       dmz_dev->flags |= DMZ_BDEV_DYING;
+               } else if (disk->fops->check_events) {
+                       if (disk->fops->check_events(disk, 0) &
+                                       DISK_EVENT_MEDIA_CHANGE) {
+                               dmz_dev_warn(dmz_dev, "Backing device offline");
+                               dmz_dev->flags |= DMZ_BDEV_DYING;
+                       }
+               }
+       }
+
+       return dmz_dev->flags & DMZ_BDEV_DYING;
 }
 
 /*
@@ -564,6 +603,10 @@ static int dmz_map(struct dm_target *ti, struct bio *bio)
        sector_t sector = bio->bi_iter.bi_sector;
        unsigned int nr_sectors = bio_sectors(bio);
        sector_t chunk_sector;
+       int ret;
+
+       if (dmz_bdev_is_dying(dmz->dev))
+               return DM_MAPIO_KILL;
 
        dmz_dev_debug(dev, "BIO op %d sector %llu + %u => chunk %llu, block %llu, %u blocks",
                      bio_op(bio), (unsigned long long)sector, nr_sectors,
@@ -601,8 +644,14 @@ static int dmz_map(struct dm_target *ti, struct bio *bio)
                dm_accept_partial_bio(bio, dev->zone_nr_sectors - chunk_sector);
 
        /* Now ready to handle this BIO */
-       dmz_reclaim_bio_acc(dmz->reclaim);
-       dmz_queue_chunk_work(dmz, bio);
+       ret = dmz_queue_chunk_work(dmz, bio);
+       if (ret) {
+               dmz_dev_debug(dmz->dev,
+                             "BIO op %d, can't process chunk %llu, err %i\n",
+                             bio_op(bio), (u64)dmz_bio_chunk(dmz->dev, bio),
+                             ret);
+               return DM_MAPIO_REQUEUE;
+       }
 
        return DM_MAPIO_SUBMITTED;
 }
@@ -855,6 +904,9 @@ static int dmz_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
 {
        struct dmz_target *dmz = ti->private;
 
+       if (dmz_bdev_is_dying(dmz->dev))
+               return -ENODEV;
+
        *bdev = dmz->dev->bdev;
 
        return 0;
index ed8de49..d8e70b0 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2017 Western Digital Corporation or its affiliates.
  *
@@ -56,6 +57,8 @@ struct dmz_dev {
 
        unsigned int            nr_zones;
 
+       unsigned int            flags;
+
        sector_t                zone_nr_sectors;
        unsigned int            zone_nr_sectors_shift;
 
@@ -67,6 +70,9 @@ struct dmz_dev {
                                 (dev)->zone_nr_sectors_shift)
 #define dmz_chunk_block(dev, b)        ((b) & ((dev)->zone_nr_blocks - 1))
 
+/* Device flags. */
+#define DMZ_BDEV_DYING         (1 << 0)
+
 /*
  * Zone descriptor.
  */
@@ -245,4 +251,9 @@ void dmz_resume_reclaim(struct dmz_reclaim *zrc);
 void dmz_reclaim_bio_acc(struct dmz_reclaim *zrc);
 void dmz_schedule_reclaim(struct dmz_reclaim *zrc);
 
+/*
+ * Functions defined in dm-zoned-target.c
+ */
+bool dmz_bdev_is_dying(struct dmz_dev *dmz_dev);
+
 #endif /* DM_ZONED_H */
index 58b3197..8aae062 100644 (file)
@@ -628,39 +628,40 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
 
        new_parent = shadow_current(s);
 
+       pn = dm_block_data(new_parent);
+       size = le32_to_cpu(pn->header.flags) & INTERNAL_NODE ?
+               sizeof(__le64) : s->info->value_type.size;
+
+       /* create & init the left block */
        r = new_block(s->info, &left);
        if (r < 0)
                return r;
 
+       ln = dm_block_data(left);
+       nr_left = le32_to_cpu(pn->header.nr_entries) / 2;
+
+       ln->header.flags = pn->header.flags;
+       ln->header.nr_entries = cpu_to_le32(nr_left);
+       ln->header.max_entries = pn->header.max_entries;
+       ln->header.value_size = pn->header.value_size;
+       memcpy(ln->keys, pn->keys, nr_left * sizeof(pn->keys[0]));
+       memcpy(value_ptr(ln, 0), value_ptr(pn, 0), nr_left * size);
+
+       /* create & init the right block */
        r = new_block(s->info, &right);
        if (r < 0) {
                unlock_block(s->info, left);
                return r;
        }
 
-       pn = dm_block_data(new_parent);
-       ln = dm_block_data(left);
        rn = dm_block_data(right);
-
-       nr_left = le32_to_cpu(pn->header.nr_entries) / 2;
        nr_right = le32_to_cpu(pn->header.nr_entries) - nr_left;
 
-       ln->header.flags = pn->header.flags;
-       ln->header.nr_entries = cpu_to_le32(nr_left);
-       ln->header.max_entries = pn->header.max_entries;
-       ln->header.value_size = pn->header.value_size;
-
        rn->header.flags = pn->header.flags;
        rn->header.nr_entries = cpu_to_le32(nr_right);
        rn->header.max_entries = pn->header.max_entries;
        rn->header.value_size = pn->header.value_size;
-
-       memcpy(ln->keys, pn->keys, nr_left * sizeof(pn->keys[0]));
        memcpy(rn->keys, pn->keys + nr_left, nr_right * sizeof(pn->keys[0]));
-
-       size = le32_to_cpu(pn->header.flags) & INTERNAL_NODE ?
-               sizeof(__le64) : s->info->value_type.size;
-       memcpy(value_ptr(ln, 0), value_ptr(pn, 0), nr_left * size);
        memcpy(value_ptr(rn, 0), value_ptr(pn, nr_left),
               nr_right * size);
 
index aec4492..2532858 100644 (file)
@@ -249,7 +249,7 @@ static int out(struct sm_metadata *smm)
        }
 
        if (smm->recursion_count == 1)
-               apply_bops(smm);
+               r = apply_bops(smm);
 
        smm->recursion_count--;
 
index 895510d..47602af 100644 (file)
@@ -81,6 +81,7 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r
        default:
                printk(KERN_WARNING "SA1100 flash: unknown base address "
                       "0x%08lx, assuming CS0\n", phys);
+               /* Fall through */
 
        case SA1100_CS0_PHYS:
                subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
index 02fd782..931d9d9 100644 (file)
@@ -1126,6 +1126,8 @@ static void bond_compute_features(struct bonding *bond)
 done:
        bond_dev->vlan_features = vlan_features;
        bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
+                                   NETIF_F_HW_VLAN_CTAG_TX |
+                                   NETIF_F_HW_VLAN_STAG_TX |
                                    NETIF_F_GSO_UDP_L4;
        bond_dev->mpls_features = mpls_features;
        bond_dev->gso_max_segs = gso_max_segs;
index d073baf..df976b2 100644 (file)
@@ -1223,12 +1223,8 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
 {
        struct sja1105_private *priv = ds->priv;
        struct device *dev = ds->dev;
-       u16 rx_vid, tx_vid;
        int i;
 
-       rx_vid = dsa_8021q_rx_vid(ds, port);
-       tx_vid = dsa_8021q_tx_vid(ds, port);
-
        for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
                struct sja1105_l2_lookup_entry l2_lookup = {0};
                u8 macaddr[ETH_ALEN];
index e47ea92..d10b421 100644 (file)
@@ -3057,12 +3057,13 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
        /* if VF indicate to PF this function is going down (PF will delete sp
         * elements and clear initializations
         */
-       if (IS_VF(bp))
+       if (IS_VF(bp)) {
+               bnx2x_clear_vlan_info(bp);
                bnx2x_vfpf_close_vf(bp);
-       else if (unload_mode != UNLOAD_RECOVERY)
+       } else if (unload_mode != UNLOAD_RECOVERY) {
                /* if this is a normal/close unload need to clean up chip*/
                bnx2x_chip_cleanup(bp, unload_mode, keep_link);
-       else {
+       else {
                /* Send the UNLOAD_REQUEST to the MCP */
                bnx2x_send_unload_req(bp, unload_mode);
 
index c2f6e44..8b08cb1 100644 (file)
@@ -425,6 +425,8 @@ void bnx2x_set_reset_global(struct bnx2x *bp);
 void bnx2x_disable_close_the_gate(struct bnx2x *bp);
 int bnx2x_init_hw_func_cnic(struct bnx2x *bp);
 
+void bnx2x_clear_vlan_info(struct bnx2x *bp);
+
 /**
  * bnx2x_sp_event - handle ramrods completion.
  *
index 2cc14db..192ff8d 100644 (file)
@@ -8482,11 +8482,21 @@ int bnx2x_set_vlan_one(struct bnx2x *bp, u16 vlan,
        return rc;
 }
 
+void bnx2x_clear_vlan_info(struct bnx2x *bp)
+{
+       struct bnx2x_vlan_entry *vlan;
+
+       /* Mark that hw forgot all entries */
+       list_for_each_entry(vlan, &bp->vlan_reg, link)
+               vlan->hw = false;
+
+       bp->vlan_cnt = 0;
+}
+
 static int bnx2x_del_all_vlans(struct bnx2x *bp)
 {
        struct bnx2x_vlan_mac_obj *vlan_obj = &bp->sp_objs[0].vlan_obj;
        unsigned long ramrod_flags = 0, vlan_flags = 0;
-       struct bnx2x_vlan_entry *vlan;
        int rc;
 
        __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
@@ -8495,10 +8505,7 @@ static int bnx2x_del_all_vlans(struct bnx2x *bp)
        if (rc)
                return rc;
 
-       /* Mark that hw forgot all entries */
-       list_for_each_entry(vlan, &bp->vlan_reg, link)
-               vlan->hw = false;
-       bp->vlan_cnt = 0;
+       bnx2x_clear_vlan_info(bp);
 
        return 0;
 }
index 7070349..8dce406 100644 (file)
@@ -2021,9 +2021,9 @@ static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi)
        if (bnapi->events & BNXT_RX_EVENT) {
                struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
 
-               bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
                if (bnapi->events & BNXT_AGG_EVENT)
                        bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod);
+               bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
        }
        bnapi->events = 0;
 }
@@ -5064,6 +5064,7 @@ static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type,
 
 static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
 {
+       bool agg_rings = !!(bp->flags & BNXT_FLAG_AGG_RINGS);
        int i, rc = 0;
        u32 type;
 
@@ -5139,7 +5140,9 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
                if (rc)
                        goto err_out;
                bnxt_set_db(bp, &rxr->rx_db, type, map_idx, ring->fw_ring_id);
-               bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
+               /* If we have agg rings, post agg buffers first. */
+               if (!agg_rings)
+                       bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
                bp->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id;
                if (bp->flags & BNXT_FLAG_CHIP_P5) {
                        struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
@@ -5158,7 +5161,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
                }
        }
 
-       if (bp->flags & BNXT_FLAG_AGG_RINGS) {
+       if (agg_rings) {
                type = HWRM_RING_ALLOC_AGG;
                for (i = 0; i < bp->rx_nr_rings; i++) {
                        struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
@@ -5174,6 +5177,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
                        bnxt_set_db(bp, &rxr->rx_agg_db, type, map_idx,
                                    ring->fw_ring_id);
                        bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod);
+                       bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
                        bp->grp_info[grp_idx].agg_fw_ring_id = ring->fw_ring_id;
                }
        }
@@ -7016,19 +7020,29 @@ static void bnxt_hwrm_clear_vnic_rss(struct bnxt *bp)
                bnxt_hwrm_vnic_set_rss(bp, i, false);
 }
 
-static void bnxt_hwrm_resource_free(struct bnxt *bp, bool close_path,
-                                   bool irq_re_init)
+static void bnxt_clear_vnic(struct bnxt *bp)
 {
-       if (bp->vnic_info) {
-               bnxt_hwrm_clear_vnic_filter(bp);
+       if (!bp->vnic_info)
+               return;
+
+       bnxt_hwrm_clear_vnic_filter(bp);
+       if (!(bp->flags & BNXT_FLAG_CHIP_P5)) {
                /* clear all RSS setting before free vnic ctx */
                bnxt_hwrm_clear_vnic_rss(bp);
                bnxt_hwrm_vnic_ctx_free(bp);
-               /* before free the vnic, undo the vnic tpa settings */
-               if (bp->flags & BNXT_FLAG_TPA)
-                       bnxt_set_tpa(bp, false);
-               bnxt_hwrm_vnic_free(bp);
        }
+       /* before free the vnic, undo the vnic tpa settings */
+       if (bp->flags & BNXT_FLAG_TPA)
+               bnxt_set_tpa(bp, false);
+       bnxt_hwrm_vnic_free(bp);
+       if (bp->flags & BNXT_FLAG_CHIP_P5)
+               bnxt_hwrm_vnic_ctx_free(bp);
+}
+
+static void bnxt_hwrm_resource_free(struct bnxt *bp, bool close_path,
+                                   bool irq_re_init)
+{
+       bnxt_clear_vnic(bp);
        bnxt_hwrm_ring_free(bp, close_path);
        bnxt_hwrm_ring_grp_free(bp);
        if (irq_re_init) {
index 549c90d..c05d663 100644 (file)
@@ -98,10 +98,13 @@ static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
        if (idx)
                req->dimensions = cpu_to_le16(1);
 
-       if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE))
+       if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) {
                memcpy(data_addr, buf, bytesize);
-
-       rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
+               rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
+       } else {
+               rc = hwrm_send_message_silent(bp, msg, msg_len,
+                                             HWRM_CMD_TIMEOUT);
+       }
        if (!rc && req->req_type == cpu_to_le16(HWRM_NVM_GET_VARIABLE))
                memcpy(buf, data_addr, bytesize);
 
index c7ee63d..8445a0c 100644 (file)
@@ -2016,21 +2016,19 @@ static int bnxt_flash_package_from_file(struct net_device *dev,
        mutex_lock(&bp->hwrm_cmd_lock);
        hwrm_err = _hwrm_send_message(bp, &install, sizeof(install),
                                      INSTALL_PACKAGE_TIMEOUT);
-       if (hwrm_err)
-               goto flash_pkg_exit;
-
-       if (resp->error_code) {
+       if (hwrm_err) {
                u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err;
 
-               if (error_code == NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) {
+               if (resp->error_code && error_code ==
+                   NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) {
                        install.flags |= cpu_to_le16(
                               NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG);
                        hwrm_err = _hwrm_send_message(bp, &install,
                                                      sizeof(install),
                                                      INSTALL_PACKAGE_TIMEOUT);
-                       if (hwrm_err)
-                               goto flash_pkg_exit;
                }
+               if (hwrm_err)
+                       goto flash_pkg_exit;
        }
 
        if (resp->result) {
index 6fe4a71..dd621f6 100644 (file)
@@ -1236,7 +1236,7 @@ static int __bnxt_tc_del_flow(struct bnxt *bp,
 static void bnxt_tc_set_flow_dir(struct bnxt *bp, struct bnxt_tc_flow *flow,
                                 u16 src_fid)
 {
-       flow->dir = (bp->pf.fw_fid == src_fid) ? BNXT_DIR_RX : BNXT_DIR_TX;
+       flow->l2_key.dir = (bp->pf.fw_fid == src_fid) ? BNXT_DIR_RX : BNXT_DIR_TX;
 }
 
 static void bnxt_tc_set_src_fid(struct bnxt *bp, struct bnxt_tc_flow *flow,
@@ -1285,9 +1285,7 @@ static int bnxt_tc_add_flow(struct bnxt *bp, u16 src_fid,
                goto free_node;
 
        bnxt_tc_set_src_fid(bp, flow, src_fid);
-
-       if (bp->fw_cap & BNXT_FW_CAP_OVS_64BIT_HANDLE)
-               bnxt_tc_set_flow_dir(bp, flow, src_fid);
+       bnxt_tc_set_flow_dir(bp, flow, flow->src_fid);
 
        if (!bnxt_tc_can_offload(bp, flow)) {
                rc = -EOPNOTSUPP;
@@ -1407,7 +1405,7 @@ static void bnxt_fill_cfa_stats_req(struct bnxt *bp,
                 * 2. 15th bit of flow_handle must specify the flow
                 *    direction (TX/RX).
                 */
-               if (flow_node->flow.dir == BNXT_DIR_RX)
+               if (flow_node->flow.l2_key.dir == BNXT_DIR_RX)
                        handle = CFA_FLOW_INFO_REQ_FLOW_HANDLE_DIR_RX |
                                 CFA_FLOW_INFO_REQ_FLOW_HANDLE_MAX_MASK;
                else
index ffec57d..4f05305 100644 (file)
@@ -23,6 +23,9 @@ struct bnxt_tc_l2_key {
        __be16          inner_vlan_tci;
        __be16          ether_type;
        u8              num_vlans;
+       u8              dir;
+#define BNXT_DIR_RX    1
+#define BNXT_DIR_TX    0
 };
 
 struct bnxt_tc_l3_key {
@@ -98,9 +101,6 @@ struct bnxt_tc_flow {
 
        /* flow applicable to pkts ingressing on this fid */
        u16                             src_fid;
-       u8                              dir;
-#define BNXT_DIR_RX    1
-#define BNXT_DIR_TX    0
        struct bnxt_tc_l2_key           l2_key;
        struct bnxt_tc_l2_key           l2_mask;
        struct bnxt_tc_l3_key           l3_key;
index 73632b8..b821c9e 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "cavium_ptp.h"
 
-#define DRV_NAME       "Cavium PTP Driver"
+#define DRV_NAME "cavium_ptp"
 
 #define PCI_DEVICE_ID_CAVIUM_PTP       0xA00C
 #define PCI_DEVICE_ID_CAVIUM_RST       0xA00E
index 0322241..6dd65f9 100644 (file)
@@ -237,8 +237,10 @@ int octeon_setup_iq(struct octeon_device *oct,
        }
 
        oct->num_iqs++;
-       if (oct->fn_list.enable_io_queues(oct))
+       if (oct->fn_list.enable_io_queues(oct)) {
+               octeon_delete_instr_queue(oct, iq_no);
                return 1;
+       }
 
        return 0;
 }
index 0295903..d692251 100644 (file)
@@ -3236,8 +3236,10 @@ static ssize_t blocked_fl_write(struct file *filp, const char __user *ubuf,
                return -ENOMEM;
 
        err = bitmap_parse_user(ubuf, count, t, adap->sge.egr_sz);
-       if (err)
+       if (err) {
+               kvfree(t);
                return err;
+       }
 
        bitmap_copy(adap->sge.blocked_fl, t, adap->sge.egr_sz);
        kvfree(t);
index 133acca..092da2d 100644 (file)
@@ -167,7 +167,7 @@ struct nps_enet_priv {
 };
 
 /**
- * nps_reg_set - Sets ENET register with provided value.
+ * nps_enet_reg_set - Sets ENET register with provided value.
  * @priv:       Pointer to EZchip ENET private data structure.
  * @reg:        Register offset from base address.
  * @value:      Value to set in register.
@@ -179,7 +179,7 @@ static inline void nps_enet_reg_set(struct nps_enet_priv *priv,
 }
 
 /**
- * nps_reg_get - Gets value of specified ENET register.
+ * nps_enet_reg_get - Gets value of specified ENET register.
  * @priv:       Pointer to EZchip ENET private data structure.
  * @reg:        Register offset from base address.
  *
index d654c23..c5be4eb 100644 (file)
@@ -1605,7 +1605,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
        struct net_device *netdev;
        struct ibmveth_adapter *adapter;
        unsigned char *mac_addr_p;
-       unsigned int *mcastFilterSize_p;
+       __be32 *mcastFilterSize_p;
        long ret;
        unsigned long ret_attr;
 
@@ -1627,8 +1627,9 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
                return -EINVAL;
        }
 
-       mcastFilterSize_p = (unsigned int *)vio_get_attribute(dev,
-                                               VETH_MCAST_FILTER_SIZE, NULL);
+       mcastFilterSize_p = (__be32 *)vio_get_attribute(dev,
+                                                       VETH_MCAST_FILTER_SIZE,
+                                                       NULL);
        if (!mcastFilterSize_p) {
                dev_err(&dev->dev, "Can't find VETH_MCAST_FILTER_SIZE "
                        "attribute\n");
@@ -1645,7 +1646,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
        adapter->vdev = dev;
        adapter->netdev = netdev;
-       adapter->mcastFilterSize = *mcastFilterSize_p;
+       adapter->mcastFilterSize = be32_to_cpu(*mcastFilterSize_p);
        adapter->pool_config = 0;
 
        netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
index 3da6800..cebd20f 100644 (file)
@@ -1568,6 +1568,8 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
                lpar_rc = send_subcrq_indirect(adapter, handle_array[queue_num],
                                               (u64)tx_buff->indir_dma,
                                               (u64)num_entries);
+               dma_unmap_single(dev, tx_buff->indir_dma,
+                                sizeof(tx_buff->indir_arr), DMA_TO_DEVICE);
        } else {
                tx_buff->num_entries = num_entries;
                lpar_rc = send_subcrq(adapter, handle_array[queue_num],
@@ -2788,7 +2790,6 @@ static int ibmvnic_complete_tx(struct ibmvnic_adapter *adapter,
        union sub_crq *next;
        int index;
        int i, j;
-       u8 *first;
 
 restart_loop:
        while (pending_scrq(adapter, scrq)) {
@@ -2818,14 +2819,6 @@ restart_loop:
 
                                txbuff->data_dma[j] = 0;
                        }
-                       /* if sub_crq was sent indirectly */
-                       first = &txbuff->indir_arr[0].generic.first;
-                       if (*first == IBMVNIC_CRQ_CMD) {
-                               dma_unmap_single(dev, txbuff->indir_dma,
-                                                sizeof(txbuff->indir_arr),
-                                                DMA_TO_DEVICE);
-                               *first = 0;
-                       }
 
                        if (txbuff->last_frag) {
                                dev_kfree_skb_any(txbuff->skb);
index cbaf712..7882148 100644 (file)
@@ -7897,11 +7897,8 @@ static void ixgbe_service_task(struct work_struct *work)
                return;
        }
        if (ixgbe_check_fw_error(adapter)) {
-               if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
-                       rtnl_lock();
+               if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        unregister_netdev(adapter->netdev);
-                       rtnl_unlock();
-               }
                ixgbe_service_event_complete(adapter);
                return;
        }
index 6c01314..db3552f 100644 (file)
@@ -1187,7 +1187,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
        err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, rss_map->indir_qp);
        if (err) {
                en_err(priv, "Failed to allocate RSS indirection QP\n");
-               goto rss_err;
+               goto qp_alloc_err;
        }
 
        rss_map->indir_qp->event = mlx4_en_sqp_event;
@@ -1241,6 +1241,7 @@ indir_err:
                       MLX4_QP_STATE_RST, NULL, 0, 0, rss_map->indir_qp);
        mlx4_qp_remove(mdev->dev, rss_map->indir_qp);
        mlx4_qp_free(mdev->dev, rss_map->indir_qp);
+qp_alloc_err:
        kfree(rss_map->indir_qp);
        rss_map->indir_qp = NULL;
 rss_err:
index ce1be2a..65bec19 100644 (file)
@@ -184,8 +184,13 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
 
 struct mlx5e_tx_wqe {
        struct mlx5_wqe_ctrl_seg ctrl;
-       struct mlx5_wqe_eth_seg  eth;
-       struct mlx5_wqe_data_seg data[0];
+       union {
+               struct {
+                       struct mlx5_wqe_eth_seg  eth;
+                       struct mlx5_wqe_data_seg data[0];
+               };
+               u8 tls_progress_params_ctx[0];
+       };
 };
 
 struct mlx5e_rx_wqe_ll {
@@ -1100,6 +1105,8 @@ u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv);
 u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv);
 int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
                              struct ethtool_ts_info *info);
+int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
+                              struct ethtool_flash *flash);
 void mlx5e_ethtool_get_pauseparam(struct mlx5e_priv *priv,
                                  struct ethtool_pauseparam *pauseparam);
 int mlx5e_ethtool_set_pauseparam(struct mlx5e_priv *priv,
index f3d9874..c7f8645 100644 (file)
@@ -76,26 +76,21 @@ static int mlx5e_tx_reporter_err_cqe_recover(struct mlx5e_txqsq *sq)
        u8 state;
        int err;
 
-       if (!test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state))
-               return 0;
-
        err = mlx5_core_query_sq_state(mdev, sq->sqn, &state);
        if (err) {
                netdev_err(dev, "Failed to query SQ 0x%x state. err = %d\n",
                           sq->sqn, err);
-               return err;
+               goto out;
        }
 
-       if (state != MLX5_SQC_STATE_ERR) {
-               netdev_err(dev, "SQ 0x%x not in ERROR state\n", sq->sqn);
-               return -EINVAL;
-       }
+       if (state != MLX5_SQC_STATE_ERR)
+               goto out;
 
        mlx5e_tx_disable_queue(sq->txq);
 
        err = mlx5e_wait_for_sq_flush(sq);
        if (err)
-               return err;
+               goto out;
 
        /* At this point, no new packets will arrive from the stack as TXQ is
         * marked with QUEUE_STATE_DRV_XOFF. In addition, NAPI cleared all
@@ -104,13 +99,17 @@ static int mlx5e_tx_reporter_err_cqe_recover(struct mlx5e_txqsq *sq)
 
        err = mlx5e_sq_to_ready(sq, state);
        if (err)
-               return err;
+               goto out;
 
        mlx5e_reset_txqsq_cc_pc(sq);
        sq->stats->recover++;
+       clear_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state);
        mlx5e_activate_txqsq(sq);
 
        return 0;
+out:
+       clear_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state);
+       return err;
 }
 
 static int mlx5_tx_health_report(struct devlink_health_reporter *tx_reporter,
index aaffa6f..7f78c00 100644 (file)
@@ -143,7 +143,10 @@ void mlx5e_activate_xsk(struct mlx5e_channel *c)
 {
        set_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
        /* TX queue is created active. */
+
+       spin_lock(&c->xskicosq_lock);
        mlx5e_trigger_irq(&c->xskicosq);
+       spin_unlock(&c->xskicosq_lock);
 }
 
 void mlx5e_deactivate_xsk(struct mlx5e_channel *c)
index 407da83..b7298f9 100644 (file)
 #include "accel/tls.h"
 
 #define MLX5E_KTLS_STATIC_UMR_WQE_SZ \
-       (sizeof(struct mlx5e_umr_wqe) + MLX5_ST_SZ_BYTES(tls_static_params))
+       (offsetof(struct mlx5e_umr_wqe, tls_static_params_ctx) + \
+        MLX5_ST_SZ_BYTES(tls_static_params))
 #define MLX5E_KTLS_STATIC_WQEBBS \
        (DIV_ROUND_UP(MLX5E_KTLS_STATIC_UMR_WQE_SZ, MLX5_SEND_WQE_BB))
 
 #define MLX5E_KTLS_PROGRESS_WQE_SZ \
-       (sizeof(struct mlx5e_tx_wqe) + MLX5_ST_SZ_BYTES(tls_progress_params))
+       (offsetof(struct mlx5e_tx_wqe, tls_progress_params_ctx) + \
+        MLX5_ST_SZ_BYTES(tls_progress_params))
 #define MLX5E_KTLS_PROGRESS_WQEBBS \
        (DIV_ROUND_UP(MLX5E_KTLS_PROGRESS_WQE_SZ, MLX5_SEND_WQE_BB))
 #define MLX5E_KTLS_MAX_DUMP_WQEBBS 2
index 3766545..8b93101 100644 (file)
@@ -69,7 +69,7 @@ build_static_params(struct mlx5e_umr_wqe *wqe, u16 pc, u32 sqn,
        cseg->qpn_ds           = cpu_to_be32((sqn << MLX5_WQE_CTRL_QPN_SHIFT) |
                                             STATIC_PARAMS_DS_CNT);
        cseg->fm_ce_se         = fence ? MLX5_FENCE_MODE_INITIATOR_SMALL : 0;
-       cseg->imm              = cpu_to_be32(priv_tx->tisn);
+       cseg->tisn             = cpu_to_be32(priv_tx->tisn << 8);
 
        ucseg->flags = MLX5_UMR_INLINE;
        ucseg->bsf_octowords = cpu_to_be16(MLX5_ST_SZ_BYTES(tls_static_params) / 16);
@@ -80,7 +80,7 @@ build_static_params(struct mlx5e_umr_wqe *wqe, u16 pc, u32 sqn,
 static void
 fill_progress_params_ctx(void *ctx, struct mlx5e_ktls_offload_context_tx *priv_tx)
 {
-       MLX5_SET(tls_progress_params, ctx, pd, priv_tx->tisn);
+       MLX5_SET(tls_progress_params, ctx, tisn, priv_tx->tisn);
        MLX5_SET(tls_progress_params, ctx, record_tracker_state,
                 MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START);
        MLX5_SET(tls_progress_params, ctx, auth_state,
@@ -104,7 +104,7 @@ build_progress_params(struct mlx5e_tx_wqe *wqe, u16 pc, u32 sqn,
                                             PROGRESS_PARAMS_DS_CNT);
        cseg->fm_ce_se         = fence ? MLX5_FENCE_MODE_INITIATOR_SMALL : 0;
 
-       fill_progress_params_ctx(wqe->data, priv_tx);
+       fill_progress_params_ctx(wqe->tls_progress_params_ctx, priv_tx);
 }
 
 static void tx_fill_wi(struct mlx5e_txqsq *sq,
@@ -278,7 +278,7 @@ tx_post_resync_dump(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 
        cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8)  | MLX5_OPCODE_DUMP);
        cseg->qpn_ds           = cpu_to_be32((sq->sqn << 8) | ds_cnt);
-       cseg->imm              = cpu_to_be32(tisn);
+       cseg->tisn             = cpu_to_be32(tisn << 8);
        cseg->fm_ce_se         = first ? MLX5_FENCE_MODE_INITIATOR_SMALL : 0;
 
        eseg->inline_hdr.sz = cpu_to_be16(ihs);
@@ -434,7 +434,7 @@ struct sk_buff *mlx5e_ktls_handle_tx_skb(struct net_device *netdev,
        priv_tx->expected_seq = seq + datalen;
 
        cseg = &(*wqe)->ctrl;
-       cseg->imm = cpu_to_be32(priv_tx->tisn);
+       cseg->tisn = cpu_to_be32(priv_tx->tisn << 8);
 
        stats->tls_encrypted_packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
        stats->tls_encrypted_bytes   += datalen;
index 8657e0f..2c75b27 100644 (file)
@@ -437,12 +437,6 @@ arfs_hash_bucket(struct arfs_table *arfs_t, __be16 src_port,
        return &arfs_t->rules_hash[bucket_idx];
 }
 
-static u8 arfs_get_ip_proto(const struct sk_buff *skb)
-{
-       return (skb->protocol == htons(ETH_P_IP)) ?
-               ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr;
-}
-
 static struct arfs_table *arfs_get_table(struct mlx5e_arfs_tables *arfs,
                                         u8 ip_proto, __be16 etype)
 {
@@ -602,31 +596,9 @@ out:
        arfs_may_expire_flow(priv);
 }
 
-/* return L4 destination port from ip4/6 packets */
-static __be16 arfs_get_dst_port(const struct sk_buff *skb)
-{
-       char *transport_header;
-
-       transport_header = skb_transport_header(skb);
-       if (arfs_get_ip_proto(skb) == IPPROTO_TCP)
-               return ((struct tcphdr *)transport_header)->dest;
-       return ((struct udphdr *)transport_header)->dest;
-}
-
-/* return L4 source port from ip4/6 packets */
-static __be16 arfs_get_src_port(const struct sk_buff *skb)
-{
-       char *transport_header;
-
-       transport_header = skb_transport_header(skb);
-       if (arfs_get_ip_proto(skb) == IPPROTO_TCP)
-               return ((struct tcphdr *)transport_header)->source;
-       return ((struct udphdr *)transport_header)->source;
-}
-
 static struct arfs_rule *arfs_alloc_rule(struct mlx5e_priv *priv,
                                         struct arfs_table *arfs_t,
-                                        const struct sk_buff *skb,
+                                        const struct flow_keys *fk,
                                         u16 rxq, u32 flow_id)
 {
        struct arfs_rule *rule;
@@ -641,19 +613,19 @@ static struct arfs_rule *arfs_alloc_rule(struct mlx5e_priv *priv,
        INIT_WORK(&rule->arfs_work, arfs_handle_work);
 
        tuple = &rule->tuple;
-       tuple->etype = skb->protocol;
+       tuple->etype = fk->basic.n_proto;
+       tuple->ip_proto = fk->basic.ip_proto;
        if (tuple->etype == htons(ETH_P_IP)) {
-               tuple->src_ipv4 = ip_hdr(skb)->saddr;
-               tuple->dst_ipv4 = ip_hdr(skb)->daddr;
+               tuple->src_ipv4 = fk->addrs.v4addrs.src;
+               tuple->dst_ipv4 = fk->addrs.v4addrs.dst;
        } else {
-               memcpy(&tuple->src_ipv6, &ipv6_hdr(skb)->saddr,
+               memcpy(&tuple->src_ipv6, &fk->addrs.v6addrs.src,
                       sizeof(struct in6_addr));
-               memcpy(&tuple->dst_ipv6, &ipv6_hdr(skb)->daddr,
+               memcpy(&tuple->dst_ipv6, &fk->addrs.v6addrs.dst,
                       sizeof(struct in6_addr));
        }
-       tuple->ip_proto = arfs_get_ip_proto(skb);
-       tuple->src_port = arfs_get_src_port(skb);
-       tuple->dst_port = arfs_get_dst_port(skb);
+       tuple->src_port = fk->ports.src;
+       tuple->dst_port = fk->ports.dst;
 
        rule->flow_id = flow_id;
        rule->filter_id = priv->fs.arfs.last_filter_id++ % RPS_NO_FILTER;
@@ -664,37 +636,33 @@ static struct arfs_rule *arfs_alloc_rule(struct mlx5e_priv *priv,
        return rule;
 }
 
-static bool arfs_cmp_ips(struct arfs_tuple *tuple,
-                        const struct sk_buff *skb)
+static bool arfs_cmp(const struct arfs_tuple *tuple, const struct flow_keys *fk)
 {
-       if (tuple->etype == htons(ETH_P_IP) &&
-           tuple->src_ipv4 == ip_hdr(skb)->saddr &&
-           tuple->dst_ipv4 == ip_hdr(skb)->daddr)
-               return true;
-       if (tuple->etype == htons(ETH_P_IPV6) &&
-           (!memcmp(&tuple->src_ipv6, &ipv6_hdr(skb)->saddr,
-                    sizeof(struct in6_addr))) &&
-           (!memcmp(&tuple->dst_ipv6, &ipv6_hdr(skb)->daddr,
-                    sizeof(struct in6_addr))))
-               return true;
+       if (tuple->src_port != fk->ports.src || tuple->dst_port != fk->ports.dst)
+               return false;
+       if (tuple->etype != fk->basic.n_proto)
+               return false;
+       if (tuple->etype == htons(ETH_P_IP))
+               return tuple->src_ipv4 == fk->addrs.v4addrs.src &&
+                      tuple->dst_ipv4 == fk->addrs.v4addrs.dst;
+       if (tuple->etype == htons(ETH_P_IPV6))
+               return !memcmp(&tuple->src_ipv6, &fk->addrs.v6addrs.src,
+                              sizeof(struct in6_addr)) &&
+                      !memcmp(&tuple->dst_ipv6, &fk->addrs.v6addrs.dst,
+                              sizeof(struct in6_addr));
        return false;
 }
 
 static struct arfs_rule *arfs_find_rule(struct arfs_table *arfs_t,
-                                       const struct sk_buff *skb)
+                                       const struct flow_keys *fk)
 {
        struct arfs_rule *arfs_rule;
        struct hlist_head *head;
-       __be16 src_port = arfs_get_src_port(skb);
-       __be16 dst_port = arfs_get_dst_port(skb);
 
-       head = arfs_hash_bucket(arfs_t, src_port, dst_port);
+       head = arfs_hash_bucket(arfs_t, fk->ports.src, fk->ports.dst);
        hlist_for_each_entry(arfs_rule, head, hlist) {
-               if (arfs_rule->tuple.src_port == src_port &&
-                   arfs_rule->tuple.dst_port == dst_port &&
-                   arfs_cmp_ips(&arfs_rule->tuple, skb)) {
+               if (arfs_cmp(&arfs_rule->tuple, fk))
                        return arfs_rule;
-               }
        }
 
        return NULL;
@@ -707,20 +675,24 @@ int mlx5e_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
        struct mlx5e_arfs_tables *arfs = &priv->fs.arfs;
        struct arfs_table *arfs_t;
        struct arfs_rule *arfs_rule;
+       struct flow_keys fk;
+
+       if (!skb_flow_dissect_flow_keys(skb, &fk, 0))
+               return -EPROTONOSUPPORT;
 
-       if (skb->protocol != htons(ETH_P_IP) &&
-           skb->protocol != htons(ETH_P_IPV6))
+       if (fk.basic.n_proto != htons(ETH_P_IP) &&
+           fk.basic.n_proto != htons(ETH_P_IPV6))
                return -EPROTONOSUPPORT;
 
        if (skb->encapsulation)
                return -EPROTONOSUPPORT;
 
-       arfs_t = arfs_get_table(arfs, arfs_get_ip_proto(skb), skb->protocol);
+       arfs_t = arfs_get_table(arfs, fk.basic.ip_proto, fk.basic.n_proto);
        if (!arfs_t)
                return -EPROTONOSUPPORT;
 
        spin_lock_bh(&arfs->arfs_lock);
-       arfs_rule = arfs_find_rule(arfs_t, skb);
+       arfs_rule = arfs_find_rule(arfs_t, &fk);
        if (arfs_rule) {
                if (arfs_rule->rxq == rxq_index) {
                        spin_unlock_bh(&arfs->arfs_lock);
@@ -728,8 +700,7 @@ int mlx5e_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
                }
                arfs_rule->rxq = rxq_index;
        } else {
-               arfs_rule = arfs_alloc_rule(priv, arfs_t, skb,
-                                           rxq_index, flow_id);
+               arfs_rule = arfs_alloc_rule(priv, arfs_t, &fk, rxq_index, flow_id);
                if (!arfs_rule) {
                        spin_unlock_bh(&arfs->arfs_lock);
                        return -ENOMEM;
index 03bed71..20e628c 100644 (file)
@@ -1081,6 +1081,14 @@ int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
        link_modes = autoneg == AUTONEG_ENABLE ? ethtool2ptys_adver_func(adver) :
                mlx5e_port_speed2linkmodes(mdev, speed, !ext);
 
+       if ((link_modes & MLX5E_PROT_MASK(MLX5E_56GBASE_R4)) &&
+           autoneg != AUTONEG_ENABLE) {
+               netdev_err(priv->netdev, "%s: 56G link speed requires autoneg enabled\n",
+                          __func__);
+               err = -EINVAL;
+               goto out;
+       }
+
        link_modes = link_modes & eproto.cap;
        if (!link_modes) {
                netdev_err(priv->netdev, "%s: Not supported link mode(s) requested",
@@ -1338,6 +1346,9 @@ int mlx5e_ethtool_set_pauseparam(struct mlx5e_priv *priv,
        struct mlx5_core_dev *mdev = priv->mdev;
        int err;
 
+       if (!MLX5_CAP_GEN(mdev, vport_group_manager))
+               return -EOPNOTSUPP;
+
        if (pauseparam->autoneg)
                return -EINVAL;
 
@@ -1679,6 +1690,40 @@ static int mlx5e_get_module_eeprom(struct net_device *netdev,
        return 0;
 }
 
+int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
+                              struct ethtool_flash *flash)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+       struct net_device *dev = priv->netdev;
+       const struct firmware *fw;
+       int err;
+
+       if (flash->region != ETHTOOL_FLASH_ALL_REGIONS)
+               return -EOPNOTSUPP;
+
+       err = request_firmware_direct(&fw, flash->data, &dev->dev);
+       if (err)
+               return err;
+
+       dev_hold(dev);
+       rtnl_unlock();
+
+       err = mlx5_firmware_flash(mdev, fw, NULL);
+       release_firmware(fw);
+
+       rtnl_lock();
+       dev_put(dev);
+       return err;
+}
+
+static int mlx5e_flash_device(struct net_device *dev,
+                             struct ethtool_flash *flash)
+{
+       struct mlx5e_priv *priv = netdev_priv(dev);
+
+       return mlx5e_ethtool_flash_device(priv, flash);
+}
+
 static int set_pflag_cqe_based_moder(struct net_device *netdev, bool enable,
                                     bool is_rx_cq)
 {
@@ -1961,6 +2006,7 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
        .set_wol           = mlx5e_set_wol,
        .get_module_info   = mlx5e_get_module_info,
        .get_module_eeprom = mlx5e_get_module_eeprom,
+       .flash_device      = mlx5e_flash_device,
        .get_priv_flags    = mlx5e_get_priv_flags,
        .set_priv_flags    = mlx5e_set_priv_flags,
        .self_test         = mlx5e_self_test,
index 6c712c5..9d5f6e5 100644 (file)
@@ -1321,7 +1321,6 @@ err_free_txqsq:
 void mlx5e_activate_txqsq(struct mlx5e_txqsq *sq)
 {
        sq->txq = netdev_get_tx_queue(sq->channel->netdev, sq->txq_ix);
-       clear_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state);
        set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
        netdev_tx_reset_queue(sq->txq);
        netif_tx_start_queue(sq->txq);
index 7ecfc53..00b2d4a 100644 (file)
@@ -1480,7 +1480,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
                              struct mlx5_flow_spec *spec,
                              struct flow_cls_offload *f,
                              struct net_device *filter_dev,
-                             u8 *match_level, u8 *tunnel_match_level)
+                             u8 *inner_match_level, u8 *outer_match_level)
 {
        struct netlink_ext_ack *extack = f->common.extack;
        void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
@@ -1495,8 +1495,9 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
        struct flow_dissector *dissector = rule->match.dissector;
        u16 addr_type = 0;
        u8 ip_proto = 0;
+       u8 *match_level;
 
-       *match_level = MLX5_MATCH_NONE;
+       match_level = outer_match_level;
 
        if (dissector->used_keys &
            ~(BIT(FLOW_DISSECTOR_KEY_META) |
@@ -1524,12 +1525,14 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
        }
 
        if (mlx5e_get_tc_tun(filter_dev)) {
-               if (parse_tunnel_attr(priv, spec, f, filter_dev, tunnel_match_level))
+               if (parse_tunnel_attr(priv, spec, f, filter_dev,
+                                     outer_match_level))
                        return -EOPNOTSUPP;
 
-               /* In decap flow, header pointers should point to the inner
+               /* At this point, header pointers should point to the inner
                 * headers, outer header were already set by parse_tunnel_attr
                 */
+               match_level = inner_match_level;
                headers_c = get_match_headers_criteria(MLX5_FLOW_CONTEXT_ACTION_DECAP,
                                                       spec);
                headers_v = get_match_headers_value(MLX5_FLOW_CONTEXT_ACTION_DECAP,
@@ -1831,35 +1834,41 @@ static int parse_cls_flower(struct mlx5e_priv *priv,
                            struct flow_cls_offload *f,
                            struct net_device *filter_dev)
 {
+       u8 inner_match_level, outer_match_level, non_tunnel_match_level;
        struct netlink_ext_ack *extack = f->common.extack;
        struct mlx5_core_dev *dev = priv->mdev;
        struct mlx5_eswitch *esw = dev->priv.eswitch;
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
-       u8 match_level, tunnel_match_level = MLX5_MATCH_NONE;
        struct mlx5_eswitch_rep *rep;
        int err;
 
-       err = __parse_cls_flower(priv, spec, f, filter_dev, &match_level, &tunnel_match_level);
+       inner_match_level = MLX5_MATCH_NONE;
+       outer_match_level = MLX5_MATCH_NONE;
+
+       err = __parse_cls_flower(priv, spec, f, filter_dev, &inner_match_level,
+                                &outer_match_level);
+       non_tunnel_match_level = (inner_match_level == MLX5_MATCH_NONE) ?
+                                outer_match_level : inner_match_level;
 
        if (!err && (flow->flags & MLX5E_TC_FLOW_ESWITCH)) {
                rep = rpriv->rep;
                if (rep->vport != MLX5_VPORT_UPLINK &&
                    (esw->offloads.inline_mode != MLX5_INLINE_MODE_NONE &&
-                   esw->offloads.inline_mode < match_level)) {
+                   esw->offloads.inline_mode < non_tunnel_match_level)) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Flow is not offloaded due to min inline setting");
                        netdev_warn(priv->netdev,
                                    "Flow is not offloaded due to min inline setting, required %d actual %d\n",
-                                   match_level, esw->offloads.inline_mode);
+                                   non_tunnel_match_level, esw->offloads.inline_mode);
                        return -EOPNOTSUPP;
                }
        }
 
        if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
-               flow->esw_attr->match_level = match_level;
-               flow->esw_attr->tunnel_match_level = tunnel_match_level;
+               flow->esw_attr->inner_match_level = inner_match_level;
+               flow->esw_attr->outer_match_level = outer_match_level;
        } else {
-               flow->nic_attr->match_level = match_level;
+               flow->nic_attr->match_level = non_tunnel_match_level;
        }
 
        return err;
@@ -3158,7 +3167,7 @@ mlx5e_flow_esw_attr_init(struct mlx5_esw_flow_attr *esw_attr,
 
        esw_attr->parse_attr = parse_attr;
        esw_attr->chain = f->common.chain_index;
-       esw_attr->prio = TC_H_MAJ(f->common.prio) >> 16;
+       esw_attr->prio = f->common.prio;
 
        esw_attr->in_rep = in_rep;
        esw_attr->in_mdev = in_mdev;
index a38e8a3..04685db 100644 (file)
@@ -377,8 +377,8 @@ struct mlx5_esw_flow_attr {
                struct mlx5_termtbl_handle *termtbl;
        } dests[MLX5_MAX_FLOW_FWD_VPORTS];
        u32     mod_hdr_id;
-       u8      match_level;
-       u8      tunnel_match_level;
+       u8      inner_match_level;
+       u8      outer_match_level;
        struct mlx5_fc *counter;
        u32     chain;
        u16     prio;
index 089ae4d..0323fd0 100644 (file)
@@ -207,14 +207,10 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
 
        mlx5_eswitch_set_rule_source_port(esw, spec, attr);
 
-       if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) {
-               if (attr->tunnel_match_level != MLX5_MATCH_NONE)
-                       spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
-               if (attr->match_level != MLX5_MATCH_NONE)
-                       spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
-       } else if (attr->match_level != MLX5_MATCH_NONE) {
+       if (attr->outer_match_level != MLX5_MATCH_NONE)
                spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
-       }
+       if (attr->inner_match_level != MLX5_MATCH_NONE)
+               spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
 
        if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
                flow_act.modify_id = attr->mod_hdr_id;
@@ -290,7 +286,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
        mlx5_eswitch_set_rule_source_port(esw, spec, attr);
 
        spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
-       if (attr->match_level != MLX5_MATCH_NONE)
+       if (attr->outer_match_level != MLX5_MATCH_NONE)
                spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
 
        rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
index ebd81f6..90cb50f 100644 (file)
@@ -122,6 +122,14 @@ static int mlx5i_get_ts_info(struct net_device *netdev,
        return mlx5e_ethtool_get_ts_info(priv, info);
 }
 
+static int mlx5i_flash_device(struct net_device *netdev,
+                             struct ethtool_flash *flash)
+{
+       struct mlx5e_priv *priv = mlx5i_epriv(netdev);
+
+       return mlx5e_ethtool_flash_device(priv, flash);
+}
+
 enum mlx5_ptys_width {
        MLX5_PTYS_WIDTH_1X      = 1 << 0,
        MLX5_PTYS_WIDTH_2X      = 1 << 1,
@@ -233,6 +241,7 @@ const struct ethtool_ops mlx5i_ethtool_ops = {
        .get_ethtool_stats  = mlx5i_get_ethtool_stats,
        .get_ringparam      = mlx5i_get_ringparam,
        .set_ringparam      = mlx5i_set_ringparam,
+       .flash_device       = mlx5i_flash_device,
        .get_channels       = mlx5i_get_channels,
        .set_channels       = mlx5i_set_channels,
        .get_coalesce       = mlx5i_get_coalesce,
index ea9ee88..ea1d4d2 100644 (file)
@@ -27,6 +27,7 @@ int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
        case 128:
                general_obj_key_size =
                        MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_128;
+               key_p += sz_bytes;
                break;
        case 256:
                general_obj_key_size =
index e8ac905..84a87d0 100644 (file)
@@ -471,7 +471,7 @@ int mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info *rulei)
 void mlxsw_sp_acl_rulei_priority(struct mlxsw_sp_acl_rule_info *rulei,
                                 unsigned int priority)
 {
-       rulei->priority = priority >> 16;
+       rulei->priority = priority;
 }
 
 void mlxsw_sp_acl_rulei_keymask_u32(struct mlxsw_sp_acl_rule_info *rulei,
index 63b07ed..38bb1cf 100644 (file)
@@ -29,7 +29,7 @@
 
 struct mlxsw_sp_ptp_state {
        struct mlxsw_sp *mlxsw_sp;
-       struct rhashtable unmatched_ht;
+       struct rhltable unmatched_ht;
        spinlock_t unmatched_lock; /* protects the HT */
        struct delayed_work ht_gc_dw;
        u32 gc_cycle;
@@ -45,7 +45,7 @@ struct mlxsw_sp1_ptp_key {
 
 struct mlxsw_sp1_ptp_unmatched {
        struct mlxsw_sp1_ptp_key key;
-       struct rhash_head ht_node;
+       struct rhlist_head ht_node;
        struct rcu_head rcu;
        struct sk_buff *skb;
        u64 timestamp;
@@ -359,7 +359,7 @@ static int mlxsw_sp_ptp_parse(struct sk_buff *skb,
 /* Returns NULL on successful insertion, a pointer on conflict, or an ERR_PTR on
  * error.
  */
-static struct mlxsw_sp1_ptp_unmatched *
+static int
 mlxsw_sp1_ptp_unmatched_save(struct mlxsw_sp *mlxsw_sp,
                             struct mlxsw_sp1_ptp_key key,
                             struct sk_buff *skb,
@@ -368,41 +368,51 @@ mlxsw_sp1_ptp_unmatched_save(struct mlxsw_sp *mlxsw_sp,
        int cycles = MLXSW_SP1_PTP_HT_GC_TIMEOUT / MLXSW_SP1_PTP_HT_GC_INTERVAL;
        struct mlxsw_sp_ptp_state *ptp_state = mlxsw_sp->ptp_state;
        struct mlxsw_sp1_ptp_unmatched *unmatched;
-       struct mlxsw_sp1_ptp_unmatched *conflict;
+       int err;
 
        unmatched = kzalloc(sizeof(*unmatched), GFP_ATOMIC);
        if (!unmatched)
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
 
        unmatched->key = key;
        unmatched->skb = skb;
        unmatched->timestamp = timestamp;
        unmatched->gc_cycle = mlxsw_sp->ptp_state->gc_cycle + cycles;
 
-       conflict = rhashtable_lookup_get_insert_fast(&ptp_state->unmatched_ht,
-                                           &unmatched->ht_node,
-                                           mlxsw_sp1_ptp_unmatched_ht_params);
-       if (conflict)
+       err = rhltable_insert(&ptp_state->unmatched_ht, &unmatched->ht_node,
+                             mlxsw_sp1_ptp_unmatched_ht_params);
+       if (err)
                kfree(unmatched);
 
-       return conflict;
+       return err;
 }
 
 static struct mlxsw_sp1_ptp_unmatched *
 mlxsw_sp1_ptp_unmatched_lookup(struct mlxsw_sp *mlxsw_sp,
-                              struct mlxsw_sp1_ptp_key key)
+                              struct mlxsw_sp1_ptp_key key, int *p_length)
 {
-       return rhashtable_lookup(&mlxsw_sp->ptp_state->unmatched_ht, &key,
-                                mlxsw_sp1_ptp_unmatched_ht_params);
+       struct mlxsw_sp1_ptp_unmatched *unmatched, *last = NULL;
+       struct rhlist_head *tmp, *list;
+       int length = 0;
+
+       list = rhltable_lookup(&mlxsw_sp->ptp_state->unmatched_ht, &key,
+                              mlxsw_sp1_ptp_unmatched_ht_params);
+       rhl_for_each_entry_rcu(unmatched, tmp, list, ht_node) {
+               last = unmatched;
+               length++;
+       }
+
+       *p_length = length;
+       return last;
 }
 
 static int
 mlxsw_sp1_ptp_unmatched_remove(struct mlxsw_sp *mlxsw_sp,
                               struct mlxsw_sp1_ptp_unmatched *unmatched)
 {
-       return rhashtable_remove_fast(&mlxsw_sp->ptp_state->unmatched_ht,
-                                     &unmatched->ht_node,
-                                     mlxsw_sp1_ptp_unmatched_ht_params);
+       return rhltable_remove(&mlxsw_sp->ptp_state->unmatched_ht,
+                              &unmatched->ht_node,
+                              mlxsw_sp1_ptp_unmatched_ht_params);
 }
 
 /* This function is called in the following scenarios:
@@ -489,75 +499,38 @@ static void mlxsw_sp1_ptp_got_piece(struct mlxsw_sp *mlxsw_sp,
                                    struct mlxsw_sp1_ptp_key key,
                                    struct sk_buff *skb, u64 timestamp)
 {
-       struct mlxsw_sp1_ptp_unmatched *unmatched, *conflict;
+       struct mlxsw_sp1_ptp_unmatched *unmatched;
+       int length;
        int err;
 
        rcu_read_lock();
 
-       unmatched = mlxsw_sp1_ptp_unmatched_lookup(mlxsw_sp, key);
-
        spin_lock(&mlxsw_sp->ptp_state->unmatched_lock);
 
-       if (unmatched) {
-               /* There was an unmatched entry when we looked, but it may have
-                * been removed before we took the lock.
-                */
-               err = mlxsw_sp1_ptp_unmatched_remove(mlxsw_sp, unmatched);
-               if (err)
-                       unmatched = NULL;
-       }
-
-       if (!unmatched) {
-               /* We have no unmatched entry, but one may have been added after
-                * we looked, but before we took the lock.
-                */
-               unmatched = mlxsw_sp1_ptp_unmatched_save(mlxsw_sp, key,
-                                                        skb, timestamp);
-               if (IS_ERR(unmatched)) {
-                       if (skb)
-                               mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb,
-                                                           key.local_port,
-                                                           key.ingress, NULL);
-                       unmatched = NULL;
-               } else if (unmatched) {
-                       /* Save just told us, under lock, that the entry is
-                        * there, so this has to work.
-                        */
-                       err = mlxsw_sp1_ptp_unmatched_remove(mlxsw_sp,
-                                                            unmatched);
-                       WARN_ON_ONCE(err);
-               }
-       }
-
-       /* If unmatched is non-NULL here, it comes either from the lookup, or
-        * from the save attempt above. In either case the entry was removed
-        * from the hash table. If unmatched is NULL, a new unmatched entry was
-        * added to the hash table, and there was no conflict.
-        */
-
+       unmatched = mlxsw_sp1_ptp_unmatched_lookup(mlxsw_sp, key, &length);
        if (skb && unmatched && unmatched->timestamp) {
                unmatched->skb = skb;
        } else if (timestamp && unmatched && unmatched->skb) {
                unmatched->timestamp = timestamp;
-       } else if (unmatched) {
-               /* unmatched holds an older entry of the same type: either an
-                * skb if we are handling skb, or a timestamp if we are handling
-                * timestamp. We can't match that up, so save what we have.
+       } else {
+               /* Either there is no entry to match, or one that is there is
+                * incompatible.
                 */
-               conflict = mlxsw_sp1_ptp_unmatched_save(mlxsw_sp, key,
-                                                       skb, timestamp);
-               if (IS_ERR(conflict)) {
-                       if (skb)
-                               mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb,
-                                                           key.local_port,
-                                                           key.ingress, NULL);
-               } else {
-                       /* Above, we removed an object with this key from the
-                        * hash table, under lock, so conflict can not be a
-                        * valid pointer.
-                        */
-                       WARN_ON_ONCE(conflict);
-               }
+               if (length < 100)
+                       err = mlxsw_sp1_ptp_unmatched_save(mlxsw_sp, key,
+                                                          skb, timestamp);
+               else
+                       err = -E2BIG;
+               if (err && skb)
+                       mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb,
+                                                   key.local_port,
+                                                   key.ingress, NULL);
+               unmatched = NULL;
+       }
+
+       if (unmatched) {
+               err = mlxsw_sp1_ptp_unmatched_remove(mlxsw_sp, unmatched);
+               WARN_ON_ONCE(err);
        }
 
        spin_unlock(&mlxsw_sp->ptp_state->unmatched_lock);
@@ -669,9 +642,8 @@ mlxsw_sp1_ptp_ht_gc_collect(struct mlxsw_sp_ptp_state *ptp_state,
        local_bh_disable();
 
        spin_lock(&ptp_state->unmatched_lock);
-       err = rhashtable_remove_fast(&ptp_state->unmatched_ht,
-                                    &unmatched->ht_node,
-                                    mlxsw_sp1_ptp_unmatched_ht_params);
+       err = rhltable_remove(&ptp_state->unmatched_ht, &unmatched->ht_node,
+                             mlxsw_sp1_ptp_unmatched_ht_params);
        spin_unlock(&ptp_state->unmatched_lock);
 
        if (err)
@@ -702,7 +674,7 @@ static void mlxsw_sp1_ptp_ht_gc(struct work_struct *work)
        ptp_state = container_of(dwork, struct mlxsw_sp_ptp_state, ht_gc_dw);
        gc_cycle = ptp_state->gc_cycle++;
 
-       rhashtable_walk_enter(&ptp_state->unmatched_ht, &iter);
+       rhltable_walk_enter(&ptp_state->unmatched_ht, &iter);
        rhashtable_walk_start(&iter);
        while ((obj = rhashtable_walk_next(&iter))) {
                if (IS_ERR(obj))
@@ -855,8 +827,8 @@ struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 
        spin_lock_init(&ptp_state->unmatched_lock);
 
-       err = rhashtable_init(&ptp_state->unmatched_ht,
-                             &mlxsw_sp1_ptp_unmatched_ht_params);
+       err = rhltable_init(&ptp_state->unmatched_ht,
+                           &mlxsw_sp1_ptp_unmatched_ht_params);
        if (err)
                goto err_hashtable_init;
 
@@ -891,7 +863,7 @@ err_fifo_clr:
 err_mtptpt1_set:
        mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0, 0);
 err_mtptpt_set:
-       rhashtable_destroy(&ptp_state->unmatched_ht);
+       rhltable_destroy(&ptp_state->unmatched_ht);
 err_hashtable_init:
        kfree(ptp_state);
        return ERR_PTR(err);
@@ -906,8 +878,8 @@ void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
        mlxsw_sp1_ptp_set_fifo_clr_on_trap(mlxsw_sp, false);
        mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1, 0);
        mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0, 0);
-       rhashtable_free_and_destroy(&ptp_state->unmatched_ht,
-                                   &mlxsw_sp1_ptp_unmatched_free_fn, NULL);
+       rhltable_free_and_destroy(&ptp_state->unmatched_ht,
+                                 &mlxsw_sp1_ptp_unmatched_free_fn, NULL);
        kfree(ptp_state);
 }
 
index 59487d4..b894bc0 100644 (file)
@@ -13,12 +13,6 @@ struct ocelot_port_block {
        struct ocelot_port *port;
 };
 
-static u16 get_prio(u32 prio)
-{
-       /* prio starts from 0x1000 while the ids starts from 0 */
-       return prio >> 16;
-}
-
 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
                                      struct ocelot_ace_rule *rule)
 {
@@ -168,7 +162,7 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
        }
 
 finished_key_parsing:
-       ocelot_rule->prio = get_prio(f->common.prio);
+       ocelot_rule->prio = f->common.prio;
        ocelot_rule->id = f->cookie;
        return ocelot_flower_parse_action(f, ocelot_rule);
 }
@@ -218,7 +212,7 @@ static int ocelot_flower_destroy(struct flow_cls_offload *f,
        struct ocelot_ace_rule rule;
        int ret;
 
-       rule.prio = get_prio(f->common.prio);
+       rule.prio = f->common.prio;
        rule.port = port_block->port;
        rule.id = f->cookie;
 
@@ -236,7 +230,7 @@ static int ocelot_flower_stats_update(struct flow_cls_offload *f,
        struct ocelot_ace_rule rule;
        int ret;
 
-       rule.prio = get_prio(f->common.prio);
+       rule.prio = f->common.prio;
        rule.port = port_block->port;
        rule.id = f->cookie;
        ret = ocelot_ace_rule_stats_update(&rule);
index d8b7fba..337b0cb 100644 (file)
@@ -3919,7 +3919,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * setup (if available). */
        status = myri10ge_request_irq(mgp);
        if (status != 0)
-               goto abort_with_firmware;
+               goto abort_with_slices;
        myri10ge_free_irq(mgp);
 
        /* Save configuration space to be restored if the
index 86e968c..124a43d 100644 (file)
@@ -93,7 +93,7 @@ nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev,
                return -EOPNOTSUPP;
        }
 
-       if (flow->common.prio != (1 << 16)) {
+       if (flow->common.prio != 1) {
                NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload requires highest priority");
                return -EOPNOTSUPP;
        }
index ef8f089..6cacd5e 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Renesas Ethernet AVB device driver
  *
- * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2014-2019 Renesas Electronics Corporation
  * Copyright (C) 2015 Renesas Solutions Corp.
  * Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com>
  *
@@ -513,7 +513,10 @@ static void ravb_get_tx_tstamp(struct net_device *ndev)
                        kfree(ts_skb);
                        if (tag == tfa_tag) {
                                skb_tstamp_tx(skb, &shhwtstamps);
+                               dev_consume_skb_any(skb);
                                break;
+                       } else {
+                               dev_kfree_skb_any(skb);
                        }
                }
                ravb_modify(ndev, TCCR, TCCR_TFR, TCCR_TFR);
@@ -1564,7 +1567,7 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                        }
                        goto unmap;
                }
-               ts_skb->skb = skb;
+               ts_skb->skb = skb_get(skb);
                ts_skb->tag = priv->ts_skb_tag++;
                priv->ts_skb_tag &= 0x3ff;
                list_add_tail(&ts_skb->list, &priv->ts_skb_list);
@@ -1693,6 +1696,7 @@ static int ravb_close(struct net_device *ndev)
        /* Clear the timestamp list */
        list_for_each_entry_safe(ts_skb, ts_skb2, &priv->ts_skb_list, list) {
                list_del(&ts_skb->list);
+               kfree_skb(ts_skb->skb);
                kfree(ts_skb);
        }
 
index 37c0bc6..6c305b6 100644 (file)
@@ -94,7 +94,7 @@ static int tc_fill_entry(struct stmmac_priv *priv,
        struct stmmac_tc_entry *entry, *frag = NULL;
        struct tc_u32_sel *sel = cls->knode.sel;
        u32 off, data, mask, real_off, rem;
-       u32 prio = cls->common.prio;
+       u32 prio = cls->common.prio << 16;
        int ret;
 
        /* Only 1 match per entry */
index 8479a44..12466a7 100644 (file)
@@ -1504,7 +1504,7 @@ tc35815_rx(struct net_device *dev, int limit)
                        pci_unmap_single(lp->pci_dev,
                                         lp->rx_skbs[cur_bd].skb_dma,
                                         RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-                       if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN)
+                       if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN != 0)
                                memmove(skb->data, skb->data - NET_IP_ALIGN,
                                        pkt_len);
                        data = skb_put(skb, pkt_len);
index 78a7de3..c62f474 100644 (file)
@@ -371,9 +371,10 @@ tsi108_stat_carry_one(int carry, int carry_bit, int carry_shift,
 static void tsi108_stat_carry(struct net_device *dev)
 {
        struct tsi108_prv_data *data = netdev_priv(dev);
+       unsigned long flags;
        u32 carry1, carry2;
 
-       spin_lock_irq(&data->misclock);
+       spin_lock_irqsave(&data->misclock, flags);
 
        carry1 = TSI_READ(TSI108_STAT_CARRY1);
        carry2 = TSI_READ(TSI108_STAT_CARRY2);
@@ -441,7 +442,7 @@ static void tsi108_stat_carry(struct net_device *dev)
                              TSI108_STAT_TXPAUSEDROP_CARRY,
                              &data->tx_pause_drop);
 
-       spin_unlock_irq(&data->misclock);
+       spin_unlock_irqrestore(&data->misclock, flags);
 }
 
 /* Read a stat counter atomically with respect to carries.
index 3544e19..e8fce6d 100644 (file)
@@ -1239,12 +1239,15 @@ static void netvsc_get_stats64(struct net_device *net,
                               struct rtnl_link_stats64 *t)
 {
        struct net_device_context *ndev_ctx = netdev_priv(net);
-       struct netvsc_device *nvdev = rcu_dereference_rtnl(ndev_ctx->nvdev);
+       struct netvsc_device *nvdev;
        struct netvsc_vf_pcpu_stats vf_tot;
        int i;
 
+       rcu_read_lock();
+
+       nvdev = rcu_dereference(ndev_ctx->nvdev);
        if (!nvdev)
-               return;
+               goto out;
 
        netdev_stats_to_stats64(t, &net->stats);
 
@@ -1283,6 +1286,8 @@ static void netvsc_get_stats64(struct net_device *net,
                t->rx_packets   += packets;
                t->multicast    += multicast;
        }
+out:
+       rcu_read_unlock();
 }
 
 static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
index c5c417a..bcc40a2 100644 (file)
@@ -73,46 +73,47 @@ static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port)
        debugfs_remove_recursive(nsim_dev_port->ddir);
 }
 
+static struct net *nsim_devlink_net(struct devlink *devlink)
+{
+       return &init_net;
+}
+
 static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv)
 {
-       struct nsim_dev *nsim_dev = priv;
+       struct net *net = priv;
 
-       return nsim_fib_get_val(nsim_dev->fib_data,
-                               NSIM_RESOURCE_IPV4_FIB, false);
+       return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false);
 }
 
 static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv)
 {
-       struct nsim_dev *nsim_dev = priv;
+       struct net *net = priv;
 
-       return nsim_fib_get_val(nsim_dev->fib_data,
-                               NSIM_RESOURCE_IPV4_FIB_RULES, false);
+       return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false);
 }
 
 static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv)
 {
-       struct nsim_dev *nsim_dev = priv;
+       struct net *net = priv;
 
-       return nsim_fib_get_val(nsim_dev->fib_data,
-                               NSIM_RESOURCE_IPV6_FIB, false);
+       return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false);
 }
 
 static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv)
 {
-       struct nsim_dev *nsim_dev = priv;
+       struct net *net = priv;
 
-       return nsim_fib_get_val(nsim_dev->fib_data,
-                               NSIM_RESOURCE_IPV6_FIB_RULES, false);
+       return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false);
 }
 
 static int nsim_dev_resources_register(struct devlink *devlink)
 {
-       struct nsim_dev *nsim_dev = devlink_priv(devlink);
        struct devlink_resource_size_params params = {
                .size_max = (u64)-1,
                .size_granularity = 1,
                .unit = DEVLINK_RESOURCE_UNIT_ENTRY
        };
+       struct net *net = nsim_devlink_net(devlink);
        int err;
        u64 n;
 
@@ -126,8 +127,7 @@ static int nsim_dev_resources_register(struct devlink *devlink)
                goto out;
        }
 
-       n = nsim_fib_get_val(nsim_dev->fib_data,
-                            NSIM_RESOURCE_IPV4_FIB, true);
+       n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true);
        err = devlink_resource_register(devlink, "fib", n,
                                        NSIM_RESOURCE_IPV4_FIB,
                                        NSIM_RESOURCE_IPV4, &params);
@@ -136,8 +136,7 @@ static int nsim_dev_resources_register(struct devlink *devlink)
                return err;
        }
 
-       n = nsim_fib_get_val(nsim_dev->fib_data,
-                            NSIM_RESOURCE_IPV4_FIB_RULES, true);
+       n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true);
        err = devlink_resource_register(devlink, "fib-rules", n,
                                        NSIM_RESOURCE_IPV4_FIB_RULES,
                                        NSIM_RESOURCE_IPV4, &params);
@@ -156,8 +155,7 @@ static int nsim_dev_resources_register(struct devlink *devlink)
                goto out;
        }
 
-       n = nsim_fib_get_val(nsim_dev->fib_data,
-                            NSIM_RESOURCE_IPV6_FIB, true);
+       n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true);
        err = devlink_resource_register(devlink, "fib", n,
                                        NSIM_RESOURCE_IPV6_FIB,
                                        NSIM_RESOURCE_IPV6, &params);
@@ -166,8 +164,7 @@ static int nsim_dev_resources_register(struct devlink *devlink)
                return err;
        }
 
-       n = nsim_fib_get_val(nsim_dev->fib_data,
-                            NSIM_RESOURCE_IPV6_FIB_RULES, true);
+       n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true);
        err = devlink_resource_register(devlink, "fib-rules", n,
                                        NSIM_RESOURCE_IPV6_FIB_RULES,
                                        NSIM_RESOURCE_IPV6, &params);
@@ -179,19 +176,19 @@ static int nsim_dev_resources_register(struct devlink *devlink)
        devlink_resource_occ_get_register(devlink,
                                          NSIM_RESOURCE_IPV4_FIB,
                                          nsim_dev_ipv4_fib_resource_occ_get,
-                                         nsim_dev);
+                                         net);
        devlink_resource_occ_get_register(devlink,
                                          NSIM_RESOURCE_IPV4_FIB_RULES,
                                          nsim_dev_ipv4_fib_rules_res_occ_get,
-                                         nsim_dev);
+                                         net);
        devlink_resource_occ_get_register(devlink,
                                          NSIM_RESOURCE_IPV6_FIB,
                                          nsim_dev_ipv6_fib_resource_occ_get,
-                                         nsim_dev);
+                                         net);
        devlink_resource_occ_get_register(devlink,
                                          NSIM_RESOURCE_IPV6_FIB_RULES,
                                          nsim_dev_ipv6_fib_rules_res_occ_get,
-                                         nsim_dev);
+                                         net);
 out:
        return err;
 }
@@ -199,11 +196,11 @@ out:
 static int nsim_dev_reload(struct devlink *devlink,
                           struct netlink_ext_ack *extack)
 {
-       struct nsim_dev *nsim_dev = devlink_priv(devlink);
        enum nsim_resource_id res_ids[] = {
                NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
                NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
        };
+       struct net *net = nsim_devlink_net(devlink);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
@@ -212,8 +209,7 @@ static int nsim_dev_reload(struct devlink *devlink,
 
                err = devlink_resource_size_get(devlink, res_ids[i], &val);
                if (!err) {
-                       err = nsim_fib_set_max(nsim_dev->fib_data,
-                                              res_ids[i], val, extack);
+                       err = nsim_fib_set_max(net, res_ids[i], val, extack);
                        if (err)
                                return err;
                }
@@ -285,15 +281,9 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
        mutex_init(&nsim_dev->port_list_lock);
        nsim_dev->fw_update_status = true;
 
-       nsim_dev->fib_data = nsim_fib_create();
-       if (IS_ERR(nsim_dev->fib_data)) {
-               err = PTR_ERR(nsim_dev->fib_data);
-               goto err_devlink_free;
-       }
-
        err = nsim_dev_resources_register(devlink);
        if (err)
-               goto err_fib_destroy;
+               goto err_devlink_free;
 
        err = devlink_register(devlink, &nsim_bus_dev->dev);
        if (err)
@@ -315,8 +305,6 @@ err_dl_unregister:
        devlink_unregister(devlink);
 err_resources_unregister:
        devlink_resources_unregister(devlink, NULL);
-err_fib_destroy:
-       nsim_fib_destroy(nsim_dev->fib_data);
 err_devlink_free:
        devlink_free(devlink);
        return ERR_PTR(err);
@@ -330,7 +318,6 @@ static void nsim_dev_destroy(struct nsim_dev *nsim_dev)
        nsim_dev_debugfs_exit(nsim_dev);
        devlink_unregister(devlink);
        devlink_resources_unregister(devlink, NULL);
-       nsim_fib_destroy(nsim_dev->fib_data);
        mutex_destroy(&nsim_dev->port_list_lock);
        devlink_free(devlink);
 }
index 8c57ba7..f61d094 100644 (file)
@@ -18,6 +18,7 @@
 #include <net/ip_fib.h>
 #include <net/ip6_fib.h>
 #include <net/fib_rules.h>
+#include <net/netns/generic.h>
 
 #include "netdevsim.h"
 
@@ -32,14 +33,15 @@ struct nsim_per_fib_data {
 };
 
 struct nsim_fib_data {
-       struct notifier_block fib_nb;
        struct nsim_per_fib_data ipv4;
        struct nsim_per_fib_data ipv6;
 };
 
-u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
-                    enum nsim_resource_id res_id, bool max)
+static unsigned int nsim_fib_net_id;
+
+u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max)
 {
+       struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id);
        struct nsim_fib_entry *entry;
 
        switch (res_id) {
@@ -62,10 +64,10 @@ u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
        return max ? entry->max : entry->num;
 }
 
-int nsim_fib_set_max(struct nsim_fib_data *fib_data,
-                    enum nsim_resource_id res_id, u64 val,
+int nsim_fib_set_max(struct net *net, enum nsim_resource_id res_id, u64 val,
                     struct netlink_ext_ack *extack)
 {
+       struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id);
        struct nsim_fib_entry *entry;
        int err = 0;
 
@@ -118,9 +120,9 @@ static int nsim_fib_rule_account(struct nsim_fib_entry *entry, bool add,
        return err;
 }
 
-static int nsim_fib_rule_event(struct nsim_fib_data *data,
-                              struct fib_notifier_info *info, bool add)
+static int nsim_fib_rule_event(struct fib_notifier_info *info, bool add)
 {
+       struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id);
        struct netlink_ext_ack *extack = info->extack;
        int err = 0;
 
@@ -155,9 +157,9 @@ static int nsim_fib_account(struct nsim_fib_entry *entry, bool add,
        return err;
 }
 
-static int nsim_fib_event(struct nsim_fib_data *data,
-                         struct fib_notifier_info *info, bool add)
+static int nsim_fib_event(struct fib_notifier_info *info, bool add)
 {
+       struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id);
        struct netlink_ext_ack *extack = info->extack;
        int err = 0;
 
@@ -176,22 +178,18 @@ static int nsim_fib_event(struct nsim_fib_data *data,
 static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event,
                             void *ptr)
 {
-       struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data,
-                                                 fib_nb);
        struct fib_notifier_info *info = ptr;
        int err = 0;
 
        switch (event) {
        case FIB_EVENT_RULE_ADD: /* fall through */
        case FIB_EVENT_RULE_DEL:
-               err = nsim_fib_rule_event(data, info,
-                                         event == FIB_EVENT_RULE_ADD);
+               err = nsim_fib_rule_event(info, event == FIB_EVENT_RULE_ADD);
                break;
 
        case FIB_EVENT_ENTRY_ADD:  /* fall through */
        case FIB_EVENT_ENTRY_DEL:
-               err = nsim_fib_event(data, info,
-                                    event == FIB_EVENT_ENTRY_ADD);
+               err = nsim_fib_event(info, event == FIB_EVENT_ENTRY_ADD);
                break;
        }
 
@@ -201,23 +199,30 @@ static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event,
 /* inconsistent dump, trying again */
 static void nsim_fib_dump_inconsistent(struct notifier_block *nb)
 {
-       struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data,
-                                                 fib_nb);
+       struct nsim_fib_data *data;
+       struct net *net;
+
+       rcu_read_lock();
+       for_each_net_rcu(net) {
+               data = net_generic(net, nsim_fib_net_id);
+
+               data->ipv4.fib.num = 0ULL;
+               data->ipv4.rules.num = 0ULL;
 
-       data->ipv4.fib.num = 0ULL;
-       data->ipv4.rules.num = 0ULL;
-       data->ipv6.fib.num = 0ULL;
-       data->ipv6.rules.num = 0ULL;
+               data->ipv6.fib.num = 0ULL;
+               data->ipv6.rules.num = 0ULL;
+       }
+       rcu_read_unlock();
 }
 
-struct nsim_fib_data *nsim_fib_create(void)
-{
-       struct nsim_fib_data *data;
-       int err;
+static struct notifier_block nsim_fib_nb = {
+       .notifier_call = nsim_fib_event_nb,
+};
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return ERR_PTR(-ENOMEM);
+/* Initialize per network namespace state */
+static int __net_init nsim_fib_netns_init(struct net *net)
+{
+       struct nsim_fib_data *data = net_generic(net, nsim_fib_net_id);
 
        data->ipv4.fib.max = (u64)-1;
        data->ipv4.rules.max = (u64)-1;
@@ -225,22 +230,37 @@ struct nsim_fib_data *nsim_fib_create(void)
        data->ipv6.fib.max = (u64)-1;
        data->ipv6.rules.max = (u64)-1;
 
-       data->fib_nb.notifier_call = nsim_fib_event_nb;
-       err = register_fib_notifier(&data->fib_nb, nsim_fib_dump_inconsistent);
-       if (err) {
-               pr_err("Failed to register fib notifier\n");
-               goto err_out;
-       }
+       return 0;
+}
 
-       return data;
+static struct pernet_operations nsim_fib_net_ops = {
+       .init = nsim_fib_netns_init,
+       .id   = &nsim_fib_net_id,
+       .size = sizeof(struct nsim_fib_data),
+};
 
-err_out:
-       kfree(data);
-       return ERR_PTR(err);
+void nsim_fib_exit(void)
+{
+       unregister_pernet_subsys(&nsim_fib_net_ops);
+       unregister_fib_notifier(&nsim_fib_nb);
 }
 
-void nsim_fib_destroy(struct nsim_fib_data *data)
+int nsim_fib_init(void)
 {
-       unregister_fib_notifier(&data->fib_nb);
-       kfree(data);
+       int err;
+
+       err = register_pernet_subsys(&nsim_fib_net_ops);
+       if (err < 0) {
+               pr_err("Failed to register pernet subsystem\n");
+               goto err_out;
+       }
+
+       err = register_fib_notifier(&nsim_fib_nb, nsim_fib_dump_inconsistent);
+       if (err < 0) {
+               pr_err("Failed to register fib notifier\n");
+               goto err_out;
+       }
+
+err_out:
+       return err;
 }
index 0740940..55f57f7 100644 (file)
@@ -357,12 +357,18 @@ static int __init nsim_module_init(void)
        if (err)
                goto err_dev_exit;
 
-       err = rtnl_link_register(&nsim_link_ops);
+       err = nsim_fib_init();
        if (err)
                goto err_bus_exit;
 
+       err = rtnl_link_register(&nsim_link_ops);
+       if (err)
+               goto err_fib_exit;
+
        return 0;
 
+err_fib_exit:
+       nsim_fib_exit();
 err_bus_exit:
        nsim_bus_exit();
 err_dev_exit:
@@ -373,6 +379,7 @@ err_dev_exit:
 static void __exit nsim_module_exit(void)
 {
        rtnl_link_unregister(&nsim_link_ops);
+       nsim_fib_exit();
        nsim_bus_exit();
        nsim_dev_exit();
 }
index 79c05af..9404637 100644 (file)
@@ -169,12 +169,10 @@ int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev,
 int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev,
                      unsigned int port_index);
 
-struct nsim_fib_data *nsim_fib_create(void);
-void nsim_fib_destroy(struct nsim_fib_data *fib_data);
-u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
-                    enum nsim_resource_id res_id, bool max);
-int nsim_fib_set_max(struct nsim_fib_data *fib_data,
-                    enum nsim_resource_id res_id, u64 val,
+int nsim_fib_init(void);
+void nsim_fib_exit(void);
+u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max);
+int nsim_fib_set_max(struct net *net, enum nsim_resource_id res_id, u64 val,
                     struct netlink_ext_ack *extack);
 
 #if IS_ENABLED(CONFIG_XFRM_OFFLOAD)
index 222ccd9..6ad8b1c 100644 (file)
@@ -257,36 +257,20 @@ static int at803x_config_init(struct phy_device *phydev)
         *   after HW reset: RX delay enabled and TX delay disabled
         *   after SW reset: RX delay enabled, while TX delay retains the
         *   value before reset.
-        *
-        * So let's first disable the RX and TX delays in PHY and enable
-        * them based on the mode selected (this also takes care of RGMII
-        * mode where we expect delays to be disabled)
         */
-
-       ret = at803x_disable_rx_delay(phydev);
-       if (ret < 0)
-               return ret;
-       ret = at803x_disable_tx_delay(phydev);
-       if (ret < 0)
-               return ret;
-
        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-           phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
-               /* If RGMII_ID or RGMII_RXID are specified enable RX delay,
-                * otherwise keep it disabled
-                */
+           phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
                ret = at803x_enable_rx_delay(phydev);
-               if (ret < 0)
-                       return ret;
-       }
+       else
+               ret = at803x_disable_rx_delay(phydev);
+       if (ret < 0)
+               return ret;
 
        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-           phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
-               /* If RGMII_ID or RGMII_TXID are specified enable TX delay,
-                * otherwise keep it disabled
-                */
+           phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
                ret = at803x_enable_tx_delay(phydev);
-       }
+       else
+               ret = at803x_disable_tx_delay(phydev);
 
        return ret;
 }
index b9d4145..58bb25e 100644 (file)
@@ -219,6 +219,20 @@ int genphy_c45_read_link(struct phy_device *phydev)
        int val, devad;
        bool link = true;
 
+       if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) {
+               val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
+               if (val < 0)
+                       return val;
+
+               /* Autoneg is being started, therefore disregard current
+                * link status and report link as down.
+                */
+               if (val & MDIO_AN_CTRL1_RESTART) {
+                       phydev->link = 0;
+                       return 0;
+               }
+       }
+
        while (mmd_mask && link) {
                devad = __ffs(mmd_mask);
                mmd_mask &= ~BIT(devad);
index 7ddd91d..27ebc2c 100644 (file)
@@ -1752,7 +1752,17 @@ EXPORT_SYMBOL(genphy_aneg_done);
  */
 int genphy_update_link(struct phy_device *phydev)
 {
-       int status;
+       int status = 0, bmcr;
+
+       bmcr = phy_read(phydev, MII_BMCR);
+       if (bmcr < 0)
+               return bmcr;
+
+       /* Autoneg is being started, therefore disregard BMSR value and
+        * report link as down.
+        */
+       if (bmcr & BMCR_ANRESTART)
+               goto done;
 
        /* The link state is latched low so that momentary link
         * drops can be detected. Do not double-read the status
index abfa0da..e8089de 100644 (file)
@@ -1004,6 +1004,8 @@ static void __team_compute_features(struct team *team)
 
        team->dev->vlan_features = vlan_features;
        team->dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
+                                    NETIF_F_HW_VLAN_CTAG_TX |
+                                    NETIF_F_HW_VLAN_STAG_TX |
                                     NETIF_F_GSO_UDP_L4;
        team->dev->hard_header_len = max_hard_header_len;
 
index 5519248..32b08b1 100644 (file)
@@ -163,7 +163,8 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        }
        if (!timeout) {
                dev_err(&udev->dev, "firmware not ready in time\n");
-               return -ETIMEDOUT;
+               ret = -ETIMEDOUT;
+               goto err;
        }
 
        /* enable ethernet mode (?) */
index d62b670..fc5895f 100644 (file)
@@ -113,16 +113,16 @@ kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr)
        status = kalmia_send_init_packet(dev, usb_buf, ARRAY_SIZE(init_msg_1),
                                         usb_buf, 24);
        if (status != 0)
-               return status;
+               goto out;
 
        memcpy(usb_buf, init_msg_2, 12);
        status = kalmia_send_init_packet(dev, usb_buf, ARRAY_SIZE(init_msg_2),
                                         usb_buf, 28);
        if (status != 0)
-               return status;
+               goto out;
 
        memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN);
-
+out:
        kfree(usb_buf);
        return status;
 }
index 3d92ea6..f033fee 100644 (file)
@@ -3792,7 +3792,7 @@ static int lan78xx_probe(struct usb_interface *intf,
        ret = register_netdev(netdev);
        if (ret != 0) {
                netif_err(dev, probe, netdev, "couldn't register the device\n");
-               goto out3;
+               goto out4;
        }
 
        usb_set_intfdata(intf, dev);
@@ -3807,12 +3807,14 @@ static int lan78xx_probe(struct usb_interface *intf,
 
        ret = lan78xx_phy_init(dev);
        if (ret < 0)
-               goto out4;
+               goto out5;
 
        return 0;
 
-out4:
+out5:
        unregister_netdev(netdev);
+out4:
+       usb_free_urb(dev->urb_intr);
 out3:
        lan78xx_unbind(dev, intf);
 out2:
index e9fc168..489cba9 100644 (file)
@@ -351,13 +351,15 @@ int i2400m_barker_db_init(const char *_options)
                        }
                        result = i2400m_barker_db_add(barker);
                        if (result < 0)
-                               goto error_add;
+                               goto error_parse_add;
                }
                kfree(options_orig);
        }
        return 0;
 
+error_parse_add:
 error_parse:
+       kfree(options_orig);
 error_add:
        kfree(i2400m_barker_db);
        return result;
index 1d9940d..c9262ff 100644 (file)
@@ -925,6 +925,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        skb_shinfo(skb)->nr_frags = MAX_SKB_FRAGS;
                        nskb = xenvif_alloc_skb(0);
                        if (unlikely(nskb == NULL)) {
+                               skb_shinfo(skb)->nr_frags = 0;
                                kfree_skb(skb);
                                xenvif_tx_err(queue, &txreq, extra_count, idx);
                                if (net_ratelimit())
@@ -940,6 +941,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
 
                        if (xenvif_set_skb_gso(queue->vif, skb, gso)) {
                                /* Failure in xenvif_set_skb_gso is fatal. */
+                               skb_shinfo(skb)->nr_frags = 0;
                                kfree_skb(skb);
                                kfree_skb(nskb);
                                break;
index c258a1c..d3d6b7b 100644 (file)
@@ -2257,6 +2257,16 @@ static const struct nvme_core_quirk_entry core_quirks[] = {
                .vid = 0x1179,
                .mn = "THNSF5256GPUK TOSHIBA",
                .quirks = NVME_QUIRK_NO_APST,
+       },
+       {
+               /*
+                * This LiteON CL1-3D*-Q11 firmware version has a race
+                * condition associated with actions related to suspend to idle
+                * LiteON has resolved the problem in future firmware
+                */
+               .vid = 0x14a4,
+               .fr = "22301111",
+               .quirks = NVME_QUIRK_SIMPLE_SUSPEND,
        }
 };
 
@@ -2597,6 +2607,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
                        goto out_free;
        }
 
+       if (!(ctrl->ops->flags & NVME_F_FABRICS))
+               ctrl->cntlid = le16_to_cpu(id->cntlid);
+
        if (!ctrl->identified) {
                int i;
 
@@ -2697,7 +2710,6 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
                        goto out_free;
                }
        } else {
-               ctrl->cntlid = le16_to_cpu(id->cntlid);
                ctrl->hmpre = le32_to_cpu(id->hmpre);
                ctrl->hmmin = le32_to_cpu(id->hmmin);
                ctrl->hmminds = le32_to_cpu(id->hmminds);
index 888d454..af831d3 100644 (file)
@@ -428,6 +428,7 @@ static void nvme_mpath_set_live(struct nvme_ns *ns)
                srcu_read_unlock(&head->srcu, srcu_idx);
        }
 
+       synchronize_srcu(&ns->head->srcu);
        kblockd_schedule_work(&ns->head->requeue_work);
 }
 
index 778b3a0..2d678fb 100644 (file)
@@ -92,6 +92,11 @@ enum nvme_quirks {
         * Broken Write Zeroes.
         */
        NVME_QUIRK_DISABLE_WRITE_ZEROES         = (1 << 9),
+
+       /*
+        * Force simple suspend/resume path.
+        */
+       NVME_QUIRK_SIMPLE_SUSPEND               = (1 << 10),
 };
 
 /*
index 6bd9b10..732d5b6 100644 (file)
@@ -2876,7 +2876,8 @@ static int nvme_suspend(struct device *dev)
         * state (which may not be possible if the link is up).
         */
        if (pm_suspend_via_firmware() || !ctrl->npss ||
-           !pcie_aspm_enabled(pdev)) {
+           !pcie_aspm_enabled(pdev) ||
+           (ndev->ctrl.quirks & NVME_QUIRK_SIMPLE_SUSPEND)) {
                nvme_dev_disable(ndev, true);
                return 0;
        }
index 208aacf..44c4ae1 100644 (file)
@@ -5256,7 +5256,7 @@ static void quirk_reset_lenovo_thinkpad_p50_nvgpu(struct pci_dev *pdev)
         */
        if (ioread32(map + 0x2240c) & 0x2) {
                pci_info(pdev, FW_BUG "GPU left initialized by EFI, resetting\n");
-               ret = pci_reset_function(pdev);
+               ret = pci_reset_bus(pdev);
                if (ret < 0)
                        pci_err(pdev, "Failed to reset GPU: %d\n", ret);
        }
index e504d25..430731c 100644 (file)
@@ -707,7 +707,7 @@ static int cros_ec_ishtp_reset(struct ishtp_cl_device *cl_device)
  */
 static int __maybe_unused cros_ec_ishtp_suspend(struct device *device)
 {
-       struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+       struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
        struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
        struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
 
@@ -722,7 +722,7 @@ static int __maybe_unused cros_ec_ishtp_suspend(struct device *device)
  */
 static int __maybe_unused cros_ec_ishtp_resume(struct device *device)
 {
-       struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+       struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
        struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
        struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
 
index 30de448..86d88ae 100644 (file)
@@ -742,6 +742,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
                                                USB_CH_IP_CUR_LVL_1P5;
                        break;
                }
+               /* Else, fall through */
        case USB_STAT_HM_IDGND:
                dev_err(di->dev, "USB Type - Charging not allowed\n");
                di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05;
index c7ee07c..28db887 100644 (file)
@@ -629,6 +629,7 @@ struct qeth_seqno {
 struct qeth_reply {
        struct list_head list;
        struct completion received;
+       spinlock_t lock;
        int (*callback)(struct qeth_card *, struct qeth_reply *,
                unsigned long);
        u32 seqno;
index 4d0caee..9c3310c 100644 (file)
@@ -544,6 +544,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
        if (reply) {
                refcount_set(&reply->refcnt, 1);
                init_completion(&reply->received);
+               spin_lock_init(&reply->lock);
        }
        return reply;
 }
@@ -799,6 +800,13 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
 
        if (!reply->callback) {
                rc = 0;
+               goto no_callback;
+       }
+
+       spin_lock_irqsave(&reply->lock, flags);
+       if (reply->rc) {
+               /* Bail out when the requestor has already left: */
+               rc = reply->rc;
        } else {
                if (cmd) {
                        reply->offset = (u16)((char *)cmd - (char *)iob->data);
@@ -807,7 +815,9 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
                        rc = reply->callback(card, reply, (unsigned long)iob);
                }
        }
+       spin_unlock_irqrestore(&reply->lock, flags);
 
+no_callback:
        if (rc <= 0)
                qeth_notify_reply(reply, rc);
        qeth_put_reply(reply);
@@ -1749,6 +1759,16 @@ static int qeth_send_control_data(struct qeth_card *card,
                rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
 
        qeth_dequeue_reply(card, reply);
+
+       if (reply_cb) {
+               /* Wait until the callback for a late reply has completed: */
+               spin_lock_irq(&reply->lock);
+               if (rc)
+                       /* Zap any callback that's still pending: */
+                       reply->rc = rc;
+               spin_unlock_irq(&reply->lock);
+       }
+
        if (!rc)
                rc = reply->rc;
        qeth_put_reply(reply);
index abcad09..f47b4b2 100644 (file)
@@ -459,6 +459,7 @@ static void sas_discover_domain(struct work_struct *work)
                pr_notice("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n");
                /* Fall through */
 #endif
+               /* Fall through - only for the #else condition above. */
        default:
                error = -ENXIO;
                pr_err("unhandled device %d\n", dev->dev_type);
index 2c3bb8a..bade2e0 100644 (file)
@@ -824,6 +824,7 @@ struct lpfc_hba {
        uint32_t cfg_cq_poll_threshold;
        uint32_t cfg_cq_max_proc_limit;
        uint32_t cfg_fcp_cpu_map;
+       uint32_t cfg_fcp_mq_threshold;
        uint32_t cfg_hdw_queue;
        uint32_t cfg_irq_chann;
        uint32_t cfg_suppress_rsp;
index ea62322..8d8c495 100644 (file)
@@ -5708,6 +5708,19 @@ LPFC_ATTR_RW(nvme_oas, 0, 0, 1,
 LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2,
             "Embed NVME Command in WQE");
 
+/*
+ * lpfc_fcp_mq_threshold: Set the maximum number of Hardware Queues
+ * the driver will advertise it supports to the SCSI layer.
+ *
+ *      0    = Set nr_hw_queues by the number of CPUs or HW queues.
+ *      1,128 = Manually specify the maximum nr_hw_queue value to be set,
+ *
+ * Value range is [0,128]. Default value is 8.
+ */
+LPFC_ATTR_R(fcp_mq_threshold, LPFC_FCP_MQ_THRESHOLD_DEF,
+           LPFC_FCP_MQ_THRESHOLD_MIN, LPFC_FCP_MQ_THRESHOLD_MAX,
+           "Set the number of SCSI Queues advertised");
+
 /*
  * lpfc_hdw_queue: Set the number of Hardware Queues the driver
  * will advertise it supports to the NVME and  SCSI layers. This also
@@ -6030,6 +6043,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_cq_poll_threshold,
        &dev_attr_lpfc_cq_max_proc_limit,
        &dev_attr_lpfc_fcp_cpu_map,
+       &dev_attr_lpfc_fcp_mq_threshold,
        &dev_attr_lpfc_hdw_queue,
        &dev_attr_lpfc_irq_chann,
        &dev_attr_lpfc_suppress_rsp,
@@ -7112,6 +7126,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        /* Initialize first burst. Target vs Initiator are different. */
        lpfc_nvme_enable_fb_init(phba, lpfc_nvme_enable_fb);
        lpfc_nvmet_fb_size_init(phba, lpfc_nvmet_fb_size);
+       lpfc_fcp_mq_threshold_init(phba, lpfc_fcp_mq_threshold);
        lpfc_hdw_queue_init(phba, lpfc_hdw_queue);
        lpfc_irq_chann_init(phba, lpfc_irq_chann);
        lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr);
index a7549ae..1ac98be 100644 (file)
@@ -4309,10 +4309,12 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        shost->max_cmd_len = 16;
 
        if (phba->sli_rev == LPFC_SLI_REV4) {
-               if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ)
-                       shost->nr_hw_queues = phba->cfg_hdw_queue;
-               else
-                       shost->nr_hw_queues = phba->sli4_hba.num_present_cpu;
+               if (!phba->cfg_fcp_mq_threshold ||
+                   phba->cfg_fcp_mq_threshold > phba->cfg_hdw_queue)
+                       phba->cfg_fcp_mq_threshold = phba->cfg_hdw_queue;
+
+               shost->nr_hw_queues = min_t(int, 2 * num_possible_nodes(),
+                                           phba->cfg_fcp_mq_threshold);
 
                shost->dma_boundary =
                        phba->sli4_hba.pc_sli4_params.sge_supp_len-1;
index 3aeca38..329f7aa 100644 (file)
 #define LPFC_HBA_HDWQ_MAX      128
 #define LPFC_HBA_HDWQ_DEF      0
 
+/* FCP MQ queue count limiting */
+#define LPFC_FCP_MQ_THRESHOLD_MIN      0
+#define LPFC_FCP_MQ_THRESHOLD_MAX      128
+#define LPFC_FCP_MQ_THRESHOLD_DEF      8
+
 /* Common buffer size to accomidate SCSI and NVME IO buffers */
 #define LPFC_COMMON_IO_BUF_SZ  768
 
index 8d560c5..6b7b390 100644 (file)
@@ -2956,6 +2956,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
        dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l,
            vha->gnl.ldma);
 
+       vha->gnl.l = NULL;
+
        vfree(vha->scan.l);
 
        if (vha->qpair && vha->qpair->vp_idx == vha->vp_idx) {
index 2e58cff..98e60a3 100644 (file)
@@ -3440,6 +3440,12 @@ skip_dpc:
        return 0;
 
 probe_failed:
+       if (base_vha->gnl.l) {
+               dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size,
+                               base_vha->gnl.l, base_vha->gnl.ldma);
+               base_vha->gnl.l = NULL;
+       }
+
        if (base_vha->timer_active)
                qla2x00_stop_timer(base_vha);
        base_vha->flags.online = 0;
@@ -3673,7 +3679,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
        if (!atomic_read(&pdev->enable_cnt)) {
                dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size,
                    base_vha->gnl.l, base_vha->gnl.ldma);
-
+               base_vha->gnl.l = NULL;
                scsi_host_put(base_vha->host);
                kfree(ha);
                pci_set_drvdata(pdev, NULL);
@@ -3713,6 +3719,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
        dma_free_coherent(&ha->pdev->dev,
                base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma);
 
+       base_vha->gnl.l = NULL;
+
        vfree(base_vha->scan.l);
 
        if (IS_QLAFX00(ha))
@@ -4816,6 +4824,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
                    "Alloc failed for scan database.\n");
                dma_free_coherent(&ha->pdev->dev, vha->gnl.size,
                    vha->gnl.l, vha->gnl.ldma);
+               vha->gnl.l = NULL;
                scsi_remove_host(vha->host);
                return NULL;
        }
index e274053..029da74 100644 (file)
@@ -7062,6 +7062,9 @@ static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
 static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
                                         struct ufs_vreg *vreg)
 {
+       if (!vreg)
+               return 0;
+
        return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
 }
 
index 04eda11..661bb93 100644 (file)
@@ -1132,14 +1132,16 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
        struct se_cmd *se_cmd = cmd->se_cmd;
        struct tcmu_dev *udev = cmd->tcmu_dev;
        bool read_len_valid = false;
-       uint32_t read_len = se_cmd->data_length;
+       uint32_t read_len;
 
        /*
         * cmd has been completed already from timeout, just reclaim
         * data area space and free cmd
         */
-       if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags))
+       if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
+               WARN_ON_ONCE(se_cmd);
                goto out;
+       }
 
        list_del_init(&cmd->queue_entry);
 
@@ -1152,6 +1154,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
                goto done;
        }
 
+       read_len = se_cmd->data_length;
        if (se_cmd->data_direction == DMA_FROM_DEVICE &&
            (entry->hdr.uflags & TCMU_UFLAG_READ_LEN) && entry->rsp.read_len) {
                read_len_valid = true;
@@ -1307,6 +1310,7 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data)
                 */
                scsi_status = SAM_STAT_CHECK_CONDITION;
                list_del_init(&cmd->queue_entry);
+               cmd->se_cmd = NULL;
        } else {
                list_del_init(&cmd->queue_entry);
                idr_remove(&udev->commands, id);
@@ -2022,6 +2026,7 @@ static void tcmu_reset_ring(struct tcmu_dev *udev, u8 err_level)
 
                idr_remove(&udev->commands, i);
                if (!test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
+                       WARN_ON(!cmd->se_cmd);
                        list_del_init(&cmd->queue_entry);
                        if (err_level == 1) {
                                /*
index 92f23e3..7cacae5 100644 (file)
@@ -858,6 +858,7 @@ static void acornfb_parse_dram(char *opt)
                case 'M':
                case 'm':
                        size *= 1024;
+                       /* Fall through */
                case 'K':
                case 'k':
                        size *= 1024;
index 4eacfb1..eb729d7 100644 (file)
@@ -168,7 +168,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
                soft_margin = new_margin;
                reload = soft_margin * (mem_fclk_21285 / 256);
                watchdog_ping();
-               /* Fall */
+               /* Fall through */
        case WDIOC_GETTIMEOUT:
                ret = put_user(soft_margin, int_arg);
                break;
index a2a8711..fd5133e 100644 (file)
@@ -74,6 +74,7 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
                        cell = rcu_dereference_raw(net->ws_cell);
                        if (cell) {
                                afs_get_cell(cell);
+                               ret = 0;
                                break;
                        }
                        ret = -EDESTADDRREQ;
@@ -108,6 +109,9 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
 
        done_seqretry(&net->cells_lock, seq);
 
+       if (ret != 0 && cell)
+               afs_put_cell(net, cell);
+
        return ret == 0 ? cell : ERR_PTR(ret);
 }
 
index 81207dc..139b4e3 100644 (file)
@@ -959,7 +959,8 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
                                 inode ? AFS_FS_I(inode) : NULL);
        } else {
                trace_afs_lookup(dvnode, &dentry->d_name,
-                                inode ? AFS_FS_I(inode) : NULL);
+                                IS_ERR_OR_NULL(inode) ? NULL
+                                : AFS_FS_I(inode));
        }
        return d;
 }
index 2575503..ca24528 100644 (file)
@@ -2171,7 +2171,7 @@ int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl
               key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
 
        size = round_up(acl->size, 4);
-       call = afs_alloc_flat_call(net, &yfs_RXYFSStoreStatus,
+       call = afs_alloc_flat_call(net, &yfs_RXYFSStoreOpaqueACL2,
                                   sizeof(__be32) * 2 +
                                   sizeof(struct yfs_xdr_YFSFid) +
                                   sizeof(__be32) + size,
index e078cc5..b3c8b88 100644 (file)
@@ -913,8 +913,9 @@ get_more_pages:
                        if (page_offset(page) >= ceph_wbc.i_size) {
                                dout("%p page eof %llu\n",
                                     page, ceph_wbc.i_size);
-                               if (ceph_wbc.size_stable ||
-                                   page_offset(page) >= i_size_read(inode))
+                               if ((ceph_wbc.size_stable ||
+                                   page_offset(page) >= i_size_read(inode)) &&
+                                   clear_page_dirty_for_io(page))
                                        mapping->a_ops->invalidatepage(page,
                                                                0, PAGE_SIZE);
                                unlock_page(page);
index d98dcd9..ce0f565 100644 (file)
@@ -1301,6 +1301,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
 {
        struct ceph_inode_info *ci = cap->ci;
        struct inode *inode = &ci->vfs_inode;
+       struct ceph_buffer *old_blob = NULL;
        struct cap_msg_args arg;
        int held, revoking;
        int wake = 0;
@@ -1365,7 +1366,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        ci->i_requested_max_size = arg.max_size;
 
        if (flushing & CEPH_CAP_XATTR_EXCL) {
-               __ceph_build_xattrs_blob(ci);
+               old_blob = __ceph_build_xattrs_blob(ci);
                arg.xattr_version = ci->i_xattrs.version;
                arg.xattr_buf = ci->i_xattrs.blob;
        } else {
@@ -1409,6 +1410,8 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
 
        spin_unlock(&ci->i_ceph_lock);
 
+       ceph_buffer_put(old_blob);
+
        ret = send_cap_msg(&arg);
        if (ret < 0) {
                dout("error sending cap msg, must requeue %p\n", inode);
index 791f84a..18500ed 100644 (file)
@@ -736,6 +736,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        int issued, new_issued, info_caps;
        struct timespec64 mtime, atime, ctime;
        struct ceph_buffer *xattr_blob = NULL;
+       struct ceph_buffer *old_blob = NULL;
        struct ceph_string *pool_ns = NULL;
        struct ceph_cap *new_cap = NULL;
        int err = 0;
@@ -881,7 +882,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        if ((ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL))  &&
            le64_to_cpu(info->xattr_version) > ci->i_xattrs.version) {
                if (ci->i_xattrs.blob)
-                       ceph_buffer_put(ci->i_xattrs.blob);
+                       old_blob = ci->i_xattrs.blob;
                ci->i_xattrs.blob = xattr_blob;
                if (xattr_blob)
                        memcpy(ci->i_xattrs.blob->vec.iov_base,
@@ -1022,8 +1023,8 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
 out:
        if (new_cap)
                ceph_put_cap(mdsc, new_cap);
-       if (xattr_blob)
-               ceph_buffer_put(xattr_blob);
+       ceph_buffer_put(old_blob);
+       ceph_buffer_put(xattr_blob);
        ceph_put_string(pool_ns);
        return err;
 }
index ac9b53b..5083e23 100644 (file)
@@ -111,8 +111,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode,
                req->r_wait_for_completion = ceph_lock_wait_for_completion;
 
        err = ceph_mdsc_do_request(mdsc, inode, req);
-
-       if (operation == CEPH_MDS_OP_GETFILELOCK) {
+       if (!err && operation == CEPH_MDS_OP_GETFILELOCK) {
                fl->fl_pid = -le64_to_cpu(req->r_reply_info.filelock_reply->pid);
                if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type)
                        fl->fl_type = F_RDLCK;
index 4c6494e..ccfcc66 100644 (file)
@@ -465,6 +465,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
        struct inode *inode = &ci->vfs_inode;
        struct ceph_cap_snap *capsnap;
        struct ceph_snap_context *old_snapc, *new_snapc;
+       struct ceph_buffer *old_blob = NULL;
        int used, dirty;
 
        capsnap = kzalloc(sizeof(*capsnap), GFP_NOFS);
@@ -541,7 +542,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
        capsnap->gid = inode->i_gid;
 
        if (dirty & CEPH_CAP_XATTR_EXCL) {
-               __ceph_build_xattrs_blob(ci);
+               old_blob = __ceph_build_xattrs_blob(ci);
                capsnap->xattr_blob =
                        ceph_buffer_get(ci->i_xattrs.blob);
                capsnap->xattr_version = ci->i_xattrs.version;
@@ -584,6 +585,7 @@ update_snapc:
        }
        spin_unlock(&ci->i_ceph_lock);
 
+       ceph_buffer_put(old_blob);
        kfree(capsnap);
        ceph_put_snap_context(old_snapc);
 }
index d2352fd..6b9f1ee 100644 (file)
@@ -926,7 +926,7 @@ extern int ceph_getattr(const struct path *path, struct kstat *stat,
 int __ceph_setxattr(struct inode *, const char *, const void *, size_t, int);
 ssize_t __ceph_getxattr(struct inode *, const char *, void *, size_t);
 extern ssize_t ceph_listxattr(struct dentry *, char *, size_t);
-extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci);
+extern struct ceph_buffer *__ceph_build_xattrs_blob(struct ceph_inode_info *ci);
 extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
 extern const struct xattr_handler *ceph_xattr_handlers[];
 
index 37b458a..939eab7 100644 (file)
@@ -754,12 +754,15 @@ static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size,
 
 /*
  * If there are dirty xattrs, reencode xattrs into the prealloc_blob
- * and swap into place.
+ * and swap into place.  It returns the old i_xattrs.blob (or NULL) so
+ * that it can be freed by the caller as the i_ceph_lock is likely to be
+ * held.
  */
-void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
+struct ceph_buffer *__ceph_build_xattrs_blob(struct ceph_inode_info *ci)
 {
        struct rb_node *p;
        struct ceph_inode_xattr *xattr = NULL;
+       struct ceph_buffer *old_blob = NULL;
        void *dest;
 
        dout("__build_xattrs_blob %p\n", &ci->vfs_inode);
@@ -790,12 +793,14 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
                        dest - ci->i_xattrs.prealloc_blob->vec.iov_base;
 
                if (ci->i_xattrs.blob)
-                       ceph_buffer_put(ci->i_xattrs.blob);
+                       old_blob = ci->i_xattrs.blob;
                ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob;
                ci->i_xattrs.prealloc_blob = NULL;
                ci->i_xattrs.dirty = false;
                ci->i_xattrs.version++;
        }
+
+       return old_blob;
 }
 
 static inline int __get_request_mask(struct inode *in) {
@@ -1036,6 +1041,7 @@ int __ceph_setxattr(struct inode *inode, const char *name,
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_cap_flush *prealloc_cf = NULL;
+       struct ceph_buffer *old_blob = NULL;
        int issued;
        int err;
        int dirty = 0;
@@ -1109,13 +1115,15 @@ retry:
                struct ceph_buffer *blob;
 
                spin_unlock(&ci->i_ceph_lock);
-               dout(" preaallocating new blob size=%d\n", required_blob_size);
+               ceph_buffer_put(old_blob); /* Shouldn't be required */
+               dout(" pre-allocating new blob size=%d\n", required_blob_size);
                blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
                if (!blob)
                        goto do_sync_unlocked;
                spin_lock(&ci->i_ceph_lock);
+               /* prealloc_blob can't be released while holding i_ceph_lock */
                if (ci->i_xattrs.prealloc_blob)
-                       ceph_buffer_put(ci->i_xattrs.prealloc_blob);
+                       old_blob = ci->i_xattrs.prealloc_blob;
                ci->i_xattrs.prealloc_blob = blob;
                goto retry;
        }
@@ -1131,6 +1139,7 @@ retry:
        }
 
        spin_unlock(&ci->i_ceph_lock);
+       ceph_buffer_put(old_blob);
        if (lock_snap_rwsem)
                up_read(&mdsc->snap_rwsem);
        if (dirty)
index a15a6e7..1795e80 100644 (file)
@@ -1113,7 +1113,7 @@ cifs_demultiplex_thread(void *p)
                mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
 
        set_freezable();
-       allow_signal(SIGKILL);
+       allow_kernel_signal(SIGKILL);
        while (server->tcpStatus != CifsExiting) {
                if (try_to_freeze())
                        continue;
index 24bbe3c..cfb48bd 100644 (file)
@@ -679,6 +679,13 @@ static void io_put_req(struct io_kiocb *req)
                io_free_req(req);
 }
 
+static unsigned io_cqring_events(struct io_cq_ring *ring)
+{
+       /* See comment at the top of this file */
+       smp_rmb();
+       return READ_ONCE(ring->r.tail) - READ_ONCE(ring->r.head);
+}
+
 /*
  * Find and free completed poll iocbs
  */
@@ -771,7 +778,7 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
 static int io_iopoll_getevents(struct io_ring_ctx *ctx, unsigned int *nr_events,
                                long min)
 {
-       while (!list_empty(&ctx->poll_list)) {
+       while (!list_empty(&ctx->poll_list) && !need_resched()) {
                int ret;
 
                ret = io_do_iopoll(ctx, nr_events, min);
@@ -798,6 +805,12 @@ static void io_iopoll_reap_events(struct io_ring_ctx *ctx)
                unsigned int nr_events = 0;
 
                io_iopoll_getevents(ctx, &nr_events, 1);
+
+               /*
+                * Ensure we allow local-to-the-cpu processing to take place,
+                * in this case we need to ensure that we reap all events.
+                */
+               cond_resched();
        }
        mutex_unlock(&ctx->uring_lock);
 }
@@ -805,11 +818,42 @@ static void io_iopoll_reap_events(struct io_ring_ctx *ctx)
 static int io_iopoll_check(struct io_ring_ctx *ctx, unsigned *nr_events,
                           long min)
 {
-       int ret = 0;
+       int iters, ret = 0;
 
+       /*
+        * We disallow the app entering submit/complete with polling, but we
+        * still need to lock the ring to prevent racing with polled issue
+        * that got punted to a workqueue.
+        */
+       mutex_lock(&ctx->uring_lock);
+
+       iters = 0;
        do {
                int tmin = 0;
 
+               /*
+                * Don't enter poll loop if we already have events pending.
+                * If we do, we can potentially be spinning for commands that
+                * already triggered a CQE (eg in error).
+                */
+               if (io_cqring_events(ctx->cq_ring))
+                       break;
+
+               /*
+                * If a submit got punted to a workqueue, we can have the
+                * application entering polling for a command before it gets
+                * issued. That app will hold the uring_lock for the duration
+                * of the poll right here, so we need to take a breather every
+                * now and then to ensure that the issue has a chance to add
+                * the poll to the issued list. Otherwise we can spin here
+                * forever, while the workqueue is stuck trying to acquire the
+                * very same mutex.
+                */
+               if (!(++iters & 7)) {
+                       mutex_unlock(&ctx->uring_lock);
+                       mutex_lock(&ctx->uring_lock);
+               }
+
                if (*nr_events < min)
                        tmin = min - *nr_events;
 
@@ -819,6 +863,7 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, unsigned *nr_events,
                ret = 0;
        } while (min && !*nr_events && !need_resched());
 
+       mutex_unlock(&ctx->uring_lock);
        return ret;
 }
 
@@ -2280,15 +2325,7 @@ static int io_sq_thread(void *data)
                        unsigned nr_events = 0;
 
                        if (ctx->flags & IORING_SETUP_IOPOLL) {
-                               /*
-                                * We disallow the app entering submit/complete
-                                * with polling, but we still need to lock the
-                                * ring to prevent racing with polled issue
-                                * that got punted to a workqueue.
-                                */
-                               mutex_lock(&ctx->uring_lock);
                                io_iopoll_check(ctx, &nr_events, 0);
-                               mutex_unlock(&ctx->uring_lock);
                        } else {
                                /*
                                 * Normal IO, just pretend everything completed.
@@ -2433,13 +2470,6 @@ static int io_ring_submit(struct io_ring_ctx *ctx, unsigned int to_submit)
        return submit;
 }
 
-static unsigned io_cqring_events(struct io_cq_ring *ring)
-{
-       /* See comment at the top of this file */
-       smp_rmb();
-       return READ_ONCE(ring->r.tail) - READ_ONCE(ring->r.head);
-}
-
 /*
  * Wait until events become available, if we don't already have some. The
  * application must reap them itself, as they reside on the shared cq ring.
@@ -3190,9 +3220,7 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
                min_complete = min(min_complete, ctx->cq_entries);
 
                if (ctx->flags & IORING_SETUP_IOPOLL) {
-                       mutex_lock(&ctx->uring_lock);
                        ret = io_iopoll_check(ctx, &nr_events, min_complete);
-                       mutex_unlock(&ctx->uring_lock);
                } else {
                        ret = io_cqring_wait(ctx, min_complete, sig, sigsz);
                }
index 26ad75a..96352ab 100644 (file)
@@ -571,7 +571,7 @@ nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *data)
  */
 static int nfsd_reply_cache_stats_show(struct seq_file *m, void *v)
 {
-       struct nfsd_net *nn = v;
+       struct nfsd_net *nn = m->private;
 
        seq_printf(m, "max entries:           %u\n", nn->max_drc_entries);
        seq_printf(m, "num entries:           %u\n",
index 13c5487..3cf4f6a 100644 (file)
@@ -1171,13 +1171,17 @@ static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode)
        return inode;
 }
 
-static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode, struct nfsdfs_client *ncl)
 {
        struct inode *inode;
 
        inode = nfsd_get_inode(dir->i_sb, mode);
        if (!inode)
                return -ENOMEM;
+       if (ncl) {
+               inode->i_private = ncl;
+               kref_get(&ncl->cl_ref);
+       }
        d_add(dentry, inode);
        inc_nlink(dir);
        fsnotify_mkdir(dir, dentry);
@@ -1194,17 +1198,14 @@ static struct dentry *nfsd_mkdir(struct dentry *parent, struct nfsdfs_client *nc
        dentry = d_alloc_name(parent, name);
        if (!dentry)
                goto out_err;
-       ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600);
+       ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600, ncl);
        if (ret)
                goto out_err;
-       if (ncl) {
-               d_inode(dentry)->i_private = ncl;
-               kref_get(&ncl->cl_ref);
-       }
 out:
        inode_unlock(dir);
        return dentry;
 out_err:
+       dput(dentry);
        dentry = ERR_PTR(ret);
        goto out;
 }
@@ -1214,11 +1215,9 @@ static void clear_ncl(struct inode *inode)
        struct nfsdfs_client *ncl = inode->i_private;
 
        inode->i_private = NULL;
-       synchronize_rcu();
        kref_put(&ncl->cl_ref, ncl->cl_release);
 }
 
-
 static struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode)
 {
        struct nfsdfs_client *nc = inode->i_private;
@@ -1232,9 +1231,9 @@ struct nfsdfs_client *get_nfsdfs_client(struct inode *inode)
 {
        struct nfsdfs_client *nc;
 
-       rcu_read_lock();
+       inode_lock_shared(inode);
        nc = __get_nfsdfs_client(inode);
-       rcu_read_unlock();
+       inode_unlock_shared(inode);
        return nc;
 }
 /* from __rpc_unlink */
index 1f5088d..5bbf587 100644 (file)
@@ -1811,10 +1811,7 @@ static int generic_remap_check_len(struct inode *inode_in,
        return (remap_flags & REMAP_FILE_DEDUP) ? -EBADE : -EINVAL;
 }
 
-/*
- * Read a page's worth of file data into the page cache.  Return the page
- * locked.
- */
+/* Read a page's worth of file data into the page cache. */
 static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset)
 {
        struct page *page;
@@ -1826,10 +1823,32 @@ static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset)
                put_page(page);
                return ERR_PTR(-EIO);
        }
-       lock_page(page);
        return page;
 }
 
+/*
+ * Lock two pages, ensuring that we lock in offset order if the pages are from
+ * the same file.
+ */
+static void vfs_lock_two_pages(struct page *page1, struct page *page2)
+{
+       /* Always lock in order of increasing index. */
+       if (page1->index > page2->index)
+               swap(page1, page2);
+
+       lock_page(page1);
+       if (page1 != page2)
+               lock_page(page2);
+}
+
+/* Unlock two pages, being careful not to unlock the same page twice. */
+static void vfs_unlock_two_pages(struct page *page1, struct page *page2)
+{
+       unlock_page(page1);
+       if (page1 != page2)
+               unlock_page(page2);
+}
+
 /*
  * Compare extents of two files to see if they are the same.
  * Caller must have locked both inodes to prevent write races.
@@ -1867,10 +1886,24 @@ static int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
                dest_page = vfs_dedupe_get_page(dest, destoff);
                if (IS_ERR(dest_page)) {
                        error = PTR_ERR(dest_page);
-                       unlock_page(src_page);
                        put_page(src_page);
                        goto out_error;
                }
+
+               vfs_lock_two_pages(src_page, dest_page);
+
+               /*
+                * Now that we've locked both pages, make sure they're still
+                * mapped to the file data we're interested in.  If not,
+                * someone is invalidating pages on us and we lose.
+                */
+               if (!PageUptodate(src_page) || !PageUptodate(dest_page) ||
+                   src_page->mapping != src->i_mapping ||
+                   dest_page->mapping != dest->i_mapping) {
+                       same = false;
+                       goto unlock;
+               }
+
                src_addr = kmap_atomic(src_page);
                dest_addr = kmap_atomic(dest_page);
 
@@ -1882,8 +1915,8 @@ static int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
 
                kunmap_atomic(dest_addr);
                kunmap_atomic(src_addr);
-               unlock_page(dest_page);
-               unlock_page(src_page);
+unlock:
+               vfs_unlock_two_pages(src_page, dest_page);
                put_page(dest_page);
                put_page(src_page);
 
index 80d7301..c0b84e9 100644 (file)
@@ -51,7 +51,7 @@
 static void shrink_liability(struct ubifs_info *c, int nr_to_write)
 {
        down_read(&c->vfs_sb->s_umount);
-       writeback_inodes_sb(c->vfs_sb, WB_REASON_FS_FREE_SPACE);
+       writeback_inodes_sb_nr(c->vfs_sb, nr_to_write, WB_REASON_FS_FREE_SPACE);
        up_read(&c->vfs_sb->s_umount);
 }
 
index b52624e..3b4b411 100644 (file)
@@ -129,7 +129,6 @@ static void __orphan_drop(struct ubifs_info *c, struct ubifs_orphan *o)
 static void orphan_delete(struct ubifs_info *c, struct ubifs_orphan *orph)
 {
        if (orph->del) {
-               spin_unlock(&c->orphan_lock);
                dbg_gen("deleted twice ino %lu", orph->inum);
                return;
        }
@@ -138,7 +137,6 @@ static void orphan_delete(struct ubifs_info *c, struct ubifs_orphan *orph)
                orph->del = 1;
                orph->dnext = c->orph_dnext;
                c->orph_dnext = orph;
-               spin_unlock(&c->orphan_lock);
                dbg_gen("delete later ino %lu", orph->inum);
                return;
        }
index 2c0803b..8c1d571 100644 (file)
@@ -609,6 +609,10 @@ static int init_constants_early(struct ubifs_info *c)
        c->max_bu_buf_len = UBIFS_MAX_BULK_READ * UBIFS_MAX_DATA_NODE_SZ;
        if (c->max_bu_buf_len > c->leb_size)
                c->max_bu_buf_len = c->leb_size;
+
+       /* Log is ready, preserve one LEB for commits. */
+       c->min_log_bytes = c->leb_size;
+
        return 0;
 }
 
index ccbdbd6..fe6d804 100644 (file)
@@ -880,6 +880,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
        /* len == 0 means wake all */
        struct userfaultfd_wake_range range = { .len = 0, };
        unsigned long new_flags;
+       bool still_valid;
 
        WRITE_ONCE(ctx->released, true);
 
@@ -895,8 +896,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
         * taking the mmap_sem for writing.
         */
        down_write(&mm->mmap_sem);
-       if (!mmget_still_valid(mm))
-               goto skip_mm;
+       still_valid = mmget_still_valid(mm);
        prev = NULL;
        for (vma = mm->mmap; vma; vma = vma->vm_next) {
                cond_resched();
@@ -907,19 +907,20 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
                        continue;
                }
                new_flags = vma->vm_flags & ~(VM_UFFD_MISSING | VM_UFFD_WP);
-               prev = vma_merge(mm, prev, vma->vm_start, vma->vm_end,
-                                new_flags, vma->anon_vma,
-                                vma->vm_file, vma->vm_pgoff,
-                                vma_policy(vma),
-                                NULL_VM_UFFD_CTX);
-               if (prev)
-                       vma = prev;
-               else
-                       prev = vma;
+               if (still_valid) {
+                       prev = vma_merge(mm, prev, vma->vm_start, vma->vm_end,
+                                        new_flags, vma->anon_vma,
+                                        vma->vm_file, vma->vm_pgoff,
+                                        vma_policy(vma),
+                                        NULL_VM_UFFD_CTX);
+                       if (prev)
+                               vma = prev;
+                       else
+                               prev = vma;
+               }
                vma->vm_flags = new_flags;
                vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
        }
-skip_mm:
        up_write(&mm->mmap_sem);
        mmput(mm);
 wakeup:
index 7fcf756..7bd7534 100644 (file)
@@ -547,63 +547,12 @@ xfs_file_compat_ioctl(
        struct inode            *inode = file_inode(filp);
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
-       void                    __user *arg = (void __user *)p;
+       void                    __user *arg = compat_ptr(p);
        int                     error;
 
        trace_xfs_file_compat_ioctl(ip);
 
        switch (cmd) {
-       /* No size or alignment issues on any arch */
-       case XFS_IOC_DIOINFO:
-       case XFS_IOC_FSGEOMETRY_V4:
-       case XFS_IOC_FSGEOMETRY:
-       case XFS_IOC_AG_GEOMETRY:
-       case XFS_IOC_FSGETXATTR:
-       case XFS_IOC_FSSETXATTR:
-       case XFS_IOC_FSGETXATTRA:
-       case XFS_IOC_FSSETDM:
-       case XFS_IOC_GETBMAP:
-       case XFS_IOC_GETBMAPA:
-       case XFS_IOC_GETBMAPX:
-       case XFS_IOC_FSCOUNTS:
-       case XFS_IOC_SET_RESBLKS:
-       case XFS_IOC_GET_RESBLKS:
-       case XFS_IOC_FSGROWFSLOG:
-       case XFS_IOC_GOINGDOWN:
-       case XFS_IOC_ERROR_INJECTION:
-       case XFS_IOC_ERROR_CLEARALL:
-       case FS_IOC_GETFSMAP:
-       case XFS_IOC_SCRUB_METADATA:
-       case XFS_IOC_BULKSTAT:
-       case XFS_IOC_INUMBERS:
-               return xfs_file_ioctl(filp, cmd, p);
-#if !defined(BROKEN_X86_ALIGNMENT) || defined(CONFIG_X86_X32)
-       /*
-        * These are handled fine if no alignment issues.  To support x32
-        * which uses native 64-bit alignment we must emit these cases in
-        * addition to the ia-32 compat set below.
-        */
-       case XFS_IOC_ALLOCSP:
-       case XFS_IOC_FREESP:
-       case XFS_IOC_RESVSP:
-       case XFS_IOC_UNRESVSP:
-       case XFS_IOC_ALLOCSP64:
-       case XFS_IOC_FREESP64:
-       case XFS_IOC_RESVSP64:
-       case XFS_IOC_UNRESVSP64:
-       case XFS_IOC_FSGEOMETRY_V1:
-       case XFS_IOC_FSGROWFSDATA:
-       case XFS_IOC_FSGROWFSRT:
-       case XFS_IOC_ZERO_RANGE:
-#ifdef CONFIG_X86_X32
-       /*
-        * x32 special: this gets a different cmd number from the ia-32 compat
-        * case below; the associated data will match native 64-bit alignment.
-        */
-       case XFS_IOC_SWAPEXT:
-#endif
-               return xfs_file_ioctl(filp, cmd, p);
-#endif
 #if defined(BROKEN_X86_ALIGNMENT)
        case XFS_IOC_ALLOCSP_32:
        case XFS_IOC_FREESP_32:
@@ -705,6 +654,7 @@ xfs_file_compat_ioctl(
        case XFS_IOC_FSSETDM_BY_HANDLE_32:
                return xfs_compat_fssetdm_by_handle(filp, arg);
        default:
-               return -ENOIOCTLCMD;
+               /* try the native version */
+               return xfs_file_ioctl(filp, cmd, (unsigned long)arg);
        }
 }
index ff3c1fa..fe285d1 100644 (file)
@@ -793,6 +793,7 @@ xfs_setattr_nonsize(
 
 out_cancel:
        xfs_trans_cancel(tp);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
 out_dqrele:
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
index 0c954ca..a339bd5 100644 (file)
@@ -32,7 +32,7 @@ xfs_break_leased_layouts(
        struct xfs_inode        *ip = XFS_I(inode);
        int                     error;
 
-       while ((error = break_layout(inode, false) == -EWOULDBLOCK)) {
+       while ((error = break_layout(inode, false)) == -EWOULDBLOCK) {
                xfs_iunlock(ip, *iolock);
                *did_unlock = true;
                error = break_layout(inode, true);
index c4ec7af..edbe37b 100644 (file)
@@ -1190,11 +1190,11 @@ xfs_reflink_remap_blocks(
 }
 
 /*
- * Grab the exclusive iolock for a data copy from src to dest, making
- * sure to abide vfs locking order (lowest pointer value goes first) and
- * breaking the pnfs layout leases on dest before proceeding.  The loop
- * is needed because we cannot call the blocking break_layout() with the
- * src iolock held, and therefore have to back out both locks.
+ * Grab the exclusive iolock for a data copy from src to dest, making sure to
+ * abide vfs locking order (lowest pointer value goes first) and breaking the
+ * layout leases before proceeding.  The loop is needed because we cannot call
+ * the blocking break_layout() with the iolocks held, and therefore have to
+ * back out both locks.
  */
 static int
 xfs_iolock_two_inodes_and_break_layout(
@@ -1203,33 +1203,44 @@ xfs_iolock_two_inodes_and_break_layout(
 {
        int                     error;
 
-retry:
-       if (src < dest) {
-               inode_lock_shared(src);
-               inode_lock_nested(dest, I_MUTEX_NONDIR2);
-       } else {
-               /* src >= dest */
-               inode_lock(dest);
-       }
+       if (src > dest)
+               swap(src, dest);
 
-       error = break_layout(dest, false);
-       if (error == -EWOULDBLOCK) {
-               inode_unlock(dest);
-               if (src < dest)
-                       inode_unlock_shared(src);
+retry:
+       /* Wait to break both inodes' layouts before we start locking. */
+       error = break_layout(src, true);
+       if (error)
+               return error;
+       if (src != dest) {
                error = break_layout(dest, true);
                if (error)
                        return error;
-               goto retry;
        }
+
+       /* Lock one inode and make sure nobody got in and leased it. */
+       inode_lock(src);
+       error = break_layout(src, false);
        if (error) {
+               inode_unlock(src);
+               if (error == -EWOULDBLOCK)
+                       goto retry;
+               return error;
+       }
+
+       if (src == dest)
+               return 0;
+
+       /* Lock the other inode and make sure nobody got in and leased it. */
+       inode_lock_nested(dest, I_MUTEX_NONDIR2);
+       error = break_layout(dest, false);
+       if (error) {
+               inode_unlock(src);
                inode_unlock(dest);
-               if (src < dest)
-                       inode_unlock_shared(src);
+               if (error == -EWOULDBLOCK)
+                       goto retry;
                return error;
        }
-       if (src > dest)
-               inode_lock_shared_nested(src, I_MUTEX_NONDIR2);
+
        return 0;
 }
 
@@ -1247,10 +1258,10 @@ xfs_reflink_remap_unlock(
 
        xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
        if (!same_inode)
-               xfs_iunlock(src, XFS_MMAPLOCK_SHARED);
+               xfs_iunlock(src, XFS_MMAPLOCK_EXCL);
        inode_unlock(inode_out);
        if (!same_inode)
-               inode_unlock_shared(inode_in);
+               inode_unlock(inode_in);
 }
 
 /*
@@ -1325,7 +1336,7 @@ xfs_reflink_remap_prep(
        if (same_inode)
                xfs_ilock(src, XFS_MMAPLOCK_EXCL);
        else
-               xfs_lock_two_inodes(src, XFS_MMAPLOCK_SHARED, dest,
+               xfs_lock_two_inodes(src, XFS_MMAPLOCK_EXCL, dest,
                                XFS_MMAPLOCK_EXCL);
 
        /* Check file eligibility and prepare for block sharing. */
index 5e58bb2..11cdc7c 100644 (file)
@@ -30,7 +30,8 @@ static inline struct ceph_buffer *ceph_buffer_get(struct ceph_buffer *b)
 
 static inline void ceph_buffer_put(struct ceph_buffer *b)
 {
-       kref_put(&b->kref, ceph_buffer_release);
+       if (b)
+               kref_put(&b->kref, ceph_buffer_release);
 }
 
 extern int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end);
index c05d4e6..03f8e98 100644 (file)
@@ -160,10 +160,7 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
 static inline struct page *dma_alloc_contiguous(struct device *dev, size_t size,
                gfp_t gfp)
 {
-       int node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
-       size_t align = get_order(PAGE_ALIGN(size));
-
-       return alloc_pages_node(node, gfp, align);
+       return NULL;
 }
 
 static inline void dma_free_contiguous(struct device *dev, struct page *page,
index 40915b4..f757a58 100644 (file)
@@ -241,30 +241,6 @@ static inline int irq_to_gpio(unsigned irq)
        return -EINVAL;
 }
 
-static inline int
-gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
-                      unsigned int gpio_offset, unsigned int pin_offset,
-                      unsigned int npins)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-static inline int
-gpiochip_add_pingroup_range(struct gpio_chip *chip,
-                       struct pinctrl_dev *pctldev,
-                       unsigned int gpio_offset, const char *pin_group)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-static inline void
-gpiochip_remove_pin_ranges(struct gpio_chip *chip)
-{
-       WARN_ON(1);
-}
-
 static inline int devm_gpio_request(struct device *dev, unsigned gpio,
                                    const char *label)
 {
index 91f391c..5002833 100644 (file)
@@ -94,11 +94,11 @@ struct keyring_index_key {
        union {
                struct {
 #ifdef __LITTLE_ENDIAN /* Put desc_len at the LSB of x */
-                       u     desc_len;
-                       char    desc[sizeof(long) - 1]; /* First few chars of description */
+                       u16     desc_len;
+                       char    desc[sizeof(long) - 2]; /* First few chars of description */
 #else
-                       char    desc[sizeof(long) - 1]; /* First few chars of description */
-                       u     desc_len;
+                       char    desc[sizeof(long) - 2]; /* First few chars of description */
+                       u16     desc_len;
 #endif
                };
                unsigned long x;
index ce9839c..c2f056b 100644 (file)
@@ -446,11 +446,11 @@ enum {
 };
 
 enum {
-       MLX5_OPC_MOD_TLS_TIS_STATIC_PARAMS = 0x20,
+       MLX5_OPC_MOD_TLS_TIS_STATIC_PARAMS = 0x1,
 };
 
 enum {
-       MLX5_OPC_MOD_TLS_TIS_PROGRESS_PARAMS = 0x20,
+       MLX5_OPC_MOD_TLS_TIS_PROGRESS_PARAMS = 0x1,
 };
 
 enum {
index ec571fd..b8b570c 100644 (file)
@@ -10054,9 +10054,8 @@ struct mlx5_ifc_tls_static_params_bits {
 };
 
 struct mlx5_ifc_tls_progress_params_bits {
-       u8         valid[0x1];
-       u8         reserved_at_1[0x7];
-       u8         pd[0x18];
+       u8         reserved_at_0[0x8];
+       u8         tisn[0x18];
 
        u8         next_record_tcp_sn[0x20];
 
index b5d9948..1a5f883 100644 (file)
@@ -282,6 +282,9 @@ extern void signal_setup_done(int failed, struct ksignal *ksig, int stepping);
 extern void exit_signals(struct task_struct *tsk);
 extern void kernel_sigaction(int, __sighandler_t);
 
+#define SIG_KTHREAD ((__force __sighandler_t)2)
+#define SIG_KTHREAD_KERNEL ((__force __sighandler_t)3)
+
 static inline void allow_signal(int sig)
 {
        /*
@@ -289,7 +292,17 @@ static inline void allow_signal(int sig)
         * know it'll be handled, so that they don't get converted to
         * SIGKILL or just silently dropped.
         */
-       kernel_sigaction(sig, (__force __sighandler_t)2);
+       kernel_sigaction(sig, SIG_KTHREAD);
+}
+
+static inline void allow_kernel_signal(int sig)
+{
+       /*
+        * Kernel threads handle their own signals. Let the signal code
+        * know signals sent by the kernel will be handled, so that they
+        * don't get silently dropped.
+        */
+       kernel_sigaction(sig, SIG_KTHREAD_KERNEL);
 }
 
 static inline void disallow_signal(int sig)
index d8af86d..ba55835 100644 (file)
@@ -1374,6 +1374,14 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
        to->l4_hash = from->l4_hash;
 };
 
+static inline void skb_copy_decrypted(struct sk_buff *to,
+                                     const struct sk_buff *from)
+{
+#ifdef CONFIG_TLS_DEVICE
+       to->decrypted = from->decrypted;
+#endif
+}
+
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 {
index 9752381..fc0bed5 100644 (file)
@@ -292,6 +292,9 @@ struct ucred {
 #define MSG_BATCH      0x40000 /* sendmmsg(): more messages coming */
 #define MSG_EOF         MSG_FIN
 #define MSG_NO_SHARED_FRAGS 0x80000 /* sendpage() internal : page frags are not shared */
+#define MSG_SENDPAGE_DECRYPTED 0x100000 /* sendpage() internal : page may carry
+                                         * plain text and require encryption
+                                         */
 
 #define MSG_ZEROCOPY   0x4000000       /* Use user data in kernel path */
 #define MSG_FASTOPEN   0x20000000      /* Send data in TCP SYN */
index 7acb953..84ff284 100644 (file)
@@ -57,6 +57,7 @@ struct tk_read_base {
  * @cs_was_changed_seq:        The sequence number of clocksource change events
  * @next_leap_ktime:   CLOCK_MONOTONIC time value of a pending leap-second
  * @raw_sec:           CLOCK_MONOTONIC_RAW  time in seconds
+ * @monotonic_to_boot: CLOCK_MONOTONIC to CLOCK_BOOTTIME offset
  * @cycle_interval:    Number of clock cycles in one NTP interval
  * @xtime_interval:    Number of clock shifted nano seconds in one NTP
  *                     interval.
@@ -84,6 +85,9 @@ struct tk_read_base {
  *
  * wall_to_monotonic is no longer the boot time, getboottime must be
  * used instead.
+ *
+ * @monotonic_to_boottime is a timespec64 representation of @offs_boot to
+ * accelerate the VDSO update for CLOCK_BOOTTIME.
  */
 struct timekeeper {
        struct tk_read_base     tkr_mono;
@@ -99,6 +103,7 @@ struct timekeeper {
        u8                      cs_was_changed_seq;
        ktime_t                 next_leap_ktime;
        u64                     raw_sec;
+       struct timespec64       monotonic_to_boot;
 
        /* The following members are for timekeeping internal use */
        u64                     cycle_interval;
index ded574b..ffc95b3 100644 (file)
@@ -278,6 +278,7 @@ struct hci_dev {
        __u16           conn_info_min_age;
        __u16           conn_info_max_age;
        __u16           auth_payload_timeout;
+       __u8            min_enc_key_size;
        __u8            ssp_debug_mode;
        __u8            hw_error_code;
        __u32           clock;
index 010f26b..bac79e8 100644 (file)
@@ -171,7 +171,7 @@ int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb,
 void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb,
                              struct sk_buff *parent);
 void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
-                           void *reasm_data);
+                           void *reasm_data, bool try_coalesce);
 struct sk_buff *inet_frag_pull_head(struct inet_frag_queue *q);
 
 #endif
index 4a9da95..cb668bc 100644 (file)
@@ -61,7 +61,6 @@ struct net {
        spinlock_t              rules_mod_lock;
 
        u32                     hash_mix;
-       atomic64_t              cookie_gen;
 
        struct list_head        list;           /* list of network namespaces */
        struct list_head        exit_list;      /* To linked to call pernet exit
index 9b62456..475d6f2 100644 (file)
@@ -421,8 +421,7 @@ struct nft_set {
        unsigned char                   *udata;
        /* runtime data below here */
        const struct nft_set_ops        *ops ____cacheline_aligned;
-       u16                             flags:13,
-                                       bound:1,
+       u16                             flags:14,
                                        genmask:2;
        u8                              klen;
        u8                              dlen;
@@ -1348,12 +1347,15 @@ struct nft_trans_rule {
 struct nft_trans_set {
        struct nft_set                  *set;
        u32                             set_id;
+       bool                            bound;
 };
 
 #define nft_trans_set(trans)   \
        (((struct nft_trans_set *)trans->data)->set)
 #define nft_trans_set_id(trans)        \
        (((struct nft_trans_set *)trans->data)->set_id)
+#define nft_trans_set_bound(trans)     \
+       (((struct nft_trans_set *)trans->data)->bound)
 
 struct nft_trans_chain {
        bool                            update;
@@ -1384,12 +1386,15 @@ struct nft_trans_table {
 struct nft_trans_elem {
        struct nft_set                  *set;
        struct nft_set_elem             elem;
+       bool                            bound;
 };
 
 #define nft_trans_elem_set(trans)      \
        (((struct nft_trans_elem *)trans->data)->set)
 #define nft_trans_elem(trans)  \
        (((struct nft_trans_elem *)trans->data)->elem)
+#define nft_trans_elem_set_bound(trans)        \
+       (((struct nft_trans_elem *)trans->data)->bound)
 
 struct nft_trans_obj {
        struct nft_object               *obj;
index 3196663..c8b9dec 100644 (file)
@@ -73,4 +73,6 @@ int nft_flow_rule_offload_commit(struct net *net);
        (__reg)->key            = __key;                                \
        memset(&(__reg)->mask, 0xff, (__reg)->len);
 
+int nft_chain_offload_priority(struct nft_base_chain *basechain);
+
 #endif
index e4650e5..b140c8f 100644 (file)
@@ -684,9 +684,8 @@ static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,
                              const struct nla_policy *policy,
                              struct netlink_ext_ack *extack)
 {
-       return __nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
-                          nlmsg_attrlen(nlh, hdrlen), policy,
-                          NL_VALIDATE_STRICT, extack);
+       return __nlmsg_parse(nlh, hdrlen, tb, maxtype, policy,
+                            NL_VALIDATE_STRICT, extack);
 }
 
 /**
index e429809..98be18e 100644 (file)
@@ -646,7 +646,7 @@ tc_cls_common_offload_init(struct flow_cls_common_offload *cls_common,
 {
        cls_common->chain_index = tp->chain->index;
        cls_common->protocol = tp->protocol;
-       cls_common->prio = tp->prio;
+       cls_common->prio = tp->prio >> 16;
        if (tc_skip_sw(flags) || flags & TCA_CLS_FLAGS_VERBOSE)
                cls_common->extack = extack;
 }
index 228db39..2c53f1a 100644 (file)
@@ -2482,6 +2482,7 @@ static inline bool sk_fullsock(const struct sock *sk)
 
 /* Checks if this SKB belongs to an HW offloaded socket
  * and whether any SW fallbacks are required based on dev.
+ * Check decrypted mark in case skb_orphan() cleared socket.
  */
 static inline struct sk_buff *sk_validate_xmit_skb(struct sk_buff *skb,
                                                   struct net_device *dev)
@@ -2489,8 +2490,15 @@ static inline struct sk_buff *sk_validate_xmit_skb(struct sk_buff *skb,
 #ifdef CONFIG_SOCK_VALIDATE_XMIT
        struct sock *sk = skb->sk;
 
-       if (sk && sk_fullsock(sk) && sk->sk_validate_xmit_skb)
+       if (sk && sk_fullsock(sk) && sk->sk_validate_xmit_skb) {
                skb = sk->sk_validate_xmit_skb(sk, dev, skb);
+#ifdef CONFIG_TLS_DEVICE
+       } else if (unlikely(skb->decrypted)) {
+               pr_warn_ratelimited("unencrypted skb with no associated socket - dropping\n");
+               kfree_skb(skb);
+               skb = NULL;
+#endif
+       }
 #endif
 
        return skb;
index b0fc6b2..83df1ec 100644 (file)
@@ -105,8 +105,7 @@ struct rdma_restrack_entry {
 };
 
 int rdma_restrack_count(struct ib_device *dev,
-                       enum rdma_restrack_type type,
-                       struct pid_namespace *ns);
+                       enum rdma_restrack_type type);
 
 void rdma_restrack_kadd(struct rdma_restrack_entry *res);
 void rdma_restrack_uadd(struct rdma_restrack_entry *res);
index cc1d060..fa06b52 100644 (file)
@@ -498,10 +498,10 @@ rxrpc_tx_points;
 #define E_(a, b)       { a, b }
 
 TRACE_EVENT(rxrpc_local,
-           TP_PROTO(struct rxrpc_local *local, enum rxrpc_local_trace op,
+           TP_PROTO(unsigned int local_debug_id, enum rxrpc_local_trace op,
                     int usage, const void *where),
 
-           TP_ARGS(local, op, usage, where),
+           TP_ARGS(local_debug_id, op, usage, where),
 
            TP_STRUCT__entry(
                    __field(unsigned int,       local           )
@@ -511,7 +511,7 @@ TRACE_EVENT(rxrpc_local,
                             ),
 
            TP_fast_assign(
-                   __entry->local = local->debug_id;
+                   __entry->local = local_debug_id;
                    __entry->op = op;
                    __entry->usage = usage;
                    __entry->where = where;
index fa1c753..a5aa7d3 100644 (file)
@@ -1466,8 +1466,8 @@ union bpf_attr {
  *             If no cookie has been set yet, generate a new cookie. Once
  *             generated, the socket cookie remains stable for the life of the
  *             socket. This helper can be useful for monitoring per socket
- *             networking traffic statistics as it provides a unique socket
- *             identifier per namespace.
+ *             networking traffic statistics as it provides a global socket
+ *             identifier that can be assumed unique.
  *     Return
  *             A 8-byte long non-decreasing number on success, or 0 if the
  *             socket field is missing inside *skb*.
index a18b719..784ba0b 100644 (file)
 
 #define JFFS2_ACL_VERSION              0x0001
 
-// Maybe later...
-//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
-//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
-
-
 #define JFFS2_INO_FLAG_PREREAD   1     /* Do read_inode() for this one at
                                           mount time, don't wait for it to
                                           happen later */
index 2bd410f..69cfb43 100644 (file)
@@ -230,9 +230,7 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
  */
 struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
 {
-       int node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
-       size_t count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       size_t align = get_order(PAGE_ALIGN(size));
+       size_t count = size >> PAGE_SHIFT;
        struct page *page = NULL;
        struct cma *cma = NULL;
 
@@ -243,14 +241,12 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
 
        /* CMA can be used only in the context which permits sleeping */
        if (cma && gfpflags_allow_blocking(gfp)) {
+               size_t align = get_order(size);
                size_t cma_align = min_t(size_t, align, CONFIG_CMA_ALIGNMENT);
 
                page = cma_alloc(cma, count, cma_align, gfp & __GFP_NOWARN);
        }
 
-       /* Fallback allocation of normal pages */
-       if (!page)
-               page = alloc_pages_node(node, gfp, align);
        return page;
 }
 
index 795c9b0..706113c 100644 (file)
@@ -85,6 +85,8 @@ static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
 struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
                dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
+       size_t alloc_size = PAGE_ALIGN(size);
+       int node = dev_to_node(dev);
        struct page *page = NULL;
        u64 phys_mask;
 
@@ -95,8 +97,14 @@ struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
        gfp &= ~__GFP_ZERO;
        gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
                        &phys_mask);
+       page = dma_alloc_contiguous(dev, alloc_size, gfp);
+       if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
+               dma_free_contiguous(dev, page, alloc_size);
+               page = NULL;
+       }
 again:
-       page = dma_alloc_contiguous(dev, size, gfp);
+       if (!page)
+               page = alloc_pages_node(node, gfp, get_order(alloc_size));
        if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
                dma_free_contiguous(dev, page, size);
                page = NULL;
index 9484e88..9be995f 100644 (file)
@@ -295,6 +295,18 @@ static void irq_sysfs_add(int irq, struct irq_desc *desc)
        }
 }
 
+static void irq_sysfs_del(struct irq_desc *desc)
+{
+       /*
+        * If irq_sysfs_init() has not yet been invoked (early boot), then
+        * irq_kobj_base is NULL and the descriptor was never added.
+        * kobject_del() complains about a object with no parent, so make
+        * it conditional.
+        */
+       if (irq_kobj_base)
+               kobject_del(&desc->kobj);
+}
+
 static int __init irq_sysfs_init(void)
 {
        struct irq_desc *desc;
@@ -325,6 +337,7 @@ static struct kobj_type irq_kobj_type = {
 };
 
 static void irq_sysfs_add(int irq, struct irq_desc *desc) {}
+static void irq_sysfs_del(struct irq_desc *desc) {}
 
 #endif /* CONFIG_SYSFS */
 
@@ -438,7 +451,7 @@ static void free_desc(unsigned int irq)
         * The sysfs entry must be serialized against a concurrent
         * irq_sysfs_init() as well.
         */
-       kobject_del(&desc->kobj);
+       irq_sysfs_del(desc);
        delete_irq_desc(irq);
 
        /*
index 9873fc6..d9770a5 100644 (file)
@@ -470,6 +470,7 @@ static DECLARE_DELAYED_WORK(optimizing_work, kprobe_optimizer);
  */
 static void do_optimize_kprobes(void)
 {
+       lockdep_assert_held(&text_mutex);
        /*
         * The optimization/unoptimization refers online_cpus via
         * stop_machine() and cpu-hotplug modifies online_cpus.
@@ -487,9 +488,7 @@ static void do_optimize_kprobes(void)
            list_empty(&optimizing_list))
                return;
 
-       mutex_lock(&text_mutex);
        arch_optimize_kprobes(&optimizing_list);
-       mutex_unlock(&text_mutex);
 }
 
 /*
@@ -500,6 +499,7 @@ static void do_unoptimize_kprobes(void)
 {
        struct optimized_kprobe *op, *tmp;
 
+       lockdep_assert_held(&text_mutex);
        /* See comment in do_optimize_kprobes() */
        lockdep_assert_cpus_held();
 
@@ -507,7 +507,6 @@ static void do_unoptimize_kprobes(void)
        if (list_empty(&unoptimizing_list))
                return;
 
-       mutex_lock(&text_mutex);
        arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);
        /* Loop free_list for disarming */
        list_for_each_entry_safe(op, tmp, &freeing_list, list) {
@@ -524,7 +523,6 @@ static void do_unoptimize_kprobes(void)
                } else
                        list_del_init(&op->list);
        }
-       mutex_unlock(&text_mutex);
 }
 
 /* Reclaim all kprobes on the free_list */
@@ -556,6 +554,7 @@ static void kprobe_optimizer(struct work_struct *work)
 {
        mutex_lock(&kprobe_mutex);
        cpus_read_lock();
+       mutex_lock(&text_mutex);
        /* Lock modules while optimizing kprobes */
        mutex_lock(&module_mutex);
 
@@ -583,6 +582,7 @@ static void kprobe_optimizer(struct work_struct *work)
        do_free_cleaned_kprobes();
 
        mutex_unlock(&module_mutex);
+       mutex_unlock(&text_mutex);
        cpus_read_unlock();
        mutex_unlock(&kprobe_mutex);
 
index 5933395..9ee9342 100644 (file)
@@ -65,9 +65,9 @@
 /*
  * Modules' sections will be aligned on page boundaries
  * to ensure complete separation of code and data, but
- * only when CONFIG_STRICT_MODULE_RWX=y
+ * only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
  */
-#ifdef CONFIG_STRICT_MODULE_RWX
+#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
 # define debug_align(X) ALIGN(X, PAGE_SIZE)
 #else
 # define debug_align(X) (X)
index 2b037f1..010d578 100644 (file)
@@ -3904,7 +3904,7 @@ void __noreturn do_task_dead(void)
 
 static inline void sched_submit_work(struct task_struct *tsk)
 {
-       if (!tsk->state || tsk_is_pi_blocked(tsk))
+       if (!tsk->state)
                return;
 
        /*
@@ -3920,6 +3920,9 @@ static inline void sched_submit_work(struct task_struct *tsk)
                preempt_enable_no_resched();
        }
 
+       if (tsk_is_pi_blocked(tsk))
+               return;
+
        /*
         * If we are going to sleep and we have plugged IO queued,
         * make sure to submit it to avoid deadlocks.
index 23fbbcc..6e52b67 100644 (file)
@@ -1131,7 +1131,15 @@ static void psi_trigger_destroy(struct kref *ref)
         * deadlock while waiting for psi_poll_work to acquire trigger_lock
         */
        if (kworker_to_destroy) {
+               /*
+                * After the RCU grace period has expired, the worker
+                * can no longer be found through group->poll_kworker.
+                * But it might have been already scheduled before
+                * that - deschedule it cleanly before destroying it.
+                */
                kthread_cancel_delayed_work_sync(&group->poll_work);
+               atomic_set(&group->poll_scheduled, 0);
+
                kthread_destroy_worker(kworker_to_destroy);
        }
        kfree(t);
index e667be6..534fec2 100644 (file)
@@ -90,6 +90,11 @@ static bool sig_task_ignored(struct task_struct *t, int sig, bool force)
            handler == SIG_DFL && !(force && sig_kernel_only(sig)))
                return true;
 
+       /* Only allow kernel generated signals to this kthread */
+       if (unlikely((t->flags & PF_KTHREAD) &&
+                    (handler == SIG_KTHREAD_KERNEL) && !force))
+               return true;
+
        return sig_handler_ignored(handler, sig);
 }
 
index d911c84..ca69290 100644 (file)
@@ -146,6 +146,11 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm)
 static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
 {
        tk->offs_boot = ktime_add(tk->offs_boot, delta);
+       /*
+        * Timespec representation for VDSO update to avoid 64bit division
+        * on every update.
+        */
+       tk->monotonic_to_boot = ktime_to_timespec64(tk->offs_boot);
 }
 
 /*
index 8cf3596..4bc37ac 100644 (file)
@@ -17,7 +17,7 @@ static inline void update_vdso_data(struct vdso_data *vdata,
                                    struct timekeeper *tk)
 {
        struct vdso_timestamp *vdso_ts;
-       u64 nsec;
+       u64 nsec, sec;
 
        vdata[CS_HRES_COARSE].cycle_last        = tk->tkr_mono.cycle_last;
        vdata[CS_HRES_COARSE].mask              = tk->tkr_mono.mask;
@@ -45,23 +45,27 @@ static inline void update_vdso_data(struct vdso_data *vdata,
        }
        vdso_ts->nsec   = nsec;
 
-       /* CLOCK_MONOTONIC_RAW */
-       vdso_ts         = &vdata[CS_RAW].basetime[CLOCK_MONOTONIC_RAW];
-       vdso_ts->sec    = tk->raw_sec;
-       vdso_ts->nsec   = tk->tkr_raw.xtime_nsec;
+       /* Copy MONOTONIC time for BOOTTIME */
+       sec     = vdso_ts->sec;
+       /* Add the boot offset */
+       sec     += tk->monotonic_to_boot.tv_sec;
+       nsec    += (u64)tk->monotonic_to_boot.tv_nsec << tk->tkr_mono.shift;
 
        /* CLOCK_BOOTTIME */
        vdso_ts         = &vdata[CS_HRES_COARSE].basetime[CLOCK_BOOTTIME];
-       vdso_ts->sec    = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
-       nsec = tk->tkr_mono.xtime_nsec;
-       nsec += ((u64)(tk->wall_to_monotonic.tv_nsec +
-                      ktime_to_ns(tk->offs_boot)) << tk->tkr_mono.shift);
+       vdso_ts->sec    = sec;
+
        while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
                nsec -= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift);
                vdso_ts->sec++;
        }
        vdso_ts->nsec   = nsec;
 
+       /* CLOCK_MONOTONIC_RAW */
+       vdso_ts         = &vdata[CS_RAW].basetime[CLOCK_MONOTONIC_RAW];
+       vdso_ts->sec    = tk->raw_sec;
+       vdso_ts->nsec   = tk->tkr_raw.xtime_nsec;
+
        /* CLOCK_TAI */
        vdso_ts         = &vdata[CS_HRES_COARSE].basetime[CLOCK_TAI];
        vdso_ts->sec    = tk->xtime_sec + (s64)tk->tai_offset;
index 738065f..de1f159 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/shmem_fs.h>
 #include <linux/oom.h>
 #include <linux/numa.h>
+#include <linux/page_owner.h>
 
 #include <asm/tlb.h>
 #include <asm/pgalloc.h>
@@ -2516,6 +2517,9 @@ static void __split_huge_page(struct page *page, struct list_head *list,
        }
 
        ClearPageCompound(head);
+
+       split_page_owner(head, HPAGE_PMD_ORDER);
+
        /* See comment in __split_huge_page_tail() */
        if (PageAnon(head)) {
                /* Additional pin to swap cache */
index 2277b82..95d16a4 100644 (file)
@@ -407,8 +407,14 @@ static inline bool shadow_invalid(u8 tag, s8 shadow_byte)
        if (IS_ENABLED(CONFIG_KASAN_GENERIC))
                return shadow_byte < 0 ||
                        shadow_byte >= KASAN_SHADOW_SCALE_SIZE;
-       else
-               return tag != (u8)shadow_byte;
+
+       /* else CONFIG_KASAN_SW_TAGS: */
+       if ((u8)shadow_byte == KASAN_TAG_INVALID)
+               return true;
+       if ((tag != KASAN_TAG_KERNEL) && (tag != (u8)shadow_byte))
+               return true;
+
+       return false;
 }
 
 static bool __kasan_slab_free(struct kmem_cache *cache, void *object,
index 6f5c0c5..26e2999 100644 (file)
@@ -3260,6 +3260,60 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
        }
 }
 
+static void memcg_flush_percpu_vmstats(struct mem_cgroup *memcg)
+{
+       unsigned long stat[MEMCG_NR_STAT];
+       struct mem_cgroup *mi;
+       int node, cpu, i;
+
+       for (i = 0; i < MEMCG_NR_STAT; i++)
+               stat[i] = 0;
+
+       for_each_online_cpu(cpu)
+               for (i = 0; i < MEMCG_NR_STAT; i++)
+                       stat[i] += raw_cpu_read(memcg->vmstats_percpu->stat[i]);
+
+       for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
+               for (i = 0; i < MEMCG_NR_STAT; i++)
+                       atomic_long_add(stat[i], &mi->vmstats[i]);
+
+       for_each_node(node) {
+               struct mem_cgroup_per_node *pn = memcg->nodeinfo[node];
+               struct mem_cgroup_per_node *pi;
+
+               for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+                       stat[i] = 0;
+
+               for_each_online_cpu(cpu)
+                       for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+                               stat[i] += raw_cpu_read(
+                                       pn->lruvec_stat_cpu->count[i]);
+
+               for (pi = pn; pi; pi = parent_nodeinfo(pi, node))
+                       for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+                               atomic_long_add(stat[i], &pi->lruvec_stat[i]);
+       }
+}
+
+static void memcg_flush_percpu_vmevents(struct mem_cgroup *memcg)
+{
+       unsigned long events[NR_VM_EVENT_ITEMS];
+       struct mem_cgroup *mi;
+       int cpu, i;
+
+       for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
+               events[i] = 0;
+
+       for_each_online_cpu(cpu)
+               for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
+                       events[i] += raw_cpu_read(
+                               memcg->vmstats_percpu->events[i]);
+
+       for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
+               for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
+                       atomic_long_add(events[i], &mi->vmevents[i]);
+}
+
 #ifdef CONFIG_MEMCG_KMEM
 static int memcg_online_kmem(struct mem_cgroup *memcg)
 {
@@ -4682,6 +4736,12 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
 {
        int node;
 
+       /*
+        * Flush percpu vmstats and vmevents to guarantee the value correctness
+        * on parent's and all ancestor levels.
+        */
+       memcg_flush_percpu_vmstats(memcg);
+       memcg_flush_percpu_vmevents(memcg);
        for_each_node(node)
                free_mem_cgroup_per_node_info(memcg, node);
        free_percpu(memcg->vmstats_percpu);
index 272c6de..9c91949 100644 (file)
@@ -2238,27 +2238,12 @@ static int move_freepages(struct zone *zone,
        unsigned int order;
        int pages_moved = 0;
 
-#ifndef CONFIG_HOLES_IN_ZONE
-       /*
-        * page_zone is not safe to call in this context when
-        * CONFIG_HOLES_IN_ZONE is set. This bug check is probably redundant
-        * anyway as we check zone boundaries in move_freepages_block().
-        * Remove at a later date when no bug reports exist related to
-        * grouping pages by mobility
-        */
-       VM_BUG_ON(pfn_valid(page_to_pfn(start_page)) &&
-                 pfn_valid(page_to_pfn(end_page)) &&
-                 page_zone(start_page) != page_zone(end_page));
-#endif
        for (page = start_page; page <= end_page;) {
                if (!pfn_valid_within(page_to_pfn(page))) {
                        page++;
                        continue;
                }
 
-               /* Make sure we are not inadvertently changing nodes */
-               VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
-
                if (!PageBuddy(page)) {
                        /*
                         * We assume that pages that could be isolated for
@@ -2273,6 +2258,10 @@ static int move_freepages(struct zone *zone,
                        continue;
                }
 
+               /* Make sure we are not inadvertently changing nodes */
+               VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
+               VM_BUG_ON_PAGE(page_zone(page) != zone, page);
+
                order = page_order(page);
                move_to_free_area(page, &zone->free_area[order], migratetype);
                page += 1 << order;
index ed19d98..e31cd9b 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/wait.h>
 #include <linux/zpool.h>
 #include <linux/magic.h>
 
@@ -145,6 +146,8 @@ struct z3fold_header {
  * @release_wq:        workqueue for safe page release
  * @work:      work_struct for safe page release
  * @inode:     inode for z3fold pseudo filesystem
+ * @destroying: bool to stop migration once we start destruction
+ * @isolated: int to count the number of pages currently in isolation
  *
  * This structure is allocated at pool creation time and maintains metadata
  * pertaining to a particular z3fold pool.
@@ -163,8 +166,11 @@ struct z3fold_pool {
        const struct zpool_ops *zpool_ops;
        struct workqueue_struct *compact_wq;
        struct workqueue_struct *release_wq;
+       struct wait_queue_head isolate_wait;
        struct work_struct work;
        struct inode *inode;
+       bool destroying;
+       int isolated;
 };
 
 /*
@@ -769,6 +775,7 @@ static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp,
                goto out_c;
        spin_lock_init(&pool->lock);
        spin_lock_init(&pool->stale_lock);
+       init_waitqueue_head(&pool->isolate_wait);
        pool->unbuddied = __alloc_percpu(sizeof(struct list_head)*NCHUNKS, 2);
        if (!pool->unbuddied)
                goto out_pool;
@@ -808,6 +815,15 @@ out:
        return NULL;
 }
 
+static bool pool_isolated_are_drained(struct z3fold_pool *pool)
+{
+       bool ret;
+
+       spin_lock(&pool->lock);
+       ret = pool->isolated == 0;
+       spin_unlock(&pool->lock);
+       return ret;
+}
 /**
  * z3fold_destroy_pool() - destroys an existing z3fold pool
  * @pool:      the z3fold pool to be destroyed
@@ -817,6 +833,22 @@ out:
 static void z3fold_destroy_pool(struct z3fold_pool *pool)
 {
        kmem_cache_destroy(pool->c_handle);
+       /*
+        * We set pool-> destroying under lock to ensure that
+        * z3fold_page_isolate() sees any changes to destroying. This way we
+        * avoid the need for any memory barriers.
+        */
+
+       spin_lock(&pool->lock);
+       pool->destroying = true;
+       spin_unlock(&pool->lock);
+
+       /*
+        * We need to ensure that no pages are being migrated while we destroy
+        * these workqueues, as migration can queue work on either of the
+        * workqueues.
+        */
+       wait_event(pool->isolate_wait, !pool_isolated_are_drained(pool));
 
        /*
         * We need to destroy pool->compact_wq before pool->release_wq,
@@ -1307,6 +1339,28 @@ static u64 z3fold_get_pool_size(struct z3fold_pool *pool)
        return atomic64_read(&pool->pages_nr);
 }
 
+/*
+ * z3fold_dec_isolated() expects to be called while pool->lock is held.
+ */
+static void z3fold_dec_isolated(struct z3fold_pool *pool)
+{
+       assert_spin_locked(&pool->lock);
+       VM_BUG_ON(pool->isolated <= 0);
+       pool->isolated--;
+
+       /*
+        * If we have no more isolated pages, we have to see if
+        * z3fold_destroy_pool() is waiting for a signal.
+        */
+       if (pool->isolated == 0 && waitqueue_active(&pool->isolate_wait))
+               wake_up_all(&pool->isolate_wait);
+}
+
+static void z3fold_inc_isolated(struct z3fold_pool *pool)
+{
+       pool->isolated++;
+}
+
 static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
 {
        struct z3fold_header *zhdr;
@@ -1333,6 +1387,33 @@ static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
                spin_lock(&pool->lock);
                if (!list_empty(&page->lru))
                        list_del(&page->lru);
+               /*
+                * We need to check for destruction while holding pool->lock, as
+                * otherwise destruction could see 0 isolated pages, and
+                * proceed.
+                */
+               if (unlikely(pool->destroying)) {
+                       spin_unlock(&pool->lock);
+                       /*
+                        * If this page isn't stale, somebody else holds a
+                        * reference to it. Let't drop our refcount so that they
+                        * can call the release logic.
+                        */
+                       if (unlikely(kref_put(&zhdr->refcount,
+                                             release_z3fold_page_locked))) {
+                               /*
+                                * If we get here we have kref problems, so we
+                                * should freak out.
+                                */
+                               WARN(1, "Z3fold is experiencing kref problems\n");
+                               return false;
+                       }
+                       z3fold_page_unlock(zhdr);
+                       return false;
+               }
+
+
+               z3fold_inc_isolated(pool);
                spin_unlock(&pool->lock);
                z3fold_page_unlock(zhdr);
                return true;
@@ -1401,6 +1482,10 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa
 
        queue_work_on(new_zhdr->cpu, pool->compact_wq, &new_zhdr->work);
 
+       spin_lock(&pool->lock);
+       z3fold_dec_isolated(pool);
+       spin_unlock(&pool->lock);
+
        page_mapcount_reset(page);
        put_page(page);
        return 0;
@@ -1420,10 +1505,14 @@ static void z3fold_page_putback(struct page *page)
        INIT_LIST_HEAD(&page->lru);
        if (kref_put(&zhdr->refcount, release_z3fold_page_locked)) {
                atomic64_dec(&pool->pages_nr);
+               spin_lock(&pool->lock);
+               z3fold_dec_isolated(pool);
+               spin_unlock(&pool->lock);
                return;
        }
        spin_lock(&pool->lock);
        list_add(&page->lru, &pool->lru);
+       z3fold_dec_isolated(pool);
        spin_unlock(&pool->lock);
        z3fold_page_unlock(zhdr);
 }
index 57fbb7c..08def3a 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/mount.h>
 #include <linux/pseudo_fs.h>
 #include <linux/migrate.h>
+#include <linux/wait.h>
 #include <linux/pagemap.h>
 #include <linux/fs.h>
 
@@ -268,6 +269,10 @@ struct zs_pool {
 #ifdef CONFIG_COMPACTION
        struct inode *inode;
        struct work_struct free_work;
+       /* A wait queue for when migration races with async_free_zspage() */
+       struct wait_queue_head migration_wait;
+       atomic_long_t isolated_pages;
+       bool destroying;
 #endif
 };
 
@@ -1862,6 +1867,31 @@ static void dec_zspage_isolation(struct zspage *zspage)
        zspage->isolated--;
 }
 
+static void putback_zspage_deferred(struct zs_pool *pool,
+                                   struct size_class *class,
+                                   struct zspage *zspage)
+{
+       enum fullness_group fg;
+
+       fg = putback_zspage(class, zspage);
+       if (fg == ZS_EMPTY)
+               schedule_work(&pool->free_work);
+
+}
+
+static inline void zs_pool_dec_isolated(struct zs_pool *pool)
+{
+       VM_BUG_ON(atomic_long_read(&pool->isolated_pages) <= 0);
+       atomic_long_dec(&pool->isolated_pages);
+       /*
+        * There's no possibility of racing, since wait_for_isolated_drain()
+        * checks the isolated count under &class->lock after enqueuing
+        * on migration_wait.
+        */
+       if (atomic_long_read(&pool->isolated_pages) == 0 && pool->destroying)
+               wake_up_all(&pool->migration_wait);
+}
+
 static void replace_sub_page(struct size_class *class, struct zspage *zspage,
                                struct page *newpage, struct page *oldpage)
 {
@@ -1931,6 +1961,7 @@ static bool zs_page_isolate(struct page *page, isolate_mode_t mode)
         */
        if (!list_empty(&zspage->list) && !is_zspage_isolated(zspage)) {
                get_zspage_mapping(zspage, &class_idx, &fullness);
+               atomic_long_inc(&pool->isolated_pages);
                remove_zspage(class, zspage, fullness);
        }
 
@@ -2030,8 +2061,16 @@ static int zs_page_migrate(struct address_space *mapping, struct page *newpage,
         * Page migration is done so let's putback isolated zspage to
         * the list if @page is final isolated subpage in the zspage.
         */
-       if (!is_zspage_isolated(zspage))
-               putback_zspage(class, zspage);
+       if (!is_zspage_isolated(zspage)) {
+               /*
+                * We cannot race with zs_destroy_pool() here because we wait
+                * for isolation to hit zero before we start destroying.
+                * Also, we ensure that everyone can see pool->destroying before
+                * we start waiting.
+                */
+               putback_zspage_deferred(pool, class, zspage);
+               zs_pool_dec_isolated(pool);
+       }
 
        reset_page(page);
        put_page(page);
@@ -2077,13 +2116,12 @@ static void zs_page_putback(struct page *page)
        spin_lock(&class->lock);
        dec_zspage_isolation(zspage);
        if (!is_zspage_isolated(zspage)) {
-               fg = putback_zspage(class, zspage);
                /*
                 * Due to page_lock, we cannot free zspage immediately
                 * so let's defer.
                 */
-               if (fg == ZS_EMPTY)
-                       schedule_work(&pool->free_work);
+               putback_zspage_deferred(pool, class, zspage);
+               zs_pool_dec_isolated(pool);
        }
        spin_unlock(&class->lock);
 }
@@ -2107,8 +2145,36 @@ static int zs_register_migration(struct zs_pool *pool)
        return 0;
 }
 
+static bool pool_isolated_are_drained(struct zs_pool *pool)
+{
+       return atomic_long_read(&pool->isolated_pages) == 0;
+}
+
+/* Function for resolving migration */
+static void wait_for_isolated_drain(struct zs_pool *pool)
+{
+
+       /*
+        * We're in the process of destroying the pool, so there are no
+        * active allocations. zs_page_isolate() fails for completely free
+        * zspages, so we need only wait for the zs_pool's isolated
+        * count to hit zero.
+        */
+       wait_event(pool->migration_wait,
+                  pool_isolated_are_drained(pool));
+}
+
 static void zs_unregister_migration(struct zs_pool *pool)
 {
+       pool->destroying = true;
+       /*
+        * We need a memory barrier here to ensure global visibility of
+        * pool->destroying. Thus pool->isolated pages will either be 0 in which
+        * case we don't care, or it will be > 0 and pool->destroying will
+        * ensure that we wake up once isolation hits 0.
+        */
+       smp_mb();
+       wait_for_isolated_drain(pool); /* This can block */
        flush_work(&pool->free_work);
        iput(pool->inode);
 }
@@ -2346,6 +2412,8 @@ struct zs_pool *zs_create_pool(const char *name)
        if (!pool->name)
                goto err;
 
+       init_waitqueue_head(&pool->migration_wait);
+
        if (create_cache(pool))
                goto err;
 
index 67d7f83..1d5bdf3 100644 (file)
@@ -2303,7 +2303,7 @@ __batadv_mcast_flags_dump(struct sk_buff *msg, u32 portid,
 
        while (bucket_tmp < hash->size) {
                if (batadv_mcast_flags_dump_bucket(msg, portid, cb, hash,
-                                                  *bucket, &idx_tmp))
+                                                  bucket_tmp, &idx_tmp))
                        break;
 
                bucket_tmp++;
@@ -2420,8 +2420,10 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
        batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
        batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS);
        batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS);
-       batadv_mcast_want_rtr4_update(bat_priv, orig, BATADV_NO_FLAGS);
-       batadv_mcast_want_rtr6_update(bat_priv, orig, BATADV_NO_FLAGS);
+       batadv_mcast_want_rtr4_update(bat_priv, orig,
+                                     BATADV_MCAST_WANT_NO_RTR4);
+       batadv_mcast_want_rtr6_update(bat_priv, orig,
+                                     BATADV_MCAST_WANT_NO_RTR6);
 
        spin_unlock_bh(&orig->mcast_handler_lock);
 }
index b9585e7..04bc793 100644 (file)
@@ -3202,6 +3202,7 @@ struct hci_dev *hci_alloc_dev(void)
        hdev->conn_info_min_age = DEFAULT_CONN_INFO_MIN_AGE;
        hdev->conn_info_max_age = DEFAULT_CONN_INFO_MAX_AGE;
        hdev->auth_payload_timeout = DEFAULT_AUTH_PAYLOAD_TIMEOUT;
+       hdev->min_enc_key_size = HCI_MIN_ENC_KEY_SIZE;
 
        mutex_init(&hdev->lock);
        mutex_init(&hdev->req_lock);
index bb67f4a..402e2cc 100644 (file)
@@ -433,6 +433,35 @@ static int auto_accept_delay_set(void *data, u64 val)
        return 0;
 }
 
+static int min_encrypt_key_size_set(void *data, u64 val)
+{
+       struct hci_dev *hdev = data;
+
+       if (val < 1 || val > 16)
+               return -EINVAL;
+
+       hci_dev_lock(hdev);
+       hdev->min_enc_key_size = val;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+static int min_encrypt_key_size_get(void *data, u64 *val)
+{
+       struct hci_dev *hdev = data;
+
+       hci_dev_lock(hdev);
+       *val = hdev->min_enc_key_size;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(min_encrypt_key_size_fops,
+                       min_encrypt_key_size_get,
+                       min_encrypt_key_size_set, "%llu\n");
+
 static int auto_accept_delay_get(void *data, u64 *val)
 {
        struct hci_dev *hdev = data;
@@ -545,6 +574,8 @@ void hci_debugfs_create_bredr(struct hci_dev *hdev)
        if (lmp_ssp_capable(hdev)) {
                debugfs_create_file("ssp_debug_mode", 0444, hdev->debugfs,
                                    hdev, &ssp_debug_mode_fops);
+               debugfs_create_file("min_encrypt_key_size", 0644, hdev->debugfs,
+                                   hdev, &min_encrypt_key_size_fops);
                debugfs_create_file("auto_accept_delay", 0644, hdev->debugfs,
                                    hdev, &auto_accept_delay_fops);
        }
index 5abd423..8d88996 100644 (file)
@@ -101,6 +101,7 @@ static int hidp_send_message(struct hidp_session *session, struct socket *sock,
 {
        struct sk_buff *skb;
        struct sock *sk = sock->sk;
+       int ret;
 
        BT_DBG("session %p data %p size %d", session, data, size);
 
@@ -114,13 +115,17 @@ static int hidp_send_message(struct hidp_session *session, struct socket *sock,
        }
 
        skb_put_u8(skb, hdr);
-       if (data && size > 0)
+       if (data && size > 0) {
                skb_put_data(skb, data, size);
+               ret = size;
+       } else {
+               ret = 0;
+       }
 
        skb_queue_tail(transmit, skb);
        wake_up_interruptible(sk_sleep(sk));
 
-       return 0;
+       return ret;
 }
 
 static int hidp_send_ctrl_message(struct hidp_session *session,
index cc506fe..dfc1edb 100644 (file)
@@ -1361,7 +1361,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon)
         * actually encrypted before enforcing a key size.
         */
        return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) ||
-               hcon->enc_key_size >= HCI_MIN_ENC_KEY_SIZE);
+               hcon->enc_key_size >= hcon->hdev->min_enc_key_size);
 }
 
 static void l2cap_do_start(struct l2cap_chan *chan)
index 0b2df09..78ae6e8 100644 (file)
@@ -1496,7 +1496,7 @@ static enum calc_target_result calc_target(struct ceph_osd_client *osdc,
        struct ceph_osds up, acting;
        bool force_resend = false;
        bool unpaused = false;
-       bool legacy_change;
+       bool legacy_change = false;
        bool split = false;
        bool sort_bitwise = ceph_osdmap_flag(osdc, CEPH_OSDMAP_SORTBITWISE);
        bool recovery_deletes = ceph_osdmap_flag(osdc,
@@ -1584,15 +1584,14 @@ static enum calc_target_result calc_target(struct ceph_osd_client *osdc,
                t->osd = acting.primary;
        }
 
-       if (unpaused || legacy_change || force_resend ||
-           (split && con && CEPH_HAVE_FEATURE(con->peer_features,
-                                              RESEND_ON_SPLIT)))
+       if (unpaused || legacy_change || force_resend || split)
                ct_res = CALC_TARGET_NEED_RESEND;
        else
                ct_res = CALC_TARGET_NO_ACTION;
 
 out:
-       dout("%s t %p -> ct_res %d osd %d\n", __func__, t, ct_res, t->osd);
+       dout("%s t %p -> %d%d%d%d ct_res %d osd%d\n", __func__, t, unpaused,
+            legacy_change, force_resend, split, ct_res, t->osd);
        return ct_res;
 }
 
index d57b0cc..6d08553 100644 (file)
@@ -1992,6 +1992,19 @@ void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
 }
 EXPORT_SYMBOL(skb_set_owner_w);
 
+static bool can_skb_orphan_partial(const struct sk_buff *skb)
+{
+#ifdef CONFIG_TLS_DEVICE
+       /* Drivers depend on in-order delivery for crypto offload,
+        * partial orphan breaks out-of-order-OK logic.
+        */
+       if (skb->decrypted)
+               return false;
+#endif
+       return (skb->destructor == sock_wfree ||
+               (IS_ENABLED(CONFIG_INET) && skb->destructor == tcp_wfree));
+}
+
 /* This helper is used by netem, as it can hold packets in its
  * delay queue. We want to allow the owner socket to send more
  * packets, as if they were already TX completed by a typical driver.
@@ -2003,11 +2016,7 @@ void skb_orphan_partial(struct sk_buff *skb)
        if (skb_is_tcp_pure_ack(skb))
                return;
 
-       if (skb->destructor == sock_wfree
-#ifdef CONFIG_INET
-           || skb->destructor == tcp_wfree
-#endif
-               ) {
+       if (can_skb_orphan_partial(skb)) {
                struct sock *sk = skb->sk;
 
                if (refcount_inc_not_zero(&sk->sk_refcnt)) {
index 3312a58..c13ffbd 100644 (file)
@@ -19,6 +19,7 @@ static const struct sock_diag_handler *sock_diag_handlers[AF_MAX];
 static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
 static DEFINE_MUTEX(sock_diag_table_mutex);
 static struct workqueue_struct *broadcast_wq;
+static atomic64_t cookie_gen;
 
 u64 sock_gen_cookie(struct sock *sk)
 {
@@ -27,7 +28,7 @@ u64 sock_gen_cookie(struct sock *sk)
 
                if (res)
                        return res;
-               res = atomic64_inc_return(&sock_net(sk)->cookie_gen);
+               res = atomic64_inc_return(&cookie_gen);
                atomic64_cmpxchg(&sk->sk_cookie, 0, res);
        }
 }
index 4ec5b7f..09d9286 100644 (file)
@@ -153,6 +153,9 @@ static void dsa_switch_mdb_add_bitmap(struct dsa_switch *ds,
 {
        int port;
 
+       if (!ds->ops->port_mdb_add)
+               return;
+
        for_each_set_bit(port, bitmap, ds->num_ports)
                ds->ops->port_mdb_add(ds, port, mdb);
 }
index e4aba5d..bbe9b3b 100644 (file)
@@ -170,7 +170,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *skb,
        reasm_data = inet_frag_reasm_prepare(&fq->q, skb, prev_tail);
        if (!reasm_data)
                goto out_oom;
-       inet_frag_reasm_finish(&fq->q, skb, reasm_data);
+       inet_frag_reasm_finish(&fq->q, skb, reasm_data, false);
 
        skb->dev = ldev;
        skb->tstamp = fq->q.stamp;
index a999451..10d3173 100644 (file)
@@ -475,11 +475,12 @@ void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb,
 EXPORT_SYMBOL(inet_frag_reasm_prepare);
 
 void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
-                           void *reasm_data)
+                           void *reasm_data, bool try_coalesce)
 {
        struct sk_buff **nextp = (struct sk_buff **)reasm_data;
        struct rb_node *rbn;
        struct sk_buff *fp;
+       int sum_truesize;
 
        skb_push(head, head->data - skb_network_header(head));
 
@@ -487,25 +488,41 @@ void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
        fp = FRAG_CB(head)->next_frag;
        rbn = rb_next(&head->rbnode);
        rb_erase(&head->rbnode, &q->rb_fragments);
+
+       sum_truesize = head->truesize;
        while (rbn || fp) {
                /* fp points to the next sk_buff in the current run;
                 * rbn points to the next run.
                 */
                /* Go through the current run. */
                while (fp) {
-                       *nextp = fp;
-                       nextp = &fp->next;
-                       fp->prev = NULL;
-                       memset(&fp->rbnode, 0, sizeof(fp->rbnode));
-                       fp->sk = NULL;
-                       head->data_len += fp->len;
-                       head->len += fp->len;
+                       struct sk_buff *next_frag = FRAG_CB(fp)->next_frag;
+                       bool stolen;
+                       int delta;
+
+                       sum_truesize += fp->truesize;
                        if (head->ip_summed != fp->ip_summed)
                                head->ip_summed = CHECKSUM_NONE;
                        else if (head->ip_summed == CHECKSUM_COMPLETE)
                                head->csum = csum_add(head->csum, fp->csum);
-                       head->truesize += fp->truesize;
-                       fp = FRAG_CB(fp)->next_frag;
+
+                       if (try_coalesce && skb_try_coalesce(head, fp, &stolen,
+                                                            &delta)) {
+                               kfree_skb_partial(fp, stolen);
+                       } else {
+                               fp->prev = NULL;
+                               memset(&fp->rbnode, 0, sizeof(fp->rbnode));
+                               fp->sk = NULL;
+
+                               head->data_len += fp->len;
+                               head->len += fp->len;
+                               head->truesize += fp->truesize;
+
+                               *nextp = fp;
+                               nextp = &fp->next;
+                       }
+
+                       fp = next_frag;
                }
                /* Move to the next run. */
                if (rbn) {
@@ -516,7 +533,7 @@ void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
                        rbn = rbnext;
                }
        }
-       sub_frag_mem_limit(q->fqdir, head->truesize);
+       sub_frag_mem_limit(q->fqdir, sum_truesize);
 
        *nextp = NULL;
        skb_mark_not_on_list(head);
index 4385eb9..cfeb889 100644 (file)
@@ -393,6 +393,11 @@ err:
        return err;
 }
 
+static bool ip_frag_coalesce_ok(const struct ipq *qp)
+{
+       return qp->q.key.v4.user == IP_DEFRAG_LOCAL_DELIVER;
+}
+
 /* Build a new IP datagram from all its fragments. */
 static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
                         struct sk_buff *prev_tail, struct net_device *dev)
@@ -421,7 +426,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
        if (len > 65535)
                goto out_oversize;
 
-       inet_frag_reasm_finish(&qp->q, skb, reasm_data);
+       inet_frag_reasm_finish(&qp->q, skb, reasm_data,
+                              ip_frag_coalesce_ok(qp));
 
        skb->dev = dev;
        IPCB(skb)->frag_max_size = max(qp->max_df_size, qp->q.max_size);
index 7769058..77b485d 100644 (file)
@@ -984,6 +984,9 @@ new_segment:
                        if (!skb)
                                goto wait_for_memory;
 
+#ifdef CONFIG_TLS_DEVICE
+                       skb->decrypted = !!(flags & MSG_SENDPAGE_DECRYPTED);
+#endif
                        skb_entail(sk, skb);
                        copy = size_goal;
                }
index 3d1e154..8a56e09 100644 (file)
@@ -398,10 +398,14 @@ more_data:
 static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 {
        struct sk_msg tmp, *msg_tx = NULL;
-       int flags = msg->msg_flags | MSG_NO_SHARED_FRAGS;
        int copied = 0, err = 0;
        struct sk_psock *psock;
        long timeo;
+       int flags;
+
+       /* Don't let internal do_tcp_sendpages() flags through */
+       flags = (msg->msg_flags & ~MSG_SENDPAGE_DECRYPTED);
+       flags |= MSG_NO_SHARED_FRAGS;
 
        psock = sk_psock_get(sk);
        if (unlikely(!psock))
index 6e4afc4..979520e 100644 (file)
@@ -1320,6 +1320,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue,
        buff = sk_stream_alloc_skb(sk, nsize, gfp, true);
        if (!buff)
                return -ENOMEM; /* We'll just try again later. */
+       skb_copy_decrypted(buff, skb);
 
        sk->sk_wmem_queued += buff->truesize;
        sk_mem_charge(sk, buff->truesize);
@@ -1874,6 +1875,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
        buff = sk_stream_alloc_skb(sk, 0, gfp, true);
        if (unlikely(!buff))
                return -ENOMEM;
+       skb_copy_decrypted(buff, skb);
 
        sk->sk_wmem_queued += buff->truesize;
        sk_mem_charge(sk, buff->truesize);
@@ -2143,6 +2145,7 @@ static int tcp_mtu_probe(struct sock *sk)
        sk_mem_charge(sk, nskb->truesize);
 
        skb = tcp_send_head(sk);
+       skb_copy_decrypted(nskb, skb);
 
        TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq;
        TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size;
index 0f82c15..fed9666 100644 (file)
@@ -348,7 +348,7 @@ static int nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *skb,
 
        skb_reset_transport_header(skb);
 
-       inet_frag_reasm_finish(&fq->q, skb, reasm_data);
+       inet_frag_reasm_finish(&fq->q, skb, reasm_data, false);
 
        skb->ignore_df = 1;
        skb->dev = dev;
index ca05b16..1f5d4d1 100644 (file)
@@ -282,7 +282,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
 
        skb_reset_transport_header(skb);
 
-       inet_frag_reasm_finish(&fq->q, skb, reasm_data);
+       inet_frag_reasm_finish(&fq->q, skb, reasm_data, true);
 
        skb->dev = dev;
        ipv6_hdr(skb)->payload_len = htons(payload_len);
index a542761..81a8ef4 100644 (file)
@@ -453,13 +453,12 @@ EXPORT_SYMBOL_GPL(nf_ct_invert_tuple);
  * table location, we assume id gets exposed to userspace.
  *
  * Following nf_conn items do not change throughout lifetime
- * of the nf_conn after it has been committed to main hash table:
+ * of the nf_conn:
  *
  * 1. nf_conn address
- * 2. nf_conn->ext address
- * 3. nf_conn->master address (normally NULL)
- * 4. tuple
- * 5. the associated net namespace
+ * 2. nf_conn->master address (normally NULL)
+ * 3. the associated net namespace
+ * 4. the original direction tuple
  */
 u32 nf_ct_get_id(const struct nf_conn *ct)
 {
@@ -469,9 +468,10 @@ u32 nf_ct_get_id(const struct nf_conn *ct)
        net_get_random_once(&ct_id_seed, sizeof(ct_id_seed));
 
        a = (unsigned long)ct;
-       b = (unsigned long)ct->master ^ net_hash_mix(nf_ct_net(ct));
-       c = (unsigned long)ct->ext;
-       d = (unsigned long)siphash(&ct->tuplehash, sizeof(ct->tuplehash),
+       b = (unsigned long)ct->master;
+       c = (unsigned long)nf_ct_net(ct);
+       d = (unsigned long)siphash(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+                                  sizeof(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple),
                                   &ct_id_seed);
 #ifdef CONFIG_64BIT
        return siphash_4u64((u64)a, (u64)b, (u64)c, (u64)d, &ct_id_seed);
index e3d7972..80a8f9a 100644 (file)
@@ -111,15 +111,16 @@ static void flow_offload_fixup_tcp(struct ip_ct_tcp *tcp)
 #define NF_FLOWTABLE_TCP_PICKUP_TIMEOUT        (120 * HZ)
 #define NF_FLOWTABLE_UDP_PICKUP_TIMEOUT        (30 * HZ)
 
-static void flow_offload_fixup_ct_state(struct nf_conn *ct)
+static inline __s32 nf_flow_timeout_delta(unsigned int timeout)
+{
+       return (__s32)(timeout - (u32)jiffies);
+}
+
+static void flow_offload_fixup_ct_timeout(struct nf_conn *ct)
 {
        const struct nf_conntrack_l4proto *l4proto;
+       int l4num = nf_ct_protonum(ct);
        unsigned int timeout;
-       int l4num;
-
-       l4num = nf_ct_protonum(ct);
-       if (l4num == IPPROTO_TCP)
-               flow_offload_fixup_tcp(&ct->proto.tcp);
 
        l4proto = nf_ct_l4proto_find(l4num);
        if (!l4proto)
@@ -132,7 +133,20 @@ static void flow_offload_fixup_ct_state(struct nf_conn *ct)
        else
                return;
 
-       ct->timeout = nfct_time_stamp + timeout;
+       if (nf_flow_timeout_delta(ct->timeout) > (__s32)timeout)
+               ct->timeout = nfct_time_stamp + timeout;
+}
+
+static void flow_offload_fixup_ct_state(struct nf_conn *ct)
+{
+       if (nf_ct_protonum(ct) == IPPROTO_TCP)
+               flow_offload_fixup_tcp(&ct->proto.tcp);
+}
+
+static void flow_offload_fixup_ct(struct nf_conn *ct)
+{
+       flow_offload_fixup_ct_state(ct);
+       flow_offload_fixup_ct_timeout(ct);
 }
 
 void flow_offload_free(struct flow_offload *flow)
@@ -208,6 +222,11 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
 }
 EXPORT_SYMBOL_GPL(flow_offload_add);
 
+static inline bool nf_flow_has_expired(const struct flow_offload *flow)
+{
+       return nf_flow_timeout_delta(flow->timeout) <= 0;
+}
+
 static void flow_offload_del(struct nf_flowtable *flow_table,
                             struct flow_offload *flow)
 {
@@ -223,6 +242,11 @@ static void flow_offload_del(struct nf_flowtable *flow_table,
        e = container_of(flow, struct flow_offload_entry, flow);
        clear_bit(IPS_OFFLOAD_BIT, &e->ct->status);
 
+       if (nf_flow_has_expired(flow))
+               flow_offload_fixup_ct(e->ct);
+       else if (flow->flags & FLOW_OFFLOAD_TEARDOWN)
+               flow_offload_fixup_ct_timeout(e->ct);
+
        flow_offload_free(flow);
 }
 
@@ -298,11 +322,6 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
        return err;
 }
 
-static inline bool nf_flow_has_expired(const struct flow_offload *flow)
-{
-       return (__s32)(flow->timeout - (u32)jiffies) <= 0;
-}
-
 static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data)
 {
        struct nf_flowtable *flow_table = data;
index cdfc335..d68c801 100644 (file)
@@ -214,6 +214,25 @@ static bool nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
        return true;
 }
 
+static int nf_flow_offload_dst_check(struct dst_entry *dst)
+{
+       if (unlikely(dst_xfrm(dst)))
+               return dst_check(dst, 0) ? 0 : -1;
+
+       return 0;
+}
+
+static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
+                                     const struct nf_hook_state *state,
+                                     struct dst_entry *dst)
+{
+       skb_orphan(skb);
+       skb_dst_set_noref(skb, dst);
+       skb->tstamp = 0;
+       dst_output(state->net, state->sk, skb);
+       return NF_STOLEN;
+}
+
 unsigned int
 nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
                        const struct nf_hook_state *state)
@@ -254,6 +273,11 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
        if (nf_flow_state_check(flow, ip_hdr(skb)->protocol, skb, thoff))
                return NF_ACCEPT;
 
+       if (nf_flow_offload_dst_check(&rt->dst)) {
+               flow_offload_teardown(flow);
+               return NF_ACCEPT;
+       }
+
        if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0)
                return NF_DROP;
 
@@ -261,6 +285,13 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
        iph = ip_hdr(skb);
        ip_decrease_ttl(iph);
 
+       if (unlikely(dst_xfrm(&rt->dst))) {
+               memset(skb->cb, 0, sizeof(struct inet_skb_parm));
+               IPCB(skb)->iif = skb->dev->ifindex;
+               IPCB(skb)->flags = IPSKB_FORWARDED;
+               return nf_flow_xmit_xfrm(skb, state, &rt->dst);
+       }
+
        skb->dev = outdev;
        nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
        skb_dst_set_noref(skb, &rt->dst);
@@ -467,6 +498,11 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
                                sizeof(*ip6h)))
                return NF_ACCEPT;
 
+       if (nf_flow_offload_dst_check(&rt->dst)) {
+               flow_offload_teardown(flow);
+               return NF_ACCEPT;
+       }
+
        if (skb_try_make_writable(skb, sizeof(*ip6h)))
                return NF_DROP;
 
@@ -477,6 +513,13 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
        ip6h = ipv6_hdr(skb);
        ip6h->hop_limit--;
 
+       if (unlikely(dst_xfrm(&rt->dst))) {
+               memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+               IP6CB(skb)->iif = skb->dev->ifindex;
+               IP6CB(skb)->flags = IP6SKB_FORWARDED;
+               return nf_flow_xmit_xfrm(skb, state, &rt->dst);
+       }
+
        skb->dev = outdev;
        nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
        skb_dst_set_noref(skb, &rt->dst);
index 605a7cf..d47469f 100644 (file)
@@ -138,9 +138,14 @@ static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
                return;
 
        list_for_each_entry_reverse(trans, &net->nft.commit_list, list) {
-               if (trans->msg_type == NFT_MSG_NEWSET &&
-                   nft_trans_set(trans) == set) {
-                       set->bound = true;
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWSET:
+                       if (nft_trans_set(trans) == set)
+                               nft_trans_set_bound(trans) = true;
+                       break;
+               case NFT_MSG_NEWSETELEM:
+                       if (nft_trans_elem_set(trans) == set)
+                               nft_trans_elem_set_bound(trans) = true;
                        break;
                }
        }
@@ -1662,6 +1667,10 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
 
                chain->flags |= NFT_BASE_CHAIN | flags;
                basechain->policy = NF_ACCEPT;
+               if (chain->flags & NFT_CHAIN_HW_OFFLOAD &&
+                   nft_chain_offload_priority(basechain) < 0)
+                       return -EOPNOTSUPP;
+
                flow_block_init(&basechain->flow_block);
        } else {
                chain = kzalloc(sizeof(*chain), GFP_KERNEL);
@@ -6906,7 +6915,7 @@ static int __nf_tables_abort(struct net *net)
                        break;
                case NFT_MSG_NEWSET:
                        trans->ctx.table->use--;
-                       if (nft_trans_set(trans)->bound) {
+                       if (nft_trans_set_bound(trans)) {
                                nft_trans_destroy(trans);
                                break;
                        }
@@ -6918,7 +6927,7 @@ static int __nf_tables_abort(struct net *net)
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_NEWSETELEM:
-                       if (nft_trans_elem_set(trans)->bound) {
+                       if (nft_trans_elem_set_bound(trans)) {
                                nft_trans_destroy(trans);
                                break;
                        }
index 64f5fd5..c0d18c1 100644 (file)
@@ -103,10 +103,11 @@ void nft_offload_update_dependency(struct nft_offload_ctx *ctx,
 }
 
 static void nft_flow_offload_common_init(struct flow_cls_common_offload *common,
-                                        __be16 proto,
-                                       struct netlink_ext_ack *extack)
+                                        __be16 proto, int priority,
+                                        struct netlink_ext_ack *extack)
 {
        common->protocol = proto;
+       common->prio = priority;
        common->extack = extack;
 }
 
@@ -124,6 +125,15 @@ static int nft_setup_cb_call(struct nft_base_chain *basechain,
        return 0;
 }
 
+int nft_chain_offload_priority(struct nft_base_chain *basechain)
+{
+       if (basechain->ops.priority <= 0 ||
+           basechain->ops.priority > USHRT_MAX)
+               return -1;
+
+       return 0;
+}
+
 static int nft_flow_offload_rule(struct nft_trans *trans,
                                 enum flow_cls_command command)
 {
@@ -142,7 +152,8 @@ static int nft_flow_offload_rule(struct nft_trans *trans,
        if (flow)
                proto = flow->proto;
 
-       nft_flow_offload_common_init(&cls_flow.common, proto, &extack);
+       nft_flow_offload_common_init(&cls_flow.common, proto,
+                                    basechain->ops.priority, &extack);
        cls_flow.command = command;
        cls_flow.cookie = (unsigned long) rule;
        if (flow)
index aa5f571..060a4ed 100644 (file)
@@ -72,11 +72,11 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 {
        struct nft_flow_offload *priv = nft_expr_priv(expr);
        struct nf_flowtable *flowtable = &priv->flowtable->data;
+       struct tcphdr _tcph, *tcph = NULL;
        enum ip_conntrack_info ctinfo;
        struct nf_flow_route route;
        struct flow_offload *flow;
        enum ip_conntrack_dir dir;
-       bool is_tcp = false;
        struct nf_conn *ct;
        int ret;
 
@@ -89,7 +89,10 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 
        switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
        case IPPROTO_TCP:
-               is_tcp = true;
+               tcph = skb_header_pointer(pkt->skb, pkt->xt.thoff,
+                                         sizeof(_tcph), &_tcph);
+               if (unlikely(!tcph || tcph->fin || tcph->rst))
+                       goto out;
                break;
        case IPPROTO_UDP:
                break;
@@ -115,7 +118,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
        if (!flow)
                goto err_flow_alloc;
 
-       if (is_tcp) {
+       if (tcph) {
                ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
                ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
        }
index 8d54f30..e2742b0 100644 (file)
@@ -2618,6 +2618,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
 
        mutex_lock(&po->pg_vec_lock);
 
+       /* packet_sendmsg() check on tx_ring.pg_vec was lockless,
+        * we need to confirm it under protection of pg_vec_lock.
+        */
+       if (unlikely(!po->tx_ring.pg_vec)) {
+               err = -EBUSY;
+               goto out;
+       }
        if (likely(saddr == NULL)) {
                dev     = packet_cached_dev_get(po);
                proto   = po->num;
index d09eaf1..0dbbfd1 100644 (file)
@@ -193,7 +193,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
 
 service_in_use:
        write_unlock(&local->services_lock);
-       rxrpc_put_local(local);
+       rxrpc_unuse_local(local);
        ret = -EADDRINUSE;
 error_unlock:
        release_sock(&rx->sk);
@@ -402,7 +402,7 @@ EXPORT_SYMBOL(rxrpc_kernel_check_life);
  */
 void rxrpc_kernel_probe_life(struct socket *sock, struct rxrpc_call *call)
 {
-       rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
+       rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, false,
                          rxrpc_propose_ack_ping_for_check_life);
        rxrpc_send_ack_packet(call, true, NULL);
 }
@@ -901,7 +901,7 @@ static int rxrpc_release_sock(struct sock *sk)
        rxrpc_queue_work(&rxnet->service_conn_reaper);
        rxrpc_queue_work(&rxnet->client_conn_reaper);
 
-       rxrpc_put_local(rx->local);
+       rxrpc_unuse_local(rx->local);
        rx->local = NULL;
        key_put(rx->key);
        rx->key = NULL;
index 822f453..1453356 100644 (file)
@@ -254,7 +254,8 @@ struct rxrpc_security {
  */
 struct rxrpc_local {
        struct rcu_head         rcu;
-       atomic_t                usage;
+       atomic_t                active_users;   /* Number of users of the local endpoint */
+       atomic_t                usage;          /* Number of references to the structure */
        struct rxrpc_net        *rxnet;         /* The network ns in which this resides */
        struct list_head        link;
        struct socket           *socket;        /* my UDP socket */
@@ -649,7 +650,6 @@ struct rxrpc_call {
 
        /* receive-phase ACK management */
        u8                      ackr_reason;    /* reason to ACK */
-       u16                     ackr_skew;      /* skew on packet being ACK'd */
        rxrpc_serial_t          ackr_serial;    /* serial of packet being ACK'd */
        rxrpc_serial_t          ackr_first_seq; /* first sequence number received */
        rxrpc_seq_t             ackr_prev_seq;  /* previous sequence number received */
@@ -743,7 +743,7 @@ int rxrpc_reject_call(struct rxrpc_sock *);
 /*
  * call_event.c
  */
-void rxrpc_propose_ACK(struct rxrpc_call *, u8, u16, u32, bool, bool,
+void rxrpc_propose_ACK(struct rxrpc_call *, u8, u32, bool, bool,
                       enum rxrpc_propose_ack_trace);
 void rxrpc_process_call(struct work_struct *);
 
@@ -1002,6 +1002,8 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *, const struct sockaddr_rxrpc
 struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *);
 struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *);
 void rxrpc_put_local(struct rxrpc_local *);
+struct rxrpc_local *rxrpc_use_local(struct rxrpc_local *);
+void rxrpc_unuse_local(struct rxrpc_local *);
 void rxrpc_queue_local(struct rxrpc_local *);
 void rxrpc_destroy_all_locals(struct rxrpc_net *);
 
index bc2adeb..c767679 100644 (file)
@@ -43,8 +43,7 @@ static void rxrpc_propose_ping(struct rxrpc_call *call,
  * propose an ACK be sent
  */
 static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
-                               u16 skew, u32 serial, bool immediate,
-                               bool background,
+                               u32 serial, bool immediate, bool background,
                                enum rxrpc_propose_ack_trace why)
 {
        enum rxrpc_propose_ack_outcome outcome = rxrpc_propose_ack_use;
@@ -69,14 +68,12 @@ static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
                if (RXRPC_ACK_UPDATEABLE & (1 << ack_reason)) {
                        outcome = rxrpc_propose_ack_update;
                        call->ackr_serial = serial;
-                       call->ackr_skew = skew;
                }
                if (!immediate)
                        goto trace;
        } else if (prior > rxrpc_ack_priority[call->ackr_reason]) {
                call->ackr_reason = ack_reason;
                call->ackr_serial = serial;
-               call->ackr_skew = skew;
        } else {
                outcome = rxrpc_propose_ack_subsume;
        }
@@ -137,11 +134,11 @@ trace:
  * propose an ACK be sent, locking the call structure
  */
 void rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
-                      u16 skew, u32 serial, bool immediate, bool background,
+                      u32 serial, bool immediate, bool background,
                       enum rxrpc_propose_ack_trace why)
 {
        spin_lock_bh(&call->lock);
-       __rxrpc_propose_ACK(call, ack_reason, skew, serial,
+       __rxrpc_propose_ACK(call, ack_reason, serial,
                            immediate, background, why);
        spin_unlock_bh(&call->lock);
 }
@@ -239,7 +236,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
                ack_ts = ktime_sub(now, call->acks_latest_ts);
                if (ktime_to_ns(ack_ts) < call->peer->rtt)
                        goto out;
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, false,
                                  rxrpc_propose_ack_ping_for_lost_ack);
                rxrpc_send_ack_packet(call, true, NULL);
                goto out;
@@ -372,7 +369,7 @@ recheck_state:
        if (time_after_eq(now, t)) {
                trace_rxrpc_timer(call, rxrpc_timer_exp_keepalive, now);
                cmpxchg(&call->keepalive_at, t, now + MAX_JIFFY_OFFSET);
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, true,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, true,
                                  rxrpc_propose_ack_ping_for_keepalive);
                set_bit(RXRPC_CALL_EV_PING, &call->events);
        }
@@ -407,7 +404,7 @@ recheck_state:
        send_ack = NULL;
        if (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events)) {
                call->acks_lost_top = call->tx_top;
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, false,
                                  rxrpc_propose_ack_ping_for_lost_ack);
                send_ack = &call->acks_lost_ping;
        }
index 5bd6f15..dd47d46 100644 (file)
@@ -196,15 +196,14 @@ send_extra_data:
  * Ping the other end to fill our RTT cache and to retrieve the rwind
  * and MTU parameters.
  */
-static void rxrpc_send_ping(struct rxrpc_call *call, struct sk_buff *skb,
-                           int skew)
+static void rxrpc_send_ping(struct rxrpc_call *call, struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        ktime_t now = skb->tstamp;
 
        if (call->peer->rtt_usage < 3 ||
            ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000), now))
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, skew, sp->hdr.serial,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, sp->hdr.serial,
                                  true, true,
                                  rxrpc_propose_ack_ping_for_params);
 }
@@ -419,8 +418,7 @@ static void rxrpc_input_dup_data(struct rxrpc_call *call, rxrpc_seq_t seq,
 /*
  * Process a DATA packet, adding the packet to the Rx ring.
  */
-static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,
-                            u16 skew)
+static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        enum rxrpc_call_state state;
@@ -600,11 +598,11 @@ skip:
 
 ack:
        if (ack)
-               rxrpc_propose_ACK(call, ack, skew, ack_serial,
+               rxrpc_propose_ACK(call, ack, ack_serial,
                                  immediate_ack, true,
                                  rxrpc_propose_ack_input_data);
        else
-               rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, skew, serial,
+               rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial,
                                  false, true,
                                  rxrpc_propose_ack_input_data);
 
@@ -822,8 +820,7 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call, u8 *acks,
  * soft-ACK means that the packet may be discarded and retransmission
  * requested.  A phase is complete when all packets are hard-ACK'd.
  */
-static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
-                           u16 skew)
+static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
 {
        struct rxrpc_ack_summary summary = { 0 };
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
@@ -867,11 +864,11 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
        if (buf.ack.reason == RXRPC_ACK_PING) {
                _proto("Rx ACK %%%u PING Request", sp->hdr.serial);
                rxrpc_propose_ACK(call, RXRPC_ACK_PING_RESPONSE,
-                                 skew, sp->hdr.serial, true, true,
+                                 sp->hdr.serial, true, true,
                                  rxrpc_propose_ack_respond_to_ping);
        } else if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
                rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED,
-                                 skew, sp->hdr.serial, true, true,
+                                 sp->hdr.serial, true, true,
                                  rxrpc_propose_ack_respond_to_ack);
        }
 
@@ -948,7 +945,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
            RXRPC_TX_ANNO_LAST &&
            summary.nr_acks == call->tx_top - hard_ack &&
            rxrpc_is_client_call(call))
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, skew, sp->hdr.serial,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, sp->hdr.serial,
                                  false, true,
                                  rxrpc_propose_ack_ping_for_lost_reply);
 
@@ -1004,7 +1001,7 @@ static void rxrpc_input_abort(struct rxrpc_call *call, struct sk_buff *skb)
  * Process an incoming call packet.
  */
 static void rxrpc_input_call_packet(struct rxrpc_call *call,
-                                   struct sk_buff *skb, u16 skew)
+                                   struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        unsigned long timo;
@@ -1023,11 +1020,11 @@ static void rxrpc_input_call_packet(struct rxrpc_call *call,
 
        switch (sp->hdr.type) {
        case RXRPC_PACKET_TYPE_DATA:
-               rxrpc_input_data(call, skb, skew);
+               rxrpc_input_data(call, skb);
                break;
 
        case RXRPC_PACKET_TYPE_ACK:
-               rxrpc_input_ack(call, skb, skew);
+               rxrpc_input_ack(call, skb);
                break;
 
        case RXRPC_PACKET_TYPE_BUSY:
@@ -1108,8 +1105,12 @@ static void rxrpc_post_packet_to_local(struct rxrpc_local *local,
 {
        _enter("%p,%p", local, skb);
 
-       skb_queue_tail(&local->event_queue, skb);
-       rxrpc_queue_local(local);
+       if (rxrpc_get_local_maybe(local)) {
+               skb_queue_tail(&local->event_queue, skb);
+               rxrpc_queue_local(local);
+       } else {
+               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       }
 }
 
 /*
@@ -1119,8 +1120,12 @@ static void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
 {
        CHECK_SLAB_OKAY(&local->usage);
 
-       skb_queue_tail(&local->reject_queue, skb);
-       rxrpc_queue_local(local);
+       if (rxrpc_get_local_maybe(local)) {
+               skb_queue_tail(&local->reject_queue, skb);
+               rxrpc_queue_local(local);
+       } else {
+               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       }
 }
 
 /*
@@ -1173,7 +1178,6 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
        struct rxrpc_peer *peer = NULL;
        struct rxrpc_sock *rx = NULL;
        unsigned int channel;
-       int skew = 0;
 
        _enter("%p", udp_sk);
 
@@ -1301,15 +1305,8 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
                        goto out;
                }
 
-               /* Note the serial number skew here */
-               skew = (int)sp->hdr.serial - (int)conn->hi_serial;
-               if (skew >= 0) {
-                       if (skew > 0)
-                               conn->hi_serial = sp->hdr.serial;
-               } else {
-                       skew = -skew;
-                       skew = min(skew, 65535);
-               }
+               if ((int)sp->hdr.serial - (int)conn->hi_serial > 0)
+                       conn->hi_serial = sp->hdr.serial;
 
                /* Call-bound packets are routed by connection channel. */
                channel = sp->hdr.cid & RXRPC_CHANNELMASK;
@@ -1372,11 +1369,11 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
                call = rxrpc_new_incoming_call(local, rx, skb);
                if (!call)
                        goto reject_packet;
-               rxrpc_send_ping(call, skb, skew);
+               rxrpc_send_ping(call, skb);
                mutex_unlock(&call->user_mutex);
        }
 
-       rxrpc_input_call_packet(call, skb, skew);
+       rxrpc_input_call_packet(call, skb);
        goto discard;
 
 discard:
index b1c71ba..72a6e12 100644 (file)
@@ -79,6 +79,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
        local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
        if (local) {
                atomic_set(&local->usage, 1);
+               atomic_set(&local->active_users, 1);
                local->rxnet = rxnet;
                INIT_LIST_HEAD(&local->link);
                INIT_WORK(&local->processor, rxrpc_local_processor);
@@ -92,7 +93,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
                local->debug_id = atomic_inc_return(&rxrpc_debug_id);
                memcpy(&local->srx, srx, sizeof(*srx));
                local->srx.srx_service = 0;
-               trace_rxrpc_local(local, rxrpc_local_new, 1, NULL);
+               trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, NULL);
        }
 
        _leave(" = %p", local);
@@ -266,11 +267,8 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
                 * bind the transport socket may still fail if we're attempting
                 * to use a local address that the dying object is still using.
                 */
-               if (!rxrpc_get_local_maybe(local)) {
-                       cursor = cursor->next;
-                       list_del_init(&local->link);
+               if (!rxrpc_use_local(local))
                        break;
-               }
 
                age = "old";
                goto found;
@@ -284,7 +282,10 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
        if (ret < 0)
                goto sock_error;
 
-       list_add_tail(&local->link, cursor);
+       if (cursor != &rxnet->local_endpoints)
+               list_replace_init(cursor, &local->link);
+       else
+               list_add_tail(&local->link, cursor);
        age = "new";
 
 found:
@@ -320,7 +321,7 @@ struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *local)
        int n;
 
        n = atomic_inc_return(&local->usage);
-       trace_rxrpc_local(local, rxrpc_local_got, n, here);
+       trace_rxrpc_local(local->debug_id, rxrpc_local_got, n, here);
        return local;
 }
 
@@ -334,7 +335,8 @@ struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local)
        if (local) {
                int n = atomic_fetch_add_unless(&local->usage, 1, 0);
                if (n > 0)
-                       trace_rxrpc_local(local, rxrpc_local_got, n + 1, here);
+                       trace_rxrpc_local(local->debug_id, rxrpc_local_got,
+                                         n + 1, here);
                else
                        local = NULL;
        }
@@ -342,24 +344,18 @@ struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local)
 }
 
 /*
- * Queue a local endpoint.
+ * Queue a local endpoint and pass the caller's reference to the work item.
  */
 void rxrpc_queue_local(struct rxrpc_local *local)
 {
        const void *here = __builtin_return_address(0);
+       unsigned int debug_id = local->debug_id;
+       int n = atomic_read(&local->usage);
 
        if (rxrpc_queue_work(&local->processor))
-               trace_rxrpc_local(local, rxrpc_local_queued,
-                                 atomic_read(&local->usage), here);
-}
-
-/*
- * A local endpoint reached its end of life.
- */
-static void __rxrpc_put_local(struct rxrpc_local *local)
-{
-       _enter("%d", local->debug_id);
-       rxrpc_queue_work(&local->processor);
+               trace_rxrpc_local(debug_id, rxrpc_local_queued, n, here);
+       else
+               rxrpc_put_local(local);
 }
 
 /*
@@ -372,10 +368,47 @@ void rxrpc_put_local(struct rxrpc_local *local)
 
        if (local) {
                n = atomic_dec_return(&local->usage);
-               trace_rxrpc_local(local, rxrpc_local_put, n, here);
+               trace_rxrpc_local(local->debug_id, rxrpc_local_put, n, here);
 
                if (n == 0)
-                       __rxrpc_put_local(local);
+                       call_rcu(&local->rcu, rxrpc_local_rcu);
+       }
+}
+
+/*
+ * Start using a local endpoint.
+ */
+struct rxrpc_local *rxrpc_use_local(struct rxrpc_local *local)
+{
+       unsigned int au;
+
+       local = rxrpc_get_local_maybe(local);
+       if (!local)
+               return NULL;
+
+       au = atomic_fetch_add_unless(&local->active_users, 1, 0);
+       if (au == 0) {
+               rxrpc_put_local(local);
+               return NULL;
+       }
+
+       return local;
+}
+
+/*
+ * Cease using a local endpoint.  Once the number of active users reaches 0, we
+ * start the closure of the transport in the work processor.
+ */
+void rxrpc_unuse_local(struct rxrpc_local *local)
+{
+       unsigned int au;
+
+       if (local) {
+               au = atomic_dec_return(&local->active_users);
+               if (au == 0)
+                       rxrpc_queue_local(local);
+               else
+                       rxrpc_put_local(local);
        }
 }
 
@@ -393,16 +426,6 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
 
        _enter("%d", local->debug_id);
 
-       /* We can get a race between an incoming call packet queueing the
-        * processor again and the work processor starting the destruction
-        * process which will shut down the UDP socket.
-        */
-       if (local->dead) {
-               _leave(" [already dead]");
-               return;
-       }
-       local->dead = true;
-
        mutex_lock(&rxnet->local_mutex);
        list_del_init(&local->link);
        mutex_unlock(&rxnet->local_mutex);
@@ -422,13 +445,11 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
         */
        rxrpc_purge_queue(&local->reject_queue);
        rxrpc_purge_queue(&local->event_queue);
-
-       _debug("rcu local %d", local->debug_id);
-       call_rcu(&local->rcu, rxrpc_local_rcu);
 }
 
 /*
- * Process events on an endpoint
+ * Process events on an endpoint.  The work item carries a ref which
+ * we must release.
  */
 static void rxrpc_local_processor(struct work_struct *work)
 {
@@ -436,13 +457,15 @@ static void rxrpc_local_processor(struct work_struct *work)
                container_of(work, struct rxrpc_local, processor);
        bool again;
 
-       trace_rxrpc_local(local, rxrpc_local_processing,
+       trace_rxrpc_local(local->debug_id, rxrpc_local_processing,
                          atomic_read(&local->usage), NULL);
 
        do {
                again = false;
-               if (atomic_read(&local->usage) == 0)
-                       return rxrpc_local_destroyer(local);
+               if (atomic_read(&local->active_users) == 0) {
+                       rxrpc_local_destroyer(local);
+                       break;
+               }
 
                if (!skb_queue_empty(&local->reject_queue)) {
                        rxrpc_reject_packets(local);
@@ -454,6 +477,8 @@ static void rxrpc_local_processor(struct work_struct *work)
                        again = true;
                }
        } while (again);
+
+       rxrpc_put_local(local);
 }
 
 /*
index 948e3fe..369e516 100644 (file)
@@ -87,7 +87,7 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
        *_top = top;
 
        pkt->ack.bufferSpace    = htons(8);
-       pkt->ack.maxSkew        = htons(call->ackr_skew);
+       pkt->ack.maxSkew        = htons(0);
        pkt->ack.firstPacket    = htonl(hard_ack + 1);
        pkt->ack.previousPacket = htonl(call->ackr_prev_seq);
        pkt->ack.serial         = htonl(serial);
@@ -228,7 +228,6 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
                        if (ping)
                                clear_bit(RXRPC_CALL_PINGING, &call->flags);
                        rxrpc_propose_ACK(call, pkt->ack.reason,
-                                         ntohs(pkt->ack.maxSkew),
                                          ntohl(pkt->ack.serial),
                                          false, true,
                                          rxrpc_propose_ack_retry_tx);
index 5abf46c..9a7e1bc 100644 (file)
@@ -141,7 +141,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
        ASSERTCMP(call->rx_hard_ack, ==, call->rx_top);
 
        if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY) {
-               rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, 0, serial, false, true,
+               rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, serial, false, true,
                                  rxrpc_propose_ack_terminal_ack);
                //rxrpc_send_ack_packet(call, false, NULL);
        }
@@ -159,7 +159,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
                call->state = RXRPC_CALL_SERVER_ACK_REQUEST;
                call->expect_req_by = jiffies + MAX_JIFFY_OFFSET;
                write_unlock_bh(&call->state_lock);
-               rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, 0, serial, false, true,
+               rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial, false, true,
                                  rxrpc_propose_ack_processing_op);
                break;
        default:
@@ -212,7 +212,7 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
                if (after_eq(hard_ack, call->ackr_consumed + 2) ||
                    after_eq(top, call->ackr_seen + 2) ||
                    (hard_ack == top && after(hard_ack, call->ackr_consumed)))
-                       rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, 0, serial,
+                       rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial,
                                          true, true,
                                          rxrpc_propose_ack_rotate_rx);
                if (call->ackr_reason && call->ackr_reason != RXRPC_ACK_DELAY)
index b100870..37dced0 100644 (file)
@@ -307,6 +307,17 @@ static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index)
        return tcf_idr_search(tn, a, index);
 }
 
+static size_t tcf_skbedit_get_fill_size(const struct tc_action *act)
+{
+       return nla_total_size(sizeof(struct tc_skbedit))
+               + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_PRIORITY */
+               + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_QUEUE_MAPPING */
+               + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MARK */
+               + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_PTYPE */
+               + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MASK */
+               + nla_total_size_64bit(sizeof(u64)); /* TCA_SKBEDIT_FLAGS */
+}
+
 static struct tc_action_ops act_skbedit_ops = {
        .kind           =       "skbedit",
        .id             =       TCA_ID_SKBEDIT,
@@ -316,6 +327,7 @@ static struct tc_action_ops act_skbedit_ops = {
        .init           =       tcf_skbedit_init,
        .cleanup        =       tcf_skbedit_cleanup,
        .walk           =       tcf_skbedit_walker,
+       .get_fill_size  =       tcf_skbedit_get_fill_size,
        .lookup         =       tcf_skbedit_search,
        .size           =       sizeof(struct tcf_skbedit),
 };
index c39db50..e25d414 100644 (file)
@@ -1195,7 +1195,8 @@ unlock:
        spin_unlock_bh(qdisc_lock(sch));
 
 free_sched:
-       kfree(new_admin);
+       if (new_admin)
+               call_rcu(&new_admin->rcu, taprio_free_sched_cb);
 
        return err;
 }
index a554d6d..1cf5bb5 100644 (file)
@@ -546,7 +546,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_cmd_seq *commands,
         */
        if (net->sctp.pf_enable &&
           (transport->state == SCTP_ACTIVE) &&
-          (asoc->pf_retrans < transport->pathmaxrxt) &&
+          (transport->error_count < transport->pathmaxrxt) &&
           (transport->error_count > asoc->pf_retrans)) {
 
                sctp_assoc_control_transport(asoc, transport,
index 2594660..e83cdaa 100644 (file)
@@ -316,6 +316,7 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
                nstr_list[i] = htons(str_list[i]);
 
        if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
+               kfree(nstr_list);
                retval = -EAGAIN;
                goto out;
        }
index b88d48d..0f1eaed 100644 (file)
@@ -75,6 +75,7 @@ void tipc_set_node_addr(struct net *net, u32 addr)
                tipc_set_node_id(net, node_id);
        }
        tn->trial_addr = addr;
+       tn->addr_trial_end = jiffies;
        pr_info("32-bit node address hash set to %x\n", addr);
 }
 
index 66d3a07..c2c5c53 100644 (file)
@@ -106,8 +106,6 @@ struct tipc_stats {
  * @transmitq: queue for sent, non-acked messages
  * @backlogq: queue for messages waiting to be sent
  * @snt_nxt: next sequence number to use for outbound messages
- * @prev_from: sequence number of most previous retransmission request
- * @stale_limit: time when repeated identical retransmits must force link reset
  * @ackers: # of peers that needs to ack each packet before it can be released
  * @acked: # last packet acked by a certain peer. Used for broadcast.
  * @rcv_nxt: next sequence number to expect for inbound messages
@@ -164,9 +162,7 @@ struct tipc_link {
                u16 limit;
        } backlog[5];
        u16 snd_nxt;
-       u16 prev_from;
        u16 window;
-       unsigned long stale_limit;
 
        /* Reception */
        u16 rcv_nxt;
@@ -1044,47 +1040,53 @@ static void tipc_link_advance_backlog(struct tipc_link *l,
  * link_retransmit_failure() - Detect repeated retransmit failures
  * @l: tipc link sender
  * @r: tipc link receiver (= l in case of unicast)
- * @from: seqno of the 1st packet in retransmit request
  * @rc: returned code
  *
  * Return: true if the repeated retransmit failures happens, otherwise
  * false
  */
 static bool link_retransmit_failure(struct tipc_link *l, struct tipc_link *r,
-                                   u16 from, int *rc)
+                                   int *rc)
 {
        struct sk_buff *skb = skb_peek(&l->transmq);
        struct tipc_msg *hdr;
 
        if (!skb)
                return false;
-       hdr = buf_msg(skb);
 
-       /* Detect repeated retransmit failures on same packet */
-       if (r->prev_from != from) {
-               r->prev_from = from;
-               r->stale_limit = jiffies + msecs_to_jiffies(r->tolerance);
-       } else if (time_after(jiffies, r->stale_limit)) {
-               pr_warn("Retransmission failure on link <%s>\n", l->name);
-               link_print(l, "State of link ");
-               pr_info("Failed msg: usr %u, typ %u, len %u, err %u\n",
-                       msg_user(hdr), msg_type(hdr), msg_size(hdr),
-                       msg_errcode(hdr));
-               pr_info("sqno %u, prev: %x, src: %x\n",
-                       msg_seqno(hdr), msg_prevnode(hdr), msg_orignode(hdr));
-
-               trace_tipc_list_dump(&l->transmq, true, "retrans failure!");
-               trace_tipc_link_dump(l, TIPC_DUMP_NONE, "retrans failure!");
-               trace_tipc_link_dump(r, TIPC_DUMP_NONE, "retrans failure!");
+       if (!TIPC_SKB_CB(skb)->retr_cnt)
+               return false;
 
-               if (link_is_bc_sndlink(l))
-                       *rc = TIPC_LINK_DOWN_EVT;
+       if (!time_after(jiffies, TIPC_SKB_CB(skb)->retr_stamp +
+                       msecs_to_jiffies(r->tolerance)))
+               return false;
+
+       hdr = buf_msg(skb);
+       if (link_is_bc_sndlink(l) && !less(r->acked, msg_seqno(hdr)))
+               return false;
 
+       pr_warn("Retransmission failure on link <%s>\n", l->name);
+       link_print(l, "State of link ");
+       pr_info("Failed msg: usr %u, typ %u, len %u, err %u\n",
+               msg_user(hdr), msg_type(hdr), msg_size(hdr), msg_errcode(hdr));
+       pr_info("sqno %u, prev: %x, dest: %x\n",
+               msg_seqno(hdr), msg_prevnode(hdr), msg_destnode(hdr));
+       pr_info("retr_stamp %d, retr_cnt %d\n",
+               jiffies_to_msecs(TIPC_SKB_CB(skb)->retr_stamp),
+               TIPC_SKB_CB(skb)->retr_cnt);
+
+       trace_tipc_list_dump(&l->transmq, true, "retrans failure!");
+       trace_tipc_link_dump(l, TIPC_DUMP_NONE, "retrans failure!");
+       trace_tipc_link_dump(r, TIPC_DUMP_NONE, "retrans failure!");
+
+       if (link_is_bc_sndlink(l)) {
+               r->state = LINK_RESET;
+               *rc = TIPC_LINK_DOWN_EVT;
+       } else {
                *rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT);
-               return true;
        }
 
-       return false;
+       return true;
 }
 
 /* tipc_link_bc_retrans() - retransmit zero or more packets
@@ -1110,7 +1112,7 @@ static int tipc_link_bc_retrans(struct tipc_link *l, struct tipc_link *r,
 
        trace_tipc_link_retrans(r, from, to, &l->transmq);
 
-       if (link_retransmit_failure(l, r, from, &rc))
+       if (link_retransmit_failure(l, r, &rc))
                return rc;
 
        skb_queue_walk(&l->transmq, skb) {
@@ -1119,11 +1121,10 @@ static int tipc_link_bc_retrans(struct tipc_link *l, struct tipc_link *r,
                        continue;
                if (more(msg_seqno(hdr), to))
                        break;
-               if (link_is_bc_sndlink(l)) {
-                       if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr))
-                               continue;
-                       TIPC_SKB_CB(skb)->nxt_retr = TIPC_BC_RETR_LIM;
-               }
+
+               if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr))
+                       continue;
+               TIPC_SKB_CB(skb)->nxt_retr = TIPC_BC_RETR_LIM;
                _skb = __pskb_copy(skb, LL_MAX_HEADER + MIN_H_SIZE, GFP_ATOMIC);
                if (!_skb)
                        return 0;
@@ -1133,6 +1134,10 @@ static int tipc_link_bc_retrans(struct tipc_link *l, struct tipc_link *r,
                _skb->priority = TC_PRIO_CONTROL;
                __skb_queue_tail(xmitq, _skb);
                l->stats.retransmitted++;
+
+               /* Increase actual retrans counter & mark first time */
+               if (!TIPC_SKB_CB(skb)->retr_cnt++)
+                       TIPC_SKB_CB(skb)->retr_stamp = jiffies;
        }
        return 0;
 }
@@ -1357,12 +1362,10 @@ static int tipc_link_advance_transmq(struct tipc_link *l, u16 acked, u16 gap,
        struct tipc_msg *hdr;
        u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1;
        u16 ack = l->rcv_nxt - 1;
+       bool passed = false;
        u16 seqno, n = 0;
        int rc = 0;
 
-       if (gap && link_retransmit_failure(l, l, acked + 1, &rc))
-               return rc;
-
        skb_queue_walk_safe(&l->transmq, skb, tmp) {
                seqno = buf_seqno(skb);
 
@@ -1372,12 +1375,17 @@ next_gap_ack:
                        __skb_unlink(skb, &l->transmq);
                        kfree_skb(skb);
                } else if (less_eq(seqno, acked + gap)) {
-                       /* retransmit skb */
+                       /* First, check if repeated retrans failures occurs? */
+                       if (!passed && link_retransmit_failure(l, l, &rc))
+                               return rc;
+                       passed = true;
+
+                       /* retransmit skb if unrestricted*/
                        if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr))
                                continue;
                        TIPC_SKB_CB(skb)->nxt_retr = TIPC_UC_RETR_TIME;
-
-                       _skb = __pskb_copy(skb, MIN_H_SIZE, GFP_ATOMIC);
+                       _skb = __pskb_copy(skb, LL_MAX_HEADER + MIN_H_SIZE,
+                                          GFP_ATOMIC);
                        if (!_skb)
                                continue;
                        hdr = buf_msg(_skb);
@@ -1386,6 +1394,10 @@ next_gap_ack:
                        _skb->priority = TC_PRIO_CONTROL;
                        __skb_queue_tail(xmitq, _skb);
                        l->stats.retransmitted++;
+
+                       /* Increase actual retrans counter & mark first time */
+                       if (!TIPC_SKB_CB(skb)->retr_cnt++)
+                               TIPC_SKB_CB(skb)->retr_stamp = jiffies;
                } else {
                        /* retry with Gap ACK blocks if any */
                        if (!ga || n >= ga->gack_cnt)
@@ -2577,7 +2589,7 @@ int tipc_link_dump(struct tipc_link *l, u16 dqueues, char *buf)
        i += scnprintf(buf + i, sz - i, " %x", l->peer_caps);
        i += scnprintf(buf + i, sz - i, " %u", l->silent_intv_cnt);
        i += scnprintf(buf + i, sz - i, " %u", l->rst_cnt);
-       i += scnprintf(buf + i, sz - i, " %u", l->prev_from);
+       i += scnprintf(buf + i, sz - i, " %u", 0);
        i += scnprintf(buf + i, sz - i, " %u", 0);
        i += scnprintf(buf + i, sz - i, " %u", l->acked);
 
index da509f0..d7ebc9e 100644 (file)
@@ -102,13 +102,15 @@ struct plist;
 #define TIPC_MEDIA_INFO_OFFSET 5
 
 struct tipc_skb_cb {
-       u32 bytes_read;
-       u32 orig_member;
        struct sk_buff *tail;
        unsigned long nxt_retr;
-       bool validated;
+       unsigned long retr_stamp;
+       u32 bytes_read;
+       u32 orig_member;
        u16 chain_imp;
        u16 ackers;
+       u16 retr_cnt;
+       bool validated;
 };
 
 #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
index 7c0b2b7..43922d8 100644 (file)
@@ -373,9 +373,9 @@ static int tls_push_data(struct sock *sk,
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_prot_info *prot = &tls_ctx->prot_info;
        struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx);
-       int tls_push_record_flags = flags | MSG_SENDPAGE_NOTLAST;
        int more = flags & (MSG_SENDPAGE_NOTLAST | MSG_MORE);
        struct tls_record_info *record = ctx->open_record;
+       int tls_push_record_flags;
        struct page_frag *pfrag;
        size_t orig_size = size;
        u32 max_open_record_len;
@@ -390,6 +390,9 @@ static int tls_push_data(struct sock *sk,
        if (sk->sk_err)
                return -sk->sk_err;
 
+       flags |= MSG_SENDPAGE_DECRYPTED;
+       tls_push_record_flags = flags | MSG_SENDPAGE_NOTLAST;
+
        timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
        if (tls_is_partially_sent_record(tls_ctx)) {
                rc = tls_push_partial_record(sk, tls_ctx, flags);
@@ -576,7 +579,9 @@ void tls_device_write_space(struct sock *sk, struct tls_context *ctx)
                gfp_t sk_allocation = sk->sk_allocation;
 
                sk->sk_allocation = GFP_ATOMIC;
-               tls_push_partial_record(sk, ctx, MSG_DONTWAIT | MSG_NOSIGNAL);
+               tls_push_partial_record(sk, ctx,
+                                       MSG_DONTWAIT | MSG_NOSIGNAL |
+                                       MSG_SENDPAGE_DECRYPTED);
                sk->sk_allocation = sk_allocation;
        }
 }
index 9cbbae6..43252a8 100644 (file)
@@ -308,6 +308,8 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
        if (free_ctx)
                icsk->icsk_ulp_data = NULL;
        sk->sk_prot = ctx->sk_proto;
+       if (sk->sk_write_space == tls_write_space)
+               sk->sk_write_space = ctx->sk_write_space;
        write_unlock_bh(&sk->sk_callback_lock);
        release_sock(sk);
        if (ctx->tx_conf == TLS_SW)
index 5215e08..6a71324 100644 (file)
@@ -204,7 +204,11 @@ int do_pin_fd(int fd, const char *name)
        if (err)
                return err;
 
-       return bpf_obj_pin(fd, name);
+       err = bpf_obj_pin(fd, name);
+       if (err)
+               p_err("can't pin the object (%s): %s", name, strerror(errno));
+
+       return err;
 }
 
 int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
@@ -237,7 +241,7 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
 
        fd = get_fd_by_id(id);
        if (fd < 0) {
-               p_err("can't get prog by id (%u): %s", id, strerror(errno));
+               p_err("can't open object by id (%u): %s", id, strerror(errno));
                return -1;
        }
 
index f559750..e9ef4ca 100644 (file)
@@ -809,7 +809,7 @@ kvp_get_ip_info(int family, char *if_name, int op,
        int sn_offset = 0;
        int error = 0;
        char *buffer;
-       struct hv_kvp_ipaddr_value *ip_buffer;
+       struct hv_kvp_ipaddr_value *ip_buffer = NULL;
        char cidr_mask[5]; /* /xyz */
        int weight;
        int i;
index 4e45501..a5aa7d3 100644 (file)
@@ -1466,8 +1466,8 @@ union bpf_attr {
  *             If no cookie has been set yet, generate a new cookie. Once
  *             generated, the socket cookie remains stable for the life of the
  *             socket. This helper can be useful for monitoring per socket
- *             networking traffic statistics as it provides a unique socket
- *             identifier per namespace.
+ *             networking traffic statistics as it provides a global socket
+ *             identifier that can be assumed unique.
  *     Return
  *             A 8-byte long non-decreasing number on success, or 0 if the
  *             socket field is missing inside *skb*.
@@ -1571,8 +1571,11 @@ union bpf_attr {
  *             but this is only implemented for native XDP (with driver
  *             support) as of this writing).
  *
- *             All values for *flags* are reserved for future usage, and must
- *             be left at zero.
+ *             The lower two bits of *flags* are used as the return code if
+ *             the map lookup fails. This is so that the return value can be
+ *             one of the XDP program return codes up to XDP_TX, as chosen by
+ *             the caller. Any higher bits in the *flags* argument must be
+ *             unset.
  *
  *             When used to redirect packets to net devices, this helper
  *             provides a high performance increase over **bpf_redirect**\ ().
index 2586b6c..2b57d7e 100644 (file)
@@ -182,7 +182,6 @@ struct bpf_program {
        bpf_program_clear_priv_t clear_priv;
 
        enum bpf_attach_type expected_attach_type;
-       int btf_fd;
        void *func_info;
        __u32 func_info_rec_size;
        __u32 func_info_cnt;
@@ -313,7 +312,6 @@ void bpf_program__unload(struct bpf_program *prog)
        prog->instances.nr = -1;
        zfree(&prog->instances.fds);
 
-       zclose(prog->btf_fd);
        zfree(&prog->func_info);
        zfree(&prog->line_info);
 }
@@ -392,7 +390,6 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
        prog->instances.fds = NULL;
        prog->instances.nr = -1;
        prog->type = BPF_PROG_TYPE_UNSPEC;
-       prog->btf_fd = -1;
 
        return 0;
 errout:
@@ -2288,9 +2285,6 @@ bpf_program_reloc_btf_ext(struct bpf_program *prog, struct bpf_object *obj,
                prog->line_info_rec_size = btf_ext__line_info_rec_size(obj->btf_ext);
        }
 
-       if (!insn_offset)
-               prog->btf_fd = btf__fd(obj->btf);
-
        return 0;
 }
 
@@ -2463,7 +2457,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
        char *cp, errmsg[STRERR_BUFSIZE];
        int log_buf_size = BPF_LOG_BUF_SIZE;
        char *log_buf;
-       int ret;
+       int btf_fd, ret;
 
        if (!insns || !insns_cnt)
                return -EINVAL;
@@ -2478,7 +2472,12 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
        load_attr.license = license;
        load_attr.kern_version = kern_version;
        load_attr.prog_ifindex = prog->prog_ifindex;
-       load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0;
+       /* if .BTF.ext was loaded, kernel supports associated BTF for prog */
+       if (prog->obj->btf_ext)
+               btf_fd = bpf_object__btf_fd(prog->obj);
+       else
+               btf_fd = -1;
+       load_attr.prog_btf_fd = btf_fd >= 0 ? btf_fd : 0;
        load_attr.func_info = prog->func_info;
        load_attr.func_info_rec_size = prog->func_info_rec_size;
        load_attr.func_info_cnt = prog->func_info_cnt;
@@ -5000,13 +4999,15 @@ int libbpf_num_possible_cpus(void)
        static const char *fcpu = "/sys/devices/system/cpu/possible";
        int len = 0, n = 0, il = 0, ir = 0;
        unsigned int start = 0, end = 0;
+       int tmp_cpus = 0;
        static int cpus;
        char buf[128];
        int error = 0;
        int fd = -1;
 
-       if (cpus > 0)
-               return cpus;
+       tmp_cpus = READ_ONCE(cpus);
+       if (tmp_cpus > 0)
+               return tmp_cpus;
 
        fd = open(fcpu, O_RDONLY);
        if (fd < 0) {
@@ -5029,7 +5030,7 @@ int libbpf_num_possible_cpus(void)
        }
        buf[len] = '\0';
 
-       for (ir = 0, cpus = 0; ir <= len; ir++) {
+       for (ir = 0, tmp_cpus = 0; ir <= len; ir++) {
                /* Each sub string separated by ',' has format \d+-\d+ or \d+ */
                if (buf[ir] == ',' || buf[ir] == '\0') {
                        buf[ir] = '\0';
@@ -5041,13 +5042,15 @@ int libbpf_num_possible_cpus(void)
                        } else if (n == 1) {
                                end = start;
                        }
-                       cpus += end - start + 1;
+                       tmp_cpus += end - start + 1;
                        il = ir + 1;
                }
        }
-       if (cpus <= 0) {
-               pr_warning("Invalid #CPUs %d from %s\n", cpus, fcpu);
+       if (tmp_cpus <= 0) {
+               pr_warning("Invalid #CPUs %d from %s\n", tmp_cpus, fcpu);
                return -EINVAL;
        }
-       return cpus;
+
+       WRITE_ONCE(cpus, tmp_cpus);
+       return tmp_cpus;
 }
index 5e980a5..1fc4e61 100644 (file)
        .errstr = "loop detected",
        .prog_type = BPF_PROG_TYPE_TRACEPOINT,
 },
+{
+       "not-taken loop with back jump to 1st insn",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 123),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 4, -2),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .retval = 123,
+},
+{
+       "taken loop with back jump to 1st insn",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_1, 10),
+       BPF_MOV64_IMM(BPF_REG_2, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+       BPF_EXIT_INSN(),
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1),
+       BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, -3),
+       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .retval = 55,
+},
index 4059014..4912d23 100644 (file)
@@ -220,6 +220,8 @@ struct hv_enlightened_vmcs {
 struct hv_enlightened_vmcs *current_evmcs;
 struct hv_vp_assist_page *current_vp_assist;
 
+int vcpu_enable_evmcs(struct kvm_vm *vm, int vcpu_id);
+
 static inline int enable_vp_assist(uint64_t vp_assist_pa, void *vp_assist)
 {
        u64 val = (vp_assist_pa & HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_MASK) |
index 6cb34a0..0a5e487 100644 (file)
@@ -1060,9 +1060,11 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid)
         TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XSAVE, r: %i",
                 r);
 
-       r = ioctl(vcpu->fd, KVM_GET_XCRS, &state->xcrs);
-        TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XCRS, r: %i",
-                r);
+       if (kvm_check_cap(KVM_CAP_XCRS)) {
+               r = ioctl(vcpu->fd, KVM_GET_XCRS, &state->xcrs);
+               TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XCRS, r: %i",
+                           r);
+       }
 
        r = ioctl(vcpu->fd, KVM_GET_SREGS, &state->sregs);
         TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_SREGS, r: %i",
@@ -1103,9 +1105,11 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *s
         TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XSAVE, r: %i",
                 r);
 
-       r = ioctl(vcpu->fd, KVM_SET_XCRS, &state->xcrs);
-        TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XCRS, r: %i",
-                r);
+       if (kvm_check_cap(KVM_CAP_XCRS)) {
+               r = ioctl(vcpu->fd, KVM_SET_XCRS, &state->xcrs);
+               TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XCRS, r: %i",
+                           r);
+       }
 
        r = ioctl(vcpu->fd, KVM_SET_SREGS, &state->sregs);
         TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_SREGS, r: %i",
index 204f847..9cef045 100644 (file)
 
 bool enable_evmcs;
 
+int vcpu_enable_evmcs(struct kvm_vm *vm, int vcpu_id)
+{
+       uint16_t evmcs_ver;
+
+       struct kvm_enable_cap enable_evmcs_cap = {
+               .cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS,
+                .args[0] = (unsigned long)&evmcs_ver
+       };
+
+       vcpu_ioctl(vm, vcpu_id, KVM_ENABLE_CAP, &enable_evmcs_cap);
+
+       /* KVM should return supported EVMCS version range */
+       TEST_ASSERT(((evmcs_ver >> 8) >= (evmcs_ver & 0xff)) &&
+                   (evmcs_ver & 0xff) > 0,
+                   "Incorrect EVMCS version range: %x:%x\n",
+                   evmcs_ver & 0xff, evmcs_ver >> 8);
+
+       return evmcs_ver;
+}
+
 /* Allocate memory regions for nested VMX tests.
  *
  * Input Args:
index f95c083..92915e6 100644 (file)
@@ -79,11 +79,6 @@ int main(int argc, char *argv[])
        struct kvm_x86_state *state;
        struct ucall uc;
        int stage;
-       uint16_t evmcs_ver;
-       struct kvm_enable_cap enable_evmcs_cap = {
-               .cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS,
-                .args[0] = (unsigned long)&evmcs_ver
-       };
 
        /* Create VM */
        vm = vm_create_default(VCPU_ID, 0, guest_code);
@@ -96,13 +91,7 @@ int main(int argc, char *argv[])
                exit(KSFT_SKIP);
        }
 
-       vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap);
-
-       /* KVM should return supported EVMCS version range */
-       TEST_ASSERT(((evmcs_ver >> 8) >= (evmcs_ver & 0xff)) &&
-                   (evmcs_ver & 0xff) > 0,
-                   "Incorrect EVMCS version range: %x:%x\n",
-                   evmcs_ver & 0xff, evmcs_ver >> 8);
+       vcpu_enable_evmcs(vm, VCPU_ID);
 
        run = vcpu_state(vm, VCPU_ID);
 
@@ -146,7 +135,7 @@ int main(int argc, char *argv[])
                kvm_vm_restart(vm, O_RDWR);
                vm_vcpu_add(vm, VCPU_ID);
                vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
-               vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap);
+               vcpu_enable_evmcs(vm, VCPU_ID);
                vcpu_load_state(vm, VCPU_ID, state);
                run = vcpu_state(vm, VCPU_ID);
                free(state);
index f72b304..ee59831 100644 (file)
@@ -18,6 +18,7 @@
 #include "test_util.h"
 #include "kvm_util.h"
 #include "processor.h"
+#include "vmx.h"
 
 #define VCPU_ID 0
 
@@ -106,12 +107,7 @@ int main(int argc, char *argv[])
 {
        struct kvm_vm *vm;
        int rv;
-       uint16_t evmcs_ver;
        struct kvm_cpuid2 *hv_cpuid_entries;
-       struct kvm_enable_cap enable_evmcs_cap = {
-               .cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS,
-                .args[0] = (unsigned long)&evmcs_ver
-       };
 
        /* Tell stdout not to buffer its content */
        setbuf(stdout, NULL);
@@ -136,14 +132,14 @@ int main(int argc, char *argv[])
 
        free(hv_cpuid_entries);
 
-       rv = _vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap);
-
-       if (rv) {
+       if (!kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) {
                fprintf(stderr,
                        "Enlightened VMCS is unsupported, skip related test\n");
                goto vm_free;
        }
 
+       vcpu_enable_evmcs(vm, VCPU_ID);
+
        hv_cpuid_entries = kvm_get_supported_hv_cpuid(vm);
        if (!hv_cpuid_entries)
                return 1;
index 40050e4..f9334bd 100644 (file)
@@ -99,8 +99,8 @@ int main(int argc, char *argv[])
        msr_platform_info = vcpu_get_msr(vm, VCPU_ID, MSR_PLATFORM_INFO);
        vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO,
                msr_platform_info | MSR_PLATFORM_INFO_MAX_TURBO_RATIO);
-       test_msr_platform_info_disabled(vm);
        test_msr_platform_info_enabled(vm);
+       test_msr_platform_info_disabled(vm);
        vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO, msr_platform_info);
 
        kvm_vm_free(vm);
index ed7218d..853e370 100644 (file)
 #define VMCS12_REVISION 0x11e57ed0
 #define VCPU_ID 5
 
+bool have_evmcs;
+
 void test_nested_state(struct kvm_vm *vm, struct kvm_nested_state *state)
 {
-       volatile struct kvm_run *run;
-
        vcpu_nested_state_set(vm, VCPU_ID, state, false);
-       run = vcpu_state(vm, VCPU_ID);
-       vcpu_run(vm, VCPU_ID);
-       TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN,
-               "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s),\n",
-               run->exit_reason,
-               exit_reason_str(run->exit_reason));
 }
 
 void test_nested_state_expect_errno(struct kvm_vm *vm,
                                    struct kvm_nested_state *state,
                                    int expected_errno)
 {
-       volatile struct kvm_run *run;
        int rv;
 
        rv = vcpu_nested_state_set(vm, VCPU_ID, state, true);
@@ -50,12 +43,6 @@ void test_nested_state_expect_errno(struct kvm_vm *vm,
                "Expected %s (%d) from vcpu_nested_state_set but got rv: %i errno: %s (%d)",
                strerror(expected_errno), expected_errno, rv, strerror(errno),
                errno);
-       run = vcpu_state(vm, VCPU_ID);
-       vcpu_run(vm, VCPU_ID);
-       TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN,
-               "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s),\n",
-               run->exit_reason,
-               exit_reason_str(run->exit_reason));
 }
 
 void test_nested_state_expect_einval(struct kvm_vm *vm,
@@ -90,8 +77,9 @@ void set_default_vmx_state(struct kvm_nested_state *state, int size)
 {
        memset(state, 0, size);
        state->flags = KVM_STATE_NESTED_GUEST_MODE  |
-                       KVM_STATE_NESTED_RUN_PENDING |
-                       KVM_STATE_NESTED_EVMCS;
+                       KVM_STATE_NESTED_RUN_PENDING;
+       if (have_evmcs)
+               state->flags |= KVM_STATE_NESTED_EVMCS;
        state->format = 0;
        state->size = size;
        state->hdr.vmx.vmxon_pa = 0x1000;
@@ -141,13 +129,19 @@ void test_vmx_nested_state(struct kvm_vm *vm)
        /*
         * Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without
         * setting the nested state but flags other than eVMCS must be clear.
+        * The eVMCS flag can be set if the enlightened VMCS capability has
+        * been enabled.
         */
        set_default_vmx_state(state, state_sz);
        state->hdr.vmx.vmxon_pa = -1ull;
        state->hdr.vmx.vmcs12_pa = -1ull;
        test_nested_state_expect_einval(vm, state);
 
-       state->flags = KVM_STATE_NESTED_EVMCS;
+       state->flags &= KVM_STATE_NESTED_EVMCS;
+       if (have_evmcs) {
+               test_nested_state_expect_einval(vm, state);
+               vcpu_enable_evmcs(vm, VCPU_ID);
+       }
        test_nested_state(vm, state);
 
        /* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */
@@ -232,6 +226,8 @@ int main(int argc, char *argv[])
        struct kvm_nested_state state;
        struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1);
 
+       have_evmcs = kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS);
+
        if (!kvm_check_cap(KVM_CAP_NESTED_STATE)) {
                printf("KVM_CAP_NESTED_STATE not available, skipping test\n");
                exit(KSFT_SKIP);
index 4147639..f6e6567 100755 (executable)
@@ -30,7 +30,7 @@ do_test() {
        ip netns exec "${NETNS}" ./tcp_fastopen_backup_key "$1"
        val=$(ip netns exec "${NETNS}" nstat -az | \
                grep TcpExtTCPFastOpenPassiveFail | awk '{print $2}')
-       if [ $val -ne 0 ]; then
+       if [ "$val" != 0 ]; then
                echo "FAIL: TcpExtTCPFastOpenPassiveFail non-zero"
                return 1
        fi
index fe52488..16571ac 100755 (executable)
@@ -321,4 +321,52 @@ else
        ip netns exec nsr1 nft list ruleset
 fi
 
+KEY_SHA="0x"$(ps -xaf | sha1sum | cut -d " " -f 1)
+KEY_AES="0x"$(ps -xaf | md5sum | cut -d " " -f 1)
+SPI1=$RANDOM
+SPI2=$RANDOM
+
+if [ $SPI1 -eq $SPI2 ]; then
+       SPI2=$((SPI2+1))
+fi
+
+do_esp() {
+    local ns=$1
+    local me=$2
+    local remote=$3
+    local lnet=$4
+    local rnet=$5
+    local spi_out=$6
+    local spi_in=$7
+
+    ip -net $ns xfrm state add src $remote dst $me proto esp spi $spi_in  enc aes $KEY_AES  auth sha1 $KEY_SHA mode tunnel sel src $rnet dst $lnet
+    ip -net $ns xfrm state add src $me  dst $remote proto esp spi $spi_out enc aes $KEY_AES auth sha1 $KEY_SHA mode tunnel sel src $lnet dst $rnet
+
+    # to encrypt packets as they go out (includes forwarded packets that need encapsulation)
+    ip -net $ns xfrm policy add src $lnet dst $rnet dir out tmpl src $me dst $remote proto esp mode tunnel priority 1 action allow
+    # to fwd decrypted packets after esp processing:
+    ip -net $ns xfrm policy add src $rnet dst $lnet dir fwd tmpl src $remote dst $me proto esp mode tunnel priority 1 action allow
+
+}
+
+do_esp nsr1 192.168.10.1 192.168.10.2 10.0.1.0/24 10.0.2.0/24 $SPI1 $SPI2
+
+do_esp nsr2 192.168.10.2 192.168.10.1 10.0.2.0/24 10.0.1.0/24 $SPI2 $SPI1
+
+ip netns exec nsr1 nft delete table ip nat
+
+# restore default routes
+ip -net ns2 route del 192.168.10.1 via 10.0.2.1
+ip -net ns2 route add default via 10.0.2.1
+ip -net ns2 route add default via dead:2::1
+
+test_tcp_forwarding ns1 ns2
+if [ $? -eq 0 ] ;then
+       echo "PASS: ipsec tunnel mode for ns1/ns2"
+else
+       echo "FAIL: ipsec tunnel mode for ns1/ns2"
+       ip netns exec nsr1 nft list ruleset 1>&2
+       ip netns exec nsr1 cat /proc/net/xfrm_stat 1>&2
+fi
+
 exit $ret
index bf5ebf5..9cdd2e3 100644 (file)
         "teardown": [
             "$TC actions flush action skbedit"
         ]
+    },
+    {
+        "id": "630c",
+        "name": "Add batch of 32 skbedit actions with all parameters and cookie",
+        "category": [
+            "actions",
+            "skbedit"
+        ],
+        "setup": [
+            [
+                "$TC actions flush action skbedit",
+                0,
+                1,
+                255
+            ]
+        ],
+        "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action skbedit queue_mapping 2 priority 10 mark 7/0xaabbccdd ptype host inheritdsfield index \\$i cookie aabbccddeeff112233445566778800a1 \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"",
+        "expExitCode": "0",
+        "verifyCmd": "$TC actions list action skbedit",
+        "matchPattern": "^[ \t]+index [0-9]+ ref",
+        "matchCount": "32",
+        "teardown": [
+            "$TC actions flush action skbedit"
+        ]
+    },
+    {
+        "id": "706d",
+        "name": "Delete batch of 32 skbedit actions with all parameters",
+        "category": [
+            "actions",
+            "skbedit"
+        ],
+        "setup": [
+            [
+                "$TC actions flush action skbedit",
+                0,
+                1,
+                255
+            ],
+            "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action skbedit queue_mapping 2 priority 10 mark 7/0xaabbccdd ptype host inheritdsfield index \\$i \\\"; args=\\\"\\$args\\$cmd\\\"; done && $TC actions add \\$args\""
+        ],
+        "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action skbedit index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions del \\$args\"",
+        "expExitCode": "0",
+        "verifyCmd": "$TC actions list action skbedit",
+        "matchPattern": "^[ \t]+index [0-9]+ ref",
+        "matchCount": "0",
+        "teardown": []
     }
 ]
index a8a6a0c..6af5c91 100644 (file)
@@ -86,6 +86,12 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
        unsigned int len;
        int mask;
 
+       /* Detect an already handled MMIO return */
+       if (unlikely(!vcpu->mmio_needed))
+               return 0;
+
+       vcpu->mmio_needed = 0;
+
        if (!run->mmio.is_write) {
                len = run->mmio.len;
                if (len > sizeof(unsigned long))
@@ -188,6 +194,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
        run->mmio.is_write      = is_write;
        run->mmio.phys_addr     = fault_ipa;
        run->mmio.len           = len;
+       vcpu->mmio_needed       = 1;
 
        if (!ret) {
                /* We handled the access successfully in the kernel. */
index bdbc297..e621b5d 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/cpu.h>
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
@@ -164,12 +165,18 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
                irq->vcpu = NULL;
                irq->target_vcpu = vcpu0;
                kref_init(&irq->refcount);
-               if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+               switch (dist->vgic_model) {
+               case KVM_DEV_TYPE_ARM_VGIC_V2:
                        irq->targets = 0;
                        irq->group = 0;
-               } else {
+                       break;
+               case KVM_DEV_TYPE_ARM_VGIC_V3:
                        irq->mpidr = 0;
                        irq->group = 1;
+                       break;
+               default:
+                       kfree(dist->spis);
+                       return -EINVAL;
                }
        }
        return 0;
@@ -209,7 +216,6 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
                irq->intid = i;
                irq->vcpu = NULL;
                irq->target_vcpu = vcpu;
-               irq->targets = 1U << vcpu->vcpu_id;
                kref_init(&irq->refcount);
                if (vgic_irq_is_sgi(i)) {
                        /* SGIs */
@@ -219,11 +225,6 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
                        /* PPIs */
                        irq->config = VGIC_CONFIG_LEVEL;
                }
-
-               if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
-                       irq->group = 1;
-               else
-                       irq->group = 0;
        }
 
        if (!irqchip_in_kernel(vcpu->kvm))
@@ -286,10 +287,19 @@ int vgic_init(struct kvm *kvm)
 
                for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
                        struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
-                       if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
+                       switch (dist->vgic_model) {
+                       case KVM_DEV_TYPE_ARM_VGIC_V3:
                                irq->group = 1;
-                       else
+                               irq->mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
+                               break;
+                       case KVM_DEV_TYPE_ARM_VGIC_V2:
                                irq->group = 0;
+                               irq->targets = 1U << idx;
+                               break;
+                       default:
+                               ret = -EINVAL;
+                               goto out;
+                       }
                }
        }