Merge tag 'acpi-4.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Apr 2018 18:06:36 +0000 (11:06 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Apr 2018 18:06:36 +0000 (11:06 -0700)
Pull ACPI fixes from Rafael Wysocki:
 "These are two watchdog-related fixes, fix for a backlight regression
  from the 4.16 cycle that unfortunately was propagated to -stable and a
  button module modification to prevent graphics driver modules from
  failing to load due to unmet dependencies if ACPI is disabled from the
  kernel command line.

  Specifics:

   - Change the ACPI subsystem initialization ordering to initialize the
     WDAT watchodg before reserving PNP motherboard resources so as to
     allow the watchdog to allocate its resources before the PNP code
     gets to them and prevents it from working correctly (Mika
     Westerberg).

   - Add a quirk for Lenovo Z50-70 to use the iTCO watchdog instead of
     the WDAT one which conflicts with the RTC on that platform (Mika
     Westerberg).

   - Avoid breaking backlight handling on Dell XPS 13 2013 model by
     allowing laptops to use the ACPI backlight by default even if they
     are Windows 8-ready in principle (Hans de Goede)"

* tag 'acpi-4.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI / video: Only default only_lcd to true on Win8-ready _desktops_
  ACPI / button: make module loadable when booted in non-ACPI mode
  ACPI / watchdog: Prefer iTCO_wdt on Lenovo Z50-70
  ACPI / scan: Initialize watchdog before PNP

109 files changed:
MAINTAINERS
arch/riscv/Kconfig
arch/riscv/include/asm/Kbuild
arch/riscv/kernel/vdso/Makefile
arch/s390/include/asm/thread_info.h
arch/s390/kernel/module.c
arch/s390/kernel/perf_cpum_cf_events.c
arch/s390/kernel/process.c
arch/s390/kernel/uprobes.c
block/bfq-iosched.c
block/blk-cgroup.c
block/blk-core.c
block/blk-mq.c
block/blk-mq.h
drivers/acpi/sleep.c
drivers/base/dma-coherent.c
drivers/base/dma-mapping.c
drivers/block/loop.c
drivers/block/loop.h
drivers/block/swim.c
drivers/block/swim3.c
drivers/cdrom/cdrom.c
drivers/char/random.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/brcmstb-avs-cpufreq.c
drivers/message/fusion/mptsas.c
drivers/net/bonding/bond_main.c
drivers/net/ethernet/amd/xgbe/xgbe-common.h
drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
drivers/net/ethernet/amd/xgbe/xgbe-main.c
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
drivers/net/ethernet/amd/xgbe/xgbe-pci.c
drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
drivers/net/ethernet/amd/xgbe/xgbe.h
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
drivers/net/ethernet/intel/ice/ice_common.c
drivers/net/ethernet/intel/ice/ice_hw_autogen.h
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_sched.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/farch.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/rx.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/phy/marvell.c
drivers/net/ppp/pppoe.c
drivers/net/team/team.c
drivers/pci/pci-driver.c
drivers/s390/block/dasd_alias.c
drivers/s390/cio/chsc.c
drivers/s390/cio/vfio_ccw_fsm.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_core_mpc.h
drivers/s390/net/qeth_l2_main.c
drivers/scsi/fnic/fnic_trace.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/sd.c
drivers/scsi/sd_zbc.c
drivers/scsi/ufs/ufshcd.c
drivers/target/target_core_pscsi.c
include/linux/blk-mq.h
include/linux/blkdev.h
include/linux/bpf.h
include/linux/ethtool.h
include/linux/fsnotify_backend.h
include/net/ife.h
include/net/llc_conn.h
include/scsi/scsi_dbg.h
include/trace/events/ufs.h
kernel/bpf/core.c
kernel/bpf/sockmap.c
kernel/trace/bpf_trace.c
lib/dma-direct.c
net/bridge/netfilter/ebtables.c
net/ife/ife.c
net/ipv4/tcp_input.c
net/ipv6/netfilter/Kconfig
net/ipv6/route.c
net/ipv6/seg6_iptunnel.c
net/l2tp/l2tp_debugfs.c
net/l2tp/l2tp_ppp.c
net/llc/af_llc.c
net/llc/llc_c_ac.c
net/llc/llc_conn.c
net/netfilter/Kconfig
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_extend.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_tables_api.c
net/netfilter/xt_connmark.c
net/packet/af_packet.c
net/packet/internal.h
net/sched/act_ife.c
net/strparser/strparser.c
security/commoncap.c
tools/testing/selftests/bpf/.gitignore
tools/testing/selftests/bpf/test_sock.c
tools/testing/selftests/bpf/test_sock_addr.c
tools/testing/selftests/bpf/test_sock_addr.sh

index 92be777..dd66ae9 100644 (file)
@@ -2617,7 +2617,7 @@ S:        Maintained
 F:     drivers/net/hamradio/baycom*
 
 BCACHE (BLOCK LAYER CACHE)
-M:     Michael Lyle <mlyle@lyle.org>
+M:     Coly Li <colyli@suse.de>
 M:     Kent Overstreet <kent.overstreet@gmail.com>
 L:     linux-bcache@vger.kernel.org
 W:     http://bcache.evilpiepirate.org
index 23d8acc..cd4fd85 100644 (file)
@@ -11,6 +11,7 @@ config RISCV
        select ARCH_WANT_FRAME_POINTERS
        select CLONE_BACKWARDS
        select COMMON_CLK
+       select DMA_DIRECT_OPS
        select GENERIC_CLOCKEVENTS
        select GENERIC_CPU_DEVICES
        select GENERIC_IRQ_SHOW
@@ -89,9 +90,6 @@ config PGTABLE_LEVELS
 config HAVE_KPROBES
        def_bool n
 
-config DMA_DIRECT_OPS
-       def_bool y
-
 menu "Platform type"
 
 choice
index 1e5fd28..4286a5f 100644 (file)
@@ -15,7 +15,6 @@ generic-y += fcntl.h
 generic-y += futex.h
 generic-y += hardirq.h
 generic-y += hash.h
-generic-y += handle_irq.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ioctls.h
index 324568d..f6561b7 100644 (file)
@@ -52,7 +52,7 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE
 # Add -lgcc so rv32 gets static muldi3 and lshrdi3 definitions.
 # Make sure only to export the intended __vdso_xxx symbol offsets.
 quiet_cmd_vdsold = VDSOLD  $@
-      cmd_vdsold = $(CC) $(KCFLAGS) -nostdlib $(SYSCFLAGS_$(@F)) \
+      cmd_vdsold = $(CC) $(KCFLAGS) $(call cc-option, -no-pie) -nostdlib $(SYSCFLAGS_$(@F)) \
                            -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp -lgcc && \
                    $(CROSS_COMPILE)objcopy \
                            $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@
index 83ba575..3c883c3 100644 (file)
@@ -45,6 +45,9 @@ struct thread_info {
 void arch_release_task_struct(struct task_struct *tsk);
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 
+void arch_setup_new_exec(void);
+#define arch_setup_new_exec arch_setup_new_exec
+
 #endif
 
 /*
index 5a83be9..0dc8ac8 100644 (file)
@@ -465,11 +465,11 @@ int module_finalize(const Elf_Ehdr *hdr,
                        apply_alternatives(aseg, aseg + s->sh_size);
 
                if (IS_ENABLED(CONFIG_EXPOLINE) &&
-                   (!strcmp(".nospec_call_table", secname)))
+                   (!strncmp(".s390_indirect", secname, 14)))
                        nospec_revert(aseg, aseg + s->sh_size);
 
                if (IS_ENABLED(CONFIG_EXPOLINE) &&
-                   (!strcmp(".nospec_return_table", secname)))
+                   (!strncmp(".s390_return", secname, 12)))
                        nospec_revert(aseg, aseg + s->sh_size);
        }
 
index 5ee27dc..feebb29 100644 (file)
@@ -123,7 +123,7 @@ CPUMF_EVENT_ATTR(cf_zec12, L1I_OFFBOOK_L3_SOURCED_WRITES_IV, 0x00a1);
 CPUMF_EVENT_ATTR(cf_zec12, TX_NC_TABORT, 0x00b1);
 CPUMF_EVENT_ATTR(cf_zec12, TX_C_TABORT_NO_SPECIAL, 0x00b2);
 CPUMF_EVENT_ATTR(cf_zec12, TX_C_TABORT_SPECIAL, 0x00b3);
-CPUMF_EVENT_ATTR(cf_z13, L1D_WRITES_RO_EXCL, 0x0080);
+CPUMF_EVENT_ATTR(cf_z13, L1D_RO_EXCL_WRITES, 0x0080);
 CPUMF_EVENT_ATTR(cf_z13, DTLB1_WRITES, 0x0081);
 CPUMF_EVENT_ATTR(cf_z13, DTLB1_MISSES, 0x0082);
 CPUMF_EVENT_ATTR(cf_z13, DTLB1_HPAGE_WRITES, 0x0083);
@@ -179,7 +179,7 @@ CPUMF_EVENT_ATTR(cf_z13, TX_C_TABORT_NO_SPECIAL, 0x00db);
 CPUMF_EVENT_ATTR(cf_z13, TX_C_TABORT_SPECIAL, 0x00dc);
 CPUMF_EVENT_ATTR(cf_z13, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0);
 CPUMF_EVENT_ATTR(cf_z13, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1);
-CPUMF_EVENT_ATTR(cf_z14, L1D_WRITES_RO_EXCL, 0x0080);
+CPUMF_EVENT_ATTR(cf_z14, L1D_RO_EXCL_WRITES, 0x0080);
 CPUMF_EVENT_ATTR(cf_z14, DTLB2_WRITES, 0x0081);
 CPUMF_EVENT_ATTR(cf_z14, DTLB2_MISSES, 0x0082);
 CPUMF_EVENT_ATTR(cf_z14, DTLB2_HPAGE_WRITES, 0x0083);
@@ -371,7 +371,7 @@ static struct attribute *cpumcf_zec12_pmu_event_attr[] __initdata = {
 };
 
 static struct attribute *cpumcf_z13_pmu_event_attr[] __initdata = {
-       CPUMF_EVENT_PTR(cf_z13, L1D_WRITES_RO_EXCL),
+       CPUMF_EVENT_PTR(cf_z13, L1D_RO_EXCL_WRITES),
        CPUMF_EVENT_PTR(cf_z13, DTLB1_WRITES),
        CPUMF_EVENT_PTR(cf_z13, DTLB1_MISSES),
        CPUMF_EVENT_PTR(cf_z13, DTLB1_HPAGE_WRITES),
@@ -431,7 +431,7 @@ static struct attribute *cpumcf_z13_pmu_event_attr[] __initdata = {
 };
 
 static struct attribute *cpumcf_z14_pmu_event_attr[] __initdata = {
-       CPUMF_EVENT_PTR(cf_z14, L1D_WRITES_RO_EXCL),
+       CPUMF_EVENT_PTR(cf_z14, L1D_RO_EXCL_WRITES),
        CPUMF_EVENT_PTR(cf_z14, DTLB2_WRITES),
        CPUMF_EVENT_PTR(cf_z14, DTLB2_MISSES),
        CPUMF_EVENT_PTR(cf_z14, DTLB2_HPAGE_WRITES),
index 70576a2..6e758bb 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/random.h>
 #include <linux/export.h>
 #include <linux/init_task.h>
+#include <asm/cpu_mf.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/vtimer.h>
@@ -48,6 +49,15 @@ void flush_thread(void)
 {
 }
 
+void arch_setup_new_exec(void)
+{
+       if (S390_lowcore.current_pid != current->pid) {
+               S390_lowcore.current_pid = current->pid;
+               if (test_facility(40))
+                       lpp(&S390_lowcore.lpp);
+       }
+}
+
 void arch_release_task_struct(struct task_struct *tsk)
 {
        runtime_instr_release(tsk);
index d9d1f51..5007fac 100644 (file)
@@ -150,6 +150,15 @@ unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline,
        return orig;
 }
 
+bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
+                            struct pt_regs *regs)
+{
+       if (ctx == RP_CHECK_CHAIN_CALL)
+               return user_stack_pointer(regs) <= ret->stack;
+       else
+               return user_stack_pointer(regs) < ret->stack;
+}
+
 /* Instruction Emulation */
 
 static void adjust_psw_addr(psw_t *psw, unsigned long len)
index f0ecd98..771ae97 100644 (file)
@@ -4934,8 +4934,16 @@ static void bfq_prepare_request(struct request *rq, struct bio *bio)
        bool new_queue = false;
        bool bfqq_already_existing = false, split = false;
 
-       if (!rq->elv.icq)
+       /*
+        * Even if we don't have an icq attached, we should still clear
+        * the scheduler pointers, as they might point to previously
+        * allocated bic/bfqq structs.
+        */
+       if (!rq->elv.icq) {
+               rq->elv.priv[0] = rq->elv.priv[1] = NULL;
                return;
+       }
+
        bic = icq_to_bic(rq->elv.icq);
 
        spin_lock_irq(&bfqd->lock);
index 1c16694..eb85cb8 100644 (file)
@@ -1177,26 +1177,20 @@ int blkcg_init_queue(struct request_queue *q)
 
        preloaded = !radix_tree_preload(GFP_KERNEL);
 
-       /*
-        * Make sure the root blkg exists and count the existing blkgs.  As
-        * @q is bypassing at this point, blkg_lookup_create() can't be
-        * used.  Open code insertion.
-        */
+       /* Make sure the root blkg exists. */
        rcu_read_lock();
        spin_lock_irq(q->queue_lock);
        blkg = blkg_create(&blkcg_root, q, new_blkg);
+       if (IS_ERR(blkg))
+               goto err_unlock;
+       q->root_blkg = blkg;
+       q->root_rl.blkg = blkg;
        spin_unlock_irq(q->queue_lock);
        rcu_read_unlock();
 
        if (preloaded)
                radix_tree_preload_end();
 
-       if (IS_ERR(blkg))
-               return PTR_ERR(blkg);
-
-       q->root_blkg = blkg;
-       q->root_rl.blkg = blkg;
-
        ret = blk_throtl_init(q);
        if (ret) {
                spin_lock_irq(q->queue_lock);
@@ -1204,6 +1198,13 @@ int blkcg_init_queue(struct request_queue *q)
                spin_unlock_irq(q->queue_lock);
        }
        return ret;
+
+err_unlock:
+       spin_unlock_irq(q->queue_lock);
+       rcu_read_unlock();
+       if (preloaded)
+               radix_tree_preload_end();
+       return PTR_ERR(blkg);
 }
 
 /**
@@ -1410,9 +1411,6 @@ void blkcg_deactivate_policy(struct request_queue *q,
        __clear_bit(pol->plid, q->blkcg_pols);
 
        list_for_each_entry(blkg, &q->blkg_list, q_node) {
-               /* grab blkcg lock too while removing @pd from @blkg */
-               spin_lock(&blkg->blkcg->lock);
-
                if (blkg->pd[pol->plid]) {
                        if (!blkg->pd[pol->plid]->offline &&
                            pol->pd_offline_fn) {
@@ -1422,8 +1420,6 @@ void blkcg_deactivate_policy(struct request_queue *q,
                        pol->pd_free_fn(blkg->pd[pol->plid]);
                        blkg->pd[pol->plid] = NULL;
                }
-
-               spin_unlock(&blkg->blkcg->lock);
        }
 
        spin_unlock_irq(q->queue_lock);
index 806ce24..85909b4 100644 (file)
@@ -201,6 +201,10 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
        rq->part = NULL;
        seqcount_init(&rq->gstate_seq);
        u64_stats_init(&rq->aborted_gstate_sync);
+       /*
+        * See comment of blk_mq_init_request
+        */
+       WRITE_ONCE(rq->gstate, MQ_RQ_GEN_INC);
 }
 EXPORT_SYMBOL(blk_rq_init);
 
@@ -915,7 +919,6 @@ int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)
 
        while (true) {
                bool success = false;
-               int ret;
 
                rcu_read_lock();
                if (percpu_ref_tryget_live(&q->q_usage_counter)) {
@@ -947,14 +950,12 @@ int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)
                 */
                smp_rmb();
 
-               ret = wait_event_interruptible(q->mq_freeze_wq,
-                               (atomic_read(&q->mq_freeze_depth) == 0 &&
-                                (preempt || !blk_queue_preempt_only(q))) ||
-                               blk_queue_dying(q));
+               wait_event(q->mq_freeze_wq,
+                          (atomic_read(&q->mq_freeze_depth) == 0 &&
+                           (preempt || !blk_queue_preempt_only(q))) ||
+                          blk_queue_dying(q));
                if (blk_queue_dying(q))
                        return -ENODEV;
-               if (ret)
-                       return ret;
        }
 }
 
index 0dc9e34..c362145 100644 (file)
@@ -2042,6 +2042,13 @@ static int blk_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
 
        seqcount_init(&rq->gstate_seq);
        u64_stats_init(&rq->aborted_gstate_sync);
+       /*
+        * start gstate with gen 1 instead of 0, otherwise it will be equal
+        * to aborted_gstate, and be identified timed out by
+        * blk_mq_terminate_expired.
+        */
+       WRITE_ONCE(rq->gstate, MQ_RQ_GEN_INC);
+
        return 0;
 }
 
@@ -2329,7 +2336,7 @@ static void blk_mq_free_map_and_requests(struct blk_mq_tag_set *set,
 
 static void blk_mq_map_swqueue(struct request_queue *q)
 {
-       unsigned int i;
+       unsigned int i, hctx_idx;
        struct blk_mq_hw_ctx *hctx;
        struct blk_mq_ctx *ctx;
        struct blk_mq_tag_set *set = q->tag_set;
@@ -2346,8 +2353,23 @@ static void blk_mq_map_swqueue(struct request_queue *q)
 
        /*
         * Map software to hardware queues.
+        *
+        * If the cpu isn't present, the cpu is mapped to first hctx.
         */
        for_each_possible_cpu(i) {
+               hctx_idx = q->mq_map[i];
+               /* unmapped hw queue can be remapped after CPU topo changed */
+               if (!set->tags[hctx_idx] &&
+                   !__blk_mq_alloc_rq_map(set, hctx_idx)) {
+                       /*
+                        * If tags initialization fail for some hctx,
+                        * that hctx won't be brought online.  In this
+                        * case, remap the current ctx to hctx[0] which
+                        * is guaranteed to always have tags allocated
+                        */
+                       q->mq_map[i] = 0;
+               }
+
                ctx = per_cpu_ptr(q->queue_ctx, i);
                hctx = blk_mq_map_queue(q, i);
 
@@ -2359,8 +2381,21 @@ static void blk_mq_map_swqueue(struct request_queue *q)
        mutex_unlock(&q->sysfs_lock);
 
        queue_for_each_hw_ctx(q, hctx, i) {
-               /* every hctx should get mapped by at least one CPU */
-               WARN_ON(!hctx->nr_ctx);
+               /*
+                * If no software queues are mapped to this hardware queue,
+                * disable it and free the request entries.
+                */
+               if (!hctx->nr_ctx) {
+                       /* Never unmap queue 0.  We need it as a
+                        * fallback in case of a new remap fails
+                        * allocation
+                        */
+                       if (i && set->tags[i])
+                               blk_mq_free_map_and_requests(set, i);
+
+                       hctx->tags = NULL;
+                       continue;
+               }
 
                hctx->tags = set->tags[i];
                WARN_ON(!hctx->tags);
index 88c558f..89b5cd3 100644 (file)
@@ -7,6 +7,9 @@
 
 struct blk_mq_tag_set;
 
+/**
+ * struct blk_mq_ctx - State for a software queue facing the submitting CPUs
+ */
 struct blk_mq_ctx {
        struct {
                spinlock_t              lock;
index 99a1a65..974e584 100644 (file)
@@ -364,6 +364,19 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
                DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9360"),
                },
        },
+       /*
+        * ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using
+        * the Low Power S0 Idle firmware interface (see
+        * https://bugzilla.kernel.org/show_bug.cgi?id=199057).
+        */
+       {
+       .callback = init_no_lps0,
+       .ident = "ThinkPad X1 Tablet(2016)",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"),
+               },
+       },
        {},
 };
 
index 1e6396b..597d408 100644 (file)
@@ -312,8 +312,9 @@ static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem,
  * This checks whether the memory was allocated from the per-device
  * coherent memory pool and if so, maps that memory to the provided vma.
  *
- * Returns 1 if we correctly mapped the memory, or 0 if the caller should
- * proceed with mapping memory from generic pools.
+ * Returns 1 if @vaddr belongs to the device coherent pool and the caller
+ * should return @ret, or 0 if they should proceed with mapping memory from
+ * generic areas.
  */
 int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma,
                           void *vaddr, size_t size, int *ret)
index 3b11835..d82566d 100644 (file)
@@ -226,7 +226,6 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
 #ifndef CONFIG_ARCH_NO_COHERENT_DMA_MMAP
        unsigned long user_count = vma_pages(vma);
        unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
        unsigned long off = vma->vm_pgoff;
 
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
@@ -234,12 +233,11 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
        if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
 
-       if (off < count && user_count <= (count - off)) {
+       if (off < count && user_count <= (count - off))
                ret = remap_pfn_range(vma, vma->vm_start,
-                                     pfn + off,
+                                     page_to_pfn(virt_to_page(cpu_addr)) + off,
                                      user_count << PAGE_SHIFT,
                                      vma->vm_page_prot);
-       }
 #endif /* !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */
 
        return ret;
index c9d0449..5d4e316 100644 (file)
@@ -451,25 +451,47 @@ static int lo_req_flush(struct loop_device *lo, struct request *rq)
 static void lo_complete_rq(struct request *rq)
 {
        struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+       blk_status_t ret = BLK_STS_OK;
 
-       if (unlikely(req_op(cmd->rq) == REQ_OP_READ && cmd->use_aio &&
-                    cmd->ret >= 0 && cmd->ret < blk_rq_bytes(cmd->rq))) {
-               struct bio *bio = cmd->rq->bio;
-
-               bio_advance(bio, cmd->ret);
-               zero_fill_bio(bio);
+       if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) ||
+           req_op(rq) != REQ_OP_READ) {
+               if (cmd->ret < 0)
+                       ret = BLK_STS_IOERR;
+               goto end_io;
        }
 
-       blk_mq_end_request(rq, cmd->ret < 0 ? BLK_STS_IOERR : BLK_STS_OK);
+       /*
+        * Short READ - if we got some data, advance our request and
+        * retry it. If we got no data, end the rest with EIO.
+        */
+       if (cmd->ret) {
+               blk_update_request(rq, BLK_STS_OK, cmd->ret);
+               cmd->ret = 0;
+               blk_mq_requeue_request(rq, true);
+       } else {
+               if (cmd->use_aio) {
+                       struct bio *bio = rq->bio;
+
+                       while (bio) {
+                               zero_fill_bio(bio);
+                               bio = bio->bi_next;
+                       }
+               }
+               ret = BLK_STS_IOERR;
+end_io:
+               blk_mq_end_request(rq, ret);
+       }
 }
 
 static void lo_rw_aio_do_completion(struct loop_cmd *cmd)
 {
+       struct request *rq = blk_mq_rq_from_pdu(cmd);
+
        if (!atomic_dec_and_test(&cmd->ref))
                return;
        kfree(cmd->bvec);
        cmd->bvec = NULL;
-       blk_mq_complete_request(cmd->rq);
+       blk_mq_complete_request(rq);
 }
 
 static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2)
@@ -487,7 +509,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
 {
        struct iov_iter iter;
        struct bio_vec *bvec;
-       struct request *rq = cmd->rq;
+       struct request *rq = blk_mq_rq_from_pdu(cmd);
        struct bio *bio = rq->bio;
        struct file *file = lo->lo_backing_file;
        unsigned int offset;
@@ -1702,15 +1724,16 @@ EXPORT_SYMBOL(loop_unregister_transfer);
 static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx,
                const struct blk_mq_queue_data *bd)
 {
-       struct loop_cmd *cmd = blk_mq_rq_to_pdu(bd->rq);
-       struct loop_device *lo = cmd->rq->q->queuedata;
+       struct request *rq = bd->rq;
+       struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+       struct loop_device *lo = rq->q->queuedata;
 
-       blk_mq_start_request(bd->rq);
+       blk_mq_start_request(rq);
 
        if (lo->lo_state != Lo_bound)
                return BLK_STS_IOERR;
 
-       switch (req_op(cmd->rq)) {
+       switch (req_op(rq)) {
        case REQ_OP_FLUSH:
        case REQ_OP_DISCARD:
        case REQ_OP_WRITE_ZEROES:
@@ -1723,8 +1746,8 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx,
 
        /* always use the first bio's css */
 #ifdef CONFIG_BLK_CGROUP
-       if (cmd->use_aio && cmd->rq->bio && cmd->rq->bio->bi_css) {
-               cmd->css = cmd->rq->bio->bi_css;
+       if (cmd->use_aio && rq->bio && rq->bio->bi_css) {
+               cmd->css = rq->bio->bi_css;
                css_get(cmd->css);
        } else
 #endif
@@ -1736,8 +1759,9 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 static void loop_handle_cmd(struct loop_cmd *cmd)
 {
-       const bool write = op_is_write(req_op(cmd->rq));
-       struct loop_device *lo = cmd->rq->q->queuedata;
+       struct request *rq = blk_mq_rq_from_pdu(cmd);
+       const bool write = op_is_write(req_op(rq));
+       struct loop_device *lo = rq->q->queuedata;
        int ret = 0;
 
        if (write && (lo->lo_flags & LO_FLAGS_READ_ONLY)) {
@@ -1745,12 +1769,12 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
                goto failed;
        }
 
-       ret = do_req_filebacked(lo, cmd->rq);
+       ret = do_req_filebacked(lo, rq);
  failed:
        /* complete non-aio request */
        if (!cmd->use_aio || ret) {
                cmd->ret = ret ? -EIO : 0;
-               blk_mq_complete_request(cmd->rq);
+               blk_mq_complete_request(rq);
        }
 }
 
@@ -1767,9 +1791,7 @@ static int loop_init_request(struct blk_mq_tag_set *set, struct request *rq,
 {
        struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
 
-       cmd->rq = rq;
        kthread_init_work(&cmd->work, loop_queue_work);
-
        return 0;
 }
 
index 0f45416..b78de98 100644 (file)
@@ -66,7 +66,6 @@ struct loop_device {
 
 struct loop_cmd {
        struct kthread_work work;
-       struct request *rq;
        bool use_aio; /* use AIO interface to handle I/O */
        atomic_t ref; /* only for aio */
        long ret;
index 64e066e..0e31884 100644 (file)
@@ -110,7 +110,7 @@ struct iwm {
 /* Select values for swim_select and swim_readbit */
 
 #define READ_DATA_0    0x074
-#define TWOMEG_DRIVE   0x075
+#define ONEMEG_DRIVE   0x075
 #define SINGLE_SIDED   0x076
 #define DRIVE_PRESENT  0x077
 #define DISK_IN                0x170
@@ -118,9 +118,9 @@ struct iwm {
 #define TRACK_ZERO     0x172
 #define TACHO          0x173
 #define READ_DATA_1    0x174
-#define MFM_MODE       0x175
+#define GCR_MODE       0x175
 #define SEEK_COMPLETE  0x176
-#define ONEMEG_MEDIA   0x177
+#define TWOMEG_MEDIA   0x177
 
 /* Bits in handshake register */
 
@@ -612,7 +612,6 @@ static void setup_medium(struct floppy_state *fs)
                struct floppy_struct *g;
                fs->disk_in = 1;
                fs->write_protected = swim_readbit(base, WRITE_PROT);
-               fs->type = swim_readbit(base, ONEMEG_MEDIA);
 
                if (swim_track00(base))
                        printk(KERN_ERR
@@ -620,6 +619,9 @@ static void setup_medium(struct floppy_state *fs)
 
                swim_track00(base);
 
+               fs->type = swim_readbit(base, TWOMEG_MEDIA) ?
+                       HD_MEDIA : DD_MEDIA;
+               fs->head_number = swim_readbit(base, SINGLE_SIDED) ? 1 : 2;
                get_floppy_geometry(fs, 0, &g);
                fs->total_secs = g->size;
                fs->secpercyl = g->head * g->sect;
@@ -646,7 +648,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
 
        swim_write(base, setup, S_IBM_DRIVE  | S_FCLK_DIV2);
        udelay(10);
-       swim_drive(base, INTERNAL_DRIVE);
+       swim_drive(base, fs->location);
        swim_motor(base, ON);
        swim_action(base, SETMFM);
        if (fs->ejected)
@@ -656,6 +658,8 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
                goto out;
        }
 
+       set_capacity(fs->disk, fs->total_secs);
+
        if (mode & FMODE_NDELAY)
                return 0;
 
@@ -727,14 +731,9 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
                if (copy_to_user((void __user *) param, (void *) &floppy_type,
                                 sizeof(struct floppy_struct)))
                        return -EFAULT;
-               break;
-
-       default:
-               printk(KERN_DEBUG "SWIM floppy_ioctl: unknown cmd %d\n",
-                      cmd);
-               return -ENOSYS;
+               return 0;
        }
-       return 0;
+       return -ENOTTY;
 }
 
 static int floppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
@@ -795,7 +794,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
        struct swim_priv *swd = data;
        int drive = (*part & 3);
 
-       if (drive > swd->floppy_count)
+       if (drive >= swd->floppy_count)
                return NULL;
 
        *part = 0;
@@ -813,10 +812,9 @@ static int swim_add_floppy(struct swim_priv *swd, enum drive_location location)
 
        swim_motor(base, OFF);
 
-       if (swim_readbit(base, SINGLE_SIDED))
-               fs->head_number = 1;
-       else
-               fs->head_number = 2;
+       fs->type = HD_MEDIA;
+       fs->head_number = 2;
+
        fs->ref_count = 0;
        fs->ejected = 1;
 
@@ -834,10 +832,12 @@ static int swim_floppy_init(struct swim_priv *swd)
        /* scan floppy drives */
 
        swim_drive(base, INTERNAL_DRIVE);
-       if (swim_readbit(base, DRIVE_PRESENT))
+       if (swim_readbit(base, DRIVE_PRESENT) &&
+           !swim_readbit(base, ONEMEG_DRIVE))
                swim_add_floppy(swd, INTERNAL_DRIVE);
        swim_drive(base, EXTERNAL_DRIVE);
-       if (swim_readbit(base, DRIVE_PRESENT))
+       if (swim_readbit(base, DRIVE_PRESENT) &&
+           !swim_readbit(base, ONEMEG_DRIVE))
                swim_add_floppy(swd, EXTERNAL_DRIVE);
 
        /* register floppy drives */
@@ -861,7 +861,6 @@ static int swim_floppy_init(struct swim_priv *swd)
                                                              &swd->lock);
                if (!swd->unit[drive].disk->queue) {
                        err = -ENOMEM;
-                       put_disk(swd->unit[drive].disk);
                        goto exit_put_disks;
                }
                blk_queue_bounce_limit(swd->unit[drive].disk->queue,
@@ -911,7 +910,7 @@ static int swim_probe(struct platform_device *dev)
                goto out;
        }
 
-       swim_base = ioremap(res->start, resource_size(res));
+       swim_base = (struct swim __iomem *)res->start;
        if (!swim_base) {
                ret = -ENOMEM;
                goto out_release_io;
@@ -923,7 +922,7 @@ static int swim_probe(struct platform_device *dev)
        if (!get_swim_mode(swim_base)) {
                printk(KERN_INFO "SWIM device not found !\n");
                ret = -ENODEV;
-               goto out_iounmap;
+               goto out_release_io;
        }
 
        /* set platform driver data */
@@ -931,7 +930,7 @@ static int swim_probe(struct platform_device *dev)
        swd = kzalloc(sizeof(struct swim_priv), GFP_KERNEL);
        if (!swd) {
                ret = -ENOMEM;
-               goto out_iounmap;
+               goto out_release_io;
        }
        platform_set_drvdata(dev, swd);
 
@@ -945,8 +944,6 @@ static int swim_probe(struct platform_device *dev)
 
 out_kfree:
        kfree(swd);
-out_iounmap:
-       iounmap(swim_base);
 out_release_io:
        release_mem_region(res->start, resource_size(res));
 out:
@@ -974,8 +971,6 @@ static int swim_remove(struct platform_device *dev)
        for (drive = 0; drive < swd->floppy_count; drive++)
                floppy_eject(&swd->unit[drive]);
 
-       iounmap(swd->base);
-
        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (res)
                release_mem_region(res->start, resource_size(res));
index af51015..469541c 100644 (file)
@@ -148,7 +148,7 @@ struct swim3 {
 #define MOTOR_ON       2
 #define RELAX          3       /* also eject in progress */
 #define READ_DATA_0    4
-#define TWOMEG_DRIVE   5
+#define ONEMEG_DRIVE   5
 #define SINGLE_SIDED   6       /* drive or diskette is 4MB type? */
 #define DRIVE_PRESENT  7
 #define DISK_IN                8
@@ -156,9 +156,9 @@ struct swim3 {
 #define TRACK_ZERO     10
 #define TACHO          11
 #define READ_DATA_1    12
-#define MFM_MODE       13
+#define GCR_MODE       13
 #define SEEK_COMPLETE  14
-#define ONEMEG_MEDIA   15
+#define TWOMEG_MEDIA   15
 
 /* Definitions of values used in writing and formatting */
 #define DATA_ESCAPE    0x99
index 8327478..bfc566d 100644 (file)
@@ -2371,7 +2371,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
        if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
                return media_changed(cdi, 1);
 
-       if ((unsigned int)arg >= cdi->capacity)
+       if (arg >= cdi->capacity)
                return -EINVAL;
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
index 3cd3aae..cd888d4 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/workqueue.h>
 #include <linux/irq.h>
+#include <linux/ratelimit.h>
 #include <linux/syscalls.h>
 #include <linux/completion.h>
 #include <linux/uuid.h>
@@ -438,6 +439,16 @@ static void _crng_backtrack_protect(struct crng_state *crng,
 static void process_random_ready_list(void);
 static void _get_random_bytes(void *buf, int nbytes);
 
+static struct ratelimit_state unseeded_warning =
+       RATELIMIT_STATE_INIT("warn_unseeded_randomness", HZ, 3);
+static struct ratelimit_state urandom_warning =
+       RATELIMIT_STATE_INIT("warn_urandom_randomness", HZ, 3);
+
+static int ratelimit_disable __read_mostly;
+
+module_param_named(ratelimit_disable, ratelimit_disable, int, 0644);
+MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression");
+
 /**********************************************************************
  *
  * OS independent entropy store.   Here are the functions which handle
@@ -789,7 +800,7 @@ static void crng_initialize(struct crng_state *crng)
 }
 
 #ifdef CONFIG_NUMA
-static void numa_crng_init(void)
+static void do_numa_crng_init(struct work_struct *work)
 {
        int i;
        struct crng_state *crng;
@@ -810,6 +821,13 @@ static void numa_crng_init(void)
                kfree(pool);
        }
 }
+
+static DECLARE_WORK(numa_crng_init_work, do_numa_crng_init);
+
+static void numa_crng_init(void)
+{
+       schedule_work(&numa_crng_init_work);
+}
 #else
 static void numa_crng_init(void) {}
 #endif
@@ -925,6 +943,18 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
                process_random_ready_list();
                wake_up_interruptible(&crng_init_wait);
                pr_notice("random: crng init done\n");
+               if (unseeded_warning.missed) {
+                       pr_notice("random: %d get_random_xx warning(s) missed "
+                                 "due to ratelimiting\n",
+                                 unseeded_warning.missed);
+                       unseeded_warning.missed = 0;
+               }
+               if (urandom_warning.missed) {
+                       pr_notice("random: %d urandom warning(s) missed "
+                                 "due to ratelimiting\n",
+                                 urandom_warning.missed);
+                       urandom_warning.missed = 0;
+               }
        }
 }
 
@@ -1565,8 +1595,9 @@ static void _warn_unseeded_randomness(const char *func_name, void *caller,
 #ifndef CONFIG_WARN_ALL_UNSEEDED_RANDOM
        print_once = true;
 #endif
-       pr_notice("random: %s called from %pS with crng_init=%d\n",
-                 func_name, caller, crng_init);
+       if (__ratelimit(&unseeded_warning))
+               pr_notice("random: %s called from %pS with crng_init=%d\n",
+                         func_name, caller, crng_init);
 }
 
 /*
@@ -1760,6 +1791,10 @@ static int rand_initialize(void)
        init_std_data(&blocking_pool);
        crng_initialize(&primary_crng);
        crng_global_init_time = jiffies;
+       if (ratelimit_disable) {
+               urandom_warning.interval = 0;
+               unseeded_warning.interval = 0;
+       }
        return 0;
 }
 early_initcall(rand_initialize);
@@ -1827,9 +1862,10 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
 
        if (!crng_ready() && maxwarn > 0) {
                maxwarn--;
-               printk(KERN_NOTICE "random: %s: uninitialized urandom read "
-                      "(%zd bytes read)\n",
-                      current->comm, nbytes);
+               if (__ratelimit(&urandom_warning))
+                       printk(KERN_NOTICE "random: %s: uninitialized "
+                              "urandom read (%zd bytes read)\n",
+                              current->comm, nbytes);
                spin_lock_irqsave(&primary_crng.lock, flags);
                crng_init_cnt = 0;
                spin_unlock_irqrestore(&primary_crng.lock, flags);
index 7f56fe5..de55c7d 100644 (file)
@@ -71,16 +71,6 @@ config ARM_BRCMSTB_AVS_CPUFREQ
 
          Say Y, if you have a Broadcom SoC with AVS support for DFS or DVFS.
 
-config ARM_BRCMSTB_AVS_CPUFREQ_DEBUG
-       bool "Broadcom STB AVS CPUfreq driver sysfs debug capability"
-       depends on ARM_BRCMSTB_AVS_CPUFREQ
-       help
-         Enabling this option turns on debug support via sysfs under
-         /sys/kernel/debug/brcmstb-avs-cpufreq. It is possible to read all and
-         write some AVS mailbox registers through sysfs entries.
-
-         If in doubt, say N.
-
 config ARM_EXYNOS5440_CPUFREQ
        tristate "SAMSUNG EXYNOS5440"
        depends on SOC_EXYNOS5440
index 6cdac1a..b07559b 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/semaphore.h>
 
-#ifdef CONFIG_ARM_BRCMSTB_AVS_CPUFREQ_DEBUG
-#include <linux/ctype.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#endif
-
 /* Max number of arguments AVS calls take */
 #define AVS_MAX_CMD_ARGS       4
 /*
@@ -182,88 +175,11 @@ struct private_data {
        void __iomem *base;
        void __iomem *avs_intr_base;
        struct device *dev;
-#ifdef CONFIG_ARM_BRCMSTB_AVS_CPUFREQ_DEBUG
-       struct dentry *debugfs;
-#endif
        struct completion done;
        struct semaphore sem;
        struct pmap pmap;
 };
 
-#ifdef CONFIG_ARM_BRCMSTB_AVS_CPUFREQ_DEBUG
-
-enum debugfs_format {
-       DEBUGFS_NORMAL,
-       DEBUGFS_FLOAT,
-       DEBUGFS_REV,
-};
-
-struct debugfs_data {
-       struct debugfs_entry *entry;
-       struct private_data *priv;
-};
-
-struct debugfs_entry {
-       char *name;
-       u32 offset;
-       fmode_t mode;
-       enum debugfs_format format;
-};
-
-#define DEBUGFS_ENTRY(name, mode, format)      { \
-       #name, AVS_MBOX_##name, mode, format \
-}
-
-/*
- * These are used for debugfs only. Otherwise we use AVS_MBOX_PARAM() directly.
- */
-#define AVS_MBOX_PARAM1                AVS_MBOX_PARAM(0)
-#define AVS_MBOX_PARAM2                AVS_MBOX_PARAM(1)
-#define AVS_MBOX_PARAM3                AVS_MBOX_PARAM(2)
-#define AVS_MBOX_PARAM4                AVS_MBOX_PARAM(3)
-
-/*
- * This table stores the name, access permissions and offset for each hardware
- * register and is used to generate debugfs entries.
- */
-static struct debugfs_entry debugfs_entries[] = {
-       DEBUGFS_ENTRY(COMMAND, S_IWUSR, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(STATUS, S_IWUSR, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(VOLTAGE0, 0, DEBUGFS_FLOAT),
-       DEBUGFS_ENTRY(TEMP0, 0, DEBUGFS_FLOAT),
-       DEBUGFS_ENTRY(PV0, 0, DEBUGFS_FLOAT),
-       DEBUGFS_ENTRY(MV0, 0, DEBUGFS_FLOAT),
-       DEBUGFS_ENTRY(PARAM1, S_IWUSR, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(PARAM2, S_IWUSR, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(PARAM3, S_IWUSR, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(PARAM4, S_IWUSR, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(REVISION, 0, DEBUGFS_REV),
-       DEBUGFS_ENTRY(PSTATE, 0, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(HEARTBEAT, 0, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(MAGIC, S_IWUSR, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(SIGMA_HVT, 0, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(SIGMA_SVT, 0, DEBUGFS_NORMAL),
-       DEBUGFS_ENTRY(VOLTAGE1, 0, DEBUGFS_FLOAT),
-       DEBUGFS_ENTRY(TEMP1, 0, DEBUGFS_FLOAT),
-       DEBUGFS_ENTRY(PV1, 0, DEBUGFS_FLOAT),
-       DEBUGFS_ENTRY(MV1, 0, DEBUGFS_FLOAT),
-       DEBUGFS_ENTRY(FREQUENCY, 0, DEBUGFS_NORMAL),
-};
-
-static int brcm_avs_target_index(struct cpufreq_policy *, unsigned int);
-
-static char *__strtolower(char *s)
-{
-       char *p;
-
-       for (p = s; *p; p++)
-               *p = tolower(*p);
-
-       return s;
-}
-
-#endif /* CONFIG_ARM_BRCMSTB_AVS_CPUFREQ_DEBUG */
-
 static void __iomem *__map_region(const char *name)
 {
        struct device_node *np;
@@ -516,238 +432,6 @@ brcm_avs_get_freq_table(struct device *dev, struct private_data *priv)
        return table;
 }
 
-#ifdef CONFIG_ARM_BRCMSTB_AVS_CPUFREQ_DEBUG
-
-#define MANT(x)        (unsigned int)(abs((x)) / 1000)
-#define FRAC(x)        (unsigned int)(abs((x)) - abs((x)) / 1000 * 1000)
-
-static int brcm_avs_debug_show(struct seq_file *s, void *data)
-{
-       struct debugfs_data *dbgfs = s->private;
-       void __iomem *base;
-       u32 val, offset;
-
-       if (!dbgfs) {
-               seq_puts(s, "No device pointer\n");
-               return 0;
-       }
-
-       base = dbgfs->priv->base;
-       offset = dbgfs->entry->offset;
-       val = readl(base + offset);
-       switch (dbgfs->entry->format) {
-       case DEBUGFS_NORMAL:
-               seq_printf(s, "%u\n", val);
-               break;
-       case DEBUGFS_FLOAT:
-               seq_printf(s, "%d.%03d\n", MANT(val), FRAC(val));
-               break;
-       case DEBUGFS_REV:
-               seq_printf(s, "%c.%c.%c.%c\n", (val >> 24 & 0xff),
-                          (val >> 16 & 0xff), (val >> 8 & 0xff),
-                          val & 0xff);
-               break;
-       }
-       seq_printf(s, "0x%08x\n", val);
-
-       return 0;
-}
-
-#undef MANT
-#undef FRAC
-
-static ssize_t brcm_avs_seq_write(struct file *file, const char __user *buf,
-                                 size_t size, loff_t *ppos)
-{
-       struct seq_file *s = file->private_data;
-       struct debugfs_data *dbgfs = s->private;
-       struct private_data *priv = dbgfs->priv;
-       void __iomem *base, *avs_intr_base;
-       bool use_issue_command = false;
-       unsigned long val, offset;
-       char str[128];
-       int ret;
-       char *str_ptr = str;
-
-       if (size >= sizeof(str))
-               return -E2BIG;
-
-       memset(str, 0, sizeof(str));
-       ret = copy_from_user(str, buf, size);
-       if (ret)
-               return ret;
-
-       base = priv->base;
-       avs_intr_base = priv->avs_intr_base;
-       offset = dbgfs->entry->offset;
-       /*
-        * Special case writing to "command" entry only: if the string starts
-        * with a 'c', we use the driver's __issue_avs_command() function.
-        * Otherwise, we perform a raw write. This should allow testing of raw
-        * access as well as using the higher level function. (Raw access
-        * doesn't clear the firmware return status after issuing the command.)
-        */
-       if (str_ptr[0] == 'c' && offset == AVS_MBOX_COMMAND) {
-               use_issue_command = true;
-               str_ptr++;
-       }
-       if (kstrtoul(str_ptr, 0, &val) != 0)
-               return -EINVAL;
-
-       /*
-        * Setting the P-state is a special case. We need to update the CPU
-        * frequency we report.
-        */
-       if (val == AVS_CMD_SET_PSTATE) {
-               struct cpufreq_policy *policy;
-               unsigned int pstate;
-
-               policy = cpufreq_cpu_get(smp_processor_id());
-               /* Read back the P-state we are about to set */
-               pstate = readl(base + AVS_MBOX_PARAM(0));
-               if (use_issue_command) {
-                       ret = brcm_avs_target_index(policy, pstate);
-                       return ret ? ret : size;
-               }
-               policy->cur = policy->freq_table[pstate].frequency;
-       }
-
-       if (use_issue_command) {
-               ret = __issue_avs_command(priv, val, false, NULL);
-       } else {
-               /* Locking here is not perfect, but is only for debug. */
-               ret = down_interruptible(&priv->sem);
-               if (ret)
-                       return ret;
-
-               writel(val, base + offset);
-               /* We have to wake up the firmware to process a command. */
-               if (offset == AVS_MBOX_COMMAND)
-                       writel(AVS_CPU_L2_INT_MASK,
-                              avs_intr_base + AVS_CPU_L2_SET0);
-               up(&priv->sem);
-       }
-
-       return ret ? ret : size;
-}
-
-static struct debugfs_entry *__find_debugfs_entry(const char *name)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(debugfs_entries); i++)
-               if (strcasecmp(debugfs_entries[i].name, name) == 0)
-                       return &debugfs_entries[i];
-
-       return NULL;
-}
-
-static int brcm_avs_debug_open(struct inode *inode, struct file *file)
-{
-       struct debugfs_data *data;
-       fmode_t fmode;
-       int ret;
-
-       /*
-        * seq_open(), which is called by single_open(), clears "write" access.
-        * We need write access to some files, so we preserve our access mode
-        * and restore it.
-        */
-       fmode = file->f_mode;
-       /*
-        * Check access permissions even for root. We don't want to be writing
-        * to read-only registers. Access for regular users has already been
-        * checked by the VFS layer.
-        */
-       if ((fmode & FMODE_WRITER) && !(inode->i_mode & S_IWUSR))
-               return -EACCES;
-
-       data = kmalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-       /*
-        * We use the same file system operations for all our debug files. To
-        * produce specific output, we look up the file name upon opening a
-        * debugfs entry and map it to a memory offset. This offset is then used
-        * in the generic "show" function to read a specific register.
-        */
-       data->entry = __find_debugfs_entry(file->f_path.dentry->d_iname);
-       data->priv = inode->i_private;
-
-       ret = single_open(file, brcm_avs_debug_show, data);
-       if (ret)
-               kfree(data);
-       file->f_mode = fmode;
-
-       return ret;
-}
-
-static int brcm_avs_debug_release(struct inode *inode, struct file *file)
-{
-       struct seq_file *seq_priv = file->private_data;
-       struct debugfs_data *data = seq_priv->private;
-
-       kfree(data);
-       return single_release(inode, file);
-}
-
-static const struct file_operations brcm_avs_debug_ops = {
-       .open           = brcm_avs_debug_open,
-       .read           = seq_read,
-       .write          = brcm_avs_seq_write,
-       .llseek         = seq_lseek,
-       .release        = brcm_avs_debug_release,
-};
-
-static void brcm_avs_cpufreq_debug_init(struct platform_device *pdev)
-{
-       struct private_data *priv = platform_get_drvdata(pdev);
-       struct dentry *dir;
-       int i;
-
-       if (!priv)
-               return;
-
-       dir = debugfs_create_dir(BRCM_AVS_CPUFREQ_NAME, NULL);
-       if (IS_ERR_OR_NULL(dir))
-               return;
-       priv->debugfs = dir;
-
-       for (i = 0; i < ARRAY_SIZE(debugfs_entries); i++) {
-               /*
-                * The DEBUGFS_ENTRY macro generates uppercase strings. We
-                * convert them to lowercase before creating the debugfs
-                * entries.
-                */
-               char *entry = __strtolower(debugfs_entries[i].name);
-               fmode_t mode = debugfs_entries[i].mode;
-
-               if (!debugfs_create_file(entry, S_IFREG | S_IRUGO | mode,
-                                        dir, priv, &brcm_avs_debug_ops)) {
-                       priv->debugfs = NULL;
-                       debugfs_remove_recursive(dir);
-                       break;
-               }
-       }
-}
-
-static void brcm_avs_cpufreq_debug_exit(struct platform_device *pdev)
-{
-       struct private_data *priv = platform_get_drvdata(pdev);
-
-       if (priv && priv->debugfs) {
-               debugfs_remove_recursive(priv->debugfs);
-               priv->debugfs = NULL;
-       }
-}
-
-#else
-
-static void brcm_avs_cpufreq_debug_init(struct platform_device *pdev) {}
-static void brcm_avs_cpufreq_debug_exit(struct platform_device *pdev) {}
-
-#endif /* CONFIG_ARM_BRCMSTB_AVS_CPUFREQ_DEBUG */
-
 /*
  * To ensure the right firmware is running we need to
  *    - check the MAGIC matches what we expect
@@ -1016,11 +700,8 @@ static int brcm_avs_cpufreq_probe(struct platform_device *pdev)
                return ret;
 
        brcm_avs_driver.driver_data = pdev;
-       ret = cpufreq_register_driver(&brcm_avs_driver);
-       if (!ret)
-               brcm_avs_cpufreq_debug_init(pdev);
 
-       return ret;
+       return cpufreq_register_driver(&brcm_avs_driver);
 }
 
 static int brcm_avs_cpufreq_remove(struct platform_device *pdev)
@@ -1032,8 +713,6 @@ static int brcm_avs_cpufreq_remove(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       brcm_avs_cpufreq_debug_exit(pdev);
-
        priv = platform_get_drvdata(pdev);
        iounmap(priv->base);
        iounmap(priv->avs_intr_base);
index 231f3a1..86503f6 100644 (file)
@@ -1994,6 +1994,7 @@ static struct scsi_host_template mptsas_driver_template = {
        .cmd_per_lun                    = 7,
        .use_clustering                 = ENABLE_CLUSTERING,
        .shost_attrs                    = mptscsih_host_attrs,
+       .no_write_same                  = 1,
 };
 
 static int mptsas_get_linkerrors(struct sas_phy *phy)
index b7b1130..718e491 100644 (file)
@@ -1660,8 +1660,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
        } /* switch(bond_mode) */
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       slave_dev->npinfo = bond->dev->npinfo;
-       if (slave_dev->npinfo) {
+       if (bond->dev->npinfo) {
                if (slave_enable_netpoll(new_slave)) {
                        netdev_info(bond_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n");
                        res = -EBUSY;
index 7ea72ef..d272dc6 100644 (file)
 #define MDIO_VEND2_AN_STAT             0x8002
 #endif
 
+#ifndef MDIO_VEND2_PMA_CDR_CONTROL
+#define MDIO_VEND2_PMA_CDR_CONTROL     0x8056
+#endif
+
 #ifndef MDIO_CTRL1_SPEED1G
 #define MDIO_CTRL1_SPEED1G             (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
 #endif
 #define XGBE_AN_CL37_TX_CONFIG_MASK    0x08
 #define XGBE_AN_CL37_MII_CTRL_8BIT     0x0100
 
+#define XGBE_PMA_CDR_TRACK_EN_MASK     0x01
+#define XGBE_PMA_CDR_TRACK_EN_OFF      0x00
+#define XGBE_PMA_CDR_TRACK_EN_ON       0x01
+
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
  *  the variable
index 7d128be..b911439 100644 (file)
@@ -519,6 +519,22 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
                                   "debugfs_create_file failed\n");
        }
 
+       if (pdata->vdata->an_cdr_workaround) {
+               pfile = debugfs_create_bool("an_cdr_workaround", 0600,
+                                           pdata->xgbe_debugfs,
+                                           &pdata->debugfs_an_cdr_workaround);
+               if (!pfile)
+                       netdev_err(pdata->netdev,
+                                  "debugfs_create_bool failed\n");
+
+               pfile = debugfs_create_bool("an_cdr_track_early", 0600,
+                                           pdata->xgbe_debugfs,
+                                           &pdata->debugfs_an_cdr_track_early);
+               if (!pfile)
+                       netdev_err(pdata->netdev,
+                                  "debugfs_create_bool failed\n");
+       }
+
        kfree(buf);
 }
 
index 795e556..441d097 100644 (file)
@@ -349,6 +349,7 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
        XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
 
        /* Call MDIO/PHY initialization routine */
+       pdata->debugfs_an_cdr_workaround = pdata->vdata->an_cdr_workaround;
        ret = pdata->phy_if.phy_init(pdata);
        if (ret)
                return ret;
index 072b9f6..1b45cd7 100644 (file)
@@ -432,11 +432,16 @@ static void xgbe_an73_disable(struct xgbe_prv_data *pdata)
        xgbe_an73_set(pdata, false, false);
        xgbe_an73_disable_interrupts(pdata);
 
+       pdata->an_start = 0;
+
        netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n");
 }
 
 static void xgbe_an_restart(struct xgbe_prv_data *pdata)
 {
+       if (pdata->phy_if.phy_impl.an_pre)
+               pdata->phy_if.phy_impl.an_pre(pdata);
+
        switch (pdata->an_mode) {
        case XGBE_AN_MODE_CL73:
        case XGBE_AN_MODE_CL73_REDRV:
@@ -453,6 +458,9 @@ static void xgbe_an_restart(struct xgbe_prv_data *pdata)
 
 static void xgbe_an_disable(struct xgbe_prv_data *pdata)
 {
+       if (pdata->phy_if.phy_impl.an_post)
+               pdata->phy_if.phy_impl.an_post(pdata);
+
        switch (pdata->an_mode) {
        case XGBE_AN_MODE_CL73:
        case XGBE_AN_MODE_CL73_REDRV:
@@ -505,11 +513,11 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
                XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
                            reg);
 
-               if (pdata->phy_if.phy_impl.kr_training_post)
-                       pdata->phy_if.phy_impl.kr_training_post(pdata);
-
                netif_dbg(pdata, link, pdata->netdev,
                          "KR training initiated\n");
+
+               if (pdata->phy_if.phy_impl.kr_training_post)
+                       pdata->phy_if.phy_impl.kr_training_post(pdata);
        }
 
        return XGBE_AN_PAGE_RECEIVED;
@@ -637,11 +645,11 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
                        return XGBE_AN_NO_LINK;
        }
 
-       xgbe_an73_disable(pdata);
+       xgbe_an_disable(pdata);
 
        xgbe_switch_mode(pdata);
 
-       xgbe_an73_restart(pdata);
+       xgbe_an_restart(pdata);
 
        return XGBE_AN_INCOMPAT_LINK;
 }
@@ -820,6 +828,9 @@ static void xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
                pdata->an_result = pdata->an_state;
                pdata->an_state = XGBE_AN_READY;
 
+               if (pdata->phy_if.phy_impl.an_post)
+                       pdata->phy_if.phy_impl.an_post(pdata);
+
                netif_dbg(pdata, link, pdata->netdev, "CL37 AN result: %s\n",
                          xgbe_state_as_string(pdata->an_result));
        }
@@ -903,6 +914,9 @@ again:
                pdata->kx_state = XGBE_RX_BPA;
                pdata->an_start = 0;
 
+               if (pdata->phy_if.phy_impl.an_post)
+                       pdata->phy_if.phy_impl.an_post(pdata);
+
                netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n",
                          xgbe_state_as_string(pdata->an_result));
        }
index eb23f9b..82d1f41 100644 (file)
@@ -456,6 +456,7 @@ static const struct xgbe_version_data xgbe_v2a = {
        .irq_reissue_support            = 1,
        .tx_desc_prefetch               = 5,
        .rx_desc_prefetch               = 5,
+       .an_cdr_workaround              = 1,
 };
 
 static const struct xgbe_version_data xgbe_v2b = {
@@ -470,6 +471,7 @@ static const struct xgbe_version_data xgbe_v2b = {
        .irq_reissue_support            = 1,
        .tx_desc_prefetch               = 5,
        .rx_desc_prefetch               = 5,
+       .an_cdr_workaround              = 1,
 };
 
 static const struct pci_device_id xgbe_pci_table[] = {
index 3304a29..aac8843 100644 (file)
 /* Rate-change complete wait/retry count */
 #define XGBE_RATECHANGE_COUNT          500
 
+/* CDR delay values for KR support (in usec) */
+#define XGBE_CDR_DELAY_INIT            10000
+#define XGBE_CDR_DELAY_INC             10000
+#define XGBE_CDR_DELAY_MAX             100000
+
+/* RRC frequency during link status check */
+#define XGBE_RRC_FREQUENCY             10
+
 enum xgbe_port_mode {
        XGBE_PORT_MODE_RSVD = 0,
        XGBE_PORT_MODE_BACKPLANE,
@@ -245,6 +253,10 @@ enum xgbe_sfp_speed {
 #define XGBE_SFP_BASE_VENDOR_SN                        4
 #define XGBE_SFP_BASE_VENDOR_SN_LEN            16
 
+#define XGBE_SFP_EXTD_OPT1                     1
+#define XGBE_SFP_EXTD_OPT1_RX_LOS              BIT(1)
+#define XGBE_SFP_EXTD_OPT1_TX_FAULT            BIT(3)
+
 #define XGBE_SFP_EXTD_DIAG                     28
 #define XGBE_SFP_EXTD_DIAG_ADDR_CHANGE         BIT(2)
 
@@ -324,6 +336,7 @@ struct xgbe_phy_data {
 
        unsigned int sfp_gpio_address;
        unsigned int sfp_gpio_mask;
+       unsigned int sfp_gpio_inputs;
        unsigned int sfp_gpio_rx_los;
        unsigned int sfp_gpio_tx_fault;
        unsigned int sfp_gpio_mod_absent;
@@ -355,6 +368,10 @@ struct xgbe_phy_data {
        unsigned int redrv_addr;
        unsigned int redrv_lane;
        unsigned int redrv_model;
+
+       /* KR AN support */
+       unsigned int phy_cdr_notrack;
+       unsigned int phy_cdr_delay;
 };
 
 /* I2C, MDIO and GPIO lines are muxed, so only one device at a time */
@@ -974,6 +991,49 @@ static void xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata)
        phy_data->sfp_phy_avail = 1;
 }
 
+static bool xgbe_phy_check_sfp_rx_los(struct xgbe_phy_data *phy_data)
+{
+       u8 *sfp_extd = phy_data->sfp_eeprom.extd;
+
+       if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_RX_LOS))
+               return false;
+
+       if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS)
+               return false;
+
+       if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_rx_los))
+               return true;
+
+       return false;
+}
+
+static bool xgbe_phy_check_sfp_tx_fault(struct xgbe_phy_data *phy_data)
+{
+       u8 *sfp_extd = phy_data->sfp_eeprom.extd;
+
+       if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_TX_FAULT))
+               return false;
+
+       if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT)
+               return false;
+
+       if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_tx_fault))
+               return true;
+
+       return false;
+}
+
+static bool xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data)
+{
+       if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT)
+               return false;
+
+       if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_mod_absent))
+               return true;
+
+       return false;
+}
+
 static bool xgbe_phy_belfuse_parse_quirks(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -1019,6 +1079,10 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
        if (sfp_base[XGBE_SFP_BASE_EXT_ID] != XGBE_SFP_EXT_ID_SFP)
                return;
 
+       /* Update transceiver signals (eeprom extd/options) */
+       phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
+       phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
+
        if (xgbe_phy_sfp_parse_quirks(pdata))
                return;
 
@@ -1184,7 +1248,6 @@ put:
 static void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
-       unsigned int gpio_input;
        u8 gpio_reg, gpio_ports[2];
        int ret;
 
@@ -1199,23 +1262,9 @@ static void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata)
                return;
        }
 
-       gpio_input = (gpio_ports[1] << 8) | gpio_ports[0];
-
-       if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT) {
-               /* No GPIO, just assume the module is present for now */
-               phy_data->sfp_mod_absent = 0;
-       } else {
-               if (!(gpio_input & (1 << phy_data->sfp_gpio_mod_absent)))
-                       phy_data->sfp_mod_absent = 0;
-       }
-
-       if (!(phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS) &&
-           (gpio_input & (1 << phy_data->sfp_gpio_rx_los)))
-               phy_data->sfp_rx_los = 1;
+       phy_data->sfp_gpio_inputs = (gpio_ports[1] << 8) | gpio_ports[0];
 
-       if (!(phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT) &&
-           (gpio_input & (1 << phy_data->sfp_gpio_tx_fault)))
-               phy_data->sfp_tx_fault = 1;
+       phy_data->sfp_mod_absent = xgbe_phy_check_sfp_mod_absent(phy_data);
 }
 
 static void xgbe_phy_sfp_mod_absent(struct xgbe_prv_data *pdata)
@@ -2361,7 +2410,7 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
                return 1;
 
        /* No link, attempt a receiver reset cycle */
-       if (phy_data->rrc_count++) {
+       if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) {
                phy_data->rrc_count = 0;
                xgbe_phy_rrc(pdata);
        }
@@ -2669,6 +2718,103 @@ static bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata)
        return true;
 }
 
+static void xgbe_phy_cdr_track(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+       if (!pdata->debugfs_an_cdr_workaround)
+               return;
+
+       if (!phy_data->phy_cdr_notrack)
+               return;
+
+       usleep_range(phy_data->phy_cdr_delay,
+                    phy_data->phy_cdr_delay + 500);
+
+       XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
+                        XGBE_PMA_CDR_TRACK_EN_MASK,
+                        XGBE_PMA_CDR_TRACK_EN_ON);
+
+       phy_data->phy_cdr_notrack = 0;
+}
+
+static void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+       if (!pdata->debugfs_an_cdr_workaround)
+               return;
+
+       if (phy_data->phy_cdr_notrack)
+               return;
+
+       XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
+                        XGBE_PMA_CDR_TRACK_EN_MASK,
+                        XGBE_PMA_CDR_TRACK_EN_OFF);
+
+       xgbe_phy_rrc(pdata);
+
+       phy_data->phy_cdr_notrack = 1;
+}
+
+static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata)
+{
+       if (!pdata->debugfs_an_cdr_track_early)
+               xgbe_phy_cdr_track(pdata);
+}
+
+static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata)
+{
+       if (pdata->debugfs_an_cdr_track_early)
+               xgbe_phy_cdr_track(pdata);
+}
+
+static void xgbe_phy_an_post(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+       switch (pdata->an_mode) {
+       case XGBE_AN_MODE_CL73:
+       case XGBE_AN_MODE_CL73_REDRV:
+               if (phy_data->cur_mode != XGBE_MODE_KR)
+                       break;
+
+               xgbe_phy_cdr_track(pdata);
+
+               switch (pdata->an_result) {
+               case XGBE_AN_READY:
+               case XGBE_AN_COMPLETE:
+                       break;
+               default:
+                       if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX)
+                               phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC;
+                       else
+                               phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void xgbe_phy_an_pre(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+       switch (pdata->an_mode) {
+       case XGBE_AN_MODE_CL73:
+       case XGBE_AN_MODE_CL73_REDRV:
+               if (phy_data->cur_mode != XGBE_MODE_KR)
+                       break;
+
+               xgbe_phy_cdr_notrack(pdata);
+               break;
+       default:
+               break;
+       }
+}
+
 static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -2680,6 +2826,9 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
        xgbe_phy_sfp_reset(phy_data);
        xgbe_phy_sfp_mod_absent(pdata);
 
+       /* Reset CDR support */
+       xgbe_phy_cdr_track(pdata);
+
        /* Power off the PHY */
        xgbe_phy_power_off(pdata);
 
@@ -2712,6 +2861,9 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
        /* Start in highest supported mode */
        xgbe_phy_set_mode(pdata, phy_data->start_mode);
 
+       /* Reset CDR support */
+       xgbe_phy_cdr_track(pdata);
+
        /* After starting the I2C controller, we can check for an SFP */
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_SFP:
@@ -3019,6 +3171,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
                }
        }
 
+       phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
+
        /* Register for driving external PHYs */
        mii = devm_mdiobus_alloc(pdata->dev);
        if (!mii) {
@@ -3071,4 +3225,10 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if)
        phy_impl->an_advertising        = xgbe_phy_an_advertising;
 
        phy_impl->an_outcome            = xgbe_phy_an_outcome;
+
+       phy_impl->an_pre                = xgbe_phy_an_pre;
+       phy_impl->an_post               = xgbe_phy_an_post;
+
+       phy_impl->kr_training_pre       = xgbe_phy_kr_training_pre;
+       phy_impl->kr_training_post      = xgbe_phy_kr_training_post;
 }
index ad102c8..95d4b56 100644 (file)
@@ -833,6 +833,7 @@ struct xgbe_hw_if {
 /* This structure represents implementation specific routines for an
  * implementation of a PHY. All routines are required unless noted below.
  *   Optional routines:
+ *     an_pre, an_post
  *     kr_training_pre, kr_training_post
  */
 struct xgbe_phy_impl_if {
@@ -875,6 +876,10 @@ struct xgbe_phy_impl_if {
        /* Process results of auto-negotiation */
        enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *);
 
+       /* Pre/Post auto-negotiation support */
+       void (*an_pre)(struct xgbe_prv_data *);
+       void (*an_post)(struct xgbe_prv_data *);
+
        /* Pre/Post KR training enablement support */
        void (*kr_training_pre)(struct xgbe_prv_data *);
        void (*kr_training_post)(struct xgbe_prv_data *);
@@ -989,6 +994,7 @@ struct xgbe_version_data {
        unsigned int irq_reissue_support;
        unsigned int tx_desc_prefetch;
        unsigned int rx_desc_prefetch;
+       unsigned int an_cdr_workaround;
 };
 
 struct xgbe_vxlan_data {
@@ -1257,6 +1263,9 @@ struct xgbe_prv_data {
        unsigned int debugfs_xprop_reg;
 
        unsigned int debugfs_xi2c_reg;
+
+       bool debugfs_an_cdr_workaround;
+       bool debugfs_an_cdr_track_early;
 };
 
 /* Function prototypes*/
index 2df01ad..6e8d6a6 100644 (file)
@@ -1128,7 +1128,7 @@ static void clean_rx_pools(struct ibmvnic_adapter *adapter)
        if (!adapter->rx_pool)
                return;
 
-       rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
+       rx_scrqs = adapter->num_active_rx_pools;
        rx_entries = adapter->req_rx_add_entries_per_subcrq;
 
        /* Free any remaining skbs in the rx buffer pools */
@@ -1177,7 +1177,7 @@ static void clean_tx_pools(struct ibmvnic_adapter *adapter)
        if (!adapter->tx_pool || !adapter->tso_pool)
                return;
 
-       tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
+       tx_scrqs = adapter->num_active_tx_pools;
 
        /* Free any remaining skbs in the tx buffer pools */
        for (i = 0; i < tx_scrqs; i++) {
index 5b13ca1..7dc5f04 100644 (file)
@@ -586,7 +586,7 @@ struct ice_sw_rule_lg_act {
 #define ICE_LG_ACT_MIRROR_VSI_ID_S     3
 #define ICE_LG_ACT_MIRROR_VSI_ID_M     (0x3FF << ICE_LG_ACT_MIRROR_VSI_ID_S)
 
-       /* Action type = 5 - Large Action */
+       /* Action type = 5 - Generic Value */
 #define ICE_LG_ACT_GENERIC             0x5
 #define ICE_LG_ACT_GENERIC_VALUE_S     3
 #define ICE_LG_ACT_GENERIC_VALUE_M     (0xFFFF << ICE_LG_ACT_GENERIC_VALUE_S)
index 21977ec..71d032c 100644 (file)
@@ -78,6 +78,7 @@ ice_aq_manage_mac_read(struct ice_hw *hw, void *buf, u16 buf_size,
        struct ice_aq_desc desc;
        enum ice_status status;
        u16 flags;
+       u8 i;
 
        cmd = &desc.params.mac_read;
 
@@ -98,8 +99,16 @@ ice_aq_manage_mac_read(struct ice_hw *hw, void *buf, u16 buf_size,
                return ICE_ERR_CFG;
        }
 
-       ether_addr_copy(hw->port_info->mac.lan_addr, resp->mac_addr);
-       ether_addr_copy(hw->port_info->mac.perm_addr, resp->mac_addr);
+       /* A single port can report up to two (LAN and WoL) addresses */
+       for (i = 0; i < cmd->num_addr; i++)
+               if (resp[i].addr_type == ICE_AQC_MAN_MAC_ADDR_TYPE_LAN) {
+                       ether_addr_copy(hw->port_info->mac.lan_addr,
+                                       resp[i].mac_addr);
+                       ether_addr_copy(hw->port_info->mac.perm_addr,
+                                       resp[i].mac_addr);
+                       break;
+               }
+
        return 0;
 }
 
@@ -464,9 +473,12 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
        if (status)
                goto err_unroll_sched;
 
-       /* Get port MAC information */
-       mac_buf_len = sizeof(struct ice_aqc_manage_mac_read_resp);
-       mac_buf = devm_kzalloc(ice_hw_to_dev(hw), mac_buf_len, GFP_KERNEL);
+       /* Get MAC information */
+       /* A single port can report up to two (LAN and WoL) addresses */
+       mac_buf = devm_kcalloc(ice_hw_to_dev(hw), 2,
+                              sizeof(struct ice_aqc_manage_mac_read_resp),
+                              GFP_KERNEL);
+       mac_buf_len = 2 * sizeof(struct ice_aqc_manage_mac_read_resp);
 
        if (!mac_buf) {
                status = ICE_ERR_NO_MEMORY;
index 1b9e2ef..4999048 100644 (file)
 #define PFINT_FW_CTL_CAUSE_ENA_S       30
 #define PFINT_FW_CTL_CAUSE_ENA_M       BIT(PFINT_FW_CTL_CAUSE_ENA_S)
 #define PFINT_OICR                     0x0016CA00
-#define PFINT_OICR_INTEVENT_S          0
-#define PFINT_OICR_INTEVENT_M          BIT(PFINT_OICR_INTEVENT_S)
 #define PFINT_OICR_HLP_RDY_S           14
 #define PFINT_OICR_HLP_RDY_M           BIT(PFINT_OICR_HLP_RDY_S)
 #define PFINT_OICR_CPM_RDY_S           15
index 210b791..5299caf 100644 (file)
@@ -1722,9 +1722,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
        oicr = rd32(hw, PFINT_OICR);
        ena_mask = rd32(hw, PFINT_OICR_ENA);
 
-       if (!(oicr & PFINT_OICR_INTEVENT_M))
-               goto ena_intr;
-
        if (oicr & PFINT_OICR_GRST_M) {
                u32 reset;
                /* we have a reset warning */
@@ -1782,7 +1779,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
        }
        ret = IRQ_HANDLED;
 
-ena_intr:
        /* re-enable interrupt causes that are not handled during this pass */
        wr32(hw, PFINT_OICR_ENA, ena_mask);
        if (!test_bit(__ICE_DOWN, pf->state)) {
index f16ff3e..2e6c1d9 100644 (file)
@@ -751,14 +751,14 @@ ice_sched_add_nodes_to_layer(struct ice_port_info *pi,
        u16 num_added = 0;
        u32 temp;
 
+       *num_nodes_added = 0;
+
        if (!num_nodes)
                return status;
 
        if (!parent || layer < hw->sw_entry_point_layer)
                return ICE_ERR_PARAM;
 
-       *num_nodes_added = 0;
-
        /* max children per node per layer */
        max_child_nodes =
            le16_to_cpu(hw->layer_info[parent->tx_sched_layer].max_children);
index c1c0bc3..cce7ada 100644 (file)
@@ -1700,7 +1700,22 @@ static void igb_configure_cbs(struct igb_adapter *adapter, int queue,
        WARN_ON(hw->mac.type != e1000_i210);
        WARN_ON(queue < 0 || queue > 1);
 
-       if (enable) {
+       if (enable || queue == 0) {
+               /* i210 does not allow the queue 0 to be in the Strict
+                * Priority mode while the Qav mode is enabled, so,
+                * instead of disabling strict priority mode, we give
+                * queue 0 the maximum of credits possible.
+                *
+                * See section 8.12.19 of the i210 datasheet, "Note:
+                * Queue0 QueueMode must be set to 1b when
+                * TransmitMode is set to Qav."
+                */
+               if (queue == 0 && !enable) {
+                       /* max "linkspeed" idleslope in kbps */
+                       idleslope = 1000000;
+                       hicredit = ETH_FRAME_LEN;
+               }
+
                set_tx_desc_fetch_prio(hw, queue, TX_QUEUE_PRIO_HIGH);
                set_queue_mode(hw, queue, QUEUE_MODE_STREAM_RESERVATION);
 
index 3d9033f..e3d04f2 100644 (file)
@@ -3420,7 +3420,7 @@ static int ixgbevf_setup_all_tx_resources(struct ixgbevf_adapter *adapter)
                if (!err)
                        continue;
                hw_dbg(&adapter->hw, "Allocation for XDP Queue %u failed\n", j);
-               break;
+               goto err_setup_tx;
        }
 
        return 0;
index 83ce229..63036d9 100644 (file)
@@ -3999,29 +3999,6 @@ static void efx_ef10_prepare_flr(struct efx_nic *efx)
        atomic_set(&efx->active_queues, 0);
 }
 
-static bool efx_ef10_filter_equal(const struct efx_filter_spec *left,
-                                 const struct efx_filter_spec *right)
-{
-       if ((left->match_flags ^ right->match_flags) |
-           ((left->flags ^ right->flags) &
-            (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)))
-               return false;
-
-       return memcmp(&left->outer_vid, &right->outer_vid,
-                     sizeof(struct efx_filter_spec) -
-                     offsetof(struct efx_filter_spec, outer_vid)) == 0;
-}
-
-static unsigned int efx_ef10_filter_hash(const struct efx_filter_spec *spec)
-{
-       BUILD_BUG_ON(offsetof(struct efx_filter_spec, outer_vid) & 3);
-       return jhash2((const u32 *)&spec->outer_vid,
-                     (sizeof(struct efx_filter_spec) -
-                      offsetof(struct efx_filter_spec, outer_vid)) / 4,
-                     0);
-       /* XXX should we randomise the initval? */
-}
-
 /* Decide whether a filter should be exclusive or else should allow
  * delivery to additional recipients.  Currently we decide that
  * filters for specific local unicast MAC and IP addresses are
@@ -4346,7 +4323,7 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
                goto out_unlock;
        match_pri = rc;
 
-       hash = efx_ef10_filter_hash(spec);
+       hash = efx_filter_spec_hash(spec);
        is_mc_recip = efx_filter_is_mc_recipient(spec);
        if (is_mc_recip)
                bitmap_zero(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT);
@@ -4378,7 +4355,7 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
                if (!saved_spec) {
                        if (ins_index < 0)
                                ins_index = i;
-               } else if (efx_ef10_filter_equal(spec, saved_spec)) {
+               } else if (efx_filter_spec_equal(spec, saved_spec)) {
                        if (spec->priority < saved_spec->priority &&
                            spec->priority != EFX_FILTER_PRI_AUTO) {
                                rc = -EPERM;
@@ -4762,27 +4739,62 @@ static s32 efx_ef10_filter_get_rx_ids(struct efx_nic *efx,
 static bool efx_ef10_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id,
                                           unsigned int filter_idx)
 {
+       struct efx_filter_spec *spec, saved_spec;
        struct efx_ef10_filter_table *table;
-       struct efx_filter_spec *spec;
-       bool ret;
+       struct efx_arfs_rule *rule = NULL;
+       bool ret = true, force = false;
+       u16 arfs_id;
 
        down_read(&efx->filter_sem);
        table = efx->filter_state;
        down_write(&table->lock);
        spec = efx_ef10_filter_entry_spec(table, filter_idx);
 
-       if (!spec || spec->priority != EFX_FILTER_PRI_HINT) {
-               ret = true;
+       if (!spec || spec->priority != EFX_FILTER_PRI_HINT)
                goto out_unlock;
-       }
 
-       if (!rps_may_expire_flow(efx->net_dev, spec->dmaq_id, flow_id, 0)) {
-               ret = false;
-               goto out_unlock;
+       spin_lock_bh(&efx->rps_hash_lock);
+       if (!efx->rps_hash_table) {
+               /* In the absence of the table, we always return 0 to ARFS. */
+               arfs_id = 0;
+       } else {
+               rule = efx_rps_hash_find(efx, spec);
+               if (!rule)
+                       /* ARFS table doesn't know of this filter, so remove it */
+                       goto expire;
+               arfs_id = rule->arfs_id;
+               ret = efx_rps_check_rule(rule, filter_idx, &force);
+               if (force)
+                       goto expire;
+               if (!ret) {
+                       spin_unlock_bh(&efx->rps_hash_lock);
+                       goto out_unlock;
+               }
        }
-
+       if (!rps_may_expire_flow(efx->net_dev, spec->dmaq_id, flow_id, arfs_id))
+               ret = false;
+       else if (rule)
+               rule->filter_id = EFX_ARFS_FILTER_ID_REMOVING;
+expire:
+       saved_spec = *spec; /* remove operation will kfree spec */
+       spin_unlock_bh(&efx->rps_hash_lock);
+       /* At this point (since we dropped the lock), another thread might queue
+        * up a fresh insertion request (but the actual insertion will be held
+        * up by our possession of the filter table lock).  In that case, it
+        * will set rule->filter_id to EFX_ARFS_FILTER_ID_PENDING, meaning that
+        * the rule is not removed by efx_rps_hash_del() below.
+        */
        ret = efx_ef10_filter_remove_internal(efx, 1U << spec->priority,
                                              filter_idx, true) == 0;
+       /* While we can't safely dereference rule (we dropped the lock), we can
+        * still test it for NULL.
+        */
+       if (ret && rule) {
+               /* Expiring, so remove entry from ARFS table */
+               spin_lock_bh(&efx->rps_hash_lock);
+               efx_rps_hash_del(efx, &saved_spec);
+               spin_unlock_bh(&efx->rps_hash_lock);
+       }
 out_unlock:
        up_write(&table->lock);
        up_read(&efx->filter_sem);
index 692dd72..a4ebd87 100644 (file)
@@ -3027,6 +3027,10 @@ static int efx_init_struct(struct efx_nic *efx,
        mutex_init(&efx->mac_lock);
 #ifdef CONFIG_RFS_ACCEL
        mutex_init(&efx->rps_mutex);
+       spin_lock_init(&efx->rps_hash_lock);
+       /* Failure to allocate is not fatal, but may degrade ARFS performance */
+       efx->rps_hash_table = kcalloc(EFX_ARFS_HASH_TABLE_SIZE,
+                                     sizeof(*efx->rps_hash_table), GFP_KERNEL);
 #endif
        efx->phy_op = &efx_dummy_phy_operations;
        efx->mdio.dev = net_dev;
@@ -3070,6 +3074,10 @@ static void efx_fini_struct(struct efx_nic *efx)
 {
        int i;
 
+#ifdef CONFIG_RFS_ACCEL
+       kfree(efx->rps_hash_table);
+#endif
+
        for (i = 0; i < EFX_MAX_CHANNELS; i++)
                kfree(efx->channel[i]);
 
@@ -3092,6 +3100,141 @@ void efx_update_sw_stats(struct efx_nic *efx, u64 *stats)
        stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops);
 }
 
+bool efx_filter_spec_equal(const struct efx_filter_spec *left,
+                          const struct efx_filter_spec *right)
+{
+       if ((left->match_flags ^ right->match_flags) |
+           ((left->flags ^ right->flags) &
+            (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)))
+               return false;
+
+       return memcmp(&left->outer_vid, &right->outer_vid,
+                     sizeof(struct efx_filter_spec) -
+                     offsetof(struct efx_filter_spec, outer_vid)) == 0;
+}
+
+u32 efx_filter_spec_hash(const struct efx_filter_spec *spec)
+{
+       BUILD_BUG_ON(offsetof(struct efx_filter_spec, outer_vid) & 3);
+       return jhash2((const u32 *)&spec->outer_vid,
+                     (sizeof(struct efx_filter_spec) -
+                      offsetof(struct efx_filter_spec, outer_vid)) / 4,
+                     0);
+}
+
+#ifdef CONFIG_RFS_ACCEL
+bool efx_rps_check_rule(struct efx_arfs_rule *rule, unsigned int filter_idx,
+                       bool *force)
+{
+       if (rule->filter_id == EFX_ARFS_FILTER_ID_PENDING) {
+               /* ARFS is currently updating this entry, leave it */
+               return false;
+       }
+       if (rule->filter_id == EFX_ARFS_FILTER_ID_ERROR) {
+               /* ARFS tried and failed to update this, so it's probably out
+                * of date.  Remove the filter and the ARFS rule entry.
+                */
+               rule->filter_id = EFX_ARFS_FILTER_ID_REMOVING;
+               *force = true;
+               return true;
+       } else if (WARN_ON(rule->filter_id != filter_idx)) { /* can't happen */
+               /* ARFS has moved on, so old filter is not needed.  Since we did
+                * not mark the rule with EFX_ARFS_FILTER_ID_REMOVING, it will
+                * not be removed by efx_rps_hash_del() subsequently.
+                */
+               *force = true;
+               return true;
+       }
+       /* Remove it iff ARFS wants to. */
+       return true;
+}
+
+struct hlist_head *efx_rps_hash_bucket(struct efx_nic *efx,
+                                      const struct efx_filter_spec *spec)
+{
+       u32 hash = efx_filter_spec_hash(spec);
+
+       WARN_ON(!spin_is_locked(&efx->rps_hash_lock));
+       if (!efx->rps_hash_table)
+               return NULL;
+       return &efx->rps_hash_table[hash % EFX_ARFS_HASH_TABLE_SIZE];
+}
+
+struct efx_arfs_rule *efx_rps_hash_find(struct efx_nic *efx,
+                                       const struct efx_filter_spec *spec)
+{
+       struct efx_arfs_rule *rule;
+       struct hlist_head *head;
+       struct hlist_node *node;
+
+       head = efx_rps_hash_bucket(efx, spec);
+       if (!head)
+               return NULL;
+       hlist_for_each(node, head) {
+               rule = container_of(node, struct efx_arfs_rule, node);
+               if (efx_filter_spec_equal(spec, &rule->spec))
+                       return rule;
+       }
+       return NULL;
+}
+
+struct efx_arfs_rule *efx_rps_hash_add(struct efx_nic *efx,
+                                      const struct efx_filter_spec *spec,
+                                      bool *new)
+{
+       struct efx_arfs_rule *rule;
+       struct hlist_head *head;
+       struct hlist_node *node;
+
+       head = efx_rps_hash_bucket(efx, spec);
+       if (!head)
+               return NULL;
+       hlist_for_each(node, head) {
+               rule = container_of(node, struct efx_arfs_rule, node);
+               if (efx_filter_spec_equal(spec, &rule->spec)) {
+                       *new = false;
+                       return rule;
+               }
+       }
+       rule = kmalloc(sizeof(*rule), GFP_ATOMIC);
+       *new = true;
+       if (rule) {
+               memcpy(&rule->spec, spec, sizeof(rule->spec));
+               hlist_add_head(&rule->node, head);
+       }
+       return rule;
+}
+
+void efx_rps_hash_del(struct efx_nic *efx, const struct efx_filter_spec *spec)
+{
+       struct efx_arfs_rule *rule;
+       struct hlist_head *head;
+       struct hlist_node *node;
+
+       head = efx_rps_hash_bucket(efx, spec);
+       if (WARN_ON(!head))
+               return;
+       hlist_for_each(node, head) {
+               rule = container_of(node, struct efx_arfs_rule, node);
+               if (efx_filter_spec_equal(spec, &rule->spec)) {
+                       /* Someone already reused the entry.  We know that if
+                        * this check doesn't fire (i.e. filter_id == REMOVING)
+                        * then the REMOVING mark was put there by our caller,
+                        * because caller is holding a lock on filter table and
+                        * only holders of that lock set REMOVING.
+                        */
+                       if (rule->filter_id != EFX_ARFS_FILTER_ID_REMOVING)
+                               return;
+                       hlist_del(node);
+                       kfree(rule);
+                       return;
+               }
+       }
+       /* We didn't find it. */
+       WARN_ON(1);
+}
+#endif
+
 /* RSS contexts.  We're using linked lists and crappy O(n) algorithms, because
  * (a) this is an infrequent control-plane operation and (b) n is small (max 64)
  */
index a3140e1..3f759eb 100644 (file)
@@ -186,6 +186,27 @@ static inline void efx_filter_rfs_expire(struct work_struct *data) {}
 #endif
 bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec);
 
+bool efx_filter_spec_equal(const struct efx_filter_spec *left,
+                          const struct efx_filter_spec *right);
+u32 efx_filter_spec_hash(const struct efx_filter_spec *spec);
+
+#ifdef CONFIG_RFS_ACCEL
+bool efx_rps_check_rule(struct efx_arfs_rule *rule, unsigned int filter_idx,
+                       bool *force);
+
+struct efx_arfs_rule *efx_rps_hash_find(struct efx_nic *efx,
+                                       const struct efx_filter_spec *spec);
+
+/* @new is written to indicate if entry was newly added (true) or if an old
+ * entry was found and returned (false).
+ */
+struct efx_arfs_rule *efx_rps_hash_add(struct efx_nic *efx,
+                                      const struct efx_filter_spec *spec,
+                                      bool *new);
+
+void efx_rps_hash_del(struct efx_nic *efx, const struct efx_filter_spec *spec);
+#endif
+
 /* RSS contexts */
 struct efx_rss_context *efx_alloc_rss_context_entry(struct efx_nic *efx);
 struct efx_rss_context *efx_find_rss_context_entry(struct efx_nic *efx, u32 id);
index 7174ef5..c72adf8 100644 (file)
@@ -2905,18 +2905,45 @@ bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id,
 {
        struct efx_farch_filter_state *state = efx->filter_state;
        struct efx_farch_filter_table *table;
-       bool ret = false;
+       bool ret = false, force = false;
+       u16 arfs_id;
 
        down_write(&state->lock);
+       spin_lock_bh(&efx->rps_hash_lock);
        table = &state->table[EFX_FARCH_FILTER_TABLE_RX_IP];
        if (test_bit(index, table->used_bitmap) &&
-           table->spec[index].priority == EFX_FILTER_PRI_HINT &&
-           rps_may_expire_flow(efx->net_dev, table->spec[index].dmaq_id,
-                               flow_id, 0)) {
-               efx_farch_filter_table_clear_entry(efx, table, index);
-               ret = true;
+           table->spec[index].priority == EFX_FILTER_PRI_HINT) {
+               struct efx_arfs_rule *rule = NULL;
+               struct efx_filter_spec spec;
+
+               efx_farch_filter_to_gen_spec(&spec, &table->spec[index]);
+               if (!efx->rps_hash_table) {
+                       /* In the absence of the table, we always returned 0 to
+                        * ARFS, so use the same to query it.
+                        */
+                       arfs_id = 0;
+               } else {
+                       rule = efx_rps_hash_find(efx, &spec);
+                       if (!rule) {
+                               /* ARFS table doesn't know of this filter, remove it */
+                               force = true;
+                       } else {
+                               arfs_id = rule->arfs_id;
+                               if (!efx_rps_check_rule(rule, index, &force))
+                                       goto out_unlock;
+                       }
+               }
+               if (force || rps_may_expire_flow(efx->net_dev, spec.dmaq_id,
+                                                flow_id, arfs_id)) {
+                       if (rule)
+                               rule->filter_id = EFX_ARFS_FILTER_ID_REMOVING;
+                       efx_rps_hash_del(efx, &spec);
+                       efx_farch_filter_table_clear_entry(efx, table, index);
+                       ret = true;
+               }
        }
-
+out_unlock:
+       spin_unlock_bh(&efx->rps_hash_lock);
        up_write(&state->lock);
        return ret;
 }
index eea3808..6556892 100644 (file)
@@ -734,6 +734,35 @@ struct efx_rss_context {
 };
 
 #ifdef CONFIG_RFS_ACCEL
+/* Order of these is important, since filter_id >= %EFX_ARFS_FILTER_ID_PENDING
+ * is used to test if filter does or will exist.
+ */
+#define EFX_ARFS_FILTER_ID_PENDING     -1
+#define EFX_ARFS_FILTER_ID_ERROR       -2
+#define EFX_ARFS_FILTER_ID_REMOVING    -3
+/**
+ * struct efx_arfs_rule - record of an ARFS filter and its IDs
+ * @node: linkage into hash table
+ * @spec: details of the filter (used as key for hash table).  Use efx->type to
+ *     determine which member to use.
+ * @rxq_index: channel to which the filter will steer traffic.
+ * @arfs_id: filter ID which was returned to ARFS
+ * @filter_id: index in software filter table.  May be
+ *     %EFX_ARFS_FILTER_ID_PENDING if filter was not inserted yet,
+ *     %EFX_ARFS_FILTER_ID_ERROR if filter insertion failed, or
+ *     %EFX_ARFS_FILTER_ID_REMOVING if expiry is currently removing the filter.
+ */
+struct efx_arfs_rule {
+       struct hlist_node node;
+       struct efx_filter_spec spec;
+       u16 rxq_index;
+       u16 arfs_id;
+       s32 filter_id;
+};
+
+/* Size chosen so that the table is one page (4kB) */
+#define EFX_ARFS_HASH_TABLE_SIZE       512
+
 /**
  * struct efx_async_filter_insertion - Request to asynchronously insert a filter
  * @net_dev: Reference to the netdevice
@@ -873,6 +902,10 @@ struct efx_async_filter_insertion {
  *     @rps_expire_channel's @rps_flow_id
  * @rps_slot_map: bitmap of in-flight entries in @rps_slot
  * @rps_slot: array of ARFS insertion requests for efx_filter_rfs_work()
+ * @rps_hash_lock: Protects ARFS filter mapping state (@rps_hash_table and
+ *     @rps_next_id).
+ * @rps_hash_table: Mapping between ARFS filters and their various IDs
+ * @rps_next_id: next arfs_id for an ARFS filter
  * @active_queues: Count of RX and TX queues that haven't been flushed and drained.
  * @rxq_flush_pending: Count of number of receive queues that need to be flushed.
  *     Decremented when the efx_flush_rx_queue() is called.
@@ -1029,6 +1062,9 @@ struct efx_nic {
        unsigned int rps_expire_index;
        unsigned long rps_slot_map;
        struct efx_async_filter_insertion rps_slot[EFX_RPS_MAX_IN_FLIGHT];
+       spinlock_t rps_hash_lock;
+       struct hlist_head *rps_hash_table;
+       u32 rps_next_id;
 #endif
 
        atomic_t active_queues;
index 9c593c6..64a94f2 100644 (file)
@@ -834,9 +834,29 @@ static void efx_filter_rfs_work(struct work_struct *data)
        struct efx_nic *efx = netdev_priv(req->net_dev);
        struct efx_channel *channel = efx_get_channel(efx, req->rxq_index);
        int slot_idx = req - efx->rps_slot;
+       struct efx_arfs_rule *rule;
+       u16 arfs_id = 0;
        int rc;
 
        rc = efx->type->filter_insert(efx, &req->spec, true);
+       if (efx->rps_hash_table) {
+               spin_lock_bh(&efx->rps_hash_lock);
+               rule = efx_rps_hash_find(efx, &req->spec);
+               /* The rule might have already gone, if someone else's request
+                * for the same spec was already worked and then expired before
+                * we got around to our work.  In that case we have nothing
+                * tying us to an arfs_id, meaning that as soon as the filter
+                * is considered for expiry it will be removed.
+                */
+               if (rule) {
+                       if (rc < 0)
+                               rule->filter_id = EFX_ARFS_FILTER_ID_ERROR;
+                       else
+                               rule->filter_id = rc;
+                       arfs_id = rule->arfs_id;
+               }
+               spin_unlock_bh(&efx->rps_hash_lock);
+       }
        if (rc >= 0) {
                /* Remember this so we can check whether to expire the filter
                 * later.
@@ -848,18 +868,18 @@ static void efx_filter_rfs_work(struct work_struct *data)
 
                if (req->spec.ether_type == htons(ETH_P_IP))
                        netif_info(efx, rx_status, efx->net_dev,
-                                  "steering %s %pI4:%u:%pI4:%u to queue %u [flow %u filter %d]\n",
+                                  "steering %s %pI4:%u:%pI4:%u to queue %u [flow %u filter %d id %u]\n",
                                   (req->spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP",
                                   req->spec.rem_host, ntohs(req->spec.rem_port),
                                   req->spec.loc_host, ntohs(req->spec.loc_port),
-                                  req->rxq_index, req->flow_id, rc);
+                                  req->rxq_index, req->flow_id, rc, arfs_id);
                else
                        netif_info(efx, rx_status, efx->net_dev,
-                                  "steering %s [%pI6]:%u:[%pI6]:%u to queue %u [flow %u filter %d]\n",
+                                  "steering %s [%pI6]:%u:[%pI6]:%u to queue %u [flow %u filter %d id %u]\n",
                                   (req->spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP",
                                   req->spec.rem_host, ntohs(req->spec.rem_port),
                                   req->spec.loc_host, ntohs(req->spec.loc_port),
-                                  req->rxq_index, req->flow_id, rc);
+                                  req->rxq_index, req->flow_id, rc, arfs_id);
        }
 
        /* Release references */
@@ -872,8 +892,10 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
 {
        struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_async_filter_insertion *req;
+       struct efx_arfs_rule *rule;
        struct flow_keys fk;
        int slot_idx;
+       bool new;
        int rc;
 
        /* find a free slot */
@@ -926,12 +948,42 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
        req->spec.rem_port = fk.ports.src;
        req->spec.loc_port = fk.ports.dst;
 
+       if (efx->rps_hash_table) {
+               /* Add it to ARFS hash table */
+               spin_lock(&efx->rps_hash_lock);
+               rule = efx_rps_hash_add(efx, &req->spec, &new);
+               if (!rule) {
+                       rc = -ENOMEM;
+                       goto out_unlock;
+               }
+               if (new)
+                       rule->arfs_id = efx->rps_next_id++ % RPS_NO_FILTER;
+               rc = rule->arfs_id;
+               /* Skip if existing or pending filter already does the right thing */
+               if (!new && rule->rxq_index == rxq_index &&
+                   rule->filter_id >= EFX_ARFS_FILTER_ID_PENDING)
+                       goto out_unlock;
+               rule->rxq_index = rxq_index;
+               rule->filter_id = EFX_ARFS_FILTER_ID_PENDING;
+               spin_unlock(&efx->rps_hash_lock);
+       } else {
+               /* Without an ARFS hash table, we just use arfs_id 0 for all
+                * filters.  This means if multiple flows hash to the same
+                * flow_id, all but the most recently touched will be eligible
+                * for expiry.
+                */
+               rc = 0;
+       }
+
+       /* Queue the request */
        dev_hold(req->net_dev = net_dev);
        INIT_WORK(&req->work, efx_filter_rfs_work);
        req->rxq_index = rxq_index;
        req->flow_id = flow_id;
        schedule_work(&req->work);
-       return 0;
+       return rc;
+out_unlock:
+       spin_unlock(&efx->rps_hash_lock);
 out_clear:
        clear_bit(slot_idx, &efx->rps_slot_map);
        return rc;
index 3037127..74f8284 100644 (file)
@@ -129,7 +129,7 @@ do {                                                                \
 
 #define RX_PRIORITY_MAPPING    0x76543210
 #define TX_PRIORITY_MAPPING    0x33221100
-#define CPDMA_TX_PRIORITY_MAP  0x01234567
+#define CPDMA_TX_PRIORITY_MAP  0x76543210
 
 #define CPSW_VLAN_AWARE                BIT(1)
 #define CPSW_RX_VLAN_ENCAP     BIT(2)
index c22e8e3..25e2a09 100644 (file)
@@ -1393,6 +1393,15 @@ static int m88e1318_set_wol(struct phy_device *phydev,
                if (err < 0)
                        goto error;
 
+               /* If WOL event happened once, the LED[2] interrupt pin
+                * will not be cleared unless we reading the interrupt status
+                * register. If interrupts are in use, the normal interrupt
+                * handling will clear the WOL event. Clear the WOL event
+                * before enabling it if !phy_interrupt_is_valid()
+                */
+               if (!phy_interrupt_is_valid(phydev))
+                       phy_read(phydev, MII_M1011_IEVENT);
+
                /* Enable the WOL interrupt */
                err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0,
                                   MII_88E1318S_PHY_CSIER_WOL_EIE);
index 1483bc7..7df0733 100644 (file)
@@ -620,6 +620,10 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
        lock_sock(sk);
 
        error = -EINVAL;
+
+       if (sockaddr_len != sizeof(struct sockaddr_pppox))
+               goto end;
+
        if (sp->sa_protocol != PX_PROTO_OE)
                goto end;
 
index acbe849..ddb6bf8 100644 (file)
@@ -1072,14 +1072,11 @@ static void team_port_leave(struct team *team, struct team_port *port)
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int __team_port_enable_netpoll(struct team_port *port)
 {
        struct netpoll *np;
        int err;
 
-       if (!team->dev->npinfo)
-               return 0;
-
        np = kzalloc(sizeof(*np), GFP_KERNEL);
        if (!np)
                return -ENOMEM;
@@ -1093,6 +1090,14 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port)
        return err;
 }
 
+static int team_port_enable_netpoll(struct team_port *port)
+{
+       if (!port->team->dev->npinfo)
+               return 0;
+
+       return __team_port_enable_netpoll(port);
+}
+
 static void team_port_disable_netpoll(struct team_port *port)
 {
        struct netpoll *np = port->np;
@@ -1107,7 +1112,7 @@ static void team_port_disable_netpoll(struct team_port *port)
        kfree(np);
 }
 #else
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int team_port_enable_netpoll(struct team_port *port)
 {
        return 0;
 }
@@ -1221,7 +1226,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
                goto err_vids_add;
        }
 
-       err = team_port_enable_netpoll(team, port);
+       err = team_port_enable_netpoll(port);
        if (err) {
                netdev_err(dev, "Failed to enable netpoll on device %s\n",
                           portname);
@@ -1918,7 +1923,7 @@ static int team_netpoll_setup(struct net_device *dev,
 
        mutex_lock(&team->lock);
        list_for_each_entry(port, &team->port_list, list) {
-               err = team_port_enable_netpoll(team, port);
+               err = __team_port_enable_netpoll(port);
                if (err) {
                        __team_netpoll_cleanup(team);
                        break;
index 6ace470..b9a1311 100644 (file)
@@ -958,10 +958,11 @@ static int pci_pm_freeze(struct device *dev)
         * devices should not be touched during freeze/thaw transitions,
         * however.
         */
-       if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
+       if (!dev_pm_smart_suspend_and_suspended(dev)) {
                pm_runtime_resume(dev);
+               pci_dev->state_saved = false;
+       }
 
-       pci_dev->state_saved = false;
        if (pm->freeze) {
                int error;
 
index 62f5f04..5e963fe 100644 (file)
@@ -592,13 +592,22 @@ static int _schedule_lcu_update(struct alias_lcu *lcu,
 int dasd_alias_add_device(struct dasd_device *device)
 {
        struct dasd_eckd_private *private = device->private;
-       struct alias_lcu *lcu;
+       __u8 uaddr = private->uid.real_unit_addr;
+       struct alias_lcu *lcu = private->lcu;
        unsigned long flags;
        int rc;
 
-       lcu = private->lcu;
        rc = 0;
        spin_lock_irqsave(&lcu->lock, flags);
+       /*
+        * Check if device and lcu type differ. If so, the uac data may be
+        * outdated and needs to be updated.
+        */
+       if (private->uid.type !=  lcu->uac->unit[uaddr].ua_type) {
+               lcu->flags |= UPDATE_PENDING;
+               DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+                             "uid type mismatch - trigger rescan");
+       }
        if (!(lcu->flags & UPDATE_PENDING)) {
                rc = _add_device_to_lcu(lcu, device, device);
                if (rc)
index 6652a49..9029804 100644 (file)
@@ -452,6 +452,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area)
 
 static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)
 {
+       struct channel_path *chp;
        struct chp_link link;
        struct chp_id chpid;
        int status;
@@ -464,10 +465,17 @@ static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)
        chpid.id = sei_area->rsid;
        /* allocate a new channel path structure, if needed */
        status = chp_get_status(chpid);
-       if (status < 0)
-               chp_new(chpid);
-       else if (!status)
+       if (!status)
                return;
+
+       if (status < 0) {
+               chp_new(chpid);
+       } else {
+               chp = chpid_to_chp(chpid);
+               mutex_lock(&chp->lock);
+               chp_update_desc(chp);
+               mutex_unlock(&chp->lock);
+       }
        memset(&link, 0, sizeof(struct chp_link));
        link.chpid = chpid;
        if ((sei_area->vf & 0xc0) != 0) {
index ff6963a..3c80064 100644 (file)
@@ -20,12 +20,12 @@ static int fsm_io_helper(struct vfio_ccw_private *private)
        int ccode;
        __u8 lpm;
        unsigned long flags;
+       int ret;
 
        sch = private->sch;
 
        spin_lock_irqsave(sch->lock, flags);
        private->state = VFIO_CCW_STATE_BUSY;
-       spin_unlock_irqrestore(sch->lock, flags);
 
        orb = cp_get_orb(&private->cp, (u32)(addr_t)sch, sch->lpm);
 
@@ -38,10 +38,12 @@ static int fsm_io_helper(struct vfio_ccw_private *private)
                 * Initialize device status information
                 */
                sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
-               return 0;
+               ret = 0;
+               break;
        case 1:         /* Status pending */
        case 2:         /* Busy */
-               return -EBUSY;
+               ret = -EBUSY;
+               break;
        case 3:         /* Device/path not operational */
        {
                lpm = orb->cmd.lpm;
@@ -51,13 +53,16 @@ static int fsm_io_helper(struct vfio_ccw_private *private)
                        sch->lpm = 0;
 
                if (cio_update_schib(sch))
-                       return -ENODEV;
-
-               return sch->lpm ? -EACCES : -ENODEV;
+                       ret = -ENODEV;
+               else
+                       ret = sch->lpm ? -EACCES : -ENODEV;
+               break;
        }
        default:
-               return ccode;
+               ret = ccode;
        }
+       spin_unlock_irqrestore(sch->lock, flags);
+       return ret;
 }
 
 static void fsm_notoper(struct vfio_ccw_private *private,
index 4326715..78b98b3 100644 (file)
@@ -557,7 +557,6 @@ enum qeth_prot_versions {
 enum qeth_cmd_buffer_state {
        BUF_STATE_FREE,
        BUF_STATE_LOCKED,
-       BUF_STATE_PROCESSED,
 };
 
 enum qeth_cq {
@@ -601,7 +600,6 @@ struct qeth_channel {
        struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO];
        atomic_t irq_pending;
        int io_buf_no;
-       int buf_no;
 };
 
 /**
index 04fefa5..dffd820 100644 (file)
@@ -706,7 +706,6 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
                qeth_put_reply(reply);
        }
        spin_unlock_irqrestore(&card->lock, flags);
-       atomic_set(&card->write.irq_pending, 0);
 }
 EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
 
@@ -818,7 +817,6 @@ void qeth_clear_cmd_buffers(struct qeth_channel *channel)
 
        for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++)
                qeth_release_buffer(channel, &channel->iob[cnt]);
-       channel->buf_no = 0;
        channel->io_buf_no = 0;
 }
 EXPORT_SYMBOL_GPL(qeth_clear_cmd_buffers);
@@ -924,7 +922,6 @@ static int qeth_setup_channel(struct qeth_channel *channel)
                        kfree(channel->iob[cnt].data);
                return -ENOMEM;
        }
-       channel->buf_no = 0;
        channel->io_buf_no = 0;
        atomic_set(&channel->irq_pending, 0);
        spin_lock_init(&channel->iob_lock);
@@ -1100,16 +1097,9 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
 {
        int rc;
        int cstat, dstat;
-       struct qeth_cmd_buffer *buffer;
+       struct qeth_cmd_buffer *iob = NULL;
        struct qeth_channel *channel;
        struct qeth_card *card;
-       struct qeth_cmd_buffer *iob;
-       __u8 index;
-
-       if (__qeth_check_irb_error(cdev, intparm, irb))
-               return;
-       cstat = irb->scsw.cmd.cstat;
-       dstat = irb->scsw.cmd.dstat;
 
        card = CARD_FROM_CDEV(cdev);
        if (!card)
@@ -1127,6 +1117,19 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                channel = &card->data;
                QETH_CARD_TEXT(card, 5, "data");
        }
+
+       if (qeth_intparm_is_iob(intparm))
+               iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
+
+       if (__qeth_check_irb_error(cdev, intparm, irb)) {
+               /* IO was terminated, free its resources. */
+               if (iob)
+                       qeth_release_buffer(iob->channel, iob);
+               atomic_set(&channel->irq_pending, 0);
+               wake_up(&card->wait_q);
+               return;
+       }
+
        atomic_set(&channel->irq_pending, 0);
 
        if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC))
@@ -1150,6 +1153,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                /* we don't have to handle this further */
                intparm = 0;
        }
+
+       cstat = irb->scsw.cmd.cstat;
+       dstat = irb->scsw.cmd.dstat;
+
        if ((dstat & DEV_STAT_UNIT_EXCEP) ||
            (dstat & DEV_STAT_UNIT_CHECK) ||
            (cstat)) {
@@ -1182,25 +1189,15 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                channel->state = CH_STATE_RCD_DONE;
                goto out;
        }
-       if (intparm) {
-               buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
-               buffer->state = BUF_STATE_PROCESSED;
-       }
        if (channel == &card->data)
                return;
        if (channel == &card->read &&
            channel->state == CH_STATE_UP)
                __qeth_issue_next_read(card);
 
-       iob = channel->iob;
-       index = channel->buf_no;
-       while (iob[index].state == BUF_STATE_PROCESSED) {
-               if (iob[index].callback != NULL)
-                       iob[index].callback(channel, iob + index);
+       if (iob && iob->callback)
+               iob->callback(iob->channel, iob);
 
-               index = (index + 1) % QETH_CMD_BUFFER_NO;
-       }
-       channel->buf_no = index;
 out:
        wake_up(&card->wait_q);
        return;
@@ -1870,8 +1867,8 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
                   atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
        QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
-       rc = ccw_device_start(channel->ccwdev,
-                             &channel->ccw, (addr_t) iob, 0, 0);
+       rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
+                                     (addr_t) iob, 0, 0, QETH_TIMEOUT);
        spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
 
        if (rc) {
@@ -1888,7 +1885,6 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
        if (channel->state != CH_STATE_UP) {
                rc = -ETIME;
                QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
-               qeth_clear_cmd_buffers(channel);
        } else
                rc = 0;
        return rc;
@@ -1942,8 +1938,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
                   atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
        QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
-       rc = ccw_device_start(channel->ccwdev,
-                             &channel->ccw, (addr_t) iob, 0, 0);
+       rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
+                                     (addr_t) iob, 0, 0, QETH_TIMEOUT);
        spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
 
        if (rc) {
@@ -1964,7 +1960,6 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
                QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n",
                        dev_name(&channel->ccwdev->dev));
                QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME);
-               qeth_clear_cmd_buffers(channel);
                return -ETIME;
        }
        return qeth_idx_activate_get_answer(channel, idx_reply_cb);
@@ -2166,8 +2161,8 @@ int qeth_send_control_data(struct qeth_card *card, int len,
 
        QETH_CARD_TEXT(card, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
-       rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
-                             (addr_t) iob, 0, 0);
+       rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
+                                     (addr_t) iob, 0, 0, event_timeout);
        spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
        if (rc) {
                QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
@@ -2199,8 +2194,6 @@ int qeth_send_control_data(struct qeth_card *card, int len,
                }
        }
 
-       if (reply->rc == -EIO)
-               goto error;
        rc = reply->rc;
        qeth_put_reply(reply);
        return rc;
@@ -2211,10 +2204,6 @@ time_err:
        list_del_init(&reply->list);
        spin_unlock_irqrestore(&reply->card->lock, flags);
        atomic_inc(&reply->received);
-error:
-       atomic_set(&card->write.irq_pending, 0);
-       qeth_release_buffer(iob->channel, iob);
-       card->write.buf_no = (card->write.buf_no + 1) % QETH_CMD_BUFFER_NO;
        rc = reply->rc;
        qeth_put_reply(reply);
        return rc;
@@ -3033,28 +3022,23 @@ static int qeth_send_startlan(struct qeth_card *card)
        return rc;
 }
 
-static int qeth_default_setadapterparms_cb(struct qeth_card *card,
-               struct qeth_reply *reply, unsigned long data)
+static int qeth_setadpparms_inspect_rc(struct qeth_ipa_cmd *cmd)
 {
-       struct qeth_ipa_cmd *cmd;
-
-       QETH_CARD_TEXT(card, 4, "defadpcb");
-
-       cmd = (struct qeth_ipa_cmd *) data;
-       if (cmd->hdr.return_code == 0)
+       if (!cmd->hdr.return_code)
                cmd->hdr.return_code =
                        cmd->data.setadapterparms.hdr.return_code;
-       return 0;
+       return cmd->hdr.return_code;
 }
 
 static int qeth_query_setadapterparms_cb(struct qeth_card *card,
                struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
 
        QETH_CARD_TEXT(card, 3, "quyadpcb");
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
-       cmd = (struct qeth_ipa_cmd *) data;
        if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) {
                card->info.link_type =
                      cmd->data.setadapterparms.data.query_cmds_supp.lan_type;
@@ -3062,7 +3046,7 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
        }
        card->options.adp.supported_funcs =
                cmd->data.setadapterparms.data.query_cmds_supp.supported_cmds;
-       return qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
+       return 0;
 }
 
 static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
@@ -3154,22 +3138,20 @@ EXPORT_SYMBOL_GPL(qeth_query_ipassists);
 static int qeth_query_switch_attributes_cb(struct qeth_card *card,
                                struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
-       struct qeth_switch_info *sw_info;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
        struct qeth_query_switch_attributes *attrs;
+       struct qeth_switch_info *sw_info;
 
        QETH_CARD_TEXT(card, 2, "qswiatcb");
-       cmd = (struct qeth_ipa_cmd *) data;
-       sw_info = (struct qeth_switch_info *)reply->param;
-       if (cmd->data.setadapterparms.hdr.return_code == 0) {
-               attrs = &cmd->data.setadapterparms.data.query_switch_attributes;
-               sw_info->capabilities = attrs->capabilities;
-               sw_info->settings = attrs->settings;
-               QETH_CARD_TEXT_(card, 2, "%04x%04x", sw_info->capabilities,
-                                                       sw_info->settings);
-       }
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
+       sw_info = (struct qeth_switch_info *)reply->param;
+       attrs = &cmd->data.setadapterparms.data.query_switch_attributes;
+       sw_info->capabilities = attrs->capabilities;
+       sw_info->settings = attrs->settings;
+       QETH_CARD_TEXT_(card, 2, "%04x%04x", sw_info->capabilities,
+                       sw_info->settings);
        return 0;
 }
 
@@ -4207,16 +4189,13 @@ EXPORT_SYMBOL_GPL(qeth_do_send_packet);
 static int qeth_setadp_promisc_mode_cb(struct qeth_card *card,
                struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
        struct qeth_ipacmd_setadpparms *setparms;
 
        QETH_CARD_TEXT(card, 4, "prmadpcb");
 
-       cmd = (struct qeth_ipa_cmd *) data;
        setparms = &(cmd->data.setadapterparms);
-
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
-       if (cmd->hdr.return_code) {
+       if (qeth_setadpparms_inspect_rc(cmd)) {
                QETH_CARD_TEXT_(card, 4, "prmrc%x", cmd->hdr.return_code);
                setparms->data.mode = SET_PROMISC_MODE_OFF;
        }
@@ -4286,18 +4265,18 @@ EXPORT_SYMBOL_GPL(qeth_get_stats);
 static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
                struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
 
        QETH_CARD_TEXT(card, 4, "chgmaccb");
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
-       cmd = (struct qeth_ipa_cmd *) data;
        if (!card->options.layer2 ||
            !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
                ether_addr_copy(card->dev->dev_addr,
                                cmd->data.setadapterparms.data.change_addr.addr);
                card->info.mac_bits |= QETH_LAYER2_MAC_READ;
        }
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
        return 0;
 }
 
@@ -4328,13 +4307,15 @@ EXPORT_SYMBOL_GPL(qeth_setadpparms_change_macaddr);
 static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
                struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
        struct qeth_set_access_ctrl *access_ctrl_req;
        int fallback = *(int *)reply->param;
 
        QETH_CARD_TEXT(card, 4, "setaccb");
+       if (cmd->hdr.return_code)
+               return 0;
+       qeth_setadpparms_inspect_rc(cmd);
 
-       cmd = (struct qeth_ipa_cmd *) data;
        access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
        QETH_DBF_TEXT_(SETUP, 2, "setaccb");
        QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
@@ -4407,7 +4388,6 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
                        card->options.isolation = card->options.prev_isolation;
                break;
        }
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
        return 0;
 }
 
@@ -4695,14 +4675,15 @@ out:
 static int qeth_setadpparms_query_oat_cb(struct qeth_card *card,
                struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
        struct qeth_qoat_priv *priv;
        char *resdata;
        int resdatalen;
 
        QETH_CARD_TEXT(card, 3, "qoatcb");
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
-       cmd = (struct qeth_ipa_cmd *)data;
        priv = (struct qeth_qoat_priv *)reply->param;
        resdatalen = cmd->data.setadapterparms.hdr.cmdlength;
        resdata = (char *)data + 28;
@@ -4796,21 +4777,18 @@ out:
 static int qeth_query_card_info_cb(struct qeth_card *card,
                                   struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
+       struct carrier_info *carrier_info = (struct carrier_info *)reply->param;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
        struct qeth_query_card_info *card_info;
-       struct carrier_info *carrier_info;
 
        QETH_CARD_TEXT(card, 2, "qcrdincb");
-       carrier_info = (struct carrier_info *)reply->param;
-       cmd = (struct qeth_ipa_cmd *)data;
-       card_info = &cmd->data.setadapterparms.data.card_info;
-       if (cmd->data.setadapterparms.hdr.return_code == 0) {
-               carrier_info->card_type = card_info->card_type;
-               carrier_info->port_mode = card_info->port_mode;
-               carrier_info->port_speed = card_info->port_speed;
-       }
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
+       card_info = &cmd->data.setadapterparms.data.card_info;
+       carrier_info->card_type = card_info->card_type;
+       carrier_info->port_mode = card_info->port_mode;
+       carrier_info->port_speed = card_info->port_speed;
        return 0;
 }
 
@@ -4857,7 +4835,7 @@ int qeth_vm_request_mac(struct qeth_card *card)
                goto out;
        }
 
-       ccw_device_get_id(CARD_DDEV(card), &id);
+       ccw_device_get_id(CARD_RDEV(card), &id);
        request->resp_buf_len = sizeof(*response);
        request->resp_version = DIAG26C_VERSION2;
        request->op_code = DIAG26C_GET_MAC;
@@ -6563,10 +6541,14 @@ static int __init qeth_core_init(void)
        mutex_init(&qeth_mod_mutex);
 
        qeth_wq = create_singlethread_workqueue("qeth_wq");
+       if (!qeth_wq) {
+               rc = -ENOMEM;
+               goto out_err;
+       }
 
        rc = qeth_register_dbf_views();
        if (rc)
-               goto out_err;
+               goto dbf_err;
        qeth_core_root_dev = root_device_register("qeth");
        rc = PTR_ERR_OR_ZERO(qeth_core_root_dev);
        if (rc)
@@ -6603,6 +6585,8 @@ slab_err:
        root_device_unregister(qeth_core_root_dev);
 register_err:
        qeth_unregister_dbf_views();
+dbf_err:
+       destroy_workqueue(qeth_wq);
 out_err:
        pr_err("Initializing the qeth device driver failed\n");
        return rc;
index 619f897..f4d1ec0 100644 (file)
@@ -35,6 +35,18 @@ extern unsigned char IPA_PDU_HEADER[];
 #define QETH_HALT_CHANNEL_PARM -11
 #define QETH_RCD_PARM -12
 
+static inline bool qeth_intparm_is_iob(unsigned long intparm)
+{
+       switch (intparm) {
+       case QETH_CLEAR_CHANNEL_PARM:
+       case QETH_HALT_CHANNEL_PARM:
+       case QETH_RCD_PARM:
+       case 0:
+               return false;
+       }
+       return true;
+}
+
 /*****************************************************************************/
 /* IP Assist related definitions                                             */
 /*****************************************************************************/
index 2ad6f12..b8079f2 100644 (file)
@@ -121,13 +121,10 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
        QETH_CARD_TEXT(card, 2, "L2Setmac");
        rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC);
        if (rc == 0) {
-               card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
-               ether_addr_copy(card->dev->dev_addr, mac);
                dev_info(&card->gdev->dev,
-                       "MAC address %pM successfully registered on device %s\n",
-                       card->dev->dev_addr, card->dev->name);
+                        "MAC address %pM successfully registered on device %s\n",
+                        mac, card->dev->name);
        } else {
-               card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
                switch (rc) {
                case -EEXIST:
                        dev_warn(&card->gdev->dev,
@@ -142,19 +139,6 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
        return rc;
 }
 
-static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
-{
-       int rc;
-
-       QETH_CARD_TEXT(card, 2, "L2Delmac");
-       if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
-               return 0;
-       rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELVMAC);
-       if (rc == 0)
-               card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
-       return rc;
-}
-
 static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
 {
        enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ?
@@ -519,6 +503,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
 {
        struct sockaddr *addr = p;
        struct qeth_card *card = dev->ml_priv;
+       u8 old_addr[ETH_ALEN];
        int rc = 0;
 
        QETH_CARD_TEXT(card, 3, "setmac");
@@ -530,14 +515,35 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
                return -EOPNOTSUPP;
        }
        QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN);
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
        if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
                QETH_CARD_TEXT(card, 3, "setmcREC");
                return -ERESTARTSYS;
        }
-       rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
-       if (!rc || (rc == -ENOENT))
-               rc = qeth_l2_send_setmac(card, addr->sa_data);
-       return rc ? -EINVAL : 0;
+
+       if (!qeth_card_hw_is_reachable(card)) {
+               ether_addr_copy(dev->dev_addr, addr->sa_data);
+               return 0;
+       }
+
+       /* don't register the same address twice */
+       if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) &&
+           (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
+               return 0;
+
+       /* add the new address, switch over, drop the old */
+       rc = qeth_l2_send_setmac(card, addr->sa_data);
+       if (rc)
+               return rc;
+       ether_addr_copy(old_addr, dev->dev_addr);
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
+
+       if (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED)
+               qeth_l2_remove_mac(card, old_addr);
+       card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
+       return 0;
 }
 
 static void qeth_promisc_to_bridge(struct qeth_card *card)
@@ -1067,8 +1073,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                goto out_remove;
        }
 
-       if (card->info.type != QETH_CARD_TYPE_OSN)
-               qeth_l2_send_setmac(card, &card->dev->dev_addr[0]);
+       if (card->info.type != QETH_CARD_TYPE_OSN &&
+           !qeth_l2_send_setmac(card, card->dev->dev_addr))
+               card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
 
        if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
                if (card->info.hwtrap &&
@@ -1338,8 +1345,8 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
        qeth_prepare_control_data(card, len, iob);
        QETH_CARD_TEXT(card, 6, "osnoirqp");
        spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
-       rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
-                             (addr_t) iob, 0, 0);
+       rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
+                                     (addr_t) iob, 0, 0, QETH_IPA_TIMEOUT);
        spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
        if (rc) {
                QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
index abddde1..98597b5 100644 (file)
@@ -296,7 +296,7 @@ int fnic_get_stats_data(struct stats_debug_info *debug,
                  "Number of Abort FW Timeouts: %lld\n"
                  "Number of Abort IO NOT Found: %lld\n"
 
-                 "Abord issued times: \n"
+                 "Abort issued times: \n"
                  "            < 6 sec : %lld\n"
                  "     6 sec - 20 sec : %lld\n"
                  "    20 sec - 30 sec : %lld\n"
index ce97cde..f4d988d 100644 (file)
@@ -1124,12 +1124,12 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                goto fail_fw_init;
        }
 
-       ret = 0;
+       return 0;
 
 fail_fw_init:
        dev_err(&instance->pdev->dev,
-               "Init cmd return status %s for SCSI host %d\n",
-               ret ? "FAILED" : "SUCCESS", instance->host->host_no);
+               "Init cmd return status FAILED for SCSI host %d\n",
+               instance->host->host_no);
 
        return ret;
 }
index 9ef5e3b..656c98e 100644 (file)
@@ -234,11 +234,13 @@ static const char *sdebug_version_date = "20180128";
 #define F_INV_OP               0x200
 #define F_FAKE_RW              0x400
 #define F_M_ACCESS             0x800   /* media access */
-#define F_LONG_DELAY           0x1000
+#define F_SSU_DELAY            0x1000
+#define F_SYNC_DELAY           0x2000
 
 #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
 #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
 #define FF_SA (F_SA_HIGH | F_SA_LOW)
+#define F_LONG_DELAY           (F_SSU_DELAY | F_SYNC_DELAY)
 
 #define SDEBUG_MAX_PARTS 4
 
@@ -510,7 +512,7 @@ static const struct opcode_info_t release_iarr[] = {
 };
 
 static const struct opcode_info_t sync_cache_iarr[] = {
-       {0, 0x91, 0, F_LONG_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
+       {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
            {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },     /* SYNC_CACHE (16) */
 };
@@ -553,7 +555,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
            resp_write_dt0, write_iarr,                 /* WRITE(16) */
                {16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
-       {0, 0x1b, 0, F_LONG_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
+       {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
            {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
        {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
            resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
@@ -606,7 +608,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
            resp_write_same_10, write_same_iarr,        /* WRITE SAME(10) */
                {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
                 0, 0, 0, 0, 0} },
-       {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_LONG_DELAY | F_M_ACCESS,
+       {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
            resp_sync_cache, sync_cache_iarr,
            {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
             0, 0, 0, 0} },                     /* SYNC_CACHE (10) */
@@ -667,6 +669,7 @@ static bool sdebug_strict = DEF_STRICT;
 static bool sdebug_any_injecting_opt;
 static bool sdebug_verbose;
 static bool have_dif_prot;
+static bool write_since_sync;
 static bool sdebug_statistics = DEF_STATISTICS;
 
 static unsigned int sdebug_store_sectors;
@@ -1607,6 +1610,7 @@ static int resp_start_stop(struct scsi_cmnd *scp,
 {
        unsigned char *cmd = scp->cmnd;
        int power_cond, stop;
+       bool changing;
 
        power_cond = (cmd[4] & 0xf0) >> 4;
        if (power_cond) {
@@ -1614,8 +1618,12 @@ static int resp_start_stop(struct scsi_cmnd *scp,
                return check_condition_result;
        }
        stop = !(cmd[4] & 1);
+       changing = atomic_read(&devip->stopped) == !stop;
        atomic_xchg(&devip->stopped, stop);
-       return (cmd[1] & 0x1) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
+       if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
+               return SDEG_RES_IMMED_MASK;
+       else
+               return 0;
 }
 
 static sector_t get_sdebug_capacity(void)
@@ -2473,6 +2481,7 @@ static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
        if (do_write) {
                sdb = scsi_out(scmd);
                dir = DMA_TO_DEVICE;
+               write_since_sync = true;
        } else {
                sdb = scsi_in(scmd);
                dir = DMA_FROM_DEVICE;
@@ -3583,6 +3592,7 @@ static int resp_get_lba_status(struct scsi_cmnd *scp,
 static int resp_sync_cache(struct scsi_cmnd *scp,
                           struct sdebug_dev_info *devip)
 {
+       int res = 0;
        u64 lba;
        u32 num_blocks;
        u8 *cmd = scp->cmnd;
@@ -3598,7 +3608,11 @@ static int resp_sync_cache(struct scsi_cmnd *scp,
                mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
                return check_condition_result;
        }
-       return (cmd[1] & 0x2) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
+       if (!write_since_sync || cmd[1] & 0x2)
+               res = SDEG_RES_IMMED_MASK;
+       else            /* delay if write_since_sync and IMMED clear */
+               write_since_sync = false;
+       return res;
 }
 
 #define RL_BUCKET_ELEMS 8
@@ -5777,13 +5791,14 @@ fini:
                return schedule_resp(scp, devip, errsts, pfp, 0, 0);
        else if ((sdebug_jdelay || sdebug_ndelay) && (flags & F_LONG_DELAY)) {
                /*
-                * If any delay is active, want F_LONG_DELAY to be at least 1
+                * If any delay is active, for F_SSU_DELAY want at least 1
                 * second and if sdebug_jdelay>0 want a long delay of that
-                * many seconds.
+                * many seconds; for F_SYNC_DELAY want 1/20 of that.
                 */
                int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
+               int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
 
-               jdelay = mult_frac(USER_HZ * jdelay, HZ, USER_HZ);
+               jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
                return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
        } else
                return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
index f4b52b4..65f6c94 100644 (file)
@@ -2322,6 +2322,12 @@ iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
        return nlmsg_multicast(nls, skb, 0, group, gfp);
 }
 
+static int
+iscsi_unicast_skb(struct sk_buff *skb, u32 portid)
+{
+       return nlmsg_unicast(nls, skb, portid);
+}
+
 int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
                   char *data, uint32_t data_size)
 {
@@ -2524,14 +2530,11 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
 EXPORT_SYMBOL_GPL(iscsi_ping_comp_event);
 
 static int
-iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
-                   void *payload, int size)
+iscsi_if_send_reply(u32 portid, int type, void *payload, int size)
 {
        struct sk_buff  *skb;
        struct nlmsghdr *nlh;
        int len = nlmsg_total_size(size);
-       int flags = multi ? NLM_F_MULTI : 0;
-       int t = done ? NLMSG_DONE : type;
 
        skb = alloc_skb(len, GFP_ATOMIC);
        if (!skb) {
@@ -2539,10 +2542,9 @@ iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
                return -ENOMEM;
        }
 
-       nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
-       nlh->nlmsg_flags = flags;
+       nlh = __nlmsg_put(skb, 0, 0, type, (len - sizeof(*nlh)), 0);
        memcpy(nlmsg_data(nlh), payload, size);
-       return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
+       return iscsi_unicast_skb(skb, portid);
 }
 
 static int
@@ -3470,6 +3472,7 @@ static int
 iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 {
        int err = 0;
+       u32 portid;
        struct iscsi_uevent *ev = nlmsg_data(nlh);
        struct iscsi_transport *transport = NULL;
        struct iscsi_internal *priv;
@@ -3490,10 +3493,12 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
        if (!try_module_get(transport->owner))
                return -EINVAL;
 
+       portid = NETLINK_CB(skb).portid;
+
        switch (nlh->nlmsg_type) {
        case ISCSI_UEVENT_CREATE_SESSION:
                err = iscsi_if_create_session(priv, ep, ev,
-                                             NETLINK_CB(skb).portid,
+                                             portid,
                                              ev->u.c_session.initial_cmdsn,
                                              ev->u.c_session.cmds_max,
                                              ev->u.c_session.queue_depth);
@@ -3506,7 +3511,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
                }
 
                err = iscsi_if_create_session(priv, ep, ev,
-                                       NETLINK_CB(skb).portid,
+                                       portid,
                                        ev->u.c_bound_session.initial_cmdsn,
                                        ev->u.c_bound_session.cmds_max,
                                        ev->u.c_bound_session.queue_depth);
@@ -3664,6 +3669,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 static void
 iscsi_if_rx(struct sk_buff *skb)
 {
+       u32 portid = NETLINK_CB(skb).portid;
+
        mutex_lock(&rx_queue_mutex);
        while (skb->len >= NLMSG_HDRLEN) {
                int err;
@@ -3699,8 +3706,8 @@ iscsi_if_rx(struct sk_buff *skb)
                                break;
                        if (ev->type == ISCSI_UEVENT_GET_CHAP && !err)
                                break;
-                       err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
-                               nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
+                       err = iscsi_if_send_reply(portid, nlh->nlmsg_type,
+                                                 ev, sizeof(*ev));
                } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH);
                skb_pull(skb, rlen);
        }
index a6201e6..9421d98 100644 (file)
@@ -2121,6 +2121,8 @@ sd_spinup_disk(struct scsi_disk *sdkp)
                                break;  /* standby */
                        if (sshdr.asc == 4 && sshdr.ascq == 0xc)
                                break;  /* unavailable */
+                       if (sshdr.asc == 4 && sshdr.ascq == 0x1b)
+                               break;  /* sanitize in progress */
                        /*
                         * Issue command to spin up drive when not ready
                         */
index 41df75e..210407c 100644 (file)
@@ -400,8 +400,10 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf)
  *
  * Check that all zones of the device are equal. The last zone can however
  * be smaller. The zone size must also be a power of two number of LBAs.
+ *
+ * Returns the zone size in bytes upon success or an error code upon failure.
  */
-static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
+static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
 {
        u64 zone_blocks = 0;
        sector_t block = 0;
@@ -412,8 +414,6 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
        int ret;
        u8 same;
 
-       sdkp->zone_blocks = 0;
-
        /* Get a buffer */
        buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL);
        if (!buf)
@@ -445,16 +445,17 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
 
                /* Parse zone descriptors */
                while (rec < buf + buf_len) {
-                       zone_blocks = get_unaligned_be64(&rec[8]);
-                       if (sdkp->zone_blocks == 0) {
-                               sdkp->zone_blocks = zone_blocks;
-                       } else if (zone_blocks != sdkp->zone_blocks &&
-                                  (block + zone_blocks < sdkp->capacity
-                                   || zone_blocks > sdkp->zone_blocks)) {
-                               zone_blocks = 0;
+                       u64 this_zone_blocks = get_unaligned_be64(&rec[8]);
+
+                       if (zone_blocks == 0) {
+                               zone_blocks = this_zone_blocks;
+                       } else if (this_zone_blocks != zone_blocks &&
+                                  (block + this_zone_blocks < sdkp->capacity
+                                   || this_zone_blocks > zone_blocks)) {
+                               this_zone_blocks = 0;
                                goto out;
                        }
-                       block += zone_blocks;
+                       block += this_zone_blocks;
                        rec += 64;
                }
 
@@ -467,8 +468,6 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
 
        } while (block < sdkp->capacity);
 
-       zone_blocks = sdkp->zone_blocks;
-
 out:
        if (!zone_blocks) {
                if (sdkp->first_scan)
@@ -488,8 +487,7 @@ out:
                                  "Zone size too large\n");
                ret = -ENODEV;
        } else {
-               sdkp->zone_blocks = zone_blocks;
-               sdkp->zone_shift = ilog2(zone_blocks);
+               ret = zone_blocks;
        }
 
 out_free:
@@ -500,15 +498,14 @@ out_free:
 
 /**
  * sd_zbc_alloc_zone_bitmap - Allocate a zone bitmap (one bit per zone).
- * @sdkp: The disk of the bitmap
+ * @nr_zones: Number of zones to allocate space for.
+ * @numa_node: NUMA node to allocate the memory from.
  */
-static inline unsigned long *sd_zbc_alloc_zone_bitmap(struct scsi_disk *sdkp)
+static inline unsigned long *
+sd_zbc_alloc_zone_bitmap(u32 nr_zones, int numa_node)
 {
-       struct request_queue *q = sdkp->disk->queue;
-
-       return kzalloc_node(BITS_TO_LONGS(sdkp->nr_zones)
-                           * sizeof(unsigned long),
-                           GFP_KERNEL, q->node);
+       return kzalloc_node(BITS_TO_LONGS(nr_zones) * sizeof(unsigned long),
+                           GFP_KERNEL, numa_node);
 }
 
 /**
@@ -516,6 +513,7 @@ static inline unsigned long *sd_zbc_alloc_zone_bitmap(struct scsi_disk *sdkp)
  * @sdkp: disk used
  * @buf: report reply buffer
  * @buflen: length of @buf
+ * @zone_shift: logarithm base 2 of the number of blocks in a zone
  * @seq_zones_bitmap: bitmap of sequential zones to set
  *
  * Parse reported zone descriptors in @buf to identify sequential zones and
@@ -525,7 +523,7 @@ static inline unsigned long *sd_zbc_alloc_zone_bitmap(struct scsi_disk *sdkp)
  * Return the LBA after the last zone reported.
  */
 static sector_t sd_zbc_get_seq_zones(struct scsi_disk *sdkp, unsigned char *buf,
-                                    unsigned int buflen,
+                                    unsigned int buflen, u32 zone_shift,
                                     unsigned long *seq_zones_bitmap)
 {
        sector_t lba, next_lba = sdkp->capacity;
@@ -544,7 +542,7 @@ static sector_t sd_zbc_get_seq_zones(struct scsi_disk *sdkp, unsigned char *buf,
                if (type != ZBC_ZONE_TYPE_CONV &&
                    cond != ZBC_ZONE_COND_READONLY &&
                    cond != ZBC_ZONE_COND_OFFLINE)
-                       set_bit(lba >> sdkp->zone_shift, seq_zones_bitmap);
+                       set_bit(lba >> zone_shift, seq_zones_bitmap);
                next_lba = lba + get_unaligned_be64(&rec[8]);
                rec += 64;
        }
@@ -553,12 +551,16 @@ static sector_t sd_zbc_get_seq_zones(struct scsi_disk *sdkp, unsigned char *buf,
 }
 
 /**
- * sd_zbc_setup_seq_zones_bitmap - Initialize the disk seq zone bitmap.
+ * sd_zbc_setup_seq_zones_bitmap - Initialize a seq zone bitmap.
  * @sdkp: target disk
+ * @zone_shift: logarithm base 2 of the number of blocks in a zone
+ * @nr_zones: number of zones to set up a seq zone bitmap for
  *
  * Allocate a zone bitmap and initialize it by identifying sequential zones.
  */
-static int sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp)
+static unsigned long *
+sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp, u32 zone_shift,
+                             u32 nr_zones)
 {
        struct request_queue *q = sdkp->disk->queue;
        unsigned long *seq_zones_bitmap;
@@ -566,9 +568,9 @@ static int sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp)
        unsigned char *buf;
        int ret = -ENOMEM;
 
-       seq_zones_bitmap = sd_zbc_alloc_zone_bitmap(sdkp);
+       seq_zones_bitmap = sd_zbc_alloc_zone_bitmap(nr_zones, q->node);
        if (!seq_zones_bitmap)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL);
        if (!buf)
@@ -579,7 +581,7 @@ static int sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp)
                if (ret)
                        goto out;
                lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
-                                          seq_zones_bitmap);
+                                          zone_shift, seq_zones_bitmap);
        }
 
        if (lba != sdkp->capacity) {
@@ -591,12 +593,9 @@ out:
        kfree(buf);
        if (ret) {
                kfree(seq_zones_bitmap);
-               return ret;
+               return ERR_PTR(ret);
        }
-
-       q->seq_zones_bitmap = seq_zones_bitmap;
-
-       return 0;
+       return seq_zones_bitmap;
 }
 
 static void sd_zbc_cleanup(struct scsi_disk *sdkp)
@@ -612,44 +611,64 @@ static void sd_zbc_cleanup(struct scsi_disk *sdkp)
        q->nr_zones = 0;
 }
 
-static int sd_zbc_setup(struct scsi_disk *sdkp)
+static int sd_zbc_setup(struct scsi_disk *sdkp, u32 zone_blocks)
 {
        struct request_queue *q = sdkp->disk->queue;
+       u32 zone_shift = ilog2(zone_blocks);
+       u32 nr_zones;
        int ret;
 
-       /* READ16/WRITE16 is mandatory for ZBC disks */
-       sdkp->device->use_16_for_rw = 1;
-       sdkp->device->use_10_for_rw = 0;
-
        /* chunk_sectors indicates the zone size */
-       blk_queue_chunk_sectors(sdkp->disk->queue,
-                       logical_to_sectors(sdkp->device, sdkp->zone_blocks));
-       sdkp->nr_zones =
-               round_up(sdkp->capacity, sdkp->zone_blocks) >> sdkp->zone_shift;
+       blk_queue_chunk_sectors(q,
+                       logical_to_sectors(sdkp->device, zone_blocks));
+       nr_zones = round_up(sdkp->capacity, zone_blocks) >> zone_shift;
 
        /*
         * Initialize the device request queue information if the number
         * of zones changed.
         */
-       if (sdkp->nr_zones != q->nr_zones) {
-
-               sd_zbc_cleanup(sdkp);
-
-               q->nr_zones = sdkp->nr_zones;
-               if (sdkp->nr_zones) {
-                       q->seq_zones_wlock = sd_zbc_alloc_zone_bitmap(sdkp);
-                       if (!q->seq_zones_wlock) {
+       if (nr_zones != sdkp->nr_zones || nr_zones != q->nr_zones) {
+               unsigned long *seq_zones_wlock = NULL, *seq_zones_bitmap = NULL;
+               size_t zone_bitmap_size;
+
+               if (nr_zones) {
+                       seq_zones_wlock = sd_zbc_alloc_zone_bitmap(nr_zones,
+                                                                  q->node);
+                       if (!seq_zones_wlock) {
                                ret = -ENOMEM;
                                goto err;
                        }
 
-                       ret = sd_zbc_setup_seq_zones_bitmap(sdkp);
-                       if (ret) {
-                               sd_zbc_cleanup(sdkp);
+                       seq_zones_bitmap = sd_zbc_setup_seq_zones_bitmap(sdkp,
+                                                       zone_shift, nr_zones);
+                       if (IS_ERR(seq_zones_bitmap)) {
+                               ret = PTR_ERR(seq_zones_bitmap);
+                               kfree(seq_zones_wlock);
                                goto err;
                        }
                }
-
+               zone_bitmap_size = BITS_TO_LONGS(nr_zones) *
+                       sizeof(unsigned long);
+               blk_mq_freeze_queue(q);
+               if (q->nr_zones != nr_zones) {
+                       /* READ16/WRITE16 is mandatory for ZBC disks */
+                       sdkp->device->use_16_for_rw = 1;
+                       sdkp->device->use_10_for_rw = 0;
+
+                       sdkp->zone_blocks = zone_blocks;
+                       sdkp->zone_shift = zone_shift;
+                       sdkp->nr_zones = nr_zones;
+                       q->nr_zones = nr_zones;
+                       swap(q->seq_zones_wlock, seq_zones_wlock);
+                       swap(q->seq_zones_bitmap, seq_zones_bitmap);
+               } else if (memcmp(q->seq_zones_bitmap, seq_zones_bitmap,
+                                 zone_bitmap_size) != 0) {
+                       memcpy(q->seq_zones_bitmap, seq_zones_bitmap,
+                              zone_bitmap_size);
+               }
+               blk_mq_unfreeze_queue(q);
+               kfree(seq_zones_wlock);
+               kfree(seq_zones_bitmap);
        }
 
        return 0;
@@ -661,6 +680,7 @@ err:
 
 int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
 {
+       int64_t zone_blocks;
        int ret;
 
        if (!sd_is_zoned(sdkp))
@@ -697,12 +717,16 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
         * Check zone size: only devices with a constant zone size (except
         * an eventual last runt zone) that is a power of 2 are supported.
         */
-       ret = sd_zbc_check_zone_size(sdkp);
-       if (ret)
+       zone_blocks = sd_zbc_check_zone_size(sdkp);
+       ret = -EFBIG;
+       if (zone_blocks != (u32)zone_blocks)
+               goto err;
+       ret = zone_blocks;
+       if (ret < 0)
                goto err;
 
        /* The drive satisfies the kernel restrictions: set it up */
-       ret = sd_zbc_setup(sdkp);
+       ret = sd_zbc_setup(sdkp, zone_blocks);
        if (ret)
                goto err;
 
index c5b1bf1..00e7905 100644 (file)
@@ -276,6 +276,35 @@ static inline void ufshcd_remove_non_printable(char *val)
                *val = ' ';
 }
 
+static void ufshcd_add_cmd_upiu_trace(struct ufs_hba *hba, unsigned int tag,
+               const char *str)
+{
+       struct utp_upiu_req *rq = hba->lrb[tag].ucd_req_ptr;
+
+       trace_ufshcd_upiu(dev_name(hba->dev), str, &rq->header, &rq->sc.cdb);
+}
+
+static void ufshcd_add_query_upiu_trace(struct ufs_hba *hba, unsigned int tag,
+               const char *str)
+{
+       struct utp_upiu_req *rq = hba->lrb[tag].ucd_req_ptr;
+
+       trace_ufshcd_upiu(dev_name(hba->dev), str, &rq->header, &rq->qr);
+}
+
+static void ufshcd_add_tm_upiu_trace(struct ufs_hba *hba, unsigned int tag,
+               const char *str)
+{
+       struct utp_task_req_desc *descp;
+       struct utp_upiu_task_req *task_req;
+       int off = (int)tag - hba->nutrs;
+
+       descp = &hba->utmrdl_base_addr[off];
+       task_req = (struct utp_upiu_task_req *)descp->task_req_upiu;
+       trace_ufshcd_upiu(dev_name(hba->dev), str, &task_req->header,
+                       &task_req->input_param1);
+}
+
 static void ufshcd_add_command_trace(struct ufs_hba *hba,
                unsigned int tag, const char *str)
 {
@@ -285,6 +314,9 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba,
        struct ufshcd_lrb *lrbp;
        int transfer_len = -1;
 
+       /* trace UPIU also */
+       ufshcd_add_cmd_upiu_trace(hba, tag, str);
+
        if (!trace_ufshcd_command_enabled())
                return;
 
@@ -2550,6 +2582,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
 
        hba->dev_cmd.complete = &wait;
 
+       ufshcd_add_query_upiu_trace(hba, tag, "query_send");
        /* Make sure descriptors are ready before ringing the doorbell */
        wmb();
        spin_lock_irqsave(hba->host->host_lock, flags);
@@ -2559,6 +2592,9 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
 
        err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
 
+       ufshcd_add_query_upiu_trace(hba, tag,
+                       err ? "query_complete_err" : "query_complete");
+
 out_put_tag:
        ufshcd_put_dev_cmd_tag(hba, tag);
        wake_up(&hba->dev_cmd.tag_wq);
@@ -5443,11 +5479,14 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
 
        spin_unlock_irqrestore(host->host_lock, flags);
 
+       ufshcd_add_tm_upiu_trace(hba, task_tag, "tm_send");
+
        /* wait until the task management command is completed */
        err = wait_event_timeout(hba->tm_wq,
                        test_bit(free_slot, &hba->tm_condition),
                        msecs_to_jiffies(TM_CMD_TIMEOUT));
        if (!err) {
+               ufshcd_add_tm_upiu_trace(hba, task_tag, "tm_complete_err");
                dev_err(hba->dev, "%s: task management cmd 0x%.2x timed-out\n",
                                __func__, tm_function);
                if (ufshcd_clear_tm_cmd(hba, free_slot))
@@ -5456,6 +5495,7 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
                err = -ETIMEDOUT;
        } else {
                err = ufshcd_task_req_compl(hba, free_slot, tm_response);
+               ufshcd_add_tm_upiu_trace(hba, task_tag, "tm_complete");
        }
 
        clear_bit(free_slot, &hba->tm_condition);
index 0d99b24..6cb933e 100644 (file)
@@ -890,6 +890,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
                        bytes = min(bytes, data_len);
 
                        if (!bio) {
+new_bio:
                                nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
                                nr_pages -= nr_vecs;
                                /*
@@ -931,6 +932,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
                                 * be allocated with pscsi_get_bio() above.
                                 */
                                bio = NULL;
+                               goto new_bio;
                        }
 
                        data_len -= bytes;
index e3986f4..ebc34a5 100644 (file)
@@ -9,6 +9,9 @@
 struct blk_mq_tags;
 struct blk_flush_queue;
 
+/**
+ * struct blk_mq_hw_ctx - State for a hardware queue facing the hardware block device
+ */
 struct blk_mq_hw_ctx {
        struct {
                spinlock_t              lock;
index 9af3e0f..5c4eee0 100644 (file)
@@ -605,6 +605,11 @@ struct request_queue {
         * initialized by the low level device driver (e.g. scsi/sd.c).
         * Stacking drivers (device mappers) may or may not initialize
         * these fields.
+        *
+        * Reads of this information must be protected with blk_queue_enter() /
+        * blk_queue_exit(). Modifying this information is only allowed while
+        * no requests are being processed. See also blk_mq_freeze_queue() and
+        * blk_mq_unfreeze_queue().
         */
        unsigned int            nr_zones;
        unsigned long           *seq_zones_bitmap;
@@ -737,6 +742,7 @@ bool blk_queue_flag_test_and_clear(unsigned int flag, struct request_queue *q);
 #define blk_queue_quiesced(q)  test_bit(QUEUE_FLAG_QUIESCED, &(q)->queue_flags)
 #define blk_queue_preempt_only(q)                              \
        test_bit(QUEUE_FLAG_PREEMPT_ONLY, &(q)->queue_flags)
+#define blk_queue_fua(q)       test_bit(QUEUE_FLAG_FUA, &(q)->queue_flags)
 
 extern int blk_set_preempt_only(struct request_queue *q);
 extern void blk_clear_preempt_only(struct request_queue *q);
index 95a7abd..486e65e 100644 (file)
@@ -339,8 +339,8 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
 void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs,
                                struct bpf_prog *old_prog);
 int bpf_prog_array_copy_info(struct bpf_prog_array __rcu *array,
-                            __u32 __user *prog_ids, u32 request_cnt,
-                            __u32 __user *prog_cnt);
+                            u32 *prog_ids, u32 request_cnt,
+                            u32 *prog_cnt);
 int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array,
                        struct bpf_prog *exclude_prog,
                        struct bpf_prog *include_prog,
index ebe4181..b32cd20 100644 (file)
@@ -310,6 +310,8 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
  *     fields should be ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS
  *     instead of the latter), any change to them will be overwritten
  *     by kernel. Returns a negative error code or zero.
+ * @get_fecparam: Get the network device Forward Error Correction parameters.
+ * @set_fecparam: Set the network device Forward Error Correction parameters.
  *
  * All operations are optional (i.e. the function pointer may be set
  * to %NULL) and callers must take this into account.  Callers must
index e0c95c9..e64c029 100644 (file)
@@ -217,12 +217,10 @@ struct fsnotify_mark_connector {
        union { /* Object pointer [lock] */
                struct inode *inode;
                struct vfsmount *mnt;
-       };
-       union {
-               struct hlist_head list;
                /* Used listing heads to free after srcu period expires */
                struct fsnotify_mark_connector *destroy_next;
        };
+       struct hlist_head list;
 };
 
 /*
index 44b9c00..e117617 100644 (file)
@@ -12,7 +12,8 @@
 void *ife_encode(struct sk_buff *skb, u16 metalen);
 void *ife_decode(struct sk_buff *skb, u16 *metalen);
 
-void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen);
+void *ife_tlv_meta_decode(void *skbdata, const void *ifehdr_end, u16 *attrtype,
+                         u16 *dlen, u16 *totlen);
 int ife_tlv_meta_encode(void *skbdata, u16 attrtype, u16 dlen,
                        const void *dval);
 
index 5c40f11..df528a6 100644 (file)
@@ -97,6 +97,7 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb)
 
 struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority,
                          struct proto *prot, int kern);
+void llc_sk_stop_all_timers(struct sock *sk, bool sync);
 void llc_sk_free(struct sock *sk);
 
 void llc_sk_reset(struct sock *sk);
index 04e0679..e03bd9d 100644 (file)
@@ -11,8 +11,6 @@ struct scsi_sense_hdr;
 extern void scsi_print_command(struct scsi_cmnd *);
 extern size_t __scsi_format_command(char *, size_t,
                                   const unsigned char *, size_t);
-extern void scsi_show_extd_sense(const struct scsi_device *, const char *,
-                                unsigned char, unsigned char);
 extern void scsi_print_sense_hdr(const struct scsi_device *, const char *,
                                 const struct scsi_sense_hdr *);
 extern void scsi_print_sense(const struct scsi_cmnd *);
index bf6f826..f8260e5 100644 (file)
@@ -257,6 +257,33 @@ TRACE_EVENT(ufshcd_command,
        )
 );
 
+TRACE_EVENT(ufshcd_upiu,
+       TP_PROTO(const char *dev_name, const char *str, void *hdr, void *tsf),
+
+       TP_ARGS(dev_name, str, hdr, tsf),
+
+       TP_STRUCT__entry(
+               __string(dev_name, dev_name)
+               __string(str, str)
+               __array(unsigned char, hdr, 12)
+               __array(unsigned char, tsf, 16)
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name);
+               __assign_str(str, str);
+               memcpy(__entry->hdr, hdr, sizeof(__entry->hdr));
+               memcpy(__entry->tsf, tsf, sizeof(__entry->tsf));
+       ),
+
+       TP_printk(
+               "%s: %s: HDR:%s, CDB:%s",
+               __get_str(str), __get_str(dev_name),
+               __print_hex(__entry->hdr, sizeof(__entry->hdr)),
+               __print_hex(__entry->tsf, sizeof(__entry->tsf))
+       )
+);
+
 #endif /* if !defined(_TRACE_UFS_H) || defined(TRACE_HEADER_MULTI_READ) */
 
 /* This part must be outside protection */
index d315b39..ba03ec3 100644 (file)
@@ -1572,13 +1572,32 @@ int bpf_prog_array_length(struct bpf_prog_array __rcu *progs)
        return cnt;
 }
 
+static bool bpf_prog_array_copy_core(struct bpf_prog **prog,
+                                    u32 *prog_ids,
+                                    u32 request_cnt)
+{
+       int i = 0;
+
+       for (; *prog; prog++) {
+               if (*prog == &dummy_bpf_prog.prog)
+                       continue;
+               prog_ids[i] = (*prog)->aux->id;
+               if (++i == request_cnt) {
+                       prog++;
+                       break;
+               }
+       }
+
+       return !!(*prog);
+}
+
 int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
                                __u32 __user *prog_ids, u32 cnt)
 {
        struct bpf_prog **prog;
        unsigned long err = 0;
-       u32 i = 0, *ids;
        bool nospc;
+       u32 *ids;
 
        /* users of this function are doing:
         * cnt = bpf_prog_array_length();
@@ -1595,16 +1614,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
                return -ENOMEM;
        rcu_read_lock();
        prog = rcu_dereference(progs)->progs;
-       for (; *prog; prog++) {
-               if (*prog == &dummy_bpf_prog.prog)
-                       continue;
-               ids[i] = (*prog)->aux->id;
-               if (++i == cnt) {
-                       prog++;
-                       break;
-               }
-       }
-       nospc = !!(*prog);
+       nospc = bpf_prog_array_copy_core(prog, ids, cnt);
        rcu_read_unlock();
        err = copy_to_user(prog_ids, ids, cnt * sizeof(u32));
        kfree(ids);
@@ -1683,22 +1693,25 @@ int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array,
 }
 
 int bpf_prog_array_copy_info(struct bpf_prog_array __rcu *array,
-                            __u32 __user *prog_ids, u32 request_cnt,
-                            __u32 __user *prog_cnt)
+                            u32 *prog_ids, u32 request_cnt,
+                            u32 *prog_cnt)
 {
+       struct bpf_prog **prog;
        u32 cnt = 0;
 
        if (array)
                cnt = bpf_prog_array_length(array);
 
-       if (copy_to_user(prog_cnt, &cnt, sizeof(cnt)))
-               return -EFAULT;
+       *prog_cnt = cnt;
 
        /* return early if user requested only program count or nothing to copy */
        if (!request_cnt || !cnt)
                return 0;
 
-       return bpf_prog_array_copy_to_user(array, prog_ids, request_cnt);
+       /* this function is called under trace/bpf_trace.c: bpf_event_mutex */
+       prog = rcu_dereference_check(array, 1)->progs;
+       return bpf_prog_array_copy_core(prog, prog_ids, request_cnt) ? -ENOSPC
+                                                                    : 0;
 }
 
 static void bpf_prog_free_deferred(struct work_struct *work)
index 8dd9210..a3b2138 100644 (file)
@@ -1442,9 +1442,6 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
            attr->value_size != 4 || attr->map_flags & ~SOCK_CREATE_FLAG_MASK)
                return ERR_PTR(-EINVAL);
 
-       if (attr->value_size > KMALLOC_MAX_SIZE)
-               return ERR_PTR(-E2BIG);
-
        err = bpf_tcp_ulp_register();
        if (err && err != -EEXIST)
                return ERR_PTR(err);
index d88e96d..56ba0f2 100644 (file)
@@ -977,6 +977,7 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info)
 {
        struct perf_event_query_bpf __user *uquery = info;
        struct perf_event_query_bpf query = {};
+       u32 *ids, prog_cnt, ids_len;
        int ret;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -985,16 +986,32 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info)
                return -EINVAL;
        if (copy_from_user(&query, uquery, sizeof(query)))
                return -EFAULT;
-       if (query.ids_len > BPF_TRACE_MAX_PROGS)
+
+       ids_len = query.ids_len;
+       if (ids_len > BPF_TRACE_MAX_PROGS)
                return -E2BIG;
+       ids = kcalloc(ids_len, sizeof(u32), GFP_USER | __GFP_NOWARN);
+       if (!ids)
+               return -ENOMEM;
+       /*
+        * The above kcalloc returns ZERO_SIZE_PTR when ids_len = 0, which
+        * is required when user only wants to check for uquery->prog_cnt.
+        * There is no need to check for it since the case is handled
+        * gracefully in bpf_prog_array_copy_info.
+        */
 
        mutex_lock(&bpf_event_mutex);
        ret = bpf_prog_array_copy_info(event->tp_event->prog_array,
-                                      uquery->ids,
-                                      query.ids_len,
-                                      &uquery->prog_cnt);
+                                      ids,
+                                      ids_len,
+                                      &prog_cnt);
        mutex_unlock(&bpf_event_mutex);
 
+       if (copy_to_user(&uquery->prog_cnt, &prog_cnt, sizeof(prog_cnt)) ||
+           copy_to_user(uquery->ids, ids, ids_len * sizeof(u32)))
+               ret = -EFAULT;
+
+       kfree(ids);
        return ret;
 }
 
index c0bba30..bbfb229 100644 (file)
@@ -84,7 +84,8 @@ again:
                __free_pages(page, page_order);
                page = NULL;
 
-               if (dev->coherent_dma_mask < DMA_BIT_MASK(32) &&
+               if (IS_ENABLED(CONFIG_ZONE_DMA) &&
+                   dev->coherent_dma_mask < DMA_BIT_MASK(32) &&
                    !(gfp & GFP_DMA)) {
                        gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
                        goto again;
index 032e0fe..28a4c34 100644 (file)
@@ -1825,13 +1825,14 @@ static int compat_table_info(const struct ebt_table_info *info,
 {
        unsigned int size = info->entries_size;
        const void *entries = info->entries;
-       int ret;
 
        newinfo->entries_size = size;
-
-       ret = xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries);
-       if (ret)
-               return ret;
+       if (info->nentries) {
+               int ret = xt_compat_init_offsets(NFPROTO_BRIDGE,
+                                                info->nentries);
+               if (ret)
+                       return ret;
+       }
 
        return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info,
                                                        entries, newinfo);
index 7d1ec76..13bbf8c 100644 (file)
@@ -69,6 +69,9 @@ void *ife_decode(struct sk_buff *skb, u16 *metalen)
        int total_pull;
        u16 ifehdrln;
 
+       if (!pskb_may_pull(skb, skb->dev->hard_header_len + IFE_METAHDRLEN))
+               return NULL;
+
        ifehdr = (struct ifeheadr *) (skb->data + skb->dev->hard_header_len);
        ifehdrln = ntohs(ifehdr->metalen);
        total_pull = skb->dev->hard_header_len + ifehdrln;
@@ -92,12 +95,43 @@ struct meta_tlvhdr {
        __be16 len;
 };
 
+static bool __ife_tlv_meta_valid(const unsigned char *skbdata,
+                                const unsigned char *ifehdr_end)
+{
+       const struct meta_tlvhdr *tlv;
+       u16 tlvlen;
+
+       if (unlikely(skbdata + sizeof(*tlv) > ifehdr_end))
+               return false;
+
+       tlv = (const struct meta_tlvhdr *)skbdata;
+       tlvlen = ntohs(tlv->len);
+
+       /* tlv length field is inc header, check on minimum */
+       if (tlvlen < NLA_HDRLEN)
+               return false;
+
+       /* overflow by NLA_ALIGN check */
+       if (NLA_ALIGN(tlvlen) < tlvlen)
+               return false;
+
+       if (unlikely(skbdata + NLA_ALIGN(tlvlen) > ifehdr_end))
+               return false;
+
+       return true;
+}
+
 /* Caller takes care of presenting data in network order
  */
-void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen)
+void *ife_tlv_meta_decode(void *skbdata, const void *ifehdr_end, u16 *attrtype,
+                         u16 *dlen, u16 *totlen)
 {
-       struct meta_tlvhdr *tlv = (struct meta_tlvhdr *) skbdata;
+       struct meta_tlvhdr *tlv;
+
+       if (!__ife_tlv_meta_valid(skbdata, ifehdr_end))
+               return NULL;
 
+       tlv = (struct meta_tlvhdr *)skbdata;
        *dlen = ntohs(tlv->len) - NLA_HDRLEN;
        *attrtype = ntohs(tlv->type);
 
index 367def6..e51c644 100644 (file)
@@ -3868,11 +3868,8 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
        int length = (th->doff << 2) - sizeof(*th);
        const u8 *ptr = (const u8 *)(th + 1);
 
-       /* If the TCP option is too short, we can short cut */
-       if (length < TCPOLEN_MD5SIG)
-               return NULL;
-
-       while (length > 0) {
+       /* If not enough data remaining, we can short cut */
+       while (length >= TCPOLEN_MD5SIG) {
                int opcode = *ptr++;
                int opsize;
 
index ccbfa83..ce77bcc 100644 (file)
@@ -48,6 +48,34 @@ config NFT_CHAIN_ROUTE_IPV6
          fields such as the source, destination, flowlabel, hop-limit and
          the packet mark.
 
+if NF_NAT_IPV6
+
+config NFT_CHAIN_NAT_IPV6
+       tristate "IPv6 nf_tables nat chain support"
+       help
+         This option enables the "nat" chain for IPv6 in nf_tables. This
+         chain type is used to perform Network Address Translation (NAT)
+         packet transformations such as the source, destination address and
+         source and destination ports.
+
+config NFT_MASQ_IPV6
+       tristate "IPv6 masquerade support for nf_tables"
+       depends on NFT_MASQ
+       select NF_NAT_MASQUERADE_IPV6
+       help
+         This is the expression that provides IPv4 masquerading support for
+         nf_tables.
+
+config NFT_REDIR_IPV6
+       tristate "IPv6 redirect support for nf_tables"
+       depends on NFT_REDIR
+       select NF_NAT_REDIRECT
+       help
+         This is the expression that provides IPv4 redirect support for
+         nf_tables.
+
+endif # NF_NAT_IPV6
+
 config NFT_REJECT_IPV6
        select NF_REJECT_IPV6
        default NFT_REJECT
@@ -107,39 +135,12 @@ config NF_NAT_IPV6
 
 if NF_NAT_IPV6
 
-config NFT_CHAIN_NAT_IPV6
-       depends on NF_TABLES_IPV6
-       tristate "IPv6 nf_tables nat chain support"
-       help
-         This option enables the "nat" chain for IPv6 in nf_tables. This
-         chain type is used to perform Network Address Translation (NAT)
-         packet transformations such as the source, destination address and
-         source and destination ports.
-
 config NF_NAT_MASQUERADE_IPV6
        tristate "IPv6 masquerade support"
        help
          This is the kernel functionality to provide NAT in the masquerade
          flavour (automatic source address selection) for IPv6.
 
-config NFT_MASQ_IPV6
-       tristate "IPv6 masquerade support for nf_tables"
-       depends on NF_TABLES_IPV6
-       depends on NFT_MASQ
-       select NF_NAT_MASQUERADE_IPV6
-       help
-         This is the expression that provides IPv4 masquerading support for
-         nf_tables.
-
-config NFT_REDIR_IPV6
-       tristate "IPv6 redirect support for nf_tables"
-       depends on NF_TABLES_IPV6
-       depends on NFT_REDIR
-       select NF_NAT_REDIRECT
-       help
-         This is the expression that provides IPv4 redirect support for
-         nf_tables.
-
 endif # NF_NAT_IPV6
 
 config IP6_NF_IPTABLES
index 49b954d..cde7d82 100644 (file)
@@ -3975,6 +3975,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
 
 static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
        [RTA_GATEWAY]           = { .len = sizeof(struct in6_addr) },
+       [RTA_PREFSRC]           = { .len = sizeof(struct in6_addr) },
        [RTA_OIF]               = { .type = NLA_U32 },
        [RTA_IIF]               = { .type = NLA_U32 },
        [RTA_PRIORITY]          = { .type = NLA_U32 },
@@ -3986,6 +3987,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
        [RTA_EXPIRES]           = { .type = NLA_U32 },
        [RTA_UID]               = { .type = NLA_U32 },
        [RTA_MARK]              = { .type = NLA_U32 },
+       [RTA_TABLE]             = { .type = NLA_U32 },
 };
 
 static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
index f343e6f..5fe1394 100644 (file)
@@ -136,7 +136,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
        isrh->nexthdr = proto;
 
        hdr->daddr = isrh->segments[isrh->first_segment];
-       set_tun_src(net, ip6_dst_idev(dst)->dev, &hdr->daddr, &hdr->saddr);
+       set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
        if (sr_has_hmac(isrh)) {
index b8f9d45..7f1e842 100644 (file)
@@ -106,8 +106,11 @@ static void l2tp_dfs_seq_stop(struct seq_file *p, void *v)
                return;
 
        /* Drop reference taken by last invocation of l2tp_dfs_next_tunnel() */
-       if (pd->tunnel)
+       if (pd->tunnel) {
                l2tp_tunnel_dec_refcount(pd->tunnel);
+               pd->tunnel = NULL;
+               pd->session = NULL;
+       }
 }
 
 static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v)
index 7d0c963..1fd9e14 100644 (file)
@@ -619,6 +619,13 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        lock_sock(sk);
 
        error = -EINVAL;
+
+       if (sockaddr_len != sizeof(struct sockaddr_pppol2tp) &&
+           sockaddr_len != sizeof(struct sockaddr_pppol2tpv3) &&
+           sockaddr_len != sizeof(struct sockaddr_pppol2tpin6) &&
+           sockaddr_len != sizeof(struct sockaddr_pppol2tpv3in6))
+               goto end;
+
        if (sp->sa_protocol != PX_PROTO_OL2TP)
                goto end;
 
@@ -1618,8 +1625,11 @@ static void pppol2tp_seq_stop(struct seq_file *p, void *v)
                return;
 
        /* Drop reference taken by last invocation of pppol2tp_next_tunnel() */
-       if (pd->tunnel)
+       if (pd->tunnel) {
                l2tp_tunnel_dec_refcount(pd->tunnel);
+               pd->tunnel = NULL;
+               pd->session = NULL;
+       }
 }
 
 static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v)
index 6d29b2b..cb80ebb 100644 (file)
@@ -189,7 +189,6 @@ static int llc_ui_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
        struct llc_sock *llc;
-       struct llc_sap *sap;
 
        if (unlikely(sk == NULL))
                goto out;
@@ -200,15 +199,19 @@ static int llc_ui_release(struct socket *sock)
                llc->laddr.lsap, llc->daddr.lsap);
        if (!llc_send_disc(sk))
                llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
-       sap = llc->sap;
-       /* Hold this for release_sock(), so that llc_backlog_rcv() could still
-        * use it.
-        */
-       llc_sap_hold(sap);
-       if (!sock_flag(sk, SOCK_ZAPPED))
+       if (!sock_flag(sk, SOCK_ZAPPED)) {
+               struct llc_sap *sap = llc->sap;
+
+               /* Hold this for release_sock(), so that llc_backlog_rcv()
+                * could still use it.
+                */
+               llc_sap_hold(sap);
                llc_sap_remove_socket(llc->sap, sk);
-       release_sock(sk);
-       llc_sap_put(sap);
+               release_sock(sk);
+               llc_sap_put(sap);
+       } else {
+               release_sock(sk);
+       }
        if (llc->dev)
                dev_put(llc->dev);
        sock_put(sk);
index 1631211..4d78375 100644 (file)
@@ -1099,14 +1099,7 @@ int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb)
 
 int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_sock *llc = llc_sk(sk);
-
-       del_timer(&llc->pf_cycle_timer.timer);
-       del_timer(&llc->ack_timer.timer);
-       del_timer(&llc->rej_sent_timer.timer);
-       del_timer(&llc->busy_state_timer.timer);
-       llc->ack_must_be_send = 0;
-       llc->ack_pf = 0;
+       llc_sk_stop_all_timers(sk, false);
        return 0;
 }
 
index 110e32b..c0ac522 100644 (file)
@@ -961,6 +961,26 @@ out:
        return sk;
 }
 
+void llc_sk_stop_all_timers(struct sock *sk, bool sync)
+{
+       struct llc_sock *llc = llc_sk(sk);
+
+       if (sync) {
+               del_timer_sync(&llc->pf_cycle_timer.timer);
+               del_timer_sync(&llc->ack_timer.timer);
+               del_timer_sync(&llc->rej_sent_timer.timer);
+               del_timer_sync(&llc->busy_state_timer.timer);
+       } else {
+               del_timer(&llc->pf_cycle_timer.timer);
+               del_timer(&llc->ack_timer.timer);
+               del_timer(&llc->rej_sent_timer.timer);
+               del_timer(&llc->busy_state_timer.timer);
+       }
+
+       llc->ack_must_be_send = 0;
+       llc->ack_pf = 0;
+}
+
 /**
  *     llc_sk_free - Frees a LLC socket
  *     @sk - socket to free
@@ -973,7 +993,7 @@ void llc_sk_free(struct sock *sk)
 
        llc->state = LLC_CONN_OUT_OF_SVC;
        /* Stop all (possibly) running timers */
-       llc_conn_ac_stop_all_timers(sk, NULL);
+       llc_sk_stop_all_timers(sk, true);
 #ifdef DEBUG_LLC_CONN_ALLOC
        printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __func__,
                skb_queue_len(&llc->pdu_unack_q),
index 704b383..44d8a55 100644 (file)
@@ -594,6 +594,7 @@ config NFT_QUOTA
 config NFT_REJECT
        default m if NETFILTER_ADVANCED=n
        tristate "Netfilter nf_tables reject support"
+       depends on !NF_TABLES_INET || (IPV6!=m || m)
        help
          This option adds the "reject" expression that you can use to
          explicitly deny and notify via TCP reset/ICMP informational errors
index 5ebde4b..f360988 100644 (file)
@@ -2384,11 +2384,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
                        strlcpy(cfg.mcast_ifn, dm->mcast_ifn,
                                sizeof(cfg.mcast_ifn));
                        cfg.syncid = dm->syncid;
-                       rtnl_lock();
-                       mutex_lock(&ipvs->sync_mutex);
                        ret = start_sync_thread(ipvs, &cfg, dm->state);
-                       mutex_unlock(&ipvs->sync_mutex);
-                       rtnl_unlock();
                } else {
                        mutex_lock(&ipvs->sync_mutex);
                        ret = stop_sync_thread(ipvs, dm->state);
@@ -3481,12 +3477,8 @@ static int ip_vs_genl_new_daemon(struct netns_ipvs *ipvs, struct nlattr **attrs)
        if (ipvs->mixed_address_family_dests > 0)
                return -EINVAL;
 
-       rtnl_lock();
-       mutex_lock(&ipvs->sync_mutex);
        ret = start_sync_thread(ipvs, &c,
                                nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
-       mutex_unlock(&ipvs->sync_mutex);
-       rtnl_unlock();
        return ret;
 }
 
index fbaf3bd..001501e 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/kernel.h>
+#include <linux/sched/signal.h>
 
 #include <asm/unaligned.h>             /* Used for ntoh_seq and hton_seq */
 
@@ -1360,15 +1361,9 @@ static void set_mcast_pmtudisc(struct sock *sk, int val)
 /*
  *      Specifiy default interface for outgoing multicasts
  */
-static int set_mcast_if(struct sock *sk, char *ifname)
+static int set_mcast_if(struct sock *sk, struct net_device *dev)
 {
-       struct net_device *dev;
        struct inet_sock *inet = inet_sk(sk);
-       struct net *net = sock_net(sk);
-
-       dev = __dev_get_by_name(net, ifname);
-       if (!dev)
-               return -ENODEV;
 
        if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
                return -EINVAL;
@@ -1396,19 +1391,14 @@ static int set_mcast_if(struct sock *sk, char *ifname)
  *      in the in_addr structure passed in as a parameter.
  */
 static int
-join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname)
+join_mcast_group(struct sock *sk, struct in_addr *addr, struct net_device *dev)
 {
-       struct net *net = sock_net(sk);
        struct ip_mreqn mreq;
-       struct net_device *dev;
        int ret;
 
        memset(&mreq, 0, sizeof(mreq));
        memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr));
 
-       dev = __dev_get_by_name(net, ifname);
-       if (!dev)
-               return -ENODEV;
        if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
                return -EINVAL;
 
@@ -1423,15 +1413,10 @@ join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname)
 
 #ifdef CONFIG_IP_VS_IPV6
 static int join_mcast_group6(struct sock *sk, struct in6_addr *addr,
-                            char *ifname)
+                            struct net_device *dev)
 {
-       struct net *net = sock_net(sk);
-       struct net_device *dev;
        int ret;
 
-       dev = __dev_get_by_name(net, ifname);
-       if (!dev)
-               return -ENODEV;
        if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
                return -EINVAL;
 
@@ -1443,24 +1428,18 @@ static int join_mcast_group6(struct sock *sk, struct in6_addr *addr,
 }
 #endif
 
-static int bind_mcastif_addr(struct socket *sock, char *ifname)
+static int bind_mcastif_addr(struct socket *sock, struct net_device *dev)
 {
-       struct net *net = sock_net(sock->sk);
-       struct net_device *dev;
        __be32 addr;
        struct sockaddr_in sin;
 
-       dev = __dev_get_by_name(net, ifname);
-       if (!dev)
-               return -ENODEV;
-
        addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
        if (!addr)
                pr_err("You probably need to specify IP address on "
                       "multicast interface.\n");
 
        IP_VS_DBG(7, "binding socket with (%s) %pI4\n",
-                 ifname, &addr);
+                 dev->name, &addr);
 
        /* Now bind the socket with the address of multicast interface */
        sin.sin_family       = AF_INET;
@@ -1493,7 +1472,8 @@ static void get_mcast_sockaddr(union ipvs_sockaddr *sa, int *salen,
 /*
  *      Set up sending multicast socket over UDP
  */
-static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id)
+static int make_send_sock(struct netns_ipvs *ipvs, int id,
+                         struct net_device *dev, struct socket **sock_ret)
 {
        /* multicast addr */
        union ipvs_sockaddr mcast_addr;
@@ -1505,9 +1485,10 @@ static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id)
                                  IPPROTO_UDP, &sock);
        if (result < 0) {
                pr_err("Error during creation of socket; terminating\n");
-               return ERR_PTR(result);
+               goto error;
        }
-       result = set_mcast_if(sock->sk, ipvs->mcfg.mcast_ifn);
+       *sock_ret = sock;
+       result = set_mcast_if(sock->sk, dev);
        if (result < 0) {
                pr_err("Error setting outbound mcast interface\n");
                goto error;
@@ -1522,7 +1503,7 @@ static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id)
                set_sock_size(sock->sk, 1, result);
 
        if (AF_INET == ipvs->mcfg.mcast_af)
-               result = bind_mcastif_addr(sock, ipvs->mcfg.mcast_ifn);
+               result = bind_mcastif_addr(sock, dev);
        else
                result = 0;
        if (result < 0) {
@@ -1538,19 +1519,18 @@ static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id)
                goto error;
        }
 
-       return sock;
+       return 0;
 
 error:
-       sock_release(sock);
-       return ERR_PTR(result);
+       return result;
 }
 
 
 /*
  *      Set up receiving multicast socket over UDP
  */
-static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id,
-                                       int ifindex)
+static int make_receive_sock(struct netns_ipvs *ipvs, int id,
+                            struct net_device *dev, struct socket **sock_ret)
 {
        /* multicast addr */
        union ipvs_sockaddr mcast_addr;
@@ -1562,8 +1542,9 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id,
                                  IPPROTO_UDP, &sock);
        if (result < 0) {
                pr_err("Error during creation of socket; terminating\n");
-               return ERR_PTR(result);
+               goto error;
        }
+       *sock_ret = sock;
        /* it is equivalent to the REUSEADDR option in user-space */
        sock->sk->sk_reuse = SK_CAN_REUSE;
        result = sysctl_sync_sock_size(ipvs);
@@ -1571,7 +1552,7 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id,
                set_sock_size(sock->sk, 0, result);
 
        get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id);
-       sock->sk->sk_bound_dev_if = ifindex;
+       sock->sk->sk_bound_dev_if = dev->ifindex;
        result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen);
        if (result < 0) {
                pr_err("Error binding to the multicast addr\n");
@@ -1582,21 +1563,20 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id,
 #ifdef CONFIG_IP_VS_IPV6
        if (ipvs->bcfg.mcast_af == AF_INET6)
                result = join_mcast_group6(sock->sk, &mcast_addr.in6.sin6_addr,
-                                          ipvs->bcfg.mcast_ifn);
+                                          dev);
        else
 #endif
                result = join_mcast_group(sock->sk, &mcast_addr.in.sin_addr,
-                                         ipvs->bcfg.mcast_ifn);
+                                         dev);
        if (result < 0) {
                pr_err("Error joining to the multicast group\n");
                goto error;
        }
 
-       return sock;
+       return 0;
 
 error:
-       sock_release(sock);
-       return ERR_PTR(result);
+       return result;
 }
 
 
@@ -1778,13 +1758,12 @@ static int sync_thread_backup(void *data)
 int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
                      int state)
 {
-       struct ip_vs_sync_thread_data *tinfo;
+       struct ip_vs_sync_thread_data *tinfo = NULL;
        struct task_struct **array = NULL, *task;
-       struct socket *sock;
        struct net_device *dev;
        char *name;
        int (*threadfn)(void *data);
-       int id, count, hlen;
+       int id = 0, count, hlen;
        int result = -ENOMEM;
        u16 mtu, min_mtu;
 
@@ -1792,6 +1771,18 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
        IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %zd bytes\n",
                  sizeof(struct ip_vs_sync_conn_v0));
 
+       /* Do not hold one mutex and then to block on another */
+       for (;;) {
+               rtnl_lock();
+               if (mutex_trylock(&ipvs->sync_mutex))
+                       break;
+               rtnl_unlock();
+               mutex_lock(&ipvs->sync_mutex);
+               if (rtnl_trylock())
+                       break;
+               mutex_unlock(&ipvs->sync_mutex);
+       }
+
        if (!ipvs->sync_state) {
                count = clamp(sysctl_sync_ports(ipvs), 1, IPVS_SYNC_PORTS_MAX);
                ipvs->threads_mask = count - 1;
@@ -1810,7 +1801,8 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
        dev = __dev_get_by_name(ipvs->net, c->mcast_ifn);
        if (!dev) {
                pr_err("Unknown mcast interface: %s\n", c->mcast_ifn);
-               return -ENODEV;
+               result = -ENODEV;
+               goto out_early;
        }
        hlen = (AF_INET6 == c->mcast_af) ?
               sizeof(struct ipv6hdr) + sizeof(struct udphdr) :
@@ -1827,26 +1819,30 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
                c->sync_maxlen = mtu - hlen;
 
        if (state == IP_VS_STATE_MASTER) {
+               result = -EEXIST;
                if (ipvs->ms)
-                       return -EEXIST;
+                       goto out_early;
 
                ipvs->mcfg = *c;
                name = "ipvs-m:%d:%d";
                threadfn = sync_thread_master;
        } else if (state == IP_VS_STATE_BACKUP) {
+               result = -EEXIST;
                if (ipvs->backup_threads)
-                       return -EEXIST;
+                       goto out_early;
 
                ipvs->bcfg = *c;
                name = "ipvs-b:%d:%d";
                threadfn = sync_thread_backup;
        } else {
-               return -EINVAL;
+               result = -EINVAL;
+               goto out_early;
        }
 
        if (state == IP_VS_STATE_MASTER) {
                struct ipvs_master_sync_state *ms;
 
+               result = -ENOMEM;
                ipvs->ms = kcalloc(count, sizeof(ipvs->ms[0]), GFP_KERNEL);
                if (!ipvs->ms)
                        goto out;
@@ -1862,39 +1858,38 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
        } else {
                array = kcalloc(count, sizeof(struct task_struct *),
                                GFP_KERNEL);
+               result = -ENOMEM;
                if (!array)
                        goto out;
        }
 
-       tinfo = NULL;
        for (id = 0; id < count; id++) {
-               if (state == IP_VS_STATE_MASTER)
-                       sock = make_send_sock(ipvs, id);
-               else
-                       sock = make_receive_sock(ipvs, id, dev->ifindex);
-               if (IS_ERR(sock)) {
-                       result = PTR_ERR(sock);
-                       goto outtinfo;
-               }
+               result = -ENOMEM;
                tinfo = kmalloc(sizeof(*tinfo), GFP_KERNEL);
                if (!tinfo)
-                       goto outsocket;
+                       goto out;
                tinfo->ipvs = ipvs;
-               tinfo->sock = sock;
+               tinfo->sock = NULL;
                if (state == IP_VS_STATE_BACKUP) {
                        tinfo->buf = kmalloc(ipvs->bcfg.sync_maxlen,
                                             GFP_KERNEL);
                        if (!tinfo->buf)
-                               goto outtinfo;
+                               goto out;
                } else {
                        tinfo->buf = NULL;
                }
                tinfo->id = id;
+               if (state == IP_VS_STATE_MASTER)
+                       result = make_send_sock(ipvs, id, dev, &tinfo->sock);
+               else
+                       result = make_receive_sock(ipvs, id, dev, &tinfo->sock);
+               if (result < 0)
+                       goto out;
 
                task = kthread_run(threadfn, tinfo, name, ipvs->gen, id);
                if (IS_ERR(task)) {
                        result = PTR_ERR(task);
-                       goto outtinfo;
+                       goto out;
                }
                tinfo = NULL;
                if (state == IP_VS_STATE_MASTER)
@@ -1911,20 +1906,20 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
        ipvs->sync_state |= state;
        spin_unlock_bh(&ipvs->sync_buff_lock);
 
+       mutex_unlock(&ipvs->sync_mutex);
+       rtnl_unlock();
+
        /* increase the module use count */
        ip_vs_use_count_inc();
 
        return 0;
 
-outsocket:
-       sock_release(sock);
-
-outtinfo:
-       if (tinfo) {
-               sock_release(tinfo->sock);
-               kfree(tinfo->buf);
-               kfree(tinfo);
-       }
+out:
+       /* We do not need RTNL lock anymore, release it here so that
+        * sock_release below and in the kthreads can use rtnl_lock
+        * to leave the mcast group.
+        */
+       rtnl_unlock();
        count = id;
        while (count-- > 0) {
                if (state == IP_VS_STATE_MASTER)
@@ -1932,13 +1927,23 @@ outtinfo:
                else
                        kthread_stop(array[count]);
        }
-       kfree(array);
-
-out:
        if (!(ipvs->sync_state & IP_VS_STATE_MASTER)) {
                kfree(ipvs->ms);
                ipvs->ms = NULL;
        }
+       mutex_unlock(&ipvs->sync_mutex);
+       if (tinfo) {
+               if (tinfo->sock)
+                       sock_release(tinfo->sock);
+               kfree(tinfo->buf);
+               kfree(tinfo);
+       }
+       kfree(array);
+       return result;
+
+out_early:
+       mutex_unlock(&ipvs->sync_mutex);
+       rtnl_unlock();
        return result;
 }
 
index 8ef21d9..4b2b3d5 100644 (file)
@@ -252,7 +252,7 @@ static inline int expect_clash(const struct nf_conntrack_expect *a,
 static inline int expect_matches(const struct nf_conntrack_expect *a,
                                 const struct nf_conntrack_expect *b)
 {
-       return a->master == b->master && a->class == b->class &&
+       return a->master == b->master &&
               nf_ct_tuple_equal(&a->tuple, &b->tuple) &&
               nf_ct_tuple_mask_equal(&a->mask, &b->mask) &&
               net_eq(nf_ct_net(a->master), nf_ct_net(b->master)) &&
@@ -421,6 +421,9 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
        h = nf_ct_expect_dst_hash(net, &expect->tuple);
        hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) {
                if (expect_matches(i, expect)) {
+                       if (i->class != expect->class)
+                               return -EALREADY;
+
                        if (nf_ct_remove_expect(i))
                                break;
                } else if (expect_clash(i, expect)) {
index 9fe0ddc..277bbfe 100644 (file)
@@ -9,6 +9,7 @@
  *      2 of the License, or (at your option) any later version.
  */
 #include <linux/kernel.h>
+#include <linux/kmemleak.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/rcupdate.h>
@@ -71,6 +72,7 @@ void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
        rcu_read_unlock();
 
        alloc = max(newlen, NF_CT_EXT_PREALLOC);
+       kmemleak_not_leak(old);
        new = __krealloc(old, alloc, gfp);
        if (!new)
                return NULL;
index 4dbb5ba..908e51e 100644 (file)
@@ -938,11 +938,19 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
                                       datalen, rtp_exp, rtcp_exp,
                                       mediaoff, medialen, daddr);
        else {
-               if (nf_ct_expect_related(rtp_exp) == 0) {
-                       if (nf_ct_expect_related(rtcp_exp) != 0)
-                               nf_ct_unexpect_related(rtp_exp);
-                       else
+               /* -EALREADY handling works around end-points that send
+                * SDP messages with identical port but different media type,
+                * we pretend expectation was set up.
+                */
+               int errp = nf_ct_expect_related(rtp_exp);
+
+               if (errp == 0 || errp == -EALREADY) {
+                       int errcp = nf_ct_expect_related(rtcp_exp);
+
+                       if (errcp == 0 || errcp == -EALREADY)
                                ret = NF_ACCEPT;
+                       else if (errp == 0)
+                               nf_ct_unexpect_related(rtp_exp);
                }
        }
        nf_ct_expect_put(rtcp_exp);
index 9134cc4..04d4e37 100644 (file)
@@ -2361,41 +2361,46 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
        }
 
        if (nlh->nlmsg_flags & NLM_F_REPLACE) {
-               if (nft_is_active_next(net, old_rule)) {
-                       trans = nft_trans_rule_add(&ctx, NFT_MSG_DELRULE,
-                                                  old_rule);
-                       if (trans == NULL) {
-                               err = -ENOMEM;
-                               goto err2;
-                       }
-                       nft_deactivate_next(net, old_rule);
-                       chain->use--;
-                       list_add_tail_rcu(&rule->list, &old_rule->list);
-               } else {
+               if (!nft_is_active_next(net, old_rule)) {
                        err = -ENOENT;
                        goto err2;
                }
-       } else if (nlh->nlmsg_flags & NLM_F_APPEND)
-               if (old_rule)
-                       list_add_rcu(&rule->list, &old_rule->list);
-               else
-                       list_add_tail_rcu(&rule->list, &chain->rules);
-       else {
-               if (old_rule)
-                       list_add_tail_rcu(&rule->list, &old_rule->list);
-               else
-                       list_add_rcu(&rule->list, &chain->rules);
-       }
+               trans = nft_trans_rule_add(&ctx, NFT_MSG_DELRULE,
+                                          old_rule);
+               if (trans == NULL) {
+                       err = -ENOMEM;
+                       goto err2;
+               }
+               nft_deactivate_next(net, old_rule);
+               chain->use--;
 
-       if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) {
-               err = -ENOMEM;
-               goto err3;
+               if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) {
+                       err = -ENOMEM;
+                       goto err2;
+               }
+
+               list_add_tail_rcu(&rule->list, &old_rule->list);
+       } else {
+               if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) {
+                       err = -ENOMEM;
+                       goto err2;
+               }
+
+               if (nlh->nlmsg_flags & NLM_F_APPEND) {
+                       if (old_rule)
+                               list_add_rcu(&rule->list, &old_rule->list);
+                       else
+                               list_add_tail_rcu(&rule->list, &chain->rules);
+                } else {
+                       if (old_rule)
+                               list_add_tail_rcu(&rule->list, &old_rule->list);
+                       else
+                               list_add_rcu(&rule->list, &chain->rules);
+               }
        }
        chain->use++;
        return 0;
 
-err3:
-       list_del_rcu(&rule->list);
 err2:
        nf_tables_rule_destroy(&ctx, rule);
 err1:
@@ -3207,18 +3212,20 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 
        err = ops->init(set, &desc, nla);
        if (err < 0)
-               goto err2;
+               goto err3;
 
        err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
        if (err < 0)
-               goto err3;
+               goto err4;
 
        list_add_tail_rcu(&set->list, &table->sets);
        table->use++;
        return 0;
 
-err3:
+err4:
        ops->destroy(set);
+err3:
+       kfree(set->name);
 err2:
        kvfree(set);
 err1:
@@ -5738,7 +5745,7 @@ static void nft_chain_commit_update(struct nft_trans *trans)
        struct nft_base_chain *basechain;
 
        if (nft_trans_chain_name(trans))
-               strcpy(trans->ctx.chain->name, nft_trans_chain_name(trans));
+               swap(trans->ctx.chain->name, nft_trans_chain_name(trans));
 
        if (!nft_is_base_chain(trans->ctx.chain))
                return;
index 773da82..94df000 100644 (file)
@@ -36,11 +36,10 @@ MODULE_ALIAS("ipt_connmark");
 MODULE_ALIAS("ip6t_connmark");
 
 static unsigned int
-connmark_tg_shift(struct sk_buff *skb,
-               const struct xt_connmark_tginfo1 *info,
-               u8 shift_bits, u8 shift_dir)
+connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
 {
        enum ip_conntrack_info ctinfo;
+       u_int32_t new_targetmark;
        struct nf_conn *ct;
        u_int32_t newmark;
 
@@ -51,34 +50,39 @@ connmark_tg_shift(struct sk_buff *skb,
        switch (info->mode) {
        case XT_CONNMARK_SET:
                newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
-               if (shift_dir == D_SHIFT_RIGHT)
-                       newmark >>= shift_bits;
+               if (info->shift_dir == D_SHIFT_RIGHT)
+                       newmark >>= info->shift_bits;
                else
-                       newmark <<= shift_bits;
+                       newmark <<= info->shift_bits;
+
                if (ct->mark != newmark) {
                        ct->mark = newmark;
                        nf_conntrack_event_cache(IPCT_MARK, ct);
                }
                break;
        case XT_CONNMARK_SAVE:
-               newmark = (ct->mark & ~info->ctmask) ^
-                         (skb->mark & info->nfmask);
-               if (shift_dir == D_SHIFT_RIGHT)
-                       newmark >>= shift_bits;
+               new_targetmark = (skb->mark & info->nfmask);
+               if (info->shift_dir == D_SHIFT_RIGHT)
+                       new_targetmark >>= info->shift_bits;
                else
-                       newmark <<= shift_bits;
+                       new_targetmark <<= info->shift_bits;
+
+               newmark = (ct->mark & ~info->ctmask) ^
+                         new_targetmark;
                if (ct->mark != newmark) {
                        ct->mark = newmark;
                        nf_conntrack_event_cache(IPCT_MARK, ct);
                }
                break;
        case XT_CONNMARK_RESTORE:
-               newmark = (skb->mark & ~info->nfmask) ^
-                         (ct->mark & info->ctmask);
-               if (shift_dir == D_SHIFT_RIGHT)
-                       newmark >>= shift_bits;
+               new_targetmark = (ct->mark & info->ctmask);
+               if (info->shift_dir == D_SHIFT_RIGHT)
+                       new_targetmark >>= info->shift_bits;
                else
-                       newmark <<= shift_bits;
+                       new_targetmark <<= info->shift_bits;
+
+               newmark = (skb->mark & ~info->nfmask) ^
+                         new_targetmark;
                skb->mark = newmark;
                break;
        }
@@ -89,8 +93,14 @@ static unsigned int
 connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_connmark_tginfo1 *info = par->targinfo;
-
-       return connmark_tg_shift(skb, info, 0, 0);
+       const struct xt_connmark_tginfo2 info2 = {
+               .ctmark = info->ctmark,
+               .ctmask = info->ctmask,
+               .nfmask = info->nfmask,
+               .mode   = info->mode,
+       };
+
+       return connmark_tg_shift(skb, &info2);
 }
 
 static unsigned int
@@ -98,8 +108,7 @@ connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_connmark_tginfo2 *info = par->targinfo;
 
-       return connmark_tg_shift(skb, (const struct xt_connmark_tginfo1 *)info,
-                                info->shift_bits, info->shift_dir);
+       return connmark_tg_shift(skb, info);
 }
 
 static int connmark_tg_check(const struct xt_tgchk_param *par)
index c31b068..01f3515 100644 (file)
@@ -329,11 +329,11 @@ static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
        skb_set_queue_mapping(skb, queue_index);
 }
 
-/* register_prot_hook must be invoked with the po->bind_lock held,
+/* __register_prot_hook must be invoked through register_prot_hook
  * or from a context in which asynchronous accesses to the packet
  * socket is not possible (packet_create()).
  */
-static void register_prot_hook(struct sock *sk)
+static void __register_prot_hook(struct sock *sk)
 {
        struct packet_sock *po = pkt_sk(sk);
 
@@ -348,8 +348,13 @@ static void register_prot_hook(struct sock *sk)
        }
 }
 
-/* {,__}unregister_prot_hook() must be invoked with the po->bind_lock
- * held.   If the sync parameter is true, we will temporarily drop
+static void register_prot_hook(struct sock *sk)
+{
+       lockdep_assert_held_once(&pkt_sk(sk)->bind_lock);
+       __register_prot_hook(sk);
+}
+
+/* If the sync parameter is true, we will temporarily drop
  * the po->bind_lock and do a synchronize_net to make sure no
  * asynchronous packet processing paths still refer to the elements
  * of po->prot_hook.  If the sync parameter is false, it is the
@@ -359,6 +364,8 @@ static void __unregister_prot_hook(struct sock *sk, bool sync)
 {
        struct packet_sock *po = pkt_sk(sk);
 
+       lockdep_assert_held_once(&po->bind_lock);
+
        po->running = 0;
 
        if (po->fanout)
@@ -3252,7 +3259,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
 
        if (proto) {
                po->prot_hook.type = proto;
-               register_prot_hook(sk);
+               __register_prot_hook(sk);
        }
 
        mutex_lock(&net->packet.sklist_lock);
@@ -3732,12 +3739,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 
                if (optlen != sizeof(val))
                        return -EINVAL;
-               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
-                       return -EBUSY;
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
-               po->tp_loss = !!val;
-               return 0;
+
+               lock_sock(sk);
+               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+                       ret = -EBUSY;
+               } else {
+                       po->tp_loss = !!val;
+                       ret = 0;
+               }
+               release_sock(sk);
+               return ret;
        }
        case PACKET_AUXDATA:
        {
@@ -3748,7 +3761,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
 
+               lock_sock(sk);
                po->auxdata = !!val;
+               release_sock(sk);
                return 0;
        }
        case PACKET_ORIGDEV:
@@ -3760,7 +3775,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
 
+               lock_sock(sk);
                po->origdev = !!val;
+               release_sock(sk);
                return 0;
        }
        case PACKET_VNET_HDR:
@@ -3769,15 +3786,20 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 
                if (sock->type != SOCK_RAW)
                        return -EINVAL;
-               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
-                       return -EBUSY;
                if (optlen < sizeof(val))
                        return -EINVAL;
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
 
-               po->has_vnet_hdr = !!val;
-               return 0;
+               lock_sock(sk);
+               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+                       ret = -EBUSY;
+               } else {
+                       po->has_vnet_hdr = !!val;
+                       ret = 0;
+               }
+               release_sock(sk);
+               return ret;
        }
        case PACKET_TIMESTAMP:
        {
@@ -3815,11 +3837,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 
                if (optlen != sizeof(val))
                        return -EINVAL;
-               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
-                       return -EBUSY;
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
-               po->tp_tx_has_off = !!val;
+
+               lock_sock(sk);
+               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+                       ret = -EBUSY;
+               } else {
+                       po->tp_tx_has_off = !!val;
+                       ret = 0;
+               }
+               release_sock(sk);
                return 0;
        }
        case PACKET_QDISC_BYPASS:
index a1d2b23..3bb7c5f 100644 (file)
@@ -112,10 +112,12 @@ struct packet_sock {
        int                     copy_thresh;
        spinlock_t              bind_lock;
        struct mutex            pg_vec_lock;
-       unsigned int            running:1,      /* prot_hook is attached*/
-                               auxdata:1,
+       unsigned int            running;        /* bind_lock must be held */
+       unsigned int            auxdata:1,      /* writer must hold sock lock */
                                origdev:1,
-                               has_vnet_hdr:1;
+                               has_vnet_hdr:1,
+                               tp_loss:1,
+                               tp_tx_has_off:1;
        int                     pressure;
        int                     ifindex;        /* bound device         */
        __be16                  num;
@@ -125,8 +127,6 @@ struct packet_sock {
        enum tpacket_versions   tp_version;
        unsigned int            tp_hdrlen;
        unsigned int            tp_reserve;
-       unsigned int            tp_loss:1;
-       unsigned int            tp_tx_has_off:1;
        unsigned int            tp_tstamp;
        struct net_device __rcu *cached_dev;
        int                     (*xmit)(struct sk_buff *skb);
index a5994cf..8527cfd 100644 (file)
@@ -652,7 +652,7 @@ static int find_decode_metaid(struct sk_buff *skb, struct tcf_ife_info *ife,
                }
        }
 
-       return 0;
+       return -ENOENT;
 }
 
 static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
@@ -682,7 +682,12 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
                u16 mtype;
                u16 dlen;
 
-               curr_data = ife_tlv_meta_decode(tlv_data, &mtype, &dlen, NULL);
+               curr_data = ife_tlv_meta_decode(tlv_data, ifehdr_end, &mtype,
+                                               &dlen, NULL);
+               if (!curr_data) {
+                       qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats));
+                       return TC_ACT_SHOT;
+               }
 
                if (find_decode_metaid(skb, ife, mtype, dlen, curr_data)) {
                        /* abuse overlimits to count when we receive metadata
index 805b139..092bebc 100644 (file)
@@ -67,7 +67,7 @@ static void strp_abort_strp(struct strparser *strp, int err)
 
 static void strp_start_timer(struct strparser *strp, long timeo)
 {
-       if (timeo)
+       if (timeo && timeo != LONG_MAX)
                mod_delayed_work(strp_wq, &strp->msg_timer_work, timeo);
 }
 
index 48620c9..1ce701f 100644 (file)
@@ -449,6 +449,8 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
                                magic |= VFS_CAP_FLAGS_EFFECTIVE;
                        memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32);
                        cap->magic_etc = cpu_to_le32(magic);
+               } else {
+                       size = -ENOMEM;
                }
        }
        kfree(tmpbuf);
index 9cf83f8..5e1ab2f 100644 (file)
@@ -12,3 +12,6 @@ test_tcpbpf_user
 test_verifier_log
 feature
 test_libbpf_open
+test_sock
+test_sock_addr
+urandom_read
index 73bb20c..f4d99fa 100644 (file)
@@ -13,6 +13,7 @@
 #include <bpf/bpf.h>
 
 #include "cgroup_helpers.h"
+#include "bpf_rlimit.h"
 
 #ifndef ARRAY_SIZE
 # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
index d488f20..2950f80 100644 (file)
@@ -15,6 +15,7 @@
 #include <bpf/libbpf.h>
 
 #include "cgroup_helpers.h"
+#include "bpf_rlimit.h"
 
 #define CG_PATH        "/foo"
 #define CONNECT4_PROG_PATH     "./connect4_prog.o"
index c6e1dcf..9832a87 100755 (executable)
@@ -4,7 +4,7 @@ set -eu
 
 ping_once()
 {
-       ping -q -c 1 -W 1 ${1%%/*} >/dev/null 2>&1
+       ping -${1} -q -c 1 -W 1 ${2%%/*} >/dev/null 2>&1
 }
 
 wait_for_ip()
@@ -13,7 +13,7 @@ wait_for_ip()
        echo -n "Wait for testing IPv4/IPv6 to become available "
        for _i in $(seq ${MAX_PING_TRIES}); do
                echo -n "."
-               if ping_once ${TEST_IPv4} && ping_once ${TEST_IPv6}; then
+               if ping_once 4 ${TEST_IPv4} && ping_once 6 ${TEST_IPv6}; then
                        echo " OK"
                        return
                fi