Merge tag 'asoc-fix-v5.3-rc3' of https://git.kernel.org/pub/scm/linux/kernel/git...
authorTakashi Iwai <tiwai@suse.de>
Tue, 6 Aug 2019 10:28:08 +0000 (12:28 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 6 Aug 2019 10:28:08 +0000 (12:28 +0200)
ASoC: Fixes for v5.3

A relatively large batch of mostly unremarkable fixes here, a couple of
small core fixes for fairly obscure issues, more comment/email updates
with no code impact than usual and a bunch of small driver fixes.

The support for new sample rates in the max98373 driver is a fix for the
fact that the driver declared support for those rates but would in fact
return an error if these rates were selected.

270 files changed:
Documentation/devicetree/bindings/riscv/cpus.yaml
MAINTAINERS
Makefile
arch/arc/Makefile
arch/arc/plat-hsdk/platform.c
arch/arm/boot/dts/gemini-dlink-dir-685.dts
arch/arm/boot/dts/gemini-dlink-dns-313.dts
arch/arm/boot/dts/imx6ul.dtsi
arch/arm/boot/dts/meson8.dtsi
arch/arm/boot/dts/meson8b.dtsi
arch/arm/mach-omap2/prm3xxx.c
arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
arch/arm64/configs/defconfig
arch/csky/kernel/signal.c
arch/mips/include/asm/mips-gic.h
arch/parisc/kernel/module.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/mm/book3s64/mmu_context.c
arch/riscv/boot/dts/sifive/fu540-c000.dtsi
arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
arch/riscv/configs/defconfig
arch/riscv/mm/fault.c
arch/x86/events/core.c
arch/x86/events/intel/ds.c
arch/x86/events/perf_event.h
arch/x86/include/uapi/asm/perf_regs.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/microcode/core.c
arch/x86/kernel/cpu/resctrl/rdtgroup.c
arch/x86/kernel/head64.c
arch/x86/kernel/perf_regs.c
arch/x86/kernel/unwind_orc.c
arch/x86/mm/init_64.c
arch/x86/platform/efi/quirks.c
block/bfq-iosched.c
drivers/auxdisplay/cfag12864bfb.c
drivers/auxdisplay/ht16k33.c
drivers/clk/clk.c
drivers/clk/meson/g12a.c
drivers/clk/meson/g12a.h
drivers/clk/meson/meson8b.c
drivers/clk/socfpga/clk-s10.c
drivers/clk/tegra/clk-tegra210.c
drivers/clk/ti/clkctrl.c
drivers/firmware/efi/efi-bgrt.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/efibc.c
drivers/hid/hid-ids.h
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-quirks.c
drivers/hid/hid-uclogic-core.c
drivers/hid/hid-uclogic-params.c
drivers/hid/intel-ish-hid/ishtp-fw-loader.c
drivers/hid/intel-ish-hid/ishtp-hid-client.c
drivers/hid/intel-ish-hid/ishtp/bus.c
drivers/irqchip/irq-csky-mpintc.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-mips-gic.c
drivers/irqchip/irq-ti-sci-inta.c
drivers/md/dm-init.c
drivers/md/dm-log-writes.c
drivers/md/dm-table.c
drivers/md/dm-verity-target.c
drivers/mfd/stmfx.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/spi-nor/spi-nor.c
drivers/net/bonding/bond_main.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/ethernet/aquantia/atlantic/aq_filters.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.h
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ppp/ppp_mppe.c
drivers/net/team/team.c
drivers/net/usb/qmi_wwan.c
drivers/net/vrf.c
drivers/pci/pci-driver.c
drivers/pinctrl/mediatek/mtk-eint.c
drivers/pinctrl/pinctrl-mcp23s08.c
drivers/pinctrl/pinctrl-ocelot.c
drivers/scsi/vmw_pvscsi.c
fs/afs/callback.c
fs/afs/inode.c
fs/afs/internal.h
fs/afs/volume.c
fs/aio.c
fs/binfmt_flat.c
fs/ceph/mds_client.c
fs/eventpoll.c
fs/inode.c
fs/io_uring.c
fs/nfs/flexfilelayout/flexfilelayoutdev.c
fs/proc/array.c
fs/proc/base.c
fs/select.c
include/dt-bindings/clock/g12a-clkc.h
include/dt-bindings/clock/sifive-fu540-prci.h
include/linux/intel-ish-client-if.h
include/linux/kernel.h
include/linux/mtd/spi-nor.h
include/linux/perf_event.h
include/linux/perf_regs.h
include/linux/pfn_t.h
include/linux/signal.h
include/linux/suspend.h
include/linux/xarray.h
include/net/ip6_route.h
include/net/route.h
include/net/tls.h
include/sound/compress_driver.h
include/sound/hda_codec.h
include/sound/hdaudio.h
include/uapi/linux/usb/audio.h
init/initramfs.c
kernel/cpu.c
kernel/events/core.c
kernel/fork.c
kernel/power/suspend.c
kernel/signal.c
lib/idr.c
lib/test_xarray.c
lib/xarray.c
mm/hugetlb.c
mm/memory-failure.c
mm/mempolicy.c
mm/oom_kill.c
mm/page_idle.c
mm/page_io.c
mm/vmalloc.c
net/bluetooth/6lowpan.c
net/ipv4/ip_output.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv6/ip6_output.c
net/ipv6/route.c
net/netfilter/nf_flow_table_ip.c
net/packet/af_packet.c
net/packet/internal.h
net/sched/sch_cbs.c
net/sctp/endpointola.c
net/smc/af_smc.c
net/smc/smc_core.c
net/sunrpc/xprtsock.c
net/tipc/core.c
net/tipc/netlink_compat.c
net/tls/tls_main.c
samples/pidfd/pidfd-metadata.c
sound/ac97/bus.c
sound/core/compress_offload.c
sound/core/control.c
sound/core/oss/rate.c
sound/core/pcm_native.c
sound/core/seq/oss/seq_oss_ioctl.c
sound/core/seq/oss/seq_oss_rw.c
sound/core/seq/seq_clientmgr.c
sound/firewire/amdtp-am824.c
sound/firewire/amdtp-stream-trace.h
sound/firewire/amdtp-stream.c
sound/firewire/amdtp-stream.h
sound/firewire/bebob/bebob.h
sound/firewire/bebob/bebob_midi.c
sound/firewire/bebob/bebob_pcm.c
sound/firewire/bebob/bebob_stream.c
sound/firewire/cmp.c
sound/firewire/cmp.h
sound/firewire/dice/Makefile
sound/firewire/dice/dice-midi.c
sound/firewire/dice/dice-pcm.c
sound/firewire/dice/dice-presonus.c [new file with mode: 0644]
sound/firewire/dice/dice-stream.c
sound/firewire/dice/dice.c
sound/firewire/dice/dice.h
sound/firewire/digi00x/amdtp-dot.c
sound/firewire/digi00x/digi00x-midi.c
sound/firewire/digi00x/digi00x-pcm.c
sound/firewire/digi00x/digi00x-stream.c
sound/firewire/digi00x/digi00x.h
sound/firewire/fireface/ff-pcm.c
sound/firewire/fireface/ff-protocol-former.c
sound/firewire/fireface/ff-protocol-latter.c
sound/firewire/fireface/ff-stream.c
sound/firewire/fireface/ff.h
sound/firewire/fireworks/fireworks.h
sound/firewire/fireworks/fireworks_midi.c
sound/firewire/fireworks/fireworks_pcm.c
sound/firewire/fireworks/fireworks_stream.c
sound/firewire/motu/amdtp-motu-trace.h
sound/firewire/motu/amdtp-motu.c
sound/firewire/motu/motu-midi.c
sound/firewire/motu/motu-pcm.c
sound/firewire/motu/motu-stream.c
sound/firewire/motu/motu.h
sound/firewire/oxfw/oxfw-midi.c
sound/firewire/oxfw/oxfw-pcm.c
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/oxfw/oxfw.c
sound/firewire/oxfw/oxfw.h
sound/firewire/tascam/amdtp-tascam.c
sound/firewire/tascam/tascam-pcm.c
sound/firewire/tascam/tascam-stream.c
sound/firewire/tascam/tascam.h
sound/hda/hdac_controller.c
sound/hda/hdac_device.c
sound/hda/hdac_i915.c
sound/hda/hdac_sysfs.c
sound/pci/asihpi/asihpi.c
sound/pci/au88x0/au88x0_a3d.c
sound/pci/cs4281.c
sound/pci/echoaudio/echoaudio_dsp.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_controller.h
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/lx6464es/lx6464es.c
sound/pci/lx6464es/lx_core.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/ppc/snd_ps3.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/hdac_hdmi.c
sound/soc/codecs/nau8825.c
sound/soc/codecs/nau8825.h
sound/soc/generic/audio-graph-card.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h
sound/soc/meson/axg-tdm.h
sound/soc/meson/axg-tdmin.c
sound/soc/meson/axg-tdmout.c
sound/soc/qcom/common.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/sof/intel/hda.c
sound/soc/ti/davinci-mcasp.c
sound/soc/ti/omap-mcbsp.c
sound/usb/format.c
sound/usb/helper.c
sound/usb/helper.h
sound/usb/line6/driver.c
sound/usb/line6/driver.h
sound/usb/line6/pcm.c
sound/usb/line6/pod.c
sound/usb/line6/podhd.c
sound/usb/line6/toneport.c
sound/usb/line6/variax.c
sound/usb/mixer.c
sound/usb/mixer_quirks.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/xen/xen_snd_front_alsa.c
tools/arch/x86/include/uapi/asm/perf_regs.h
tools/perf/arch/x86/include/perf_regs.h
tools/perf/arch/x86/util/perf_regs.c
tools/testing/radix-tree/idr-test.c
tools/testing/selftests/powerpc/mm/.gitignore
tools/testing/selftests/powerpc/mm/Makefile
tools/testing/selftests/powerpc/mm/large_vm_fork_separation.c [new file with mode: 0644]

index 27f02ec..f97a4ec 100644 (file)
@@ -152,17 +152,19 @@ examples:
   - |
     // Example 2: Spike ISA Simulator with 1 Hart
     cpus {
-            cpu@0 {
-                    device_type = "cpu";
-                    reg = <0>;
-                    compatible = "riscv";
-                    riscv,isa = "rv64imafdc";
-                    mmu-type = "riscv,sv48";
-                    interrupt-controller {
-                            #interrupt-cells = <1>;
-                            interrupt-controller;
-                            compatible = "riscv,cpu-intc";
-                    };
-            };
+        #address-cells = <1>;
+        #size-cells = <0>;
+        cpu@0 {
+                device_type = "cpu";
+                reg = <0>;
+                compatible = "riscv";
+                riscv,isa = "rv64imafdc";
+                mmu-type = "riscv,sv48";
+                interrupt-controller {
+                        #interrupt-cells = <1>;
+                        interrupt-controller;
+                        compatible = "riscv,cpu-intc";
+                };
+        };
     };
 ...
index 92829ca..f227f7e 100644 (file)
@@ -3122,6 +3122,7 @@ F:        arch/arm/mach-bcm/
 BROADCOM BCM2835 ARM ARCHITECTURE
 M:     Eric Anholt <eric@anholt.net>
 M:     Stefan Wahren <wahrenst@gmx.net>
+L:     bcm-kernel-feedback-list@broadcom.com
 L:     linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://github.com/anholt/linux
@@ -3151,6 +3152,7 @@ F:        arch/arm/boot/dts/bcm953012*
 
 BROADCOM BCM53573 ARM ARCHITECTURE
 M:     RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl>
+L:     bcm-kernel-feedback-list@broadcom.com
 L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
 F:     arch/arm/boot/dts/bcm53573*
@@ -3945,6 +3947,14 @@ M:       Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
 S:     Maintained
 F:     .clang-format
 
+CLANG/LLVM BUILD SUPPORT
+L:     clang-built-linux@googlegroups.com
+W:     https://clangbuiltlinux.github.io/
+B:     https://github.com/ClangBuiltLinux/linux/issues
+C:     irc://chat.freenode.net/clangbuiltlinux
+S:     Supported
+K:     \b(?i:clang|llvm)\b
+
 CLEANCACHE API
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:     linux-kernel@vger.kernel.org
index 7a7c17e..fabc127 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,8 @@
 VERSION = 5
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
-NAME = Golden Lions
+EXTRAVERSION = -rc7
+NAME = Bobtail Squid
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
index 480af1a..03a0b19 100644 (file)
@@ -5,6 +5,10 @@
 
 KBUILD_DEFCONFIG := nsim_hs_defconfig
 
+ifeq ($(CROSS_COMPILE),)
+CROSS_COMPILE := $(call cc-cross-prefix, arc-linux- arceb-linux-)
+endif
+
 cflags-y       += -fno-common -pipe -fno-builtin -mmedium-calls -D__linux__
 cflags-$(CONFIG_ISA_ARCOMPACT) += -mA7
 cflags-$(CONFIG_ISA_ARCV2)     += -mcpu=hs38
index 6a91a74..7dd2dd3 100644 (file)
@@ -32,8 +32,6 @@ static void __init hsdk_init_per_cpu(unsigned int cpu)
 
 #define ARC_PERIPHERAL_BASE    0xf0000000
 #define CREG_BASE              (ARC_PERIPHERAL_BASE + 0x1000)
-#define CREG_PAE               (CREG_BASE + 0x180)
-#define CREG_PAE_UPDATE                (CREG_BASE + 0x194)
 
 #define SDIO_BASE              (ARC_PERIPHERAL_BASE + 0xA000)
 #define SDIO_UHS_REG_EXT       (SDIO_BASE + 0x108)
@@ -99,20 +97,167 @@ static void __init hsdk_enable_gpio_intc_wire(void)
        iowrite32(GPIO_INT_CONNECTED_MASK, (void __iomem *) GPIO_INTEN);
 }
 
-static void __init hsdk_init_early(void)
+enum hsdk_axi_masters {
+       M_HS_CORE = 0,
+       M_HS_RTT,
+       M_AXI_TUN,
+       M_HDMI_VIDEO,
+       M_HDMI_AUDIO,
+       M_USB_HOST,
+       M_ETHERNET,
+       M_SDIO,
+       M_GPU,
+       M_DMAC_0,
+       M_DMAC_1,
+       M_DVFS
+};
+
+#define UPDATE_VAL     1
+
+/*
+ * This is modified configuration of AXI bridge. Default settings
+ * are specified in "Table 111 CREG Address Decoder register reset values".
+ *
+ * AXI_M_m_SLV{0|1} - Slave Select register for master 'm'.
+ * Possible slaves are:
+ *  - 0  => no slave selected
+ *  - 1  => DDR controller port #1
+ *  - 2  => SRAM controller
+ *  - 3  => AXI tunnel
+ *  - 4  => EBI controller
+ *  - 5  => ROM controller
+ *  - 6  => AXI2APB bridge
+ *  - 7  => DDR controller port #2
+ *  - 8  => DDR controller port #3
+ *  - 9  => HS38x4 IOC
+ *  - 10 => HS38x4 DMI
+ * AXI_M_m_OFFSET{0|1} - Addr Offset register for master 'm'
+ *
+ * Please read ARC HS Development IC Specification, section 17.2 for more
+ * information about apertures configuration.
+ *
+ * m   master          AXI_M_m_SLV0    AXI_M_m_SLV1    AXI_M_m_OFFSET0 AXI_M_m_OFFSET1
+ * 0   HS (CBU)        0x11111111      0x63111111      0xFEDCBA98      0x0E543210
+ * 1   HS (RTT)        0x77777777      0x77777777      0xFEDCBA98      0x76543210
+ * 2   AXI Tunnel      0x88888888      0x88888888      0xFEDCBA98      0x76543210
+ * 3   HDMI-VIDEO      0x77777777      0x77777777      0xFEDCBA98      0x76543210
+ * 4   HDMI-ADUIO      0x77777777      0x77777777      0xFEDCBA98      0x76543210
+ * 5   USB-HOST        0x77777777      0x77999999      0xFEDCBA98      0x76DCBA98
+ * 6   ETHERNET        0x77777777      0x77999999      0xFEDCBA98      0x76DCBA98
+ * 7   SDIO            0x77777777      0x77999999      0xFEDCBA98      0x76DCBA98
+ * 8   GPU             0x77777777      0x77777777      0xFEDCBA98      0x76543210
+ * 9   DMAC (port #1)  0x77777777      0x77777777      0xFEDCBA98      0x76543210
+ * 10  DMAC (port #2)  0x77777777      0x77777777      0xFEDCBA98      0x76543210
+ * 11  DVFS            0x00000000      0x60000000      0x00000000      0x00000000
+ */
+
+#define CREG_AXI_M_SLV0(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m)))
+#define CREG_AXI_M_SLV1(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x04))
+#define CREG_AXI_M_OFT0(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x08))
+#define CREG_AXI_M_OFT1(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x0C))
+#define CREG_AXI_M_UPDT(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x14))
+
+#define CREG_AXI_M_HS_CORE_BOOT        ((void __iomem *)(CREG_BASE + 0x010))
+
+#define CREG_PAE               ((void __iomem *)(CREG_BASE + 0x180))
+#define CREG_PAE_UPDT          ((void __iomem *)(CREG_BASE + 0x194))
+
+static void __init hsdk_init_memory_bridge(void)
 {
+       u32 reg;
+
+       /*
+        * M_HS_CORE has one unique register - BOOT.
+        * We need to clean boot mirror (BOOT[1:0]) bits in them to avoid first
+        * aperture to be masked by 'boot mirror'.
+        */
+       reg = readl(CREG_AXI_M_HS_CORE_BOOT) & (~0x3);
+       writel(reg, CREG_AXI_M_HS_CORE_BOOT);
+       writel(0x11111111, CREG_AXI_M_SLV0(M_HS_CORE));
+       writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_CORE));
+       writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_HS_RTT));
+       writel(0x77777777, CREG_AXI_M_SLV1(M_HS_RTT));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_RTT));
+       writel(0x76543210, CREG_AXI_M_OFT1(M_HS_RTT));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_RTT));
+
+       writel(0x88888888, CREG_AXI_M_SLV0(M_AXI_TUN));
+       writel(0x88888888, CREG_AXI_M_SLV1(M_AXI_TUN));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_AXI_TUN));
+       writel(0x76543210, CREG_AXI_M_OFT1(M_AXI_TUN));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_AXI_TUN));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_VIDEO));
+       writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_VIDEO));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_VIDEO));
+       writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_VIDEO));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_VIDEO));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_AUDIO));
+       writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_AUDIO));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_AUDIO));
+       writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_AUDIO));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_AUDIO));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_USB_HOST));
+       writel(0x77999999, CREG_AXI_M_SLV1(M_USB_HOST));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_USB_HOST));
+       writel(0x76DCBA98, CREG_AXI_M_OFT1(M_USB_HOST));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_ETHERNET));
+       writel(0x77999999, CREG_AXI_M_SLV1(M_ETHERNET));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_ETHERNET));
+       writel(0x76DCBA98, CREG_AXI_M_OFT1(M_ETHERNET));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_SDIO));
+       writel(0x77999999, CREG_AXI_M_SLV1(M_SDIO));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_SDIO));
+       writel(0x76DCBA98, CREG_AXI_M_OFT1(M_SDIO));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_GPU));
+       writel(0x77777777, CREG_AXI_M_SLV1(M_GPU));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_GPU));
+       writel(0x76543210, CREG_AXI_M_OFT1(M_GPU));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
+       writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
+       writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
+       writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
+       writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
+
+       writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS));
+       writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS));
+       writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS));
+       writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS));
+
        /*
         * PAE remapping for DMA clients does not work due to an RTL bug, so
         * CREG_PAE register must be programmed to all zeroes, otherwise it
         * will cause problems with DMA to/from peripherals even if PAE40 is
         * not used.
         */
+       writel(0x00000000, CREG_PAE);
+       writel(UPDATE_VAL, CREG_PAE_UPDT);
+}
 
-       /* Default is 1, which means "PAE offset = 4GByte" */
-       writel_relaxed(0, (void __iomem *) CREG_PAE);
-
-       /* Really apply settings made above */
-       writel(1, (void __iomem *) CREG_PAE_UPDATE);
+static void __init hsdk_init_early(void)
+{
+       hsdk_init_memory_bridge();
 
        /*
         * Switch SDIO external ciu clock divider from default div-by-8 to
index cfbfbc9..3613f05 100644 (file)
@@ -20,7 +20,7 @@
        };
 
        chosen {
-               bootargs = "console=ttyS0,19200n8 root=/dev/sda1 rw rootwait";
+               bootargs = "console=ttyS0,19200n8 root=/dev/sda1 rw rootwait consoleblank=300";
                stdout-path = "uart0:19200n8";
        };
 
index b12504e..360642a 100644 (file)
@@ -11,7 +11,7 @@
 
 / {
        model = "D-Link DNS-313 1-Bay Network Storage Enclosure";
-       compatible = "dlink,dir-313", "cortina,gemini";
+       compatible = "dlink,dns-313", "cortina,gemini";
        #address-cells = <1>;
        #size-cells = <1>;
 
index bbf010c..a7f6d1d 100644 (file)
                        pwm1: pwm@2080000 {
                                compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
                                reg = <0x02080000 0x4000>;
-                               interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6UL_CLK_PWM1>,
                                         <&clks IMX6UL_CLK_PWM1>;
                                clock-names = "ipg", "per";
                        pwm2: pwm@2084000 {
                                compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
                                reg = <0x02084000 0x4000>;
-                               interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6UL_CLK_PWM2>,
                                         <&clks IMX6UL_CLK_PWM2>;
                                clock-names = "ipg", "per";
                        pwm3: pwm@2088000 {
                                compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
                                reg = <0x02088000 0x4000>;
-                               interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6UL_CLK_PWM3>,
                                         <&clks IMX6UL_CLK_PWM3>;
                                clock-names = "ipg", "per";
                        pwm4: pwm@208c000 {
                                compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
                                reg = <0x0208c000 0x4000>;
-                               interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6UL_CLK_PWM4>,
                                         <&clks IMX6UL_CLK_PWM4>;
                                clock-names = "ipg", "per";
index 7ef4424..40c11b6 100644 (file)
                                     <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>,
                        clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>;
                        clock-names = "bus", "core";
                        operating-points-v2 = <&gpu_opp_table>;
-                       switch-delay = <0xffff>;
                };
        };
 }; /* end of / */
index 800cd65..ec67f49 100644 (file)
 
                opp-255000000 {
                        opp-hz = /bits/ 64 <255000000>;
-                       opp-microvolt = <1150000>;
+                       opp-microvolt = <1100000>;
                };
                opp-364300000 {
                        opp-hz = /bits/ 64 <364300000>;
-                       opp-microvolt = <1150000>;
+                       opp-microvolt = <1100000>;
                };
                opp-425000000 {
                        opp-hz = /bits/ 64 <425000000>;
-                       opp-microvolt = <1150000>;
+                       opp-microvolt = <1100000>;
                };
                opp-510000000 {
                        opp-hz = /bits/ 64 <510000000>;
-                       opp-microvolt = <1150000>;
+                       opp-microvolt = <1100000>;
                };
                opp-637500000 {
                        opp-hz = /bits/ 64 <637500000>;
-                       opp-microvolt = <1150000>;
+                       opp-microvolt = <1100000>;
                        turbo-mode;
                };
        };
                        clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>;
                        clock-names = "bus", "core";
                        operating-points-v2 = <&gpu_opp_table>;
-                       switch-delay = <0xffff>;
                };
        };
 }; /* end of / */
index fd4a3bf..1b442b1 100644 (file)
@@ -430,7 +430,7 @@ static void omap3_prm_reconfigure_io_chain(void)
  * registers, and omap3xxx_prm_reconfigure_io_chain() must be called.
  * No return value.
  */
-static void __init omap3xxx_prm_enable_io_wakeup(void)
+static void omap3xxx_prm_enable_io_wakeup(void)
 {
        if (prm_features & PRM_HAS_IO_WAKEUP)
                omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
index b045812..bf7f845 100644 (file)
@@ -28,7 +28,7 @@
                        enable-method = "psci";
                        clocks = <&clockgen 1 0>;
                        next-level-cache = <&l2>;
-                       cpu-idle-states = <&CPU_PH20>;
+                       cpu-idle-states = <&CPU_PW20>;
                };
 
                cpu1: cpu@1 {
@@ -38,7 +38,7 @@
                        enable-method = "psci";
                        clocks = <&clockgen 1 0>;
                        next-level-cache = <&l2>;
-                       cpu-idle-states = <&CPU_PH20>;
+                       cpu-idle-states = <&CPU_PW20>;
                };
 
                l2: l2-cache {
                 */
                entry-method = "arm,psci";
 
-               CPU_PH20: cpu-ph20 {
-                       compatible = "arm,idle-state";
-                       idle-state-name = "PH20";
-                       arm,psci-suspend-param = <0x00010000>;
-                       entry-latency-us = <1000>;
-                       exit-latency-us = <1000>;
-                       min-residency-us = <3000>;
+               CPU_PW20: cpu-pw20 {
+                         compatible = "arm,idle-state";
+                         idle-state-name = "PW20";
+                         arm,psci-suspend-param = <0x0>;
+                         entry-latency-us = <2000>;
+                         exit-latency-us = <2000>;
+                         min-residency-us = <6000>;
                };
        };
 
index 4d58351..6bca5b0 100644 (file)
@@ -613,6 +613,7 @@ CONFIG_RTC_DRV_TEGRA=y
 CONFIG_RTC_DRV_IMX_SC=m
 CONFIG_RTC_DRV_XGENE=y
 CONFIG_DMADEVICES=y
+CONFIG_FSL_EDMA=y
 CONFIG_DMA_BCM2835=m
 CONFIG_K3_DMA=y
 CONFIG_MV_XOR=y
index 04a43cf..d47a338 100644 (file)
@@ -39,6 +39,11 @@ static int save_fpu_state(struct sigcontext __user *sc)
 #endif
 
 struct rt_sigframe {
+       /*
+        * pad[3] is compatible with the same struct defined in
+        * gcc/libgcc/config/csky/linux-unwind.h
+        */
+       int pad[3];
        struct siginfo info;
        struct ucontext uc;
 };
index 75a1cde..084cac1 100644 (file)
@@ -311,6 +311,36 @@ static inline bool mips_gic_present(void)
 }
 
 /**
+ * mips_gic_vx_map_reg() - Return GIC_Vx_<intr>_MAP register offset
+ * @intr: A GIC local interrupt
+ *
+ * Determine the index of the GIC_VL_<intr>_MAP or GIC_VO_<intr>_MAP register
+ * within the block of GIC map registers. This is almost the same as the order
+ * of interrupts in the pending & mask registers, as used by enum
+ * mips_gic_local_interrupt, but moves the FDC interrupt & thus offsets the
+ * interrupts after it...
+ *
+ * Return: The map register index corresponding to @intr.
+ *
+ * The return value is suitable for use with the (read|write)_gic_v[lo]_map
+ * accessor functions.
+ */
+static inline unsigned int
+mips_gic_vx_map_reg(enum mips_gic_local_interrupt intr)
+{
+       /* WD, Compare & Timer are 1:1 */
+       if (intr <= GIC_LOCAL_INT_TIMER)
+               return intr;
+
+       /* FDC moves to after Timer... */
+       if (intr == GIC_LOCAL_INT_FDC)
+               return GIC_LOCAL_INT_TIMER + 1;
+
+       /* As a result everything else is offset by 1 */
+       return intr + 1;
+}
+
+/**
  * gic_get_c0_compare_int() - Return cp0 count/compare interrupt virq
  *
  * Determine the virq number to use for the coprocessor 0 count/compare
index f241ded..1f0f29a 100644 (file)
@@ -786,6 +786,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
                        /* 32-bit PC relative address */
                        *loc = val - dot - 8 + addend;
                        break;
+               case R_PARISC_PCREL64:
+                       /* 64-bit PC relative address */
+                       *loc64 = val - dot - 8 + addend;
+                       break;
                case R_PARISC_DIR64:
                        /* 64-bit effective address */
                        *loc64 = val + addend;
index 6b86055..73ba246 100644 (file)
@@ -315,7 +315,7 @@ TRAMP_REAL_BEGIN(machine_check_common_early)
        mfspr   r11,SPRN_DSISR          /* Save DSISR */
        std     r11,_DSISR(r1)
        std     r9,_CCR(r1)             /* Save CR in stackframe */
-       kuap_save_amr_and_lock r9, r10, cr1
+       /* We don't touch AMR here, we never go to virtual mode */
        /* Save r9 through r13 from EXMC save area to stack frame. */
        EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
        mfmsr   r11                     /* get MSR value */
index bb70391..794404d 100644 (file)
@@ -50,20 +50,52 @@ EXPORT_SYMBOL_GPL(hash__alloc_context_id);
 
 void slb_setup_new_exec(void);
 
+static int realloc_context_ids(mm_context_t *ctx)
+{
+       int i, id;
+
+       /*
+        * id 0 (aka. ctx->id) is special, we always allocate a new one, even if
+        * there wasn't one allocated previously (which happens in the exec
+        * case where ctx is newly allocated).
+        *
+        * We have to be a bit careful here. We must keep the existing ids in
+        * the array, so that we can test if they're non-zero to decide if we
+        * need to allocate a new one. However in case of error we must free the
+        * ids we've allocated but *not* any of the existing ones (or risk a
+        * UAF). That's why we decrement i at the start of the error handling
+        * loop, to skip the id that we just tested but couldn't reallocate.
+        */
+       for (i = 0; i < ARRAY_SIZE(ctx->extended_id); i++) {
+               if (i == 0 || ctx->extended_id[i]) {
+                       id = hash__alloc_context_id();
+                       if (id < 0)
+                               goto error;
+
+                       ctx->extended_id[i] = id;
+               }
+       }
+
+       /* The caller expects us to return id */
+       return ctx->id;
+
+error:
+       for (i--; i >= 0; i--) {
+               if (ctx->extended_id[i])
+                       ida_free(&mmu_context_ida, ctx->extended_id[i]);
+       }
+
+       return id;
+}
+
 static int hash__init_new_context(struct mm_struct *mm)
 {
        int index;
 
-       index = hash__alloc_context_id();
-       if (index < 0)
-               return index;
-
        mm->context.hash_context = kmalloc(sizeof(struct hash_mm_context),
                                           GFP_KERNEL);
-       if (!mm->context.hash_context) {
-               ida_free(&mmu_context_ida, index);
+       if (!mm->context.hash_context)
                return -ENOMEM;
-       }
 
        /*
         * The old code would re-promote on fork, we don't do that when using
@@ -91,13 +123,20 @@ static int hash__init_new_context(struct mm_struct *mm)
                        mm->context.hash_context->spt = kmalloc(sizeof(struct subpage_prot_table),
                                                                GFP_KERNEL);
                        if (!mm->context.hash_context->spt) {
-                               ida_free(&mmu_context_ida, index);
                                kfree(mm->context.hash_context);
                                return -ENOMEM;
                        }
                }
 #endif
+       }
 
+       index = realloc_context_ids(&mm->context);
+       if (index < 0) {
+#ifdef CONFIG_PPC_SUBPAGE_PROT
+               kfree(mm->context.hash_context->spt);
+#endif
+               kfree(mm->context.hash_context);
+               return index;
        }
 
        pkey_mm_init(mm);
index 3c06ee4..4098349 100644 (file)
                        interrupt-parent = <&plic0>;
                        interrupts = <4>;
                        clocks = <&prci PRCI_CLK_TLCLK>;
+                       status = "disabled";
                };
                uart1: serial@10011000 {
                        compatible = "sifive,fu540-c000-uart", "sifive,uart0";
                        interrupt-parent = <&plic0>;
                        interrupts = <5>;
                        clocks = <&prci PRCI_CLK_TLCLK>;
+                       status = "disabled";
                };
                i2c0: i2c@10030000 {
                        compatible = "sifive,fu540-c000-i2c", "sifive,i2c0";
                        reg-io-width = <1>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       status = "disabled";
                };
                qspi0: spi@10040000 {
                        compatible = "sifive,fu540-c000-spi", "sifive,spi0";
                        clocks = <&prci PRCI_CLK_TLCLK>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       status = "disabled";
                };
                qspi1: spi@10041000 {
                        compatible = "sifive,fu540-c000-spi", "sifive,spi0";
                        clocks = <&prci PRCI_CLK_TLCLK>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       status = "disabled";
                };
                qspi2: spi@10050000 {
                        compatible = "sifive,fu540-c000-spi", "sifive,spi0";
                        clocks = <&prci PRCI_CLK_TLCLK>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       status = "disabled";
                };
        };
 };
index 4da8870..0b55c53 100644 (file)
        };
 };
 
+&uart0 {
+       status = "okay";
+};
+
+&uart1 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+};
+
 &qspi0 {
+       status = "okay";
        flash@0 {
                compatible = "issi,is25wp256", "jedec,spi-nor";
                reg = <0>;
index 4f02967..04944fb 100644 (file)
@@ -69,6 +69,7 @@ CONFIG_VIRTIO_MMIO=y
 CONFIG_CLK_SIFIVE=y
 CONFIG_CLK_SIFIVE_FU540_PRCI=y
 CONFIG_SIFIVE_PLIC=y
+CONFIG_SPI_SIFIVE=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_AUTOFS4_FS=y
@@ -84,4 +85,8 @@ CONFIG_ROOT_NFS=y
 CONFIG_CRYPTO_USER_API_HASH=y
 CONFIG_CRYPTO_DEV_VIRTIO=y
 CONFIG_PRINTK_TIME=y
+CONFIG_SPI=y
+CONFIG_MMC_SPI=y
+CONFIG_MMC=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_RCU_TRACE is not set
index 3e2708c..f960c3f 100644 (file)
@@ -272,9 +272,6 @@ vmalloc_fault:
                 * entries, but in RISC-V, SFENCE.VMA specifies an
                 * ordering constraint, not a cache flush; it is
                 * necessary even after writing invalid entries.
-                * Relying on flush_tlb_fix_spurious_fault would
-                * suffice, but the extra traps reduce
-                * performance. So, eagerly SFENCE.VMA.
                 */
                local_flush_tlb_page(addr);
 
index f315425..3cd94a2 100644 (file)
@@ -561,14 +561,14 @@ int x86_pmu_hw_config(struct perf_event *event)
        }
 
        /* sample_regs_user never support XMM registers */
-       if (unlikely(event->attr.sample_regs_user & PEBS_XMM_REGS))
+       if (unlikely(event->attr.sample_regs_user & PERF_REG_EXTENDED_MASK))
                return -EINVAL;
        /*
         * Besides the general purpose registers, XMM registers may
         * be collected in PEBS on some platforms, e.g. Icelake
         */
-       if (unlikely(event->attr.sample_regs_intr & PEBS_XMM_REGS)) {
-               if (x86_pmu.pebs_no_xmm_regs)
+       if (unlikely(event->attr.sample_regs_intr & PERF_REG_EXTENDED_MASK)) {
+               if (!(event->pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS))
                        return -EINVAL;
 
                if (!event->attr.precise_ip)
@@ -2402,13 +2402,13 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re
                return;
        }
 
-       if (perf_hw_regs(regs)) {
-               if (perf_callchain_store(entry, regs->ip))
-                       return;
+       if (perf_callchain_store(entry, regs->ip))
+               return;
+
+       if (perf_hw_regs(regs))
                unwind_start(&state, current, regs, NULL);
-       } else {
+       else
                unwind_start(&state, current, NULL, (void *)regs->sp);
-       }
 
        for (; !unwind_done(&state); unwind_next_frame(&state)) {
                addr = unwind_get_return_address(&state);
index 7acc526..505c73d 100644 (file)
@@ -987,7 +987,7 @@ static u64 pebs_update_adaptive_cfg(struct perf_event *event)
                pebs_data_cfg |= PEBS_DATACFG_GP;
 
        if ((sample_type & PERF_SAMPLE_REGS_INTR) &&
-           (attr->sample_regs_intr & PEBS_XMM_REGS))
+           (attr->sample_regs_intr & PERF_REG_EXTENDED_MASK))
                pebs_data_cfg |= PEBS_DATACFG_XMMS;
 
        if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
@@ -1964,10 +1964,9 @@ void __init intel_ds_init(void)
        x86_pmu.bts  = boot_cpu_has(X86_FEATURE_BTS);
        x86_pmu.pebs = boot_cpu_has(X86_FEATURE_PEBS);
        x86_pmu.pebs_buffer_size = PEBS_BUFFER_SIZE;
-       if (x86_pmu.version <= 4) {
+       if (x86_pmu.version <= 4)
                x86_pmu.pebs_no_isolation = 1;
-               x86_pmu.pebs_no_xmm_regs = 1;
-       }
+
        if (x86_pmu.pebs) {
                char pebs_type = x86_pmu.intel_cap.pebs_trap ?  '+' : '-';
                char *pebs_qual = "";
@@ -2020,9 +2019,9 @@ void __init intel_ds_init(void)
                                        PERF_SAMPLE_TIME;
                                x86_pmu.flags |= PMU_FL_PEBS_ALL;
                                pebs_qual = "-baseline";
+                               x86_get_pmu()->capabilities |= PERF_PMU_CAP_EXTENDED_REGS;
                        } else {
                                /* Only basic record supported */
-                               x86_pmu.pebs_no_xmm_regs = 1;
                                x86_pmu.large_pebs_flags &=
                                        ~(PERF_SAMPLE_ADDR |
                                          PERF_SAMPLE_TIME |
index a6ac2f4..4e34685 100644 (file)
@@ -121,24 +121,6 @@ struct amd_nb {
         (1ULL << PERF_REG_X86_R14)   | \
         (1ULL << PERF_REG_X86_R15))
 
-#define PEBS_XMM_REGS                   \
-       ((1ULL << PERF_REG_X86_XMM0)  | \
-        (1ULL << PERF_REG_X86_XMM1)  | \
-        (1ULL << PERF_REG_X86_XMM2)  | \
-        (1ULL << PERF_REG_X86_XMM3)  | \
-        (1ULL << PERF_REG_X86_XMM4)  | \
-        (1ULL << PERF_REG_X86_XMM5)  | \
-        (1ULL << PERF_REG_X86_XMM6)  | \
-        (1ULL << PERF_REG_X86_XMM7)  | \
-        (1ULL << PERF_REG_X86_XMM8)  | \
-        (1ULL << PERF_REG_X86_XMM9)  | \
-        (1ULL << PERF_REG_X86_XMM10) | \
-        (1ULL << PERF_REG_X86_XMM11) | \
-        (1ULL << PERF_REG_X86_XMM12) | \
-        (1ULL << PERF_REG_X86_XMM13) | \
-        (1ULL << PERF_REG_X86_XMM14) | \
-        (1ULL << PERF_REG_X86_XMM15))
-
 /*
  * Per register state.
  */
@@ -668,8 +650,7 @@ struct x86_pmu {
                        pebs_broken             :1,
                        pebs_prec_dist          :1,
                        pebs_no_tlb             :1,
-                       pebs_no_isolation       :1,
-                       pebs_no_xmm_regs        :1;
+                       pebs_no_isolation       :1;
        int             pebs_record_size;
        int             pebs_buffer_size;
        int             max_pebs_events;
index ac67bbe..7c9d2bb 100644 (file)
@@ -52,4 +52,7 @@ enum perf_event_x86_regs {
        /* These include both GPRs and XMMX registers */
        PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2,
 };
+
+#define PERF_REG_EXTENDED_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
+
 #endif /* _ASM_X86_PERF_REGS_H */
index 177aa8e..85be316 100644 (file)
@@ -1464,7 +1464,8 @@ static void apic_pending_intr_clear(void)
                if (queued) {
                        if (boot_cpu_has(X86_FEATURE_TSC) && cpu_khz) {
                                ntsc = rdtsc();
-                               max_loops = (cpu_khz << 10) - (ntsc - tsc);
+                               max_loops = (long long)cpu_khz << 10;
+                               max_loops -= ntsc - tsc;
                        } else {
                                max_loops--;
                        }
index 03b4cc0..66ca906 100644 (file)
@@ -836,6 +836,16 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
        }
 
        /*
+        * If SSBD is controlled by the SPEC_CTRL MSR, then set the proper
+        * bit in the mask to allow guests to use the mitigation even in the
+        * case where the host does not enable it.
+        */
+       if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
+           static_cpu_has(X86_FEATURE_AMD_SSBD)) {
+               x86_spec_ctrl_mask |= SPEC_CTRL_SSBD;
+       }
+
+       /*
         * We have three CPU feature flags that are in play here:
         *  - X86_BUG_SPEC_STORE_BYPASS - CPU is susceptible.
         *  - X86_FEATURE_SSBD - CPU is able to turn off speculative store bypass
@@ -852,7 +862,6 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
                        x86_amd_ssb_disable();
                } else {
                        x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
-                       x86_spec_ctrl_mask |= SPEC_CTRL_SSBD;
                        wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
                }
        }
index a813987..cb0fdca 100644 (file)
@@ -789,13 +789,16 @@ static struct syscore_ops mc_syscore_ops = {
        .resume                 = mc_bp_resume,
 };
 
-static int mc_cpu_online(unsigned int cpu)
+static int mc_cpu_starting(unsigned int cpu)
 {
-       struct device *dev;
-
-       dev = get_cpu_device(cpu);
        microcode_update_cpu(cpu);
        pr_debug("CPU%d added\n", cpu);
+       return 0;
+}
+
+static int mc_cpu_online(unsigned int cpu)
+{
+       struct device *dev = get_cpu_device(cpu);
 
        if (sysfs_create_group(&dev->kobj, &mc_attr_group))
                pr_err("Failed to create group for CPU%d\n", cpu);
@@ -872,7 +875,9 @@ int __init microcode_init(void)
                goto out_ucode_group;
 
        register_syscore_ops(&mc_syscore_ops);
-       cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:online",
+       cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:starting",
+                                 mc_cpu_starting, NULL);
+       cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/microcode:online",
                                  mc_cpu_online, mc_cpu_down_prep);
 
        pr_info("Microcode Update Driver: v%s.", DRIVER_VERSION);
index 2131b8b..2f48247 100644 (file)
@@ -796,8 +796,12 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
                              struct seq_file *seq, void *v)
 {
        struct rdt_resource *r = of->kn->parent->priv;
-       u32 sw_shareable = 0, hw_shareable = 0;
-       u32 exclusive = 0, pseudo_locked = 0;
+       /*
+        * Use unsigned long even though only 32 bits are used to ensure
+        * test_bit() is used safely.
+        */
+       unsigned long sw_shareable = 0, hw_shareable = 0;
+       unsigned long exclusive = 0, pseudo_locked = 0;
        struct rdt_domain *dom;
        int i, hwb, swb, excl, psl;
        enum rdtgrp_mode mode;
@@ -842,10 +846,10 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
                }
                for (i = r->cache.cbm_len - 1; i >= 0; i--) {
                        pseudo_locked = dom->plr ? dom->plr->cbm : 0;
-                       hwb = test_bit(i, (unsigned long *)&hw_shareable);
-                       swb = test_bit(i, (unsigned long *)&sw_shareable);
-                       excl = test_bit(i, (unsigned long *)&exclusive);
-                       psl = test_bit(i, (unsigned long *)&pseudo_locked);
+                       hwb = test_bit(i, &hw_shareable);
+                       swb = test_bit(i, &sw_shareable);
+                       excl = test_bit(i, &exclusive);
+                       psl = test_bit(i, &pseudo_locked);
                        if (hwb && swb)
                                seq_putc(seq, 'X');
                        else if (hwb && !swb)
@@ -2486,26 +2490,19 @@ out_destroy:
  */
 static void cbm_ensure_valid(u32 *_val, struct rdt_resource *r)
 {
-       /*
-        * Convert the u32 _val to an unsigned long required by all the bit
-        * operations within this function. No more than 32 bits of this
-        * converted value can be accessed because all bit operations are
-        * additionally provided with cbm_len that is initialized during
-        * hardware enumeration using five bits from the EAX register and
-        * thus never can exceed 32 bits.
-        */
-       unsigned long *val = (unsigned long *)_val;
+       unsigned long val = *_val;
        unsigned int cbm_len = r->cache.cbm_len;
        unsigned long first_bit, zero_bit;
 
-       if (*val == 0)
+       if (val == 0)
                return;
 
-       first_bit = find_first_bit(val, cbm_len);
-       zero_bit = find_next_zero_bit(val, cbm_len, first_bit);
+       first_bit = find_first_bit(&val, cbm_len);
+       zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
 
        /* Clear any remaining bits to ensure contiguous region */
-       bitmap_clear(val, zero_bit, cbm_len - zero_bit);
+       bitmap_clear(&val, zero_bit, cbm_len - zero_bit);
+       *_val = (u32)val;
 }
 
 /*
index 16b1cbd..29ffa49 100644 (file)
@@ -184,24 +184,25 @@ unsigned long __head __startup_64(unsigned long physaddr,
        pgtable_flags = _KERNPG_TABLE_NOENC + sme_get_me_mask();
 
        if (la57) {
-               p4d = fixup_pointer(early_dynamic_pgts[next_early_pgt++], physaddr);
+               p4d = fixup_pointer(early_dynamic_pgts[(*next_pgt_ptr)++],
+                                   physaddr);
 
                i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
                pgd[i + 0] = (pgdval_t)p4d + pgtable_flags;
                pgd[i + 1] = (pgdval_t)p4d + pgtable_flags;
 
-               i = (physaddr >> P4D_SHIFT) % PTRS_PER_P4D;
-               p4d[i + 0] = (pgdval_t)pud + pgtable_flags;
-               p4d[i + 1] = (pgdval_t)pud + pgtable_flags;
+               i = physaddr >> P4D_SHIFT;
+               p4d[(i + 0) % PTRS_PER_P4D] = (pgdval_t)pud + pgtable_flags;
+               p4d[(i + 1) % PTRS_PER_P4D] = (pgdval_t)pud + pgtable_flags;
        } else {
                i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
                pgd[i + 0] = (pgdval_t)pud + pgtable_flags;
                pgd[i + 1] = (pgdval_t)pud + pgtable_flags;
        }
 
-       i = (physaddr >> PUD_SHIFT) % PTRS_PER_PUD;
-       pud[i + 0] = (pudval_t)pmd + pgtable_flags;
-       pud[i + 1] = (pudval_t)pmd + pgtable_flags;
+       i = physaddr >> PUD_SHIFT;
+       pud[(i + 0) % PTRS_PER_PUD] = (pudval_t)pmd + pgtable_flags;
+       pud[(i + 1) % PTRS_PER_PUD] = (pudval_t)pmd + pgtable_flags;
 
        pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL;
        /* Filter out unsupported __PAGE_KERNEL_* bits: */
@@ -211,8 +212,9 @@ unsigned long __head __startup_64(unsigned long physaddr,
        pmd_entry +=  physaddr;
 
        for (i = 0; i < DIV_ROUND_UP(_end - _text, PMD_SIZE); i++) {
-               int idx = i + (physaddr >> PMD_SHIFT) % PTRS_PER_PMD;
-               pmd[idx] = pmd_entry + i * PMD_SIZE;
+               int idx = i + (physaddr >> PMD_SHIFT);
+
+               pmd[idx % PTRS_PER_PMD] = pmd_entry + i * PMD_SIZE;
        }
 
        /*
index 07c30ee..bb7e113 100644 (file)
@@ -74,6 +74,9 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
        return regs_get_register(regs, pt_regs_offset[idx]);
 }
 
+#define PERF_REG_X86_RESERVED  (((1ULL << PERF_REG_X86_XMM0) - 1) & \
+                                ~((1ULL << PERF_REG_X86_MAX) - 1))
+
 #ifdef CONFIG_X86_32
 #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_R8) | \
                       (1ULL << PERF_REG_X86_R9) | \
@@ -86,7 +89,7 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
 
 int perf_reg_validate(u64 mask)
 {
-       if (!mask || (mask & REG_NOSUPPORT))
+       if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
                return -EINVAL;
 
        return 0;
@@ -112,7 +115,7 @@ void perf_get_regs_user(struct perf_regs *regs_user,
 
 int perf_reg_validate(u64 mask)
 {
-       if (!mask || (mask & REG_NOSUPPORT))
+       if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
                return -EINVAL;
 
        return 0;
index 33b66b5..72b997e 100644 (file)
@@ -82,9 +82,9 @@ static struct orc_entry *orc_find(unsigned long ip);
  * But they are copies of the ftrace entries that are static and
  * defined in ftrace_*.S, which do have orc entries.
  *
- * If the undwinder comes across a ftrace trampoline, then find the
+ * If the unwinder comes across a ftrace trampoline, then find the
  * ftrace function that was used to create it, and use that ftrace
- * function's orc entrie, as the placement of the return code in
+ * function's orc entry, as the placement of the return code in
  * the stack will be identical.
  */
 static struct orc_entry *orc_ftrace_find(unsigned long ip)
@@ -128,6 +128,16 @@ static struct orc_entry null_orc_entry = {
        .type = ORC_TYPE_CALL
 };
 
+/* Fake frame pointer entry -- used as a fallback for generated code */
+static struct orc_entry orc_fp_entry = {
+       .type           = ORC_TYPE_CALL,
+       .sp_reg         = ORC_REG_BP,
+       .sp_offset      = 16,
+       .bp_reg         = ORC_REG_PREV_SP,
+       .bp_offset      = -16,
+       .end            = 0,
+};
+
 static struct orc_entry *orc_find(unsigned long ip)
 {
        static struct orc_entry *orc;
@@ -392,8 +402,16 @@ bool unwind_next_frame(struct unwind_state *state)
         * calls and calls to noreturn functions.
         */
        orc = orc_find(state->signal ? state->ip : state->ip - 1);
-       if (!orc)
-               goto err;
+       if (!orc) {
+               /*
+                * As a fallback, try to assume this code uses a frame pointer.
+                * This is useful for generated code, like BPF, which ORC
+                * doesn't know about.  This is just a guess, so the rest of
+                * the unwind is no longer considered reliable.
+                */
+               orc = &orc_fp_entry;
+               state->error = true;
+       }
 
        /* End-of-stack check for kernel threads: */
        if (orc->sp_reg == ORC_REG_UNDEFINED) {
index 693aaf2..0f01c7b 100644 (file)
@@ -671,23 +671,25 @@ static unsigned long __meminit
 phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
              unsigned long page_size_mask, bool init)
 {
-       unsigned long paddr_next, paddr_last = paddr_end;
-       unsigned long vaddr = (unsigned long)__va(paddr);
-       int i = p4d_index(vaddr);
+       unsigned long vaddr, vaddr_end, vaddr_next, paddr_next, paddr_last;
+
+       paddr_last = paddr_end;
+       vaddr = (unsigned long)__va(paddr);
+       vaddr_end = (unsigned long)__va(paddr_end);
 
        if (!pgtable_l5_enabled())
                return phys_pud_init((pud_t *) p4d_page, paddr, paddr_end,
                                     page_size_mask, init);
 
-       for (; i < PTRS_PER_P4D; i++, paddr = paddr_next) {
-               p4d_t *p4d;
+       for (; vaddr < vaddr_end; vaddr = vaddr_next) {
+               p4d_t *p4d = p4d_page + p4d_index(vaddr);
                pud_t *pud;
 
-               vaddr = (unsigned long)__va(paddr);
-               p4d = p4d_page + p4d_index(vaddr);
-               paddr_next = (paddr & P4D_MASK) + P4D_SIZE;
+               vaddr_next = (vaddr & P4D_MASK) + P4D_SIZE;
+               paddr = __pa(vaddr);
 
                if (paddr >= paddr_end) {
+                       paddr_next = __pa(vaddr_next);
                        if (!after_bootmem &&
                            !e820__mapped_any(paddr & P4D_MASK, paddr_next,
                                             E820_TYPE_RAM) &&
@@ -699,13 +701,13 @@ phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
 
                if (!p4d_none(*p4d)) {
                        pud = pud_offset(p4d, 0);
-                       paddr_last = phys_pud_init(pud, paddr, paddr_end,
-                                                  page_size_mask, init);
+                       paddr_last = phys_pud_init(pud, paddr, __pa(vaddr_end),
+                                       page_size_mask, init);
                        continue;
                }
 
                pud = alloc_low_page();
-               paddr_last = phys_pud_init(pud, paddr, paddr_end,
+               paddr_last = phys_pud_init(pud, paddr, __pa(vaddr_end),
                                           page_size_mask, init);
 
                spin_lock(&init_mm.page_table_lock);
index 632b838..3b9fd67 100644 (file)
@@ -728,7 +728,7 @@ void efi_recover_from_page_fault(unsigned long phys_addr)
         * Address range 0x0000 - 0x0fff is always mapped in the efi_pgd, so
         * page faulting on these addresses isn't expected.
         */
-       if (phys_addr >= 0x0000 && phys_addr <= 0x0fff)
+       if (phys_addr <= 0x0fff)
                return;
 
        /*
index f8d430f..f9269ae 100644 (file)
@@ -240,7 +240,7 @@ static struct kmem_cache *bfq_pool;
  * containing only random (seeky) I/O are prevented from being tagged
  * as soft real-time.
  */
-#define BFQQ_TOTALLY_SEEKY(bfqq)       (bfqq->seek_history & -1)
+#define BFQQ_TOTALLY_SEEKY(bfqq)       (bfqq->seek_history == -1)
 
 /* Min number of samples required to perform peak-rate update */
 #define BFQ_RATE_MIN_SAMPLES   32
index 40c8a55..4074886 100644 (file)
@@ -52,8 +52,9 @@ static const struct fb_var_screeninfo cfag12864bfb_var = {
 
 static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
-       return vm_insert_page(vma, vma->vm_start,
-               virt_to_page(cfag12864b_buffer));
+       struct page *pages = virt_to_page(cfag12864b_buffer);
+
+       return vm_map_pages_zero(vma, &pages, 1);
 }
 
 static struct fb_ops cfag12864bfb_ops = {
index 21393ec..9c0bb77 100644 (file)
@@ -223,9 +223,9 @@ static const struct backlight_ops ht16k33_bl_ops = {
 static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct ht16k33_priv *priv = info->par;
+       struct page *pages = virt_to_page(priv->fbdev.buffer);
 
-       return vm_insert_page(vma, vma->vm_start,
-                             virt_to_page(priv->fbdev.buffer));
+       return vm_map_pages_zero(vma, &pages, 1);
 }
 
 static struct fb_ops ht16k33_fb_ops = {
index aa51756..87b410d 100644 (file)
@@ -368,7 +368,7 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
        const char *dev_id = dev ? dev_name(dev) : NULL;
        struct device_node *np = core->of_node;
 
-       if (np && index >= 0)
+       if (np && (name || index >= 0))
                hw = of_clk_get_hw(np, index, name);
 
        /*
index 739f64f..206fafd 100644 (file)
@@ -2734,8 +2734,8 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = {
                [CLKID_MALI_1_DIV]              = &g12a_mali_1_div.hw,
                [CLKID_MALI_1]                  = &g12a_mali_1.hw,
                [CLKID_MALI]                    = &g12a_mali.hw,
-               [CLKID_MPLL_5OM_DIV]            = &g12a_mpll_50m_div.hw,
-               [CLKID_MPLL_5OM]                = &g12a_mpll_50m.hw,
+               [CLKID_MPLL_50M_DIV]            = &g12a_mpll_50m_div.hw,
+               [CLKID_MPLL_50M]                = &g12a_mpll_50m.hw,
                [CLKID_SYS_PLL_DIV16_EN]        = &g12a_sys_pll_div16_en.hw,
                [CLKID_SYS_PLL_DIV16]           = &g12a_sys_pll_div16.hw,
                [CLKID_CPU_CLK_DYN0_SEL]        = &g12a_cpu_clk_premux0.hw,
index 39c41af..bcc05cd 100644 (file)
 #define CLKID_HDMI_DIV                         167
 #define CLKID_MALI_0_DIV                       170
 #define CLKID_MALI_1_DIV                       173
-#define CLKID_MPLL_5OM_DIV                     176
+#define CLKID_MPLL_50M_DIV                     176
 #define CLKID_SYS_PLL_DIV16_EN                 178
 #define CLKID_SYS_PLL_DIV16                    179
 #define CLKID_CPU_CLK_DYN0_SEL                 180
index 37cf0f0..62cd3a7 100644 (file)
@@ -1761,7 +1761,7 @@ static struct clk_regmap meson8m2_gp_pll = {
        },
 };
 
-static const char * const mmeson8b_vpu_0_1_parent_names[] = {
+static const char * const meson8b_vpu_0_1_parent_names[] = {
        "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7"
 };
 
@@ -1778,8 +1778,8 @@ static struct clk_regmap meson8b_vpu_0_sel = {
        .hw.init = &(struct clk_init_data){
                .name = "vpu_0_sel",
                .ops = &clk_regmap_mux_ops,
-               .parent_names = mmeson8b_vpu_0_1_parent_names,
-               .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names),
+               .parent_names = meson8b_vpu_0_1_parent_names,
+               .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names),
                .flags = CLK_SET_RATE_PARENT,
        },
 };
@@ -1837,8 +1837,8 @@ static struct clk_regmap meson8b_vpu_1_sel = {
        .hw.init = &(struct clk_init_data){
                .name = "vpu_1_sel",
                .ops = &clk_regmap_mux_ops,
-               .parent_names = mmeson8b_vpu_0_1_parent_names,
-               .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names),
+               .parent_names = meson8b_vpu_0_1_parent_names,
+               .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names),
                .flags = CLK_SET_RATE_PARENT,
        },
 };
index 8281dfb..5bed36e 100644 (file)
@@ -103,9 +103,9 @@ static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = {
        { STRATIX10_NOC_CLK, "noc_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux),
          0, 0, 0, 0x3C, 1},
        { STRATIX10_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux, ARRAY_SIZE(emaca_free_mux),
-         0, 0, 4, 0xB0, 0},
+         0, 0, 2, 0xB0, 0},
        { STRATIX10_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux),
-         0, 0, 4, 0xB0, 1},
+         0, 0, 2, 0xB0, 1},
        { STRATIX10_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk", NULL, emac_ptp_free_mux,
          ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 4, 0xB0, 2},
        { STRATIX10_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux,
index e1ba62d..ac1d27a 100644 (file)
@@ -3366,6 +3366,8 @@ static struct tegra_clk_init_table init_table[] __initdata = {
        { TEGRA210_CLK_I2S3_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
        { TEGRA210_CLK_I2S4_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
        { TEGRA210_CLK_VIMCLK_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
+       { TEGRA210_CLK_HDA, TEGRA210_CLK_PLL_P, 51000000, 0 },
+       { TEGRA210_CLK_HDA2CODEC_2X, TEGRA210_CLK_PLL_P, 48000000, 0 },
        /* This MUST be the last entry. */
        { TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0 },
 };
index 8e83431..975995e 100644 (file)
@@ -229,6 +229,7 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec,
 {
        struct omap_clkctrl_provider *provider = data;
        struct omap_clkctrl_clk *entry;
+       bool found = false;
 
        if (clkspec->args_count != 2)
                return ERR_PTR(-EINVAL);
@@ -238,11 +239,13 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec,
 
        list_for_each_entry(entry, &provider->clocks, node) {
                if (entry->reg_offset == clkspec->args[0] &&
-                   entry->bit_offset == clkspec->args[1])
+                   entry->bit_offset == clkspec->args[1]) {
+                       found = true;
                        break;
+               }
        }
 
-       if (!entry)
+       if (!found)
                return ERR_PTR(-EINVAL);
 
        return entry->clk;
index a238418..b07c176 100644 (file)
@@ -47,11 +47,6 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
                       bgrt->version);
                goto out;
        }
-       if (bgrt->status & 0xfe) {
-               pr_notice("Ignoring BGRT: reserved status bits are non-zero %u\n",
-                      bgrt->status);
-               goto out;
-       }
        if (bgrt->image_type != 0) {
                pr_notice("Ignoring BGRT: invalid image type %u (expected 0)\n",
                       bgrt->image_type);
index 16b2137..4b7cf7b 100644 (file)
@@ -1009,14 +1009,16 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
 
        /* first try to find a slot in an existing linked list entry */
        for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) {
-               rsv = __va(prsv);
+               rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB);
                index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
                if (index < rsv->size) {
                        rsv->entry[index].base = addr;
                        rsv->entry[index].size = size;
 
+                       memunmap(rsv);
                        return 0;
                }
+               memunmap(rsv);
        }
 
        /* no slot found - allocate a new linked list entry */
@@ -1024,7 +1026,13 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
        if (!rsv)
                return -ENOMEM;
 
-       rsv->size = EFI_MEMRESERVE_COUNT(PAGE_SIZE);
+       /*
+        * The memremap() call above assumes that a linux_efi_memreserve entry
+        * never crosses a page boundary, so let's ensure that this remains true
+        * even when kexec'ing a 4k pages kernel from a >4k pages kernel, by
+        * using SZ_4K explicitly in the size calculation below.
+        */
+       rsv->size = EFI_MEMRESERVE_COUNT(SZ_4K);
        atomic_set(&rsv->count, 1);
        rsv->entry[0].base = addr;
        rsv->entry[0].size = size;
index 61e0998..35dccc8 100644 (file)
@@ -43,11 +43,13 @@ static int efibc_set_variable(const char *name, const char *value)
        efibc_str_to_str16(value, (efi_char16_t *)entry->var.Data);
        memcpy(&entry->var.VendorGuid, &guid, sizeof(guid));
 
-       ret = efivar_entry_set(entry,
-                              EFI_VARIABLE_NON_VOLATILE
-                              | EFI_VARIABLE_BOOTSERVICE_ACCESS
-                              | EFI_VARIABLE_RUNTIME_ACCESS,
-                              size, entry->var.Data, NULL);
+       ret = efivar_entry_set_safe(entry->var.VariableName,
+                                   entry->var.VendorGuid,
+                                   EFI_VARIABLE_NON_VOLATILE
+                                   | EFI_VARIABLE_BOOTSERVICE_ACCESS
+                                   | EFI_VARIABLE_RUNTIME_ACCESS,
+                                   false, size, entry->var.Data);
+
        if (ret)
                pr_err("failed to set %s EFI variable: 0x%x\n",
                       name, ret);
index eac0c54..b032d38 100644 (file)
@@ -80,6 +80,7 @@
 #define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP    0x1220
 #define HID_DEVICE_ID_ALPS_U1          0x1215
 #define HID_DEVICE_ID_ALPS_T4_BTNLESS  0x120C
+#define HID_DEVICE_ID_ALPS_1222                0x1222
 
 
 #define USB_VENDOR_ID_AMI              0x046b
 #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH      0xb19d
 #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
 #define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053
+#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2        0x0939
 #define USB_DEVICE_ID_CHICONY_WIRELESS2        0x1123
 #define USB_DEVICE_ID_ASUS_AK1D                0x1125
 #define USB_DEVICE_ID_CHICONY_TOSHIBA_WT10A    0x1408
 
 #define USB_VENDOR_ID_HUION            0x256c
 #define USB_DEVICE_ID_HUION_TABLET     0x006e
+#define USB_DEVICE_ID_HUION_HS64       0x006d
 
 #define USB_VENDOR_ID_IBM                                      0x04b3
 #define USB_DEVICE_ID_IBM_SCROLLPOINT_III                      0x3100
index e564bff..bfcf2ee 100644 (file)
@@ -30,6 +30,7 @@
 
 #define REPORT_ID_HIDPP_SHORT                  0x10
 #define REPORT_ID_HIDPP_LONG                   0x11
+#define REPORT_ID_HIDPP_VERY_LONG              0x12
 
 #define HIDPP_REPORT_SHORT_LENGTH              7
 #define HIDPP_REPORT_LONG_LENGTH               20
@@ -1242,7 +1243,8 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
        int ret;
 
        if ((buf[0] == REPORT_ID_HIDPP_SHORT) ||
-           (buf[0] == REPORT_ID_HIDPP_LONG)) {
+           (buf[0] == REPORT_ID_HIDPP_LONG) ||
+           (buf[0] == REPORT_ID_HIDPP_VERY_LONG)) {
                if (count < 2)
                        return -EINVAL;
 
index 5df5dd5..b603c14 100644 (file)
@@ -1776,6 +1776,10 @@ static const struct hid_device_id mt_devices[] = {
                HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
                        USB_VENDOR_ID_ALPS_JP,
                        HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) },
+       { .driver_data = MT_CLS_WIN_8_DUAL,
+               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+                       USB_VENDOR_ID_ALPS_JP,
+                       HID_DEVICE_ID_ALPS_1222) },
 
        /* Lenovo X1 TAB Gen 2 */
        { .driver_data = MT_CLS_WIN_8_DUAL,
index e5ca6fe..671a285 100644 (file)
@@ -42,6 +42,7 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD), HID_QUIRK_BADPAD },
        { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK), HID_QUIRK_NOGET },
index 8fe02d8..914fb52 100644 (file)
@@ -369,6 +369,8 @@ static const struct hid_device_id uclogic_devices[] = {
                                USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
                                USB_DEVICE_ID_HUION_TABLET) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
+                               USB_DEVICE_ID_HUION_HS64) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
                                USB_DEVICE_ID_HUION_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
index 0187c9f..273d784 100644 (file)
@@ -977,6 +977,8 @@ int uclogic_params_init(struct uclogic_params *params,
                /* FALL THROUGH */
        case VID_PID(USB_VENDOR_ID_HUION,
                     USB_DEVICE_ID_HUION_TABLET):
+       case VID_PID(USB_VENDOR_ID_HUION,
+                    USB_DEVICE_ID_HUION_HS64):
        case VID_PID(USB_VENDOR_ID_UCLOGIC,
                     USB_DEVICE_ID_HUION_TABLET):
        case VID_PID(USB_VENDOR_ID_UCLOGIC,
index 22ba214..aa2dbed 100644 (file)
@@ -816,9 +816,9 @@ static int load_fw_from_host(struct ishtp_cl_data *client_data)
                goto end_err_fw_release;
 
        release_firmware(fw);
-       kfree(filename);
        dev_info(cl_data_to_dev(client_data), "ISH firmware %s loaded\n",
                 filename);
+       kfree(filename);
        return 0;
 
 end_err_fw_release:
index c0487b3..6ba944b 100644 (file)
@@ -891,7 +891,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
  */
 static int hid_ishtp_cl_suspend(struct device *device)
 {
-       struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+       struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
        struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
        struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 
@@ -912,7 +912,7 @@ static int hid_ishtp_cl_suspend(struct device *device)
  */
 static int hid_ishtp_cl_resume(struct device *device)
 {
-       struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+       struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
        struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
        struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 
index 794e700..c47c332 100644 (file)
@@ -471,7 +471,6 @@ static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
        }
 
        ishtp_device_ready = true;
-       dev_set_drvdata(&device->dev, device);
 
        return device;
 }
@@ -640,6 +639,20 @@ void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device)
 EXPORT_SYMBOL(ishtp_get_drvdata);
 
 /**
+ * ishtp_dev_to_cl_device() - get ishtp_cl_device instance from device instance
+ * @device: device instance
+ *
+ * Get ish_cl_device instance which embeds device instance in it.
+ *
+ * Return: pointer to ishtp_cl_device instance
+ */
+struct ishtp_cl_device *ishtp_dev_to_cl_device(struct device *device)
+{
+       return to_ishtp_cl_device(device);
+}
+EXPORT_SYMBOL(ishtp_dev_to_cl_device);
+
+/**
  * ishtp_bus_new_client() - Create a new client
  * @dev:       ISHTP device instance
  *
index c67c961..a4c1aac 100644 (file)
@@ -89,8 +89,19 @@ static int csky_irq_set_affinity(struct irq_data *d,
        if (cpu >= nr_cpu_ids)
                return -EINVAL;
 
-       /* Enable interrupt destination */
-       cpu |= BIT(31);
+       /*
+        * The csky,mpintc could support auto irq deliver, but it only
+        * could deliver external irq to one cpu or all cpus. So it
+        * doesn't support deliver external irq to a group of cpus
+        * with cpu_mask.
+        * SO we only use auto deliver mode when affinity mask_val is
+        * equal to cpu_present_mask.
+        *
+        */
+       if (cpumask_equal(mask_val, cpu_present_mask))
+               cpu = 0;
+       else
+               cpu |= BIT(31);
 
        writel_relaxed(cpu, INTCG_base + INTCG_CIDSTR + offset);
 
index d29b44b..3550080 100644 (file)
@@ -733,32 +733,43 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
 }
 
 static int its_wait_for_range_completion(struct its_node *its,
-                                        struct its_cmd_block *from,
+                                        u64    prev_idx,
                                         struct its_cmd_block *to)
 {
-       u64 rd_idx, from_idx, to_idx;
+       u64 rd_idx, to_idx, linear_idx;
        u32 count = 1000000;    /* 1s! */
 
-       from_idx = its_cmd_ptr_to_offset(its, from);
+       /* Linearize to_idx if the command set has wrapped around */
        to_idx = its_cmd_ptr_to_offset(its, to);
+       if (to_idx < prev_idx)
+               to_idx += ITS_CMD_QUEUE_SZ;
+
+       linear_idx = prev_idx;
 
        while (1) {
+               s64 delta;
+
                rd_idx = readl_relaxed(its->base + GITS_CREADR);
 
-               /* Direct case */
-               if (from_idx < to_idx && rd_idx >= to_idx)
-                       break;
+               /*
+                * Compute the read pointer progress, taking the
+                * potential wrap-around into account.
+                */
+               delta = rd_idx - prev_idx;
+               if (rd_idx < prev_idx)
+                       delta += ITS_CMD_QUEUE_SZ;
 
-               /* Wrapped case */
-               if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx)
+               linear_idx += delta;
+               if (linear_idx >= to_idx)
                        break;
 
                count--;
                if (!count) {
-                       pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n",
-                                          from_idx, to_idx, rd_idx);
+                       pr_err_ratelimited("ITS queue timeout (%llu %llu)\n",
+                                          to_idx, linear_idx);
                        return -1;
                }
+               prev_idx = rd_idx;
                cpu_relax();
                udelay(1);
        }
@@ -775,6 +786,7 @@ void name(struct its_node *its,                                             \
        struct its_cmd_block *cmd, *sync_cmd, *next_cmd;                \
        synctype *sync_obj;                                             \
        unsigned long flags;                                            \
+       u64 rd_idx;                                                     \
                                                                        \
        raw_spin_lock_irqsave(&its->lock, flags);                       \
                                                                        \
@@ -796,10 +808,11 @@ void name(struct its_node *its,                                           \
        }                                                               \
                                                                        \
 post:                                                                  \
+       rd_idx = readl_relaxed(its->base + GITS_CREADR);                \
        next_cmd = its_post_commands(its);                              \
        raw_spin_unlock_irqrestore(&its->lock, flags);                  \
                                                                        \
-       if (its_wait_for_range_completion(its, cmd, next_cmd))          \
+       if (its_wait_for_range_completion(its, rd_idx, next_cmd))       \
                pr_err_ratelimited("ITS cmd %ps failed\n", builder);    \
 }
 
index d32268c..f398546 100644 (file)
@@ -388,7 +388,7 @@ static void gic_all_vpes_irq_cpu_online(struct irq_data *d)
        intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
        cd = irq_data_get_irq_chip_data(d);
 
-       write_gic_vl_map(intr, cd->map);
+       write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
        if (cd->mask)
                write_gic_vl_smask(BIT(intr));
 }
@@ -517,7 +517,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
        spin_lock_irqsave(&gic_lock, flags);
        for_each_online_cpu(cpu) {
                write_gic_vl_other(mips_cm_vp_id(cpu));
-               write_gic_vo_map(intr, map);
+               write_gic_vo_map(mips_gic_vx_map_reg(intr), map);
        }
        spin_unlock_irqrestore(&gic_lock, flags);
 
index 011b60a..ef4d625 100644 (file)
@@ -159,9 +159,9 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
        parent_fwspec.param[1] = vint_desc->vint_id;
 
        parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
-       if (parent_virq <= 0) {
+       if (parent_virq == 0) {
                kfree(vint_desc);
-               return ERR_PTR(parent_virq);
+               return ERR_PTR(-EINVAL);
        }
        vint_desc->parent_virq = parent_virq;
 
index 352e803..728733a 100644 (file)
@@ -140,8 +140,8 @@ static char __init *dm_parse_table_entry(struct dm_device *dev, char *str)
                return ERR_PTR(-EINVAL);
        }
        /* target_args */
-       dev->target_args_array[n] = kstrndup(field[3], GFP_KERNEL,
-                                            DM_MAX_STR_SIZE);
+       dev->target_args_array[n] = kstrndup(field[3], DM_MAX_STR_SIZE,
+                                            GFP_KERNEL);
        if (!dev->target_args_array[n])
                return ERR_PTR(-ENOMEM);
 
@@ -272,10 +272,10 @@ static int __init dm_init_init(void)
                return 0;
 
        if (strlen(create) >= DM_MAX_STR_SIZE) {
-               DMERR("Argument is too big. Limit is %d\n", DM_MAX_STR_SIZE);
+               DMERR("Argument is too big. Limit is %d", DM_MAX_STR_SIZE);
                return -EINVAL;
        }
-       str = kstrndup(create, GFP_KERNEL, DM_MAX_STR_SIZE);
+       str = kstrndup(create, DM_MAX_STR_SIZE, GFP_KERNEL);
        if (!str)
                return -ENOMEM;
 
@@ -283,7 +283,7 @@ static int __init dm_init_init(void)
        if (r)
                goto out;
 
-       DMINFO("waiting for all devices to be available before creating mapped devices\n");
+       DMINFO("waiting for all devices to be available before creating mapped devices");
        wait_for_device_probe();
 
        list_for_each_entry(dev, &devices, list) {
index 9ea2b02..e549392 100644 (file)
@@ -60,6 +60,7 @@
 
 #define WRITE_LOG_VERSION 1ULL
 #define WRITE_LOG_MAGIC 0x6a736677736872ULL
+#define WRITE_LOG_SUPER_SECTOR 0
 
 /*
  * The disk format for this is braindead simple.
@@ -115,6 +116,7 @@ struct log_writes_c {
        struct list_head logging_blocks;
        wait_queue_head_t wait;
        struct task_struct *log_kthread;
+       struct completion super_done;
 };
 
 struct pending_block {
@@ -180,6 +182,14 @@ static void log_end_io(struct bio *bio)
        bio_put(bio);
 }
 
+static void log_end_super(struct bio *bio)
+{
+       struct log_writes_c *lc = bio->bi_private;
+
+       complete(&lc->super_done);
+       log_end_io(bio);
+}
+
 /*
  * Meant to be called if there is an error, it will free all the pages
  * associated with the block.
@@ -215,7 +225,8 @@ static int write_metadata(struct log_writes_c *lc, void *entry,
        bio->bi_iter.bi_size = 0;
        bio->bi_iter.bi_sector = sector;
        bio_set_dev(bio, lc->logdev->bdev);
-       bio->bi_end_io = log_end_io;
+       bio->bi_end_io = (sector == WRITE_LOG_SUPER_SECTOR) ?
+                         log_end_super : log_end_io;
        bio->bi_private = lc;
        bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
 
@@ -418,11 +429,18 @@ static int log_super(struct log_writes_c *lc)
        super.nr_entries = cpu_to_le64(lc->logged_entries);
        super.sectorsize = cpu_to_le32(lc->sectorsize);
 
-       if (write_metadata(lc, &super, sizeof(super), NULL, 0, 0)) {
+       if (write_metadata(lc, &super, sizeof(super), NULL, 0,
+                          WRITE_LOG_SUPER_SECTOR)) {
                DMERR("Couldn't write super");
                return -1;
        }
 
+       /*
+        * Super sector should be writen in-order, otherwise the
+        * nr_entries could be rewritten incorrectly by an old bio.
+        */
+       wait_for_completion_io(&lc->super_done);
+
        return 0;
 }
 
@@ -531,6 +549,7 @@ static int log_writes_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        INIT_LIST_HEAD(&lc->unflushed_blocks);
        INIT_LIST_HEAD(&lc->logging_blocks);
        init_waitqueue_head(&lc->wait);
+       init_completion(&lc->super_done);
        atomic_set(&lc->io_blocks, 0);
        atomic_set(&lc->pending_blocks, 0);
 
index 350cf04..ec8b27e 100644 (file)
@@ -561,7 +561,7 @@ static char **realloc_argv(unsigned *size, char **old_argv)
                gfp = GFP_NOIO;
        }
        argv = kmalloc_array(new_size, sizeof(*argv), gfp);
-       if (argv) {
+       if (argv && old_argv) {
                memcpy(argv, old_argv, *size * sizeof(*argv));
                *size = new_size;
        }
index 720d065..ea24ff0 100644 (file)
@@ -235,8 +235,8 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
                BUG();
        }
 
-       DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
-               block);
+       DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
+                   type_str, block);
 
        if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
                DMERR("%s: reached maximum errors", v->data_dev->name);
index fe8efba..857991c 100644 (file)
@@ -204,12 +204,11 @@ static struct irq_chip stmfx_irq_chip = {
 static irqreturn_t stmfx_irq_handler(int irq, void *data)
 {
        struct stmfx *stmfx = data;
-       unsigned long n, pending;
-       u32 ack;
-       int ret;
+       unsigned long bits;
+       u32 pending, ack;
+       int n, ret;
 
-       ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING,
-                         (u32 *)&pending);
+       ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING, &pending);
        if (ret)
                return IRQ_NONE;
 
@@ -224,7 +223,8 @@ static irqreturn_t stmfx_irq_handler(int irq, void *data)
                        return IRQ_NONE;
        }
 
-       for_each_set_bit(n, &pending, STMFX_REG_IRQ_SRC_MAX)
+       bits = pending;
+       for_each_set_bit(n, &bits, STMFX_REG_IRQ_SRC_MAX)
                handle_nested_irq(irq_find_mapping(stmfx->irq_domain, n));
 
        return IRQ_HANDLED;
index b5b68aa..6eb1312 100644 (file)
@@ -4662,7 +4662,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
        memorg = nanddev_get_memorg(&chip->base);
        memorg->planes_per_lun = 1;
        memorg->luns_per_target = 1;
-       memorg->ntargets = 1;
 
        /*
         * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
@@ -5027,6 +5026,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
        if (ret)
                return ret;
 
+       memorg->ntargets = maxchips;
+
        /* Read the flash type */
        ret = nand_detect(chip, table);
        if (ret) {
index 73172d7..0c2ec1c 100644 (file)
@@ -1636,6 +1636,95 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
        return 0;
 }
 
+/**
+ * spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits.
+ * @nor:        pointer to a 'struct spi_nor'
+ *
+ * Read-modify-write function that clears the Block Protection bits from the
+ * Status Register without affecting other bits.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_clear_sr_bp(struct spi_nor *nor)
+{
+       int ret;
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+       ret = read_sr(nor);
+       if (ret < 0) {
+               dev_err(nor->dev, "error while reading status register\n");
+               return ret;
+       }
+
+       write_enable(nor);
+
+       ret = write_sr(nor, ret & ~mask);
+       if (ret) {
+               dev_err(nor->dev, "write to status register failed\n");
+               return ret;
+       }
+
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret)
+               dev_err(nor->dev, "timeout while writing status register\n");
+       return ret;
+}
+
+/**
+ * spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection
+ * bits on spansion flashes.
+ * @nor:        pointer to a 'struct spi_nor'
+ *
+ * Read-modify-write function that clears the Block Protection bits from the
+ * Status Register without affecting other bits. The function is tightly
+ * coupled with the spansion_quad_enable() function. Both assume that the Write
+ * Register with 16 bits, together with the Read Configuration Register (35h)
+ * instructions are supported.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
+{
+       int ret;
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+       u8 sr_cr[2] = {0};
+
+       /* Check current Quad Enable bit value. */
+       ret = read_cr(nor);
+       if (ret < 0) {
+               dev_err(nor->dev,
+                       "error while reading configuration register\n");
+               return ret;
+       }
+
+       /*
+        * When the configuration register Quad Enable bit is one, only the
+        * Write Status (01h) command with two data bytes may be used.
+        */
+       if (ret & CR_QUAD_EN_SPAN) {
+               sr_cr[1] = ret;
+
+               ret = read_sr(nor);
+               if (ret < 0) {
+                       dev_err(nor->dev,
+                               "error while reading status register\n");
+                       return ret;
+               }
+               sr_cr[0] = ret & ~mask;
+
+               ret = write_sr_cr(nor, sr_cr);
+               if (ret)
+                       dev_err(nor->dev, "16-bit write register failed\n");
+               return ret;
+       }
+
+       /*
+        * If the Quad Enable bit is zero, use the Write Status (01h) command
+        * with one data byte.
+        */
+       return spi_nor_clear_sr_bp(nor);
+}
+
 /* Used when the "_ext_id" is two bytes at most */
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
                .id = {                                                 \
@@ -3660,6 +3749,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
                default:
                        /* Kept only for backward compatibility purpose. */
                        params->quad_enable = spansion_quad_enable;
+                       if (nor->clear_sr_bp)
+                               nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
                        break;
                }
 
@@ -3912,17 +4003,13 @@ static int spi_nor_init(struct spi_nor *nor)
 {
        int err;
 
-       /*
-        * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
-        * with the software protection bits set
-        */
-       if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
-           JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
-           JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
-           nor->info->flags & SPI_NOR_HAS_LOCK) {
-               write_enable(nor);
-               write_sr(nor, 0);
-               spi_nor_wait_till_ready(nor);
+       if (nor->clear_sr_bp) {
+               err = nor->clear_sr_bp(nor);
+               if (err) {
+                       dev_err(nor->dev,
+                               "fail to clear block protection bits\n");
+                       return err;
+               }
        }
 
        if (nor->quad_enable) {
@@ -4047,6 +4134,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
        if (info->flags & SPI_S3AN)
                nor->flags |=  SNOR_F_READY_XSR_RDY;
 
+       /*
+        * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
+        * with the software protection bits set.
+        */
+       if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
+           JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
+           JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
+           nor->info->flags & SPI_NOR_HAS_LOCK)
+               nor->clear_sr_bp = spi_nor_clear_sr_bp;
+
        /* Parse the Serial Flash Discoverable Parameters table. */
        ret = spi_nor_init_params(nor, &params);
        if (ret)
index 407f409..799fc38 100644 (file)
@@ -4320,12 +4320,12 @@ void bond_setup(struct net_device *bond_dev)
        bond_dev->features |= NETIF_F_NETNS_LOCAL;
 
        bond_dev->hw_features = BOND_VLAN_FEATURES |
-                               NETIF_F_HW_VLAN_CTAG_TX |
                                NETIF_F_HW_VLAN_CTAG_RX |
                                NETIF_F_HW_VLAN_CTAG_FILTER;
 
        bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
        bond_dev->features |= bond_dev->hw_features;
+       bond_dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
 }
 
 /* Destroy a bonding device.
index f46086f..db91b21 100644 (file)
@@ -436,9 +436,9 @@ int ksz_switch_register(struct ksz_device *dev,
                return PTR_ERR(dev->reset_gpio);
 
        if (dev->reset_gpio) {
-               gpiod_set_value(dev->reset_gpio, 1);
+               gpiod_set_value_cansleep(dev->reset_gpio, 1);
                mdelay(10);
-               gpiod_set_value(dev->reset_gpio, 0);
+               gpiod_set_value_cansleep(dev->reset_gpio, 0);
        }
 
        mutex_init(&dev->dev_mutex);
@@ -487,7 +487,7 @@ void ksz_switch_remove(struct ksz_device *dev)
        dsa_unregister_switch(dev->ds);
 
        if (dev->reset_gpio)
-               gpiod_set_value(dev->reset_gpio, 1);
+               gpiod_set_value_cansleep(dev->reset_gpio, 1);
 
 }
 EXPORT_SYMBOL(ksz_switch_remove);
index 18bc035..1fff462 100644 (file)
@@ -843,9 +843,14 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
                return err;
 
        if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
-               if (hweight < AQ_VLAN_MAX_FILTERS)
-                       err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, true);
+               if (hweight < AQ_VLAN_MAX_FILTERS && hweight > 0) {
+                       err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw,
+                               !(aq_nic->packet_filter & IFF_PROMISC));
+                       aq_nic->aq_nic_cfg.is_vlan_force_promisc = false;
+               } else {
                /* otherwise left in promiscue mode */
+                       aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
+               }
        }
 
        return err;
@@ -866,6 +871,7 @@ int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic)
        if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl))
                return -EOPNOTSUPP;
 
+       aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
        err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
        if (err)
                return err;
index 0da5e16..41172fb 100644 (file)
@@ -126,6 +126,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
 
        cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
        cfg->features = cfg->aq_hw_caps->hw_features;
+       cfg->is_vlan_force_promisc = true;
 }
 
 static int aq_nic_update_link_status(struct aq_nic_s *self)
index eb2e3c7..0f22f5d 100644 (file)
@@ -35,6 +35,7 @@ struct aq_nic_cfg_s {
        u32 flow_control;
        u32 link_speed_msk;
        u32 wol;
+       bool is_vlan_force_promisc;
        u16 is_mc_list_enabled;
        u16 mc_list_count;
        bool is_autoneg;
index 1c7593d..13ac266 100644 (file)
@@ -778,8 +778,15 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
                                          unsigned int packet_filter)
 {
        unsigned int i = 0U;
+       struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
+
+       hw_atl_rpfl2promiscuous_mode_en_set(self,
+                                           IS_FILTER_ENABLED(IFF_PROMISC));
+
+       hw_atl_rpf_vlan_prom_mode_en_set(self,
+                                    IS_FILTER_ENABLED(IFF_PROMISC) ||
+                                    cfg->is_vlan_force_promisc);
 
-       hw_atl_rpfl2promiscuous_mode_en_set(self, IS_FILTER_ENABLED(IFF_PROMISC));
        hw_atl_rpfl2multicast_flr_en_set(self,
                                         IS_FILTER_ENABLED(IFF_ALLMULTI), 0);
 
@@ -788,13 +795,13 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
 
        hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST));
 
-       self->aq_nic_cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST);
+       cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST);
 
        for (i = HW_ATL_B0_MAC_MIN; i < HW_ATL_B0_MAC_MAX; ++i)
                hw_atl_rpfl2_uc_flr_en_set(self,
-                                          (self->aq_nic_cfg->is_mc_list_enabled &&
-                                   (i <= self->aq_nic_cfg->mc_list_count)) ?
-                                   1U : 0U, i);
+                                          (cfg->is_mc_list_enabled &&
+                                           (i <= cfg->mc_list_count)) ?
+                                          1U : 0U, i);
 
        return aq_hw_err_from_flags(self);
 }
@@ -1086,7 +1093,7 @@ static int hw_atl_b0_hw_vlan_set(struct aq_hw_s *self,
 static int hw_atl_b0_hw_vlan_ctrl(struct aq_hw_s *self, bool enable)
 {
        /* set promisc in case of disabing the vland filter */
-       hw_atl_rpf_vlan_prom_mode_en_set(self, !!!enable);
+       hw_atl_rpf_vlan_prom_mode_en_set(self, !enable);
 
        return aq_hw_err_from_flags(self);
 }
index 2375a13..262a28f 100644 (file)
@@ -4180,7 +4180,7 @@ static int macb_probe(struct platform_device *pdev)
        if (PTR_ERR(mac) == -EPROBE_DEFER) {
                err = -EPROBE_DEFER;
                goto err_out_free_netdev;
-       } else if (!IS_ERR(mac)) {
+       } else if (!IS_ERR_OR_NULL(mac)) {
                ether_addr_copy(bp->dev->dev_addr, mac);
        } else {
                macb_get_hwaddr(bp);
index 8a67851..492f876 100644 (file)
@@ -891,7 +891,7 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
                         u64 *data)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       int status;
+       int status, cnt;
        u8 link_status = 0;
 
        if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
@@ -902,6 +902,9 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
 
        memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
 
+       /* check link status before offline tests */
+       link_status = netif_carrier_ok(netdev);
+
        if (test->flags & ETH_TEST_FL_OFFLINE) {
                if (be_loopback_test(adapter, BE_MAC_LOOPBACK, &data[0]) != 0)
                        test->flags |= ETH_TEST_FL_FAILED;
@@ -922,13 +925,26 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
                test->flags |= ETH_TEST_FL_FAILED;
        }
 
-       status = be_cmd_link_status_query(adapter, NULL, &link_status, 0);
-       if (status) {
-               test->flags |= ETH_TEST_FL_FAILED;
-               data[4] = -1;
-       } else if (!link_status) {
+       /* link status was down prior to test */
+       if (!link_status) {
                test->flags |= ETH_TEST_FL_FAILED;
                data[4] = 1;
+               return;
+       }
+
+       for (cnt = 10; cnt; cnt--) {
+               status = be_cmd_link_status_query(adapter, NULL, &link_status,
+                                                 0);
+               if (status) {
+                       test->flags |= ETH_TEST_FL_FAILED;
+                       data[4] = -1;
+                       break;
+               }
+
+               if (link_status)
+                       break;
+
+               msleep_interruptible(500);
        }
 }
 
index 67f9bb6..9b036c8 100644 (file)
@@ -1057,7 +1057,7 @@ sis900_open(struct net_device *net_dev)
        sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
 
        /* Enable all known interrupts by setting the interrupt mask. */
-       sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+       sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
        sw32(cr, RxENA | sr32(cr));
        sw32(ier, IE);
 
@@ -1578,7 +1578,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
        sw32(txdp, sis_priv->tx_ring_dma);
 
        /* Enable all known interrupts by setting the interrupt mask. */
-       sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+       sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
 }
 
 /**
@@ -1618,7 +1618,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
                        spin_unlock_irqrestore(&sis_priv->lock, flags);
                        return NETDEV_TX_OK;
        }
-       sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
+       sis_priv->tx_ring[entry].cmdsts = (OWN | INTR | skb->len);
        sw32(cr, TxENA | sr32(cr));
 
        sis_priv->cur_tx ++;
@@ -1674,7 +1674,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
        do {
                status = sr32(isr);
 
-               if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
+               if ((status & (HIBERR|TxURN|TxERR|TxIDLE|TxDESC|RxORN|RxERR|RxOK)) == 0)
                        /* nothing intresting happened */
                        break;
                handled = 1;
@@ -1684,7 +1684,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
                        /* Rx interrupt */
                        sis900_rx(net_dev);
 
-               if (status & (TxURN | TxERR | TxIDLE))
+               if (status & (TxURN | TxERR | TxIDLE | TxDESC))
                        /* Tx interrupt */
                        sis900_finish_xmit(net_dev);
 
@@ -1896,8 +1896,8 @@ static void sis900_finish_xmit (struct net_device *net_dev)
 
                if (tx_status & OWN) {
                        /* The packet is not transmitted yet (owned by hardware) !
-                        * Note: the interrupt is generated only when Tx Machine
-                        * is idle, so this is an almost impossible case */
+                        * Note: this is an almost impossible condition
+                        * in case of TxDESC ('descriptor interrupt') */
                        break;
                }
 
@@ -2473,7 +2473,7 @@ static int sis900_resume(struct pci_dev *pci_dev)
        sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
 
        /* Enable all known interrupts by setting the interrupt mask. */
-       sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+       sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
        sw32(cr, RxENA | sr32(cr));
        sw32(ier, IE);
 
index 2dcdf76..0201596 100644 (file)
@@ -112,7 +112,7 @@ static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
                 * programmed with (2^32 â€“ <new_sec_value>)
                 */
                if (gmac4)
-                       sec = (100000000ULL - sec);
+                       sec = -sec;
 
                value = readl(ioaddr + PTP_TCR);
                if (value & PTP_TCR_TSCTRLSSR)
index 06dd51f..06358fe 100644 (file)
@@ -2947,12 +2947,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Manage tx mitigation */
        tx_q->tx_count_frames += nfrags + 1;
-       if (priv->tx_coal_frames <= tx_q->tx_count_frames) {
+       if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
+           !(priv->synopsys_id >= DWMAC_CORE_4_00 &&
+           (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+           priv->hwts_tx_en)) {
+               stmmac_tx_timer_arm(priv, queue);
+       } else {
+               tx_q->tx_count_frames = 0;
                stmmac_set_tx_ic(priv, desc);
                priv->xstats.tx_set_ic_bit++;
-               tx_q->tx_count_frames = 0;
-       } else {
-               stmmac_tx_timer_arm(priv, queue);
        }
 
        skb_tx_timestamp(skb);
@@ -3166,12 +3169,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
         * element in case of no SG.
         */
        tx_q->tx_count_frames += nfrags + 1;
-       if (priv->tx_coal_frames <= tx_q->tx_count_frames) {
+       if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
+           !(priv->synopsys_id >= DWMAC_CORE_4_00 &&
+           (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+           priv->hwts_tx_en)) {
+               stmmac_tx_timer_arm(priv, queue);
+       } else {
+               tx_q->tx_count_frames = 0;
                stmmac_set_tx_ic(priv, desc);
                priv->xstats.tx_set_ic_bit++;
-               tx_q->tx_count_frames = 0;
-       } else {
-               stmmac_tx_timer_arm(priv, queue);
        }
 
        skb_tx_timestamp(skb);
index ff61dd8..66c8e65 100644 (file)
@@ -63,6 +63,7 @@ MODULE_AUTHOR("Frank Cusack <fcusack@fcusack.com>");
 MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
+MODULE_SOFTDEP("pre: arc4");
 MODULE_VERSION("1.0.2");
 
 static unsigned int
index b48006e..36916bf 100644 (file)
@@ -2128,12 +2128,12 @@ static void team_setup(struct net_device *dev)
        dev->features |= NETIF_F_NETNS_LOCAL;
 
        dev->hw_features = TEAM_VLAN_FEATURES |
-                          NETIF_F_HW_VLAN_CTAG_TX |
                           NETIF_F_HW_VLAN_CTAG_RX |
                           NETIF_F_HW_VLAN_CTAG_FILTER;
 
        dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
        dev->features |= dev->hw_features;
+       dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
 }
 
 static int team_newlink(struct net *src_net, struct net_device *dev,
index d080f80..8b4ad10 100644 (file)
@@ -1482,7 +1482,7 @@ static int qmi_wwan_probe(struct usb_interface *intf,
         * different. Ignore the current interface if the number of endpoints
         * equals the number for the diag interface (two).
         */
-       info = (void *)&id->driver_info;
+       info = (void *)id->driver_info;
 
        if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) {
                if (desc->bNumEndpoints == 2)
index 11b9525..311b0cc 100644 (file)
@@ -350,8 +350,8 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
 {
        struct dst_entry *dst = skb_dst(skb);
        struct net_device *dev = dst->dev;
+       const struct in6_addr *nexthop;
        struct neighbour *neigh;
-       struct in6_addr *nexthop;
        int ret;
 
        nf_reset(skb);
index 98af9ec..ca37930 100644 (file)
@@ -859,7 +859,7 @@ static int pci_pm_suspend_noirq(struct device *dev)
                        pci_dev->bus->self->skip_bus_pm = true;
        }
 
-       if (pci_dev->skip_bus_pm && !pm_suspend_via_firmware()) {
+       if (pci_dev->skip_bus_pm && pm_suspend_no_platform()) {
                dev_dbg(dev, "PCI PM: Skipped\n");
                goto Fixup;
        }
@@ -914,10 +914,10 @@ static int pci_pm_resume_noirq(struct device *dev)
        /*
         * In the suspend-to-idle case, devices left in D0 during suspend will
         * stay in D0, so it is not necessary to restore or update their
-        * configuration here and attempting to put them into D0 again may
-        * confuse some firmware, so avoid doing that.
+        * configuration here and attempting to put them into D0 again is
+        * pointless, so avoid doing that.
         */
-       if (!pci_dev->skip_bus_pm || pm_suspend_via_firmware())
+       if (!(pci_dev->skip_bus_pm && pm_suspend_no_platform()))
                pci_pm_default_resume_early(pci_dev);
 
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
index f464f8c..7e526bc 100644 (file)
@@ -113,6 +113,8 @@ static void mtk_eint_mask(struct irq_data *d)
        void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
                                                eint->regs->mask_set);
 
+       eint->cur_mask[d->hwirq >> 5] &= ~mask;
+
        writel(mask, reg);
 }
 
@@ -123,6 +125,8 @@ static void mtk_eint_unmask(struct irq_data *d)
        void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
                                                eint->regs->mask_clr);
 
+       eint->cur_mask[d->hwirq >> 5] |= mask;
+
        writel(mask, reg);
 
        if (eint->dual_edge[d->hwirq])
@@ -217,19 +221,6 @@ static void mtk_eint_chip_write_mask(const struct mtk_eint *eint,
        }
 }
 
-static void mtk_eint_chip_read_mask(const struct mtk_eint *eint,
-                                   void __iomem *base, u32 *buf)
-{
-       int port;
-       void __iomem *reg;
-
-       for (port = 0; port < eint->hw->ports; port++) {
-               reg = base + eint->regs->mask + (port << 2);
-               buf[port] = ~readl_relaxed(reg);
-               /* Mask is 0 when irq is enabled, and 1 when disabled. */
-       }
-}
-
 static int mtk_eint_irq_request_resources(struct irq_data *d)
 {
        struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
@@ -318,7 +309,7 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
        struct irq_chip *chip = irq_desc_get_chip(desc);
        struct mtk_eint *eint = irq_desc_get_handler_data(desc);
        unsigned int status, eint_num;
-       int offset, index, virq;
+       int offset, mask_offset, index, virq;
        void __iomem *reg =  mtk_eint_get_offset(eint, 0, eint->regs->stat);
        int dual_edge, start_level, curr_level;
 
@@ -328,10 +319,24 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
                status = readl(reg);
                while (status) {
                        offset = __ffs(status);
+                       mask_offset = eint_num >> 5;
                        index = eint_num + offset;
                        virq = irq_find_mapping(eint->domain, index);
                        status &= ~BIT(offset);
 
+                       /*
+                        * If we get an interrupt on pin that was only required
+                        * for wake (but no real interrupt requested), mask the
+                        * interrupt (as would mtk_eint_resume do anyway later
+                        * in the resume sequence).
+                        */
+                       if (eint->wake_mask[mask_offset] & BIT(offset) &&
+                           !(eint->cur_mask[mask_offset] & BIT(offset))) {
+                               writel_relaxed(BIT(offset), reg -
+                                       eint->regs->stat +
+                                       eint->regs->mask_set);
+                       }
+
                        dual_edge = eint->dual_edge[index];
                        if (dual_edge) {
                                /*
@@ -370,7 +375,6 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
 
 int mtk_eint_do_suspend(struct mtk_eint *eint)
 {
-       mtk_eint_chip_read_mask(eint, eint->base, eint->cur_mask);
        mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
 
        return 0;
index 568ca96..3a23548 100644 (file)
@@ -771,6 +771,10 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
        if (ret < 0)
                goto fail;
 
+       ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
+       if (ret < 0)
+               goto fail;
+
        mcp->irq_controller =
                device_property_read_bool(dev, "interrupt-controller");
        if (mcp->irq && mcp->irq_controller) {
@@ -812,10 +816,6 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
                        goto fail;
        }
 
-       ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
-       if (ret < 0)
-               goto fail;
-
        if (one_regmap_config) {
                mcp->pinctrl_desc.name = devm_kasprintf(dev, GFP_KERNEL,
                                "mcp23xxx-pinctrl.%d", raw_chip_address);
index 3b4ca52..fb76fb2 100644 (file)
@@ -396,7 +396,7 @@ static int ocelot_pin_function_idx(struct ocelot_pinctrl *info,
        return -1;
 }
 
-#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32)))
+#define REG_ALT(msb, info, p) (OCELOT_GPIO_ALT0 * (info)->stride + 4 * ((msb) + ((info)->stride * ((p) / 32))))
 
 static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev,
                                 unsigned int selector, unsigned int group)
@@ -412,19 +412,21 @@ static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev,
 
        /*
         * f is encoded on two bits.
-        * bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of
-        * ALT1
+        * bit 0 of f goes in BIT(pin) of ALT[0], bit 1 of f goes in BIT(pin) of
+        * ALT[1]
         * This is racy because both registers can't be updated at the same time
         * but it doesn't matter much for now.
         */
-       regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT0, info, pin->pin),
+       regmap_update_bits(info->map, REG_ALT(0, info, pin->pin),
                           BIT(p), f << p);
-       regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT1, info, pin->pin),
+       regmap_update_bits(info->map, REG_ALT(1, info, pin->pin),
                           BIT(p), f << (p - 1));
 
        return 0;
 }
 
+#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32)))
+
 static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev,
                                     struct pinctrl_gpio_range *range,
                                     unsigned int pin, bool input)
@@ -432,7 +434,7 @@ static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev,
        struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
        unsigned int p = pin % 32;
 
-       regmap_update_bits(info->map, REG(OCELOT_GPIO_OE, info, p), BIT(p),
+       regmap_update_bits(info->map, REG(OCELOT_GPIO_OE, info, pin), BIT(p),
                           input ? 0 : BIT(p));
 
        return 0;
@@ -445,9 +447,9 @@ static int ocelot_gpio_request_enable(struct pinctrl_dev *pctldev,
        struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
        unsigned int p = offset % 32;
 
-       regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT0, info, offset),
+       regmap_update_bits(info->map, REG_ALT(0, info, offset),
                           BIT(p), 0);
-       regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT1, info, offset),
+       regmap_update_bits(info->map, REG_ALT(1, info, offset),
                           BIT(p), 0);
 
        return 0;
index ecee4b3..377b07b 100644 (file)
@@ -763,6 +763,7 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
        struct pvscsi_adapter *adapter = shost_priv(host);
        struct pvscsi_ctx *ctx;
        unsigned long flags;
+       unsigned char op;
 
        spin_lock_irqsave(&adapter->hw_lock, flags);
 
@@ -775,13 +776,14 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
        }
 
        cmd->scsi_done = done;
+       op = cmd->cmnd[0];
 
        dev_dbg(&cmd->device->sdev_gendev,
-               "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]);
+               "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op);
 
        spin_unlock_irqrestore(&adapter->hw_lock, flags);
 
-       pvscsi_kick_io(adapter, cmd->cmnd[0]);
+       pvscsi_kick_io(adapter, op);
 
        return 0;
 }
index d441bef..9150104 100644 (file)
@@ -275,9 +275,9 @@ static void afs_break_one_callback(struct afs_server *server,
                        struct afs_super_info *as = AFS_FS_S(cbi->sb);
                        struct afs_volume *volume = as->volume;
 
-                       write_lock(&volume->cb_break_lock);
+                       write_lock(&volume->cb_v_break_lock);
                        volume->cb_v_break++;
-                       write_unlock(&volume->cb_break_lock);
+                       write_unlock(&volume->cb_v_break_lock);
                } else {
                        data.volume = NULL;
                        data.fid = *fid;
index b42d9d0..18a50d4 100644 (file)
@@ -56,6 +56,16 @@ static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *paren
 }
 
 /*
+ * Set the file size and block count.  Estimate the number of 512 bytes blocks
+ * used, rounded up to nearest 1K for consistency with other AFS clients.
+ */
+static void afs_set_i_size(struct afs_vnode *vnode, u64 size)
+{
+       i_size_write(&vnode->vfs_inode, size);
+       vnode->vfs_inode.i_blocks = ((size + 1023) >> 10) << 1;
+}
+
+/*
  * Initialise an inode from the vnode status.
  */
 static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key,
@@ -124,12 +134,7 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key,
                return afs_protocol_error(NULL, -EBADMSG, afs_eproto_file_type);
        }
 
-       /*
-        * Estimate 512 bytes  blocks used, rounded up to nearest 1K
-        * for consistency with other AFS clients.
-        */
-       inode->i_blocks         = ((i_size_read(inode) + 1023) >> 10) << 1;
-       i_size_write(&vnode->vfs_inode, status->size);
+       afs_set_i_size(vnode, status->size);
 
        vnode->invalid_before   = status->data_version;
        inode_set_iversion_raw(&vnode->vfs_inode, status->data_version);
@@ -207,11 +212,13 @@ static void afs_apply_status(struct afs_fs_cursor *fc,
 
        if (expected_version &&
            *expected_version != status->data_version) {
-               kdebug("vnode modified %llx on {%llx:%llu} [exp %llx] %s",
-                      (unsigned long long) status->data_version,
-                      vnode->fid.vid, vnode->fid.vnode,
-                      (unsigned long long) *expected_version,
-                      fc->type ? fc->type->name : "???");
+               if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags))
+                       pr_warn("kAFS: vnode modified {%llx:%llu} %llx->%llx %s\n",
+                               vnode->fid.vid, vnode->fid.vnode,
+                               (unsigned long long)*expected_version,
+                               (unsigned long long)status->data_version,
+                               fc->type ? fc->type->name : "???");
+
                vnode->invalid_before = status->data_version;
                if (vnode->status.type == AFS_FTYPE_DIR) {
                        if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
@@ -230,7 +237,7 @@ static void afs_apply_status(struct afs_fs_cursor *fc,
 
        if (data_changed) {
                inode_set_iversion_raw(&vnode->vfs_inode, status->data_version);
-               i_size_write(&vnode->vfs_inode, status->size);
+               afs_set_i_size(vnode, status->size);
        }
 }
 
index 8a67bf7..7ee6352 100644 (file)
@@ -109,10 +109,8 @@ struct afs_call {
        struct rxrpc_call       *rxcall;        /* RxRPC call handle */
        struct key              *key;           /* security for this call */
        struct afs_net          *net;           /* The network namespace */
-       union {
-               struct afs_server       *server;
-               struct afs_vlserver     *vlserver;
-       };
+       struct afs_server       *server;        /* The fileserver record if fs op (pins ref) */
+       struct afs_vlserver     *vlserver;      /* The vlserver record if vl op */
        struct afs_cb_interest  *cbi;           /* Callback interest for server used */
        struct afs_vnode        *lvnode;        /* vnode being locked */
        void                    *request;       /* request data (first part) */
@@ -616,7 +614,7 @@ struct afs_volume {
        unsigned int            servers_seq;    /* Incremented each time ->servers changes */
 
        unsigned                cb_v_break;     /* Break-everything counter. */
-       rwlock_t                cb_break_lock;
+       rwlock_t                cb_v_break_lock;
 
        afs_voltype_t           type;           /* type of volume */
        short                   error;
index 08fdb39..1a41430 100644 (file)
@@ -43,6 +43,7 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
        atomic_set(&volume->usage, 1);
        INIT_LIST_HEAD(&volume->proc_link);
        rwlock_init(&volume->servers_lock);
+       rwlock_init(&volume->cb_v_break_lock);
        memcpy(volume->name, vldb->name, vldb->name_len + 1);
 
        slist = afs_alloc_server_list(params->cell, params->key, vldb, type_mask);
index 3490d1f..c1e581d 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -2095,6 +2095,7 @@ SYSCALL_DEFINE6(io_pgetevents,
        struct __aio_sigset     ksig = { NULL, };
        sigset_t                ksigmask, sigsaved;
        struct timespec64       ts;
+       bool interrupted;
        int ret;
 
        if (timeout && unlikely(get_timespec64(&ts, timeout)))
@@ -2108,8 +2109,10 @@ SYSCALL_DEFINE6(io_pgetevents,
                return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
-       restore_user_sigmask(ksig.sigmask, &sigsaved);
-       if (signal_pending(current) && !ret)
+
+       interrupted = signal_pending(current);
+       restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+       if (interrupted && !ret)
                ret = -ERESTARTNOHAND;
 
        return ret;
@@ -2128,6 +2131,7 @@ SYSCALL_DEFINE6(io_pgetevents_time32,
        struct __aio_sigset     ksig = { NULL, };
        sigset_t                ksigmask, sigsaved;
        struct timespec64       ts;
+       bool interrupted;
        int ret;
 
        if (timeout && unlikely(get_old_timespec32(&ts, timeout)))
@@ -2142,8 +2146,10 @@ SYSCALL_DEFINE6(io_pgetevents_time32,
                return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
-       restore_user_sigmask(ksig.sigmask, &sigsaved);
-       if (signal_pending(current) && !ret)
+
+       interrupted = signal_pending(current);
+       restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+       if (interrupted && !ret)
                ret = -ERESTARTNOHAND;
 
        return ret;
@@ -2193,6 +2199,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
        struct __compat_aio_sigset ksig = { NULL, };
        sigset_t ksigmask, sigsaved;
        struct timespec64 t;
+       bool interrupted;
        int ret;
 
        if (timeout && get_old_timespec32(&t, timeout))
@@ -2206,8 +2213,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
                return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
-       restore_user_sigmask(ksig.sigmask, &sigsaved);
-       if (signal_pending(current) && !ret)
+
+       interrupted = signal_pending(current);
+       restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+       if (interrupted && !ret)
                ret = -ERESTARTNOHAND;
 
        return ret;
@@ -2226,6 +2235,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
        struct __compat_aio_sigset ksig = { NULL, };
        sigset_t ksigmask, sigsaved;
        struct timespec64 t;
+       bool interrupted;
        int ret;
 
        if (timeout && get_timespec64(&t, timeout))
@@ -2239,8 +2249,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
                return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
-       restore_user_sigmask(ksig.sigmask, &sigsaved);
-       if (signal_pending(current) && !ret)
+
+       interrupted = signal_pending(current);
+       restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+       if (interrupted && !ret)
                ret = -ERESTARTNOHAND;
 
        return ret;
index 82a48e8..e4b59e7 100644 (file)
@@ -856,9 +856,14 @@ err:
 
 static int load_flat_shared_library(int id, struct lib_info *libs)
 {
+       /*
+        * This is a fake bprm struct; only the members "buf", "file" and
+        * "filename" are actually used.
+        */
        struct linux_binprm bprm;
        int res;
        char buf[16];
+       loff_t pos = 0;
 
        memset(&bprm, 0, sizeof(bprm));
 
@@ -872,25 +877,11 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
        if (IS_ERR(bprm.file))
                return res;
 
-       bprm.cred = prepare_exec_creds();
-       res = -ENOMEM;
-       if (!bprm.cred)
-               goto out;
-
-       /* We don't really care about recalculating credentials at this point
-        * as we're past the point of no return and are dealing with shared
-        * libraries.
-        */
-       bprm.called_set_creds = 1;
+       res = kernel_read(bprm.file, bprm.buf, BINPRM_BUF_SIZE, &pos);
 
-       res = prepare_binprm(&bprm);
-
-       if (!res)
+       if (res >= 0)
                res = load_flat_file(&bprm, libs, id, NULL);
 
-       abort_creds(bprm.cred);
-
-out:
        allow_write_access(bprm.file);
        fput(bprm.file);
 
index 6af2d0d..c8a9b89 100644 (file)
@@ -2121,9 +2121,10 @@ retry:
                if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
                        dout("build_path path+%d: %p SNAPDIR\n",
                             pos, temp);
-               } else if (stop_on_nosnap && inode &&
+               } else if (stop_on_nosnap && inode && dentry != temp &&
                           ceph_snap(inode) == CEPH_NOSNAP) {
                        spin_unlock(&temp->d_lock);
+                       pos++; /* get rid of any prepended '/' */
                        break;
                } else {
                        pos -= temp->d_name.len;
index c6f5131..4c74c76 100644 (file)
@@ -2325,7 +2325,7 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
 
        error = do_epoll_wait(epfd, events, maxevents, timeout);
 
-       restore_user_sigmask(sigmask, &sigsaved);
+       restore_user_sigmask(sigmask, &sigsaved, error == -EINTR);
 
        return error;
 }
@@ -2350,7 +2350,7 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
 
        err = do_epoll_wait(epfd, events, maxevents, timeout);
 
-       restore_user_sigmask(sigmask, &sigsaved);
+       restore_user_sigmask(sigmask, &sigsaved, err == -EINTR);
 
        return err;
 }
index df6542e..2bf21e2 100644 (file)
@@ -362,7 +362,7 @@ EXPORT_SYMBOL(inc_nlink);
 
 static void __address_space_init_once(struct address_space *mapping)
 {
-       xa_init_flags(&mapping->i_pages, XA_FLAGS_LOCK_IRQ);
+       xa_init_flags(&mapping->i_pages, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ACCOUNT);
        init_rwsem(&mapping->i_mmap_rwsem);
        INIT_LIST_HEAD(&mapping->private_list);
        spin_lock_init(&mapping->private_lock);
index 86a2bd7..4ef62a4 100644 (file)
@@ -579,6 +579,7 @@ static struct io_kiocb *io_get_req(struct io_ring_ctx *ctx,
                state->cur_req++;
        }
 
+       req->file = NULL;
        req->ctx = ctx;
        req->flags = 0;
        /* one is dropped after submission, the other at completion */
@@ -1801,10 +1802,8 @@ static int io_req_set_file(struct io_ring_ctx *ctx, const struct sqe_submit *s,
                req->sequence = ctx->cached_sq_head - 1;
        }
 
-       if (!io_op_needs_file(s->sqe)) {
-               req->file = NULL;
+       if (!io_op_needs_file(s->sqe))
                return 0;
-       }
 
        if (flags & IOSQE_FIXED_FILE) {
                if (unlikely(!ctx->user_files ||
@@ -2201,11 +2200,12 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
        }
 
        ret = wait_event_interruptible(ctx->wait, io_cqring_events(ring) >= min_events);
-       if (ret == -ERESTARTSYS)
-               ret = -EINTR;
 
        if (sig)
-               restore_user_sigmask(sig, &sigsaved);
+               restore_user_sigmask(sig, &sigsaved, ret == -ERESTARTSYS);
+
+       if (ret == -ERESTARTSYS)
+               ret = -EINTR;
 
        return READ_ONCE(ring->r.head) == READ_ONCE(ring->r.tail) ? ret : 0;
 }
index a809989..19f856f 100644 (file)
@@ -18,7 +18,7 @@
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS_LD
 
-static unsigned int dataserver_timeo = NFS_DEF_TCP_RETRANS;
+static unsigned int dataserver_timeo = NFS_DEF_TCP_TIMEO;
 static unsigned int dataserver_retrans;
 
 static bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg);
index 2edbb65..5518050 100644 (file)
@@ -462,7 +462,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                 * a program is not able to use ptrace(2) in that case. It is
                 * safe because the task has stopped executing permanently.
                 */
-               if (permitted && (task->flags & PF_DUMPCORE)) {
+               if (permitted && (task->flags & (PF_EXITING|PF_DUMPCORE))) {
                        if (try_get_task_stack(task)) {
                                eip = KSTK_EIP(task);
                                esp = KSTK_ESP(task);
index 9c8ca6c..255f675 100644 (file)
@@ -3077,8 +3077,7 @@ static const struct file_operations proc_tgid_base_operations = {
 
 struct pid *tgid_pidfd_to_pid(const struct file *file)
 {
-       if (!d_is_dir(file->f_path.dentry) ||
-           (file->f_op != &proc_tgid_base_operations))
+       if (file->f_op != &proc_tgid_base_operations)
                return ERR_PTR(-EBADF);
 
        return proc_pid(file_inode(file));
index 6cbc9ff..a4d8f6e 100644 (file)
@@ -758,10 +758,9 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
                return ret;
 
        ret = core_sys_select(n, inp, outp, exp, to);
+       restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND);
        ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
 
-       restore_user_sigmask(sigmask, &sigsaved);
-
        return ret;
 }
 
@@ -1106,8 +1105,7 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
 
        ret = do_sys_poll(ufds, nfds, to);
 
-       restore_user_sigmask(sigmask, &sigsaved);
-
+       restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
        /* We can restart this syscall, usually */
        if (ret == -EINTR)
                ret = -ERESTARTNOHAND;
@@ -1142,8 +1140,7 @@ SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds,
 
        ret = do_sys_poll(ufds, nfds, to);
 
-       restore_user_sigmask(sigmask, &sigsaved);
-
+       restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
        /* We can restart this syscall, usually */
        if (ret == -EINTR)
                ret = -ERESTARTNOHAND;
@@ -1350,10 +1347,9 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
                return ret;
 
        ret = compat_core_sys_select(n, inp, outp, exp, to);
+       restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND);
        ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
 
-       restore_user_sigmask(sigmask, &sigsaved);
-
        return ret;
 }
 
@@ -1425,8 +1421,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds,
 
        ret = do_sys_poll(ufds, nfds, to);
 
-       restore_user_sigmask(sigmask, &sigsaved);
-
+       restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
        /* We can restart this syscall, usually */
        if (ret == -EINTR)
                ret = -ERESTARTNOHAND;
@@ -1461,8 +1456,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds,
 
        ret = do_sys_poll(ufds, nfds, to);
 
-       restore_user_sigmask(sigmask, &sigsaved);
-
+       restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
        /* We can restart this syscall, usually */
        if (ret == -EINTR)
                ret = -ERESTARTNOHAND;
index 82c9e0c..e10470e 100644 (file)
 #define CLKID_MALI_1_SEL                       172
 #define CLKID_MALI_1                           174
 #define CLKID_MALI                             175
-#define CLKID_MPLL_5OM                         177
+#define CLKID_MPLL_50M                         177
 #define CLKID_CPU_CLK                          187
 #define CLKID_PCIE_PLL                         201
 #define CLKID_VDEC_1                           204
index 6a0b70a..3b21d05 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
 /*
  * Copyright (C) 2018-2019 SiFive, Inc.
  * Wesley Terpstra
index 16255c2..0d6b4bc 100644 (file)
@@ -103,6 +103,7 @@ void ishtp_put_device(struct ishtp_cl_device *cl_dev);
 void ishtp_get_device(struct ishtp_cl_device *cl_dev);
 void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data);
 void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device);
+struct ishtp_cl_device *ishtp_dev_to_cl_device(struct device *dev);
 int ishtp_register_event_cb(struct ishtp_cl_device *device,
                                void (*read_cb)(struct ishtp_cl_device *));
 struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
index 74b1ee9..0c9bc23 100644 (file)
@@ -93,7 +93,8 @@
 #define DIV_ROUND_DOWN_ULL(ll, d) \
        ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
 
-#define DIV_ROUND_UP_ULL(ll, d)                DIV_ROUND_DOWN_ULL((ll) + (d) - 1, (d))
+#define DIV_ROUND_UP_ULL(ll, d) \
+       DIV_ROUND_DOWN_ULL((unsigned long long)(ll) + (d) - 1, (d))
 
 #if BITS_PER_LONG == 32
 # define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d)
index b3d360b..9f57cdf 100644 (file)
@@ -373,6 +373,8 @@ struct flash_info;
  * @flash_unlock:      [FLASH-SPECIFIC] unlock a region of the SPI NOR
  * @flash_is_locked:   [FLASH-SPECIFIC] check if a region of the SPI NOR is
  * @quad_enable:       [FLASH-SPECIFIC] enables SPI NOR quad mode
+ * @clear_sr_bp:       [FLASH-SPECIFIC] clears the Block Protection Bits from
+ *                     the SPI NOR Status Register.
  *                     completely locked
  * @priv:              the private data
  */
@@ -410,6 +412,7 @@ struct spi_nor {
        int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
        int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
        int (*quad_enable)(struct spi_nor *nor);
+       int (*clear_sr_bp)(struct spi_nor *nor);
 
        void *priv;
 };
index 0ab99c7..2bca72f 100644 (file)
@@ -241,6 +241,7 @@ struct perf_event;
 #define PERF_PMU_CAP_NO_INTERRUPT              0x01
 #define PERF_PMU_CAP_NO_NMI                    0x02
 #define PERF_PMU_CAP_AUX_NO_SG                 0x04
+#define PERF_PMU_CAP_EXTENDED_REGS             0x08
 #define PERF_PMU_CAP_EXCLUSIVE                 0x10
 #define PERF_PMU_CAP_ITRACE                    0x20
 #define PERF_PMU_CAP_HETEROGENEOUS_CPUS                0x40
index 4767474..2d12e97 100644 (file)
@@ -11,6 +11,11 @@ struct perf_regs {
 
 #ifdef CONFIG_HAVE_PERF_REGS
 #include <asm/perf_regs.h>
+
+#ifndef PERF_REG_EXTENDED_MASK
+#define PERF_REG_EXTENDED_MASK 0
+#endif
+
 u64 perf_reg_value(struct pt_regs *regs, int idx);
 int perf_reg_validate(u64 mask);
 u64 perf_reg_abi(struct task_struct *task);
@@ -18,6 +23,9 @@ void perf_get_regs_user(struct perf_regs *regs_user,
                        struct pt_regs *regs,
                        struct pt_regs *regs_user_copy);
 #else
+
+#define PERF_REG_EXTENDED_MASK 0
+
 static inline u64 perf_reg_value(struct pt_regs *regs, int idx)
 {
        return 0;
index 7bb7785..3c202a1 100644 (file)
@@ -68,7 +68,7 @@ static inline phys_addr_t pfn_t_to_phys(pfn_t pfn)
 
 static inline void *pfn_t_to_virt(pfn_t pfn)
 {
-       if (pfn_t_has_page(pfn))
+       if (pfn_t_has_page(pfn) && !is_device_private_page(pfn_t_to_page(pfn)))
                return __va(pfn_t_to_phys(pfn));
        return NULL;
 }
index 9702016..78c2bb3 100644 (file)
@@ -276,7 +276,7 @@ extern int sigprocmask(int, sigset_t *, sigset_t *);
 extern int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set,
        sigset_t *oldset, size_t sigsetsize);
 extern void restore_user_sigmask(const void __user *usigmask,
-                                sigset_t *sigsaved);
+                                sigset_t *sigsaved, bool interrupted);
 extern void set_current_blocked(sigset_t *);
 extern void __set_current_blocked(const sigset_t *);
 extern int show_unhandled_signals;
index 8594001..f0d262a 100644 (file)
@@ -209,8 +209,9 @@ extern int suspend_valid_only_mem(suspend_state_t state);
 
 extern unsigned int pm_suspend_global_flags;
 
-#define PM_SUSPEND_FLAG_FW_SUSPEND     (1 << 0)
-#define PM_SUSPEND_FLAG_FW_RESUME      (1 << 1)
+#define PM_SUSPEND_FLAG_FW_SUSPEND     BIT(0)
+#define PM_SUSPEND_FLAG_FW_RESUME      BIT(1)
+#define PM_SUSPEND_FLAG_NO_PLATFORM    BIT(2)
 
 static inline void pm_suspend_clear_flags(void)
 {
@@ -227,6 +228,11 @@ static inline void pm_set_resume_via_firmware(void)
        pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME;
 }
 
+static inline void pm_set_suspend_no_platform(void)
+{
+       pm_suspend_global_flags |= PM_SUSPEND_FLAG_NO_PLATFORM;
+}
+
 /**
  * pm_suspend_via_firmware - Check if platform firmware will suspend the system.
  *
@@ -268,6 +274,22 @@ static inline bool pm_resume_via_firmware(void)
        return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME);
 }
 
+/**
+ * pm_suspend_no_platform - Check if platform may change device power states.
+ *
+ * To be called during system-wide power management transitions to sleep states
+ * or during the subsequent system-wide transitions back to the working state.
+ *
+ * Return 'true' if the power states of devices remain under full control of the
+ * kernel throughout the system-wide suspend and resume cycle in progress (that
+ * is, if a device is put into a certain power state during suspend, it can be
+ * expected to remain in that state during resume).
+ */
+static inline bool pm_suspend_no_platform(void)
+{
+       return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_NO_PLATFORM);
+}
+
 /* Suspend-to-idle state machnine. */
 enum s2idle_states {
        S2IDLE_STATE_NONE,      /* Not suspended/suspending. */
index 0e01e61..5921599 100644 (file)
@@ -265,6 +265,7 @@ enum xa_lock_type {
 #define XA_FLAGS_TRACK_FREE    ((__force gfp_t)4U)
 #define XA_FLAGS_ZERO_BUSY     ((__force gfp_t)8U)
 #define XA_FLAGS_ALLOC_WRAPPED ((__force gfp_t)16U)
+#define XA_FLAGS_ACCOUNT       ((__force gfp_t)32U)
 #define XA_FLAGS_MARK(mark)    ((__force gfp_t)((1U << __GFP_BITS_SHIFT) << \
                                                (__force unsigned)(mark)))
 
index 4790bea..ee7405e 100644 (file)
@@ -262,8 +262,8 @@ static inline bool ip6_sk_ignore_df(const struct sock *sk)
               inet6_sk(sk)->pmtudisc == IPV6_PMTUDISC_OMIT;
 }
 
-static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt,
-                                          struct in6_addr *daddr)
+static inline const struct in6_addr *rt6_nexthop(const struct rt6_info *rt,
+                                                const struct in6_addr *daddr)
 {
        if (rt->rt6i_flags & RTF_GATEWAY)
                return &rt->rt6i_gateway;
index 065b477..55ff71f 100644 (file)
@@ -221,6 +221,7 @@ void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
 struct rtable *rt_dst_alloc(struct net_device *dev,
                             unsigned int flags, u16 type,
                             bool nopolicy, bool noxfrm, bool will_cache);
+struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt);
 
 struct in_ifaddr;
 void fib_add_ifaddr(struct in_ifaddr *);
index 4a55ce6..53d96bc 100644 (file)
@@ -373,21 +373,6 @@ static inline bool tls_is_partially_sent_record(struct tls_context *ctx)
        return !!ctx->partially_sent_record;
 }
 
-static inline int tls_complete_pending_work(struct sock *sk,
-                                           struct tls_context *ctx,
-                                           int flags, long *timeo)
-{
-       int rc = 0;
-
-       if (unlikely(sk->sk_write_pending))
-               rc = wait_on_pending_writer(sk, timeo);
-
-       if (!rc && tls_is_partially_sent_record(ctx))
-               rc = tls_push_partial_record(sk, ctx, flags);
-
-       return rc;
-}
-
 static inline bool tls_is_pending_open_record(struct tls_context *tls_ctx)
 {
        return tls_ctx->pending_open_record_frags;
index c5188ff..bc88d6f 100644 (file)
@@ -173,10 +173,7 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
        if (snd_BUG_ON(!stream))
                return;
 
-       if (stream->direction == SND_COMPRESS_PLAYBACK)
-               stream->runtime->state = SNDRV_PCM_STATE_SETUP;
-       else
-               stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+       stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 
        wake_up(&stream->runtime->sleep);
 }
index c4299da..8719936 100644 (file)
@@ -252,6 +252,8 @@ struct hda_codec {
        unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */
        unsigned int force_pin_prefix:1; /* Add location prefix */
        unsigned int link_down_at_suspend:1; /* link down at runtime suspend */
+       unsigned int relaxed_resume:1;  /* don't resume forcibly for jack */
+
 #ifdef CONFIG_PM
        unsigned long power_on_acct;
        unsigned long power_off_acct;
@@ -271,9 +273,6 @@ struct hda_codec {
        unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */
        struct delayed_work jackpoll_work;
 
-       /* jack detection */
-       struct snd_array jacks;
-
        int depop_delay; /* depop delay in ms, -1 for default delay time */
 
        /* fix-up list */
index e834678..612a17e 100644 (file)
@@ -120,7 +120,7 @@ void snd_hdac_device_unregister(struct hdac_device *codec);
 int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name);
 int snd_hdac_codec_modalias(struct hdac_device *hdac, char *buf, size_t size);
 
-int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs);
+int snd_hdac_refresh_widgets(struct hdac_device *codec);
 
 unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid,
                               unsigned int verb, unsigned int parm);
@@ -358,6 +358,9 @@ struct hdac_bus {
        bool align_bdle_4k:1;           /* BDLE align 4K boundary */
        bool reverse_assign:1;          /* assign devices in reverse order */
        bool corbrp_self_clear:1;       /* CORBRP clears itself after reset */
+       bool polling_mode:1;
+
+       int poll_count;
 
        int bdl_pos_adj;                /* BDL position adjustment */
 
index ddc5396..76b7c3f 100644 (file)
@@ -450,6 +450,43 @@ static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_desc
        }
 }
 
+/*
+ * Extension Unit (XU) has almost compatible layout with Processing Unit, but
+ * on UAC2, it has a different bmControls size (bControlSize); it's 1 byte for
+ * XU while 2 bytes for PU.  The last iExtension field is a one-byte index as
+ * well as iProcessing field of PU.
+ */
+static inline __u8 uac_extension_unit_bControlSize(struct uac_processing_unit_descriptor *desc,
+                                                  int protocol)
+{
+       switch (protocol) {
+       case UAC_VERSION_1:
+               return desc->baSourceID[desc->bNrInPins + 4];
+       case UAC_VERSION_2:
+               return 1; /* in UAC2, this value is constant */
+       case UAC_VERSION_3:
+               return 4; /* in UAC3, this value is constant */
+       default:
+               return 1;
+       }
+}
+
+static inline __u8 uac_extension_unit_iExtension(struct uac_processing_unit_descriptor *desc,
+                                                int protocol)
+{
+       __u8 control_size = uac_extension_unit_bControlSize(desc, protocol);
+
+       switch (protocol) {
+       case UAC_VERSION_1:
+       case UAC_VERSION_2:
+       default:
+               return *(uac_processing_unit_bmControls(desc, protocol)
+                        + control_size);
+       case UAC_VERSION_3:
+               return 0; /* UAC3 does not have this field */
+       }
+}
+
 /* 4.5.2 Class-Specific AS Interface Descriptor */
 struct uac1_as_header_descriptor {
        __u8  bLength;                  /* in bytes: 7 */
index 178130f..c47dad0 100644 (file)
@@ -617,7 +617,7 @@ static inline void clean_rootfs(void)
 #endif /* CONFIG_BLK_DEV_RAM */
 
 #ifdef CONFIG_BLK_DEV_RAM
-static void populate_initrd_image(char *err)
+static void __init populate_initrd_image(char *err)
 {
        ssize_t written;
        int fd;
@@ -637,7 +637,7 @@ static void populate_initrd_image(char *err)
        ksys_close(fd);
 }
 #else
-static void populate_initrd_image(char *err)
+static void __init populate_initrd_image(char *err)
 {
        printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
 }
index 077fde6..ef1c565 100644 (file)
@@ -1964,6 +1964,9 @@ static ssize_t write_cpuhp_fail(struct device *dev,
        if (ret)
                return ret;
 
+       if (fail < CPUHP_OFFLINE || fail > CPUHP_ONLINE)
+               return -EINVAL;
+
        /*
         * Cannot fail STARTING/DYING callbacks.
         */
@@ -2339,6 +2342,9 @@ static int __init mitigations_parse_cmdline(char *arg)
                cpu_mitigations = CPU_MITIGATIONS_AUTO;
        else if (!strcmp(arg, "auto,nosmt"))
                cpu_mitigations = CPU_MITIGATIONS_AUTO_NOSMT;
+       else
+               pr_crit("Unsupported mitigations=%s, system may still be vulnerable\n",
+                       arg);
 
        return 0;
 }
index abbd4b3..f85929c 100644 (file)
@@ -5005,6 +5005,9 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
        if (perf_event_check_period(event, value))
                return -EINVAL;
 
+       if (!event->attr.freq && (value & (1ULL << 63)))
+               return -EINVAL;
+
        event_function_call(event, __perf_event_period, &value);
 
        return 0;
@@ -5923,7 +5926,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,
        if (user_mode(regs)) {
                regs_user->abi = perf_reg_abi(current);
                regs_user->regs = regs;
-       } else if (current->mm) {
+       } else if (!(current->flags & PF_KTHREAD)) {
                perf_get_regs_user(regs_user, regs, regs_user_copy);
        } else {
                regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
@@ -10033,6 +10036,12 @@ void perf_pmu_unregister(struct pmu *pmu)
 }
 EXPORT_SYMBOL_GPL(perf_pmu_unregister);
 
+static inline bool has_extended_regs(struct perf_event *event)
+{
+       return (event->attr.sample_regs_user & PERF_REG_EXTENDED_MASK) ||
+              (event->attr.sample_regs_intr & PERF_REG_EXTENDED_MASK);
+}
+
 static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
 {
        struct perf_event_context *ctx = NULL;
@@ -10064,12 +10073,16 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
                perf_event_ctx_unlock(event->group_leader, ctx);
 
        if (!ret) {
+               if (!(pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS) &&
+                   has_extended_regs(event))
+                       ret = -EOPNOTSUPP;
+
                if (pmu->capabilities & PERF_PMU_CAP_NO_EXCLUDE &&
-                               event_has_any_exclude_flag(event)) {
-                       if (event->destroy)
-                               event->destroy(event);
+                   event_has_any_exclude_flag(event))
                        ret = -EINVAL;
-               }
+
+               if (ret && event->destroy)
+                       event->destroy(event);
        }
 
        if (ret)
index 75675b9..6166790 100644 (file)
@@ -248,7 +248,11 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)
        struct page *page = alloc_pages_node(node, THREADINFO_GFP,
                                             THREAD_SIZE_ORDER);
 
-       return page ? page_address(page) : NULL;
+       if (likely(page)) {
+               tsk->stack = page_address(page);
+               return tsk->stack;
+       }
+       return NULL;
 #endif
 }
 
@@ -1712,31 +1716,6 @@ const struct file_operations pidfd_fops = {
 #endif
 };
 
-/**
- * pidfd_create() - Create a new pid file descriptor.
- *
- * @pid:  struct pid that the pidfd will reference
- *
- * This creates a new pid file descriptor with the O_CLOEXEC flag set.
- *
- * Note, that this function can only be called after the fd table has
- * been unshared to avoid leaking the pidfd to the new process.
- *
- * Return: On success, a cloexec pidfd is returned.
- *         On error, a negative errno number will be returned.
- */
-static int pidfd_create(struct pid *pid)
-{
-       int fd;
-
-       fd = anon_inode_getfd("[pidfd]", &pidfd_fops, get_pid(pid),
-                             O_RDWR | O_CLOEXEC);
-       if (fd < 0)
-               put_pid(pid);
-
-       return fd;
-}
-
 static void __delayed_free_task(struct rcu_head *rhp)
 {
        struct task_struct *tsk = container_of(rhp, struct task_struct, rcu);
@@ -1774,6 +1753,7 @@ static __latent_entropy struct task_struct *copy_process(
        int pidfd = -1, retval;
        struct task_struct *p;
        struct multiprocess_signals delayed;
+       struct file *pidfile = NULL;
 
        /*
         * Don't allow sharing the root directory with processes in a different
@@ -1822,8 +1802,6 @@ static __latent_entropy struct task_struct *copy_process(
        }
 
        if (clone_flags & CLONE_PIDFD) {
-               int reserved;
-
                /*
                 * - CLONE_PARENT_SETTID is useless for pidfds and also
                 *   parent_tidptr is used to return pidfds.
@@ -1834,16 +1812,6 @@ static __latent_entropy struct task_struct *copy_process(
                if (clone_flags &
                    (CLONE_DETACHED | CLONE_PARENT_SETTID | CLONE_THREAD))
                        return ERR_PTR(-EINVAL);
-
-               /*
-                * Verify that parent_tidptr is sane so we can potentially
-                * reuse it later.
-                */
-               if (get_user(reserved, parent_tidptr))
-                       return ERR_PTR(-EFAULT);
-
-               if (reserved != 0)
-                       return ERR_PTR(-EINVAL);
        }
 
        /*
@@ -2058,11 +2026,20 @@ static __latent_entropy struct task_struct *copy_process(
         * if the fd table isn't shared).
         */
        if (clone_flags & CLONE_PIDFD) {
-               retval = pidfd_create(pid);
+               retval = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
                if (retval < 0)
                        goto bad_fork_free_pid;
 
                pidfd = retval;
+
+               pidfile = anon_inode_getfile("[pidfd]", &pidfd_fops, pid,
+                                             O_RDWR | O_CLOEXEC);
+               if (IS_ERR(pidfile)) {
+                       put_unused_fd(pidfd);
+                       goto bad_fork_free_pid;
+               }
+               get_pid(pid);   /* held by pidfile now */
+
                retval = put_user(pidfd, parent_tidptr);
                if (retval)
                        goto bad_fork_put_pidfd;
@@ -2180,6 +2157,9 @@ static __latent_entropy struct task_struct *copy_process(
                goto bad_fork_cancel_cgroup;
        }
 
+       /* past the last point of failure */
+       if (pidfile)
+               fd_install(pidfd, pidfile);
 
        init_task_pid_links(p);
        if (likely(p->pid)) {
@@ -2246,8 +2226,10 @@ bad_fork_cancel_cgroup:
 bad_fork_cgroup_threadgroup_change_end:
        cgroup_threadgroup_change_end(current);
 bad_fork_put_pidfd:
-       if (clone_flags & CLONE_PIDFD)
-               ksys_close(pidfd);
+       if (clone_flags & CLONE_PIDFD) {
+               fput(pidfile);
+               put_unused_fd(pidfd);
+       }
 bad_fork_free_pid:
        if (pid != &init_struct_pid)
                free_pid(pid);
index 9505101..0962112 100644 (file)
@@ -493,6 +493,9 @@ int suspend_devices_and_enter(suspend_state_t state)
 
        pm_suspend_target_state = state;
 
+       if (state == PM_SUSPEND_TO_IDLE)
+               pm_set_suspend_no_platform();
+
        error = platform_suspend_begin(state);
        if (error)
                goto Close;
index d622eac..edf8915 100644 (file)
@@ -2912,7 +2912,8 @@ EXPORT_SYMBOL(set_compat_user_sigmask);
  * This is useful for syscalls such as ppoll, pselect, io_pgetevents and
  * epoll_pwait where a new sigmask is passed in from userland for the syscalls.
  */
-void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)
+void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved,
+                               bool interrupted)
 {
 
        if (!usigmask)
@@ -2922,7 +2923,7 @@ void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)
         * Restoring sigmask here can lead to delivering signals that the above
         * syscalls are intended to block because of the sigmask passed in.
         */
-       if (signal_pending(current)) {
+       if (interrupted) {
                current->saved_sigmask = *sigsaved;
                set_restore_sigmask();
                return;
index c34e256..66a3748 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -228,11 +228,21 @@ void *idr_get_next(struct idr *idr, int *nextid)
 {
        struct radix_tree_iter iter;
        void __rcu **slot;
+       void *entry = NULL;
        unsigned long base = idr->idr_base;
        unsigned long id = *nextid;
 
        id = (id < base) ? 0 : id - base;
-       slot = radix_tree_iter_find(&idr->idr_rt, &iter, id);
+       radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, id) {
+               entry = rcu_dereference_raw(*slot);
+               if (!entry)
+                       continue;
+               if (!xa_is_internal(entry))
+                       break;
+               if (slot != &idr->idr_rt.xa_head && !xa_is_retry(entry))
+                       break;
+               slot = radix_tree_iter_retry(&iter);
+       }
        if (!slot)
                return NULL;
        id = iter.index + base;
@@ -241,7 +251,7 @@ void *idr_get_next(struct idr *idr, int *nextid)
                return NULL;
 
        *nextid = id;
-       return rcu_dereference_raw(*slot);
+       return entry;
 }
 EXPORT_SYMBOL(idr_get_next);
 
index 5d4bad8..9d631a7 100644 (file)
@@ -38,6 +38,12 @@ static void *xa_store_index(struct xarray *xa, unsigned long index, gfp_t gfp)
        return xa_store(xa, index, xa_mk_index(index), gfp);
 }
 
+static void xa_insert_index(struct xarray *xa, unsigned long index)
+{
+       XA_BUG_ON(xa, xa_insert(xa, index, xa_mk_index(index),
+                               GFP_KERNEL) != 0);
+}
+
 static void xa_alloc_index(struct xarray *xa, unsigned long index, gfp_t gfp)
 {
        u32 id;
@@ -338,6 +344,37 @@ static noinline void check_xa_shrink(struct xarray *xa)
        }
 }
 
+static noinline void check_insert(struct xarray *xa)
+{
+       unsigned long i;
+
+       for (i = 0; i < 1024; i++) {
+               xa_insert_index(xa, i);
+               XA_BUG_ON(xa, xa_load(xa, i - 1) != NULL);
+               XA_BUG_ON(xa, xa_load(xa, i + 1) != NULL);
+               xa_erase_index(xa, i);
+       }
+
+       for (i = 10; i < BITS_PER_LONG; i++) {
+               xa_insert_index(xa, 1UL << i);
+               XA_BUG_ON(xa, xa_load(xa, (1UL << i) - 1) != NULL);
+               XA_BUG_ON(xa, xa_load(xa, (1UL << i) + 1) != NULL);
+               xa_erase_index(xa, 1UL << i);
+
+               xa_insert_index(xa, (1UL << i) - 1);
+               XA_BUG_ON(xa, xa_load(xa, (1UL << i) - 2) != NULL);
+               XA_BUG_ON(xa, xa_load(xa, 1UL << i) != NULL);
+               xa_erase_index(xa, (1UL << i) - 1);
+       }
+
+       xa_insert_index(xa, ~0UL);
+       XA_BUG_ON(xa, xa_load(xa, 0UL) != NULL);
+       XA_BUG_ON(xa, xa_load(xa, ~1UL) != NULL);
+       xa_erase_index(xa, ~0UL);
+
+       XA_BUG_ON(xa, !xa_empty(xa));
+}
+
 static noinline void check_cmpxchg(struct xarray *xa)
 {
        void *FIVE = xa_mk_value(5);
@@ -1527,6 +1564,7 @@ static int xarray_checks(void)
        check_xa_mark(&array);
        check_xa_shrink(&array);
        check_xas_erase(&array);
+       check_insert(&array);
        check_cmpxchg(&array);
        check_reserve(&array);
        check_reserve(&xa0);
index 6be3acb..446b956 100644 (file)
@@ -298,6 +298,8 @@ bool xas_nomem(struct xa_state *xas, gfp_t gfp)
                xas_destroy(xas);
                return false;
        }
+       if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
+               gfp |= __GFP_ACCOUNT;
        xas->xa_alloc = kmem_cache_alloc(radix_tree_node_cachep, gfp);
        if (!xas->xa_alloc)
                return false;
@@ -325,6 +327,8 @@ static bool __xas_nomem(struct xa_state *xas, gfp_t gfp)
                xas_destroy(xas);
                return false;
        }
+       if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
+               gfp |= __GFP_ACCOUNT;
        if (gfpflags_allow_blocking(gfp)) {
                xas_unlock_type(xas, lock_type);
                xas->xa_alloc = kmem_cache_alloc(radix_tree_node_cachep, gfp);
@@ -358,8 +362,12 @@ static void *xas_alloc(struct xa_state *xas, unsigned int shift)
        if (node) {
                xas->xa_alloc = NULL;
        } else {
-               node = kmem_cache_alloc(radix_tree_node_cachep,
-                                       GFP_NOWAIT | __GFP_NOWARN);
+               gfp_t gfp = GFP_NOWAIT | __GFP_NOWARN;
+
+               if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
+                       gfp |= __GFP_ACCOUNT;
+
+               node = kmem_cache_alloc(radix_tree_node_cachep, gfp);
                if (!node) {
                        xas_set_err(xas, -ENOMEM);
                        return NULL;
index ac843d3..ede7e7f 100644 (file)
@@ -1510,16 +1510,29 @@ static int free_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed,
 
 /*
  * Dissolve a given free hugepage into free buddy pages. This function does
- * nothing for in-use (including surplus) hugepages. Returns -EBUSY if the
- * dissolution fails because a give page is not a free hugepage, or because
- * free hugepages are fully reserved.
+ * nothing for in-use hugepages and non-hugepages.
+ * This function returns values like below:
+ *
+ *  -EBUSY: failed to dissolved free hugepages or the hugepage is in-use
+ *          (allocated or reserved.)
+ *       0: successfully dissolved free hugepages or the page is not a
+ *          hugepage (considered as already dissolved)
  */
 int dissolve_free_huge_page(struct page *page)
 {
        int rc = -EBUSY;
 
+       /* Not to disrupt normal path by vainly holding hugetlb_lock */
+       if (!PageHuge(page))
+               return 0;
+
        spin_lock(&hugetlb_lock);
-       if (PageHuge(page) && !page_count(page)) {
+       if (!PageHuge(page)) {
+               rc = 0;
+               goto out;
+       }
+
+       if (!page_count(page)) {
                struct page *head = compound_head(page);
                struct hstate *h = page_hstate(head);
                int nid = page_to_nid(head);
@@ -1564,11 +1577,9 @@ int dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
 
        for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order) {
                page = pfn_to_page(pfn);
-               if (PageHuge(page) && !page_count(page)) {
-                       rc = dissolve_free_huge_page(page);
-                       if (rc)
-                               break;
-               }
+               rc = dissolve_free_huge_page(page);
+               if (rc)
+                       break;
        }
 
        return rc;
index 8da0334..d9cc660 100644 (file)
@@ -1730,6 +1730,8 @@ static int soft_offline_huge_page(struct page *page, int flags)
                if (!ret) {
                        if (set_hwpoison_free_buddy_page(page))
                                num_poisoned_pages_inc();
+                       else
+                               ret = -EBUSY;
                }
        }
        return ret;
@@ -1854,11 +1856,8 @@ static int soft_offline_in_use_page(struct page *page, int flags)
 
 static int soft_offline_free_page(struct page *page)
 {
-       int rc = 0;
-       struct page *head = compound_head(page);
+       int rc = dissolve_free_huge_page(page);
 
-       if (PageHuge(head))
-               rc = dissolve_free_huge_page(page);
        if (!rc) {
                if (set_hwpoison_free_buddy_page(page))
                        num_poisoned_pages_inc();
index 01600d8..fdcb735 100644 (file)
@@ -306,7 +306,7 @@ static void mpol_rebind_nodemask(struct mempolicy *pol, const nodemask_t *nodes)
        else {
                nodes_remap(tmp, pol->v.nodes,pol->w.cpuset_mems_allowed,
                                                                *nodes);
-               pol->w.cpuset_mems_allowed = tmp;
+               pol->w.cpuset_mems_allowed = *nodes;
        }
 
        if (nodes_empty(tmp))
index 5a58778..f719b64 100644 (file)
@@ -987,8 +987,7 @@ static void oom_kill_process(struct oom_control *oc, const char *message)
 /*
  * Determines whether the kernel must panic because of the panic_on_oom sysctl.
  */
-static void check_panic_on_oom(struct oom_control *oc,
-                              enum oom_constraint constraint)
+static void check_panic_on_oom(struct oom_control *oc)
 {
        if (likely(!sysctl_panic_on_oom))
                return;
@@ -998,7 +997,7 @@ static void check_panic_on_oom(struct oom_control *oc,
                 * does not panic for cpuset, mempolicy, or memcg allocation
                 * failures.
                 */
-               if (constraint != CONSTRAINT_NONE)
+               if (oc->constraint != CONSTRAINT_NONE)
                        return;
        }
        /* Do not panic for oom kills triggered by sysrq */
@@ -1035,7 +1034,6 @@ EXPORT_SYMBOL_GPL(unregister_oom_notifier);
 bool out_of_memory(struct oom_control *oc)
 {
        unsigned long freed = 0;
-       enum oom_constraint constraint = CONSTRAINT_NONE;
 
        if (oom_killer_disabled)
                return false;
@@ -1071,10 +1069,10 @@ bool out_of_memory(struct oom_control *oc)
         * Check if there were limitations on the allocation (only relevant for
         * NUMA and memcg) that may require different handling.
         */
-       constraint = constrained_alloc(oc);
-       if (constraint != CONSTRAINT_MEMORY_POLICY)
+       oc->constraint = constrained_alloc(oc);
+       if (oc->constraint != CONSTRAINT_MEMORY_POLICY)
                oc->nodemask = NULL;
-       check_panic_on_oom(oc, constraint);
+       check_panic_on_oom(oc);
 
        if (!is_memcg_oom(oc) && sysctl_oom_kill_allocating_task &&
            current->mm && !oom_unkillable_task(current, NULL, oc->nodemask) &&
index 0b39ec0..2955124 100644 (file)
@@ -136,7 +136,7 @@ static ssize_t page_idle_bitmap_read(struct file *file, struct kobject *kobj,
 
        end_pfn = pfn + count * BITS_PER_BYTE;
        if (end_pfn > max_pfn)
-               end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS);
+               end_pfn = max_pfn;
 
        for (; pfn < end_pfn; pfn++) {
                bit = pfn % BITMAP_CHUNK_BITS;
@@ -181,7 +181,7 @@ static ssize_t page_idle_bitmap_write(struct file *file, struct kobject *kobj,
 
        end_pfn = pfn + count * BITS_PER_BYTE;
        if (end_pfn > max_pfn)
-               end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS);
+               end_pfn = max_pfn;
 
        for (; pfn < end_pfn; pfn++) {
                bit = pfn % BITMAP_CHUNK_BITS;
index 2e8019d..1894158 100644 (file)
 static struct bio *get_swap_bio(gfp_t gfp_flags,
                                struct page *page, bio_end_io_t end_io)
 {
-       int i, nr = hpage_nr_pages(page);
        struct bio *bio;
 
-       bio = bio_alloc(gfp_flags, nr);
+       bio = bio_alloc(gfp_flags, 1);
        if (bio) {
                struct block_device *bdev;
 
@@ -41,9 +40,7 @@ static struct bio *get_swap_bio(gfp_t gfp_flags,
                bio->bi_iter.bi_sector <<= PAGE_SHIFT - 9;
                bio->bi_end_io = end_io;
 
-               for (i = 0; i < nr; i++)
-                       bio_add_page(bio, page + i, PAGE_SIZE, 0);
-               VM_BUG_ON(bio->bi_iter.bi_size != PAGE_SIZE * nr);
+               bio_add_page(bio, page, PAGE_SIZE * hpage_nr_pages(page), 0);
        }
        return bio;
 }
index 4c9e150..0f76cca 100644 (file)
@@ -913,7 +913,7 @@ adjust_va_to_fit_type(struct vmap_area *va,
        unsigned long nva_start_addr, unsigned long size,
        enum fit_type type)
 {
-       struct vmap_area *lva;
+       struct vmap_area *lva = NULL;
 
        if (type == FL_FIT_TYPE) {
                /*
@@ -972,7 +972,7 @@ adjust_va_to_fit_type(struct vmap_area *va,
        if (type != FL_FIT_TYPE) {
                augment_tree_propagate_from(va);
 
-               if (type == NE_FIT_TYPE)
+               if (lva)        /* type == NE_FIT_TYPE */
                        insert_vmap_area_augment(lva, &va->rb_node,
                                &free_vmap_area_root, &free_vmap_area_list);
        }
index 19d27be..1555b0c 100644 (file)
@@ -160,10 +160,10 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev,
                                                  struct in6_addr *daddr,
                                                  struct sk_buff *skb)
 {
-       struct lowpan_peer *peer;
-       struct in6_addr *nexthop;
        struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
        int count = atomic_read(&dev->peer_count);
+       const struct in6_addr *nexthop;
+       struct lowpan_peer *peer;
 
        BT_DBG("peers %d addr %pI6c rt %p", count, daddr, rt);
 
index 16f9159..8c2ec35 100644 (file)
@@ -318,6 +318,7 @@ static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *sk
 static int ip_mc_finish_output(struct net *net, struct sock *sk,
                               struct sk_buff *skb)
 {
+       struct rtable *new_rt;
        int ret;
 
        ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
@@ -326,6 +327,17 @@ static int ip_mc_finish_output(struct net *net, struct sock *sk,
                return ret;
        }
 
+       /* Reset rt_iif so that inet_iif() will return skb->skb_iif. Setting
+        * this to non-zero causes ipi_ifindex in in_pktinfo to be overwritten,
+        * see ipv4_pktinfo_prepare().
+        */
+       new_rt = rt_dst_clone(net->loopback_dev, skb_rtable(skb));
+       if (new_rt) {
+               new_rt->rt_iif = 0;
+               skb_dst_drop(skb);
+               skb_dst_set(skb, &new_rt->dst);
+       }
+
        return dev_loopback_xmit(net, sk, skb);
 }
 
index 0b8e06c..40a6abb 100644 (file)
@@ -197,7 +197,7 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
                }
                sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol,
                                     iph->saddr, iph->daddr,
-                                    skb->dev->ifindex, sdif);
+                                    dif, sdif);
        }
 out:
        read_unlock(&raw_v4_hashinfo.lock);
index 6cb7cff..8ea0735 100644 (file)
@@ -1647,6 +1647,39 @@ struct rtable *rt_dst_alloc(struct net_device *dev,
 }
 EXPORT_SYMBOL(rt_dst_alloc);
 
+struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt)
+{
+       struct rtable *new_rt;
+
+       new_rt = dst_alloc(&ipv4_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK,
+                          rt->dst.flags);
+
+       if (new_rt) {
+               new_rt->rt_genid = rt_genid_ipv4(dev_net(dev));
+               new_rt->rt_flags = rt->rt_flags;
+               new_rt->rt_type = rt->rt_type;
+               new_rt->rt_is_input = rt->rt_is_input;
+               new_rt->rt_iif = rt->rt_iif;
+               new_rt->rt_pmtu = rt->rt_pmtu;
+               new_rt->rt_mtu_locked = rt->rt_mtu_locked;
+               new_rt->rt_gw_family = rt->rt_gw_family;
+               if (rt->rt_gw_family == AF_INET)
+                       new_rt->rt_gw4 = rt->rt_gw4;
+               else if (rt->rt_gw_family == AF_INET6)
+                       new_rt->rt_gw6 = rt->rt_gw6;
+               INIT_LIST_HEAD(&new_rt->rt_uncached);
+
+               new_rt->dst.flags |= DST_HOST;
+               new_rt->dst.input = rt->dst.input;
+               new_rt->dst.output = rt->dst.output;
+               new_rt->dst.error = rt->dst.error;
+               new_rt->dst.lastuse = jiffies;
+               new_rt->dst.lwtstate = lwtstate_get(rt->dst.lwtstate);
+       }
+       return new_rt;
+}
+EXPORT_SYMBOL(rt_dst_clone);
+
 /* called in rcu_read_lock() section */
 int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
                          u8 tos, struct net_device *dev,
index 8344757..21efcd0 100644 (file)
@@ -59,8 +59,8 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
 {
        struct dst_entry *dst = skb_dst(skb);
        struct net_device *dev = dst->dev;
+       const struct in6_addr *nexthop;
        struct neighbour *neigh;
-       struct in6_addr *nexthop;
        int ret;
 
        if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
index 11ad62e..97a843c 100644 (file)
@@ -218,7 +218,8 @@ static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
 {
        const struct rt6_info *rt = container_of(dst, struct rt6_info, dst);
 
-       return ip6_neigh_lookup(&rt->rt6i_gateway, dst->dev, skb, daddr);
+       return ip6_neigh_lookup(rt6_nexthop(rt, &in6addr_any),
+                               dst->dev, skb, daddr);
 }
 
 static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
@@ -5281,7 +5282,7 @@ static struct ctl_table ipv6_route_table_template[] = {
                .data           =       &init_net.ipv6.sysctl.skip_notify_on_dev_down,
                .maxlen         =       sizeof(int),
                .mode           =       0644,
-               .proc_handler   =       proc_dointvec,
+               .proc_handler   =       proc_dointvec_minmax,
                .extra1         =       &zero,
                .extra2         =       &one,
        },
index 2413174..cdfc335 100644 (file)
@@ -439,9 +439,9 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
        struct nf_flowtable *flow_table = priv;
        struct flow_offload_tuple tuple = {};
        enum flow_offload_tuple_dir dir;
+       const struct in6_addr *nexthop;
        struct flow_offload *flow;
        struct net_device *outdev;
-       struct in6_addr *nexthop;
        struct ipv6hdr *ip6h;
        struct rt6_info *rt;
 
index a29d66d..5f78df0 100644 (file)
@@ -2401,6 +2401,9 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
 
                ts = __packet_set_timestamp(po, ph, skb);
                __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts);
+
+               if (!packet_read_pending(&po->tx_ring))
+                       complete(&po->skb_completion);
        }
 
        sock_wfree(skb);
@@ -2585,7 +2588,7 @@ static int tpacket_parse_header(struct packet_sock *po, void *frame,
 
 static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
 {
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
        struct net_device *dev;
        struct virtio_net_hdr *vnet_hdr = NULL;
        struct sockcm_cookie sockc;
@@ -2600,6 +2603,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        int len_sum = 0;
        int status = TP_STATUS_AVAILABLE;
        int hlen, tlen, copylen = 0;
+       long timeo = 0;
 
        mutex_lock(&po->pg_vec_lock);
 
@@ -2646,12 +2650,21 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        if ((size_max > dev->mtu + reserve + VLAN_HLEN) && !po->has_vnet_hdr)
                size_max = dev->mtu + reserve + VLAN_HLEN;
 
+       reinit_completion(&po->skb_completion);
+
        do {
                ph = packet_current_frame(po, &po->tx_ring,
                                          TP_STATUS_SEND_REQUEST);
                if (unlikely(ph == NULL)) {
-                       if (need_wait && need_resched())
-                               schedule();
+                       if (need_wait && skb) {
+                               timeo = sock_sndtimeo(&po->sk, msg->msg_flags & MSG_DONTWAIT);
+                               timeo = wait_for_completion_interruptible_timeout(&po->skb_completion, timeo);
+                               if (timeo <= 0) {
+                                       err = !timeo ? -ETIMEDOUT : -ERESTARTSYS;
+                                       goto out_put;
+                               }
+                       }
+                       /* check for additional frames */
                        continue;
                }
 
@@ -3207,6 +3220,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
        sock_init_data(sock, sk);
 
        po = pkt_sk(sk);
+       init_completion(&po->skb_completion);
        sk->sk_family = PF_PACKET;
        po->num = proto;
        po->xmit = dev_queue_xmit;
@@ -4314,7 +4328,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                                    req3->tp_sizeof_priv ||
                                    req3->tp_feature_req_word) {
                                        err = -EINVAL;
-                                       goto out;
+                                       goto out_free_pg_vec;
                                }
                        }
                        break;
@@ -4378,6 +4392,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                        prb_shutdown_retire_blk_timer(po, rb_queue);
        }
 
+out_free_pg_vec:
        if (pg_vec)
                free_pg_vec(pg_vec, order, req->tp_block_nr);
 out:
index 3bb7c5f..c70a279 100644 (file)
@@ -128,6 +128,7 @@ struct packet_sock {
        unsigned int            tp_hdrlen;
        unsigned int            tp_reserve;
        unsigned int            tp_tstamp;
+       struct completion       skb_completion;
        struct net_device __rcu *cached_dev;
        int                     (*xmit)(struct sk_buff *skb);
        struct packet_type      prot_hook ____cacheline_aligned_in_smp;
index e16a3d3..732e109 100644 (file)
@@ -549,12 +549,17 @@ static struct notifier_block cbs_device_notifier = {
 
 static int __init cbs_module_init(void)
 {
-       int err = register_netdevice_notifier(&cbs_device_notifier);
+       int err;
 
+       err = register_netdevice_notifier(&cbs_device_notifier);
        if (err)
                return err;
 
-       return register_qdisc(&cbs_qdisc_ops);
+       err = register_qdisc(&cbs_qdisc_ops);
+       if (err)
+               unregister_netdevice_notifier(&cbs_device_notifier);
+
+       return err;
 }
 
 static void __exit cbs_module_exit(void)
index e358437..69cebb2 100644 (file)
@@ -118,10 +118,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
        /* Initialize the bind addr area */
        sctp_bind_addr_init(&ep->base.bind_addr, 0);
 
-       /* Remember who we are attached to.  */
-       ep->base.sk = sk;
-       sock_hold(ep->base.sk);
-
        /* Create the lists of associations.  */
        INIT_LIST_HEAD(&ep->asocs);
 
@@ -154,6 +150,10 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
        ep->prsctp_enable = net->sctp.prsctp_enable;
        ep->reconf_enable = net->sctp.reconf_enable;
 
+       /* Remember who we are attached to.  */
+       ep->base.sk = sk;
+       sock_hold(ep->base.sk);
+
        return ep;
 
 nomem_shkey:
index 0c874e9..7621ec2 100644 (file)
@@ -2029,7 +2029,7 @@ static int __init smc_init(void)
 
        rc = smc_pnet_init();
        if (rc)
-               return rc;
+               goto out_pernet_subsys;
 
        rc = smc_llc_init();
        if (rc) {
@@ -2080,6 +2080,9 @@ out_proto:
        proto_unregister(&smc_proto);
 out_pnet:
        smc_pnet_exit();
+out_pernet_subsys:
+       unregister_pernet_subsys(&smc_net_ops);
+
        return rc;
 }
 
index 2d2850a..4ca50dd 100644 (file)
@@ -652,7 +652,10 @@ create:
                rc = smc_lgr_create(smc, ini);
                if (rc)
                        goto out;
+               lgr = conn->lgr;
+               write_lock_bh(&lgr->conns_lock);
                smc_lgr_register_conn(conn); /* add smc conn to lgr */
+               write_unlock_bh(&lgr->conns_lock);
        }
        conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
        conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
index c69951e..3665235 100644 (file)
@@ -950,6 +950,8 @@ static int xs_local_send_request(struct rpc_rqst *req)
        struct sock_xprt *transport =
                                container_of(xprt, struct sock_xprt, xprt);
        struct xdr_buf *xdr = &req->rq_snd_buf;
+       rpc_fraghdr rm = xs_stream_record_marker(xdr);
+       unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen;
        int status;
        int sent = 0;
 
@@ -964,9 +966,7 @@ static int xs_local_send_request(struct rpc_rqst *req)
 
        req->rq_xtime = ktime_get();
        status = xs_sendpages(transport->sock, NULL, 0, xdr,
-                             transport->xmit.offset,
-                             xs_stream_record_marker(xdr),
-                             &sent);
+                             transport->xmit.offset, rm, &sent);
        dprintk("RPC:       %s(%u) = %d\n",
                        __func__, xdr->len - transport->xmit.offset, status);
 
@@ -976,7 +976,7 @@ static int xs_local_send_request(struct rpc_rqst *req)
        if (likely(sent > 0) || status == 0) {
                transport->xmit.offset += sent;
                req->rq_bytes_sent = transport->xmit.offset;
-               if (likely(req->rq_bytes_sent >= req->rq_slen)) {
+               if (likely(req->rq_bytes_sent >= msglen)) {
                        req->rq_xmit_bytes_sent += transport->xmit.offset;
                        transport->xmit.offset = 0;
                        return 0;
@@ -1097,6 +1097,8 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
        struct rpc_xprt *xprt = req->rq_xprt;
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct xdr_buf *xdr = &req->rq_snd_buf;
+       rpc_fraghdr rm = xs_stream_record_marker(xdr);
+       unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen;
        bool vm_wait = false;
        int status;
        int sent;
@@ -1122,9 +1124,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
        while (1) {
                sent = 0;
                status = xs_sendpages(transport->sock, NULL, 0, xdr,
-                                     transport->xmit.offset,
-                                     xs_stream_record_marker(xdr),
-                                     &sent);
+                                     transport->xmit.offset, rm, &sent);
 
                dprintk("RPC:       xs_tcp_send_request(%u) = %d\n",
                                xdr->len - transport->xmit.offset, status);
@@ -1133,7 +1133,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
                 * reset the count of bytes sent. */
                transport->xmit.offset += sent;
                req->rq_bytes_sent = transport->xmit.offset;
-               if (likely(req->rq_bytes_sent >= req->rq_slen)) {
+               if (likely(req->rq_bytes_sent >= msglen)) {
                        req->rq_xmit_bytes_sent += transport->xmit.offset;
                        transport->xmit.offset = 0;
                        return 0;
index ed536c0..c837072 100644 (file)
@@ -134,7 +134,7 @@ static int __init tipc_init(void)
        if (err)
                goto out_sysctl;
 
-       err = register_pernet_subsys(&tipc_net_ops);
+       err = register_pernet_device(&tipc_net_ops);
        if (err)
                goto out_pernet;
 
@@ -142,7 +142,7 @@ static int __init tipc_init(void)
        if (err)
                goto out_socket;
 
-       err = register_pernet_subsys(&tipc_topsrv_net_ops);
+       err = register_pernet_device(&tipc_topsrv_net_ops);
        if (err)
                goto out_pernet_topsrv;
 
@@ -153,11 +153,11 @@ static int __init tipc_init(void)
        pr_info("Started in single node mode\n");
        return 0;
 out_bearer:
-       unregister_pernet_subsys(&tipc_topsrv_net_ops);
+       unregister_pernet_device(&tipc_topsrv_net_ops);
 out_pernet_topsrv:
        tipc_socket_stop();
 out_socket:
-       unregister_pernet_subsys(&tipc_net_ops);
+       unregister_pernet_device(&tipc_net_ops);
 out_pernet:
        tipc_unregister_sysctl();
 out_sysctl:
@@ -172,9 +172,9 @@ out_netlink:
 static void __exit tipc_exit(void)
 {
        tipc_bearer_cleanup();
-       unregister_pernet_subsys(&tipc_topsrv_net_ops);
+       unregister_pernet_device(&tipc_topsrv_net_ops);
        tipc_socket_stop();
-       unregister_pernet_subsys(&tipc_net_ops);
+       unregister_pernet_device(&tipc_net_ops);
        tipc_netlink_stop();
        tipc_netlink_compat_stop();
        tipc_unregister_sysctl();
index c6a04c0..cf15506 100644 (file)
@@ -445,7 +445,11 @@ static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd,
        if (!bearer)
                return -EMSGSIZE;
 
-       len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_BEARER_NAME);
+       len = TLV_GET_DATA_LEN(msg->req);
+       if (len <= 0)
+               return -EINVAL;
+
+       len = min_t(int, len, TIPC_MAX_BEARER_NAME);
        if (!string_is_valid(name, len))
                return -EINVAL;
 
@@ -539,7 +543,11 @@ static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg,
 
        name = (char *)TLV_DATA(msg->req);
 
-       len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME);
+       len = TLV_GET_DATA_LEN(msg->req);
+       if (len <= 0)
+               return -EINVAL;
+
+       len = min_t(int, len, TIPC_MAX_BEARER_NAME);
        if (!string_is_valid(name, len))
                return -EINVAL;
 
@@ -817,7 +825,11 @@ static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd,
        if (!link)
                return -EMSGSIZE;
 
-       len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME);
+       len = TLV_GET_DATA_LEN(msg->req);
+       if (len <= 0)
+               return -EINVAL;
+
+       len = min_t(int, len, TIPC_MAX_BEARER_NAME);
        if (!string_is_valid(name, len))
                return -EINVAL;
 
index fc81ae1..e2b69e8 100644 (file)
@@ -279,7 +279,8 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
                goto skip_tx_cleanup;
        }
 
-       if (!tls_complete_pending_work(sk, ctx, 0, &timeo))
+       if (unlikely(sk->sk_write_pending) &&
+           !wait_on_pending_writer(sk, &timeo))
                tls_handle_open_record(sk, 0);
 
        /* We need these for tls_sw_fallback handling of other packets */
index 14b4544..c459155 100644 (file)
@@ -83,7 +83,7 @@ static int pidfd_metadata_fd(pid_t pid, int pidfd)
 
 int main(int argc, char *argv[])
 {
-       int pidfd = 0, ret = EXIT_FAILURE;
+       int pidfd = -1, ret = EXIT_FAILURE;
        char buf[4096] = { 0 };
        pid_t pid;
        int procfd, statusfd;
@@ -91,7 +91,11 @@ int main(int argc, char *argv[])
 
        pid = pidfd_clone(CLONE_PIDFD, &pidfd);
        if (pid < 0)
-               exit(ret);
+               err(ret, "CLONE_PIDFD");
+       if (pidfd == -1) {
+               warnx("CLONE_PIDFD is not supported by the kernel");
+               goto out;
+       }
 
        procfd = pidfd_metadata_fd(pid, pidfd);
        close(pidfd);
index 7b977b7..7985dd8 100644 (file)
@@ -122,17 +122,12 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,
                                                      vendor_id);
 
        ret = device_add(&codec->dev);
-       if (ret)
-               goto err_free_codec;
+       if (ret) {
+               put_device(&codec->dev);
+               return ret;
+       }
 
        return 0;
-err_free_codec:
-       of_node_put(codec->dev.of_node);
-       put_device(&codec->dev);
-       kfree(codec);
-       ac97_ctrl->codecs[idx] = NULL;
-
-       return ret;
 }
 
 unsigned int snd_ac97_bus_scan_one(struct ac97_controller *adrv,
index 99b8821..41905af 100644 (file)
@@ -574,10 +574,7 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
                stream->metadata_set = false;
                stream->next_track = false;
 
-               if (stream->direction == SND_COMPRESS_PLAYBACK)
-                       stream->runtime->state = SNDRV_PCM_STATE_SETUP;
-               else
-                       stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+               stream->runtime->state = SNDRV_PCM_STATE_SETUP;
        } else {
                return -EPERM;
        }
@@ -693,8 +690,17 @@ static int snd_compr_start(struct snd_compr_stream *stream)
 {
        int retval;
 
-       if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
+       switch (stream->runtime->state) {
+       case SNDRV_PCM_STATE_SETUP:
+               if (stream->direction != SND_COMPRESS_CAPTURE)
+                       return -EPERM;
+               break;
+       case SNDRV_PCM_STATE_PREPARED:
+               break;
+       default:
                return -EPERM;
+       }
+
        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
        if (!retval)
                stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
@@ -705,9 +711,15 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
 {
        int retval;
 
-       if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
-                       stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+       switch (stream->runtime->state) {
+       case SNDRV_PCM_STATE_OPEN:
+       case SNDRV_PCM_STATE_SETUP:
+       case SNDRV_PCM_STATE_PREPARED:
                return -EPERM;
+       default:
+               break;
+       }
+
        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
        if (!retval) {
                snd_compr_drain_notify(stream);
@@ -795,9 +807,17 @@ static int snd_compr_drain(struct snd_compr_stream *stream)
 {
        int retval;
 
-       if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
-                       stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+       switch (stream->runtime->state) {
+       case SNDRV_PCM_STATE_OPEN:
+       case SNDRV_PCM_STATE_SETUP:
+       case SNDRV_PCM_STATE_PREPARED:
+       case SNDRV_PCM_STATE_PAUSED:
                return -EPERM;
+       case SNDRV_PCM_STATE_XRUN:
+               return -EPIPE;
+       default:
+               break;
+       }
 
        retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
        if (retval) {
@@ -817,6 +837,10 @@ static int snd_compr_next_track(struct snd_compr_stream *stream)
        if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
                return -EPERM;
 
+       /* next track doesn't have any meaning for capture streams */
+       if (stream->direction == SND_COMPRESS_CAPTURE)
+               return -EPERM;
+
        /* you can signal next track if this is intended to be a gapless stream
         * and current track metadata is set
         */
@@ -834,9 +858,23 @@ static int snd_compr_next_track(struct snd_compr_stream *stream)
 static int snd_compr_partial_drain(struct snd_compr_stream *stream)
 {
        int retval;
-       if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
-                       stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+
+       switch (stream->runtime->state) {
+       case SNDRV_PCM_STATE_OPEN:
+       case SNDRV_PCM_STATE_SETUP:
+       case SNDRV_PCM_STATE_PREPARED:
+       case SNDRV_PCM_STATE_PAUSED:
+               return -EPERM;
+       case SNDRV_PCM_STATE_XRUN:
+               return -EPIPE;
+       default:
+               break;
+       }
+
+       /* partial drain doesn't have any meaning for capture streams */
+       if (stream->direction == SND_COMPRESS_CAPTURE)
                return -EPERM;
+
        /* stream can be drained only when next track has been signalled */
        if (stream->next_track == false)
                return -EPERM;
index 5be5b9b..7a4d869 100644 (file)
@@ -196,16 +196,12 @@ EXPORT_SYMBOL(snd_ctl_notify);
 static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
                       unsigned int access, struct snd_ctl_file *file)
 {
-       unsigned int size;
        unsigned int idx;
 
        if (count == 0 || count > MAX_CONTROL_COUNT)
                return -EINVAL;
 
-       size  = sizeof(struct snd_kcontrol);
-       size += sizeof(struct snd_kcontrol_volatile) * count;
-
-       *kctl = kzalloc(size, GFP_KERNEL);
+       *kctl = kzalloc(struct_size(*kctl, vd, count), GFP_KERNEL);
        if (!*kctl)
                return -ENOMEM;
 
index 2fa9299..7cd09ce 100644 (file)
@@ -323,8 +323,8 @@ int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug,
 
        err = snd_pcm_plugin_build(plug, "rate conversion",
                                   src_format, dst_format,
-                                  sizeof(struct rate_priv) +
-                                  src_format->channels * sizeof(struct rate_channel),
+                                  struct_size(data, channels,
+                                              src_format->channels),
                                   &plugin);
        if (err < 0)
                return err;
index 860543a..703857a 100644 (file)
@@ -77,7 +77,7 @@ void snd_pcm_group_init(struct snd_pcm_group *group)
        spin_lock_init(&group->lock);
        mutex_init(&group->mutex);
        INIT_LIST_HEAD(&group->substreams);
-       refcount_set(&group->refs, 0);
+       refcount_set(&group->refs, 1);
 }
 
 /* define group lock helpers */
@@ -1096,8 +1096,7 @@ static void snd_pcm_group_unref(struct snd_pcm_group *group,
 
        if (!group)
                return;
-       do_free = refcount_dec_and_test(&group->refs) &&
-               list_empty(&group->substreams);
+       do_free = refcount_dec_and_test(&group->refs);
        snd_pcm_group_unlock(group, substream->pcm->nonatomic);
        if (do_free)
                kfree(group);
@@ -1874,6 +1873,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
                if (!to_check)
                        break; /* all drained */
                init_waitqueue_entry(&wait, current);
+               set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&to_check->sleep, &wait);
                snd_pcm_stream_unlock_irq(substream);
                if (runtime->no_period_wakeup)
@@ -1886,7 +1886,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
                        }
                        tout = msecs_to_jiffies(tout * 1000);
                }
-               tout = schedule_timeout_interruptible(tout);
+               tout = schedule_timeout(tout);
 
                snd_pcm_stream_lock_irq(substream);
                group = snd_pcm_stream_group_ref(substream);
@@ -2020,6 +2020,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
        snd_pcm_group_lock_irq(target_group, nonatomic);
        snd_pcm_stream_lock(substream1);
        snd_pcm_group_assign(substream1, target_group);
+       refcount_inc(&target_group->refs);
        snd_pcm_stream_unlock(substream1);
        snd_pcm_group_unlock_irq(target_group, nonatomic);
  _end:
@@ -2056,13 +2057,14 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
        snd_pcm_group_lock_irq(group, nonatomic);
 
        relink_to_local(substream);
+       refcount_dec(&group->refs);
 
        /* detach the last stream, too */
        if (list_is_singular(&group->substreams)) {
                relink_to_local(list_first_entry(&group->substreams,
                                                 struct snd_pcm_substream,
                                                 link_list));
-               do_free = !refcount_read(&group->refs);
+               do_free = refcount_dec_and_test(&group->refs);
        }
 
        snd_pcm_group_unlock_irq(group, nonatomic);
index 96ad01f..ccf6826 100644 (file)
@@ -49,7 +49,7 @@ static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg)
        if (copy_from_user(ev, arg, 8))
                return -EFAULT;
        memset(&tmpev, 0, sizeof(tmpev));
-       snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client);
+       snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.client, dp->addr.port);
        tmpev.time.tick = 0;
        if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) {
                snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
index 79ef430..537d5f4 100644 (file)
@@ -161,7 +161,7 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
        memset(&event, 0, sizeof(event));
        /* set dummy -- to be sure */
        event.type = SNDRV_SEQ_EVENT_NOTEOFF;
-       snd_seq_oss_fill_addr(dp, &event, dp->addr.port, dp->addr.client);
+       snd_seq_oss_fill_addr(dp, &event, dp->addr.client, dp->addr.port);
 
        if (snd_seq_oss_process_event(dp, rec, &event))
                return 0; /* invalid event - no need to insert queue */
index a60e7a1..7737b26 100644 (file)
@@ -1021,7 +1021,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
 {
        struct snd_seq_client *client = file->private_data;
        int written = 0, len;
-       int err;
+       int err, handled;
        struct snd_seq_event event;
 
        if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
@@ -1034,6 +1034,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
        if (!client->accept_output || client->pool == NULL)
                return -ENXIO;
 
+ repeat:
+       handled = 0;
        /* allocate the pool now if the pool is not allocated yet */ 
        mutex_lock(&client->ioctl_mutex);
        if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {
@@ -1093,12 +1095,19 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
                                                   0, 0, &client->ioctl_mutex);
                if (err < 0)
                        break;
+               handled++;
 
        __skip_event:
                /* Update pointers and counts */
                count -= len;
                buf += len;
                written += len;
+
+               /* let's have a coffee break if too many events are queued */
+               if (++handled >= 200) {
+                       mutex_unlock(&client->ioctl_mutex);
+                       goto repeat;
+               }
        }
 
  out:
index cc6eb30..fd5d6b8 100644 (file)
@@ -82,7 +82,7 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
        if (err < 0)
                return err;
 
-       s->fdf = AMDTP_FDF_AM824 | s->sfc;
+       s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc;
 
        p->pcm_channels = pcm_channels;
        p->midi_ports = midi_ports;
@@ -320,7 +320,7 @@ static void read_midi_messages(struct amdtp_stream *s,
        u8 *b;
 
        for (f = 0; f < frames; f++) {
-               port = (s->data_block_counter + f) % 8;
+               port = (8 - s->ctx_data.tx.first_dbc + s->data_block_counter + f) % 8;
                b = (u8 *)&buffer[p->midi_position];
 
                len = b[0] - 0x80;
index edb5c3a..4adbbf7 100644 (file)
 
 #include <linux/tracepoint.h>
 
-TRACE_EVENT(in_packet,
-       TP_PROTO(const struct amdtp_stream *s, u32 cycles, u32 *cip_header, unsigned int payload_length, unsigned int index),
-       TP_ARGS(s, cycles, cip_header, payload_length, index),
-       TP_STRUCT__entry(
-               __field(unsigned int, second)
-               __field(unsigned int, cycle)
-               __field(int, channel)
-               __field(int, src)
-               __field(int, dest)
-               __field(u32, cip_header0)
-               __field(u32, cip_header1)
-               __field(unsigned int, payload_quadlets)
-               __field(unsigned int, packet_index)
-               __field(unsigned int, irq)
-               __field(unsigned int, index)
-       ),
-       TP_fast_assign(
-               __entry->second = cycles / CYCLES_PER_SECOND;
-               __entry->cycle = cycles % CYCLES_PER_SECOND;
-               __entry->channel = s->context->channel;
-               __entry->src = fw_parent_device(s->unit)->node_id;
-               __entry->dest = fw_parent_device(s->unit)->card->node_id;
-               __entry->cip_header0 = cip_header[0];
-               __entry->cip_header1 = cip_header[1];
-               __entry->payload_quadlets = payload_length / 4;
-               __entry->packet_index = s->packet_index;
-               __entry->irq = !!in_interrupt();
-               __entry->index = index;
-       ),
-       TP_printk(
-               "%02u %04u %04x %04x %02d %08x %08x %03u %02u %01u %02u",
-               __entry->second,
-               __entry->cycle,
-               __entry->src,
-               __entry->dest,
-               __entry->channel,
-               __entry->cip_header0,
-               __entry->cip_header1,
-               __entry->payload_quadlets,
-               __entry->packet_index,
-               __entry->irq,
-               __entry->index)
-);
-
-TRACE_EVENT(out_packet,
-       TP_PROTO(const struct amdtp_stream *s, u32 cycles, __be32 *cip_header, unsigned int payload_length, unsigned int index),
-       TP_ARGS(s, cycles, cip_header, payload_length, index),
-       TP_STRUCT__entry(
-               __field(unsigned int, second)
-               __field(unsigned int, cycle)
-               __field(int, channel)
-               __field(int, src)
-               __field(int, dest)
-               __field(u32, cip_header0)
-               __field(u32, cip_header1)
-               __field(unsigned int, payload_quadlets)
-               __field(unsigned int, packet_index)
-               __field(unsigned int, irq)
-               __field(unsigned int, index)
-       ),
-       TP_fast_assign(
-               __entry->second = cycles / CYCLES_PER_SECOND;
-               __entry->cycle = cycles % CYCLES_PER_SECOND;
-               __entry->channel = s->context->channel;
-               __entry->src = fw_parent_device(s->unit)->card->node_id;
-               __entry->dest = fw_parent_device(s->unit)->node_id;
-               __entry->cip_header0 = be32_to_cpu(cip_header[0]);
-               __entry->cip_header1 = be32_to_cpu(cip_header[1]);
-               __entry->payload_quadlets = payload_length / 4;
-               __entry->packet_index = s->packet_index;
-               __entry->irq = !!in_interrupt();
-               __entry->index = index;
-       ),
-       TP_printk(
-               "%02u %04u %04x %04x %02d %08x %08x %03u %02u %01u %02u",
-               __entry->second,
-               __entry->cycle,
-               __entry->src,
-               __entry->dest,
-               __entry->channel,
-               __entry->cip_header0,
-               __entry->cip_header1,
-               __entry->payload_quadlets,
-               __entry->packet_index,
-               __entry->irq,
-               __entry->index)
-);
-
-TRACE_EVENT(in_packet_without_header,
-       TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_quadlets, unsigned int data_blocks, unsigned int index),
-       TP_ARGS(s, cycles, payload_quadlets, data_blocks, index),
-       TP_STRUCT__entry(
-               __field(unsigned int, second)
-               __field(unsigned int, cycle)
-               __field(int, channel)
-               __field(int, src)
-               __field(int, dest)
-               __field(unsigned int, payload_quadlets)
-               __field(unsigned int, data_blocks)
-               __field(unsigned int, data_block_counter)
-               __field(unsigned int, packet_index)
-               __field(unsigned int, irq)
-               __field(unsigned int, index)
-       ),
-       TP_fast_assign(
-               __entry->second = cycles / CYCLES_PER_SECOND;
-               __entry->cycle = cycles % CYCLES_PER_SECOND;
-               __entry->channel = s->context->channel;
-               __entry->src = fw_parent_device(s->unit)->node_id;
-               __entry->dest = fw_parent_device(s->unit)->card->node_id;
-               __entry->payload_quadlets = payload_quadlets;
-               __entry->data_blocks = data_blocks,
-               __entry->data_block_counter = s->data_block_counter,
-               __entry->packet_index = s->packet_index;
-               __entry->irq = !!in_interrupt();
-               __entry->index = index;
-       ),
-       TP_printk(
-               "%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
-               __entry->second,
-               __entry->cycle,
-               __entry->src,
-               __entry->dest,
-               __entry->channel,
-               __entry->payload_quadlets,
-               __entry->data_blocks,
-               __entry->data_block_counter,
-               __entry->packet_index,
-               __entry->irq,
-               __entry->index)
-);
-
-TRACE_EVENT(out_packet_without_header,
-       TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_length, unsigned int data_blocks, unsigned int index),
-       TP_ARGS(s, cycles, payload_length, data_blocks, index),
+TRACE_EVENT(amdtp_packet,
+       TP_PROTO(const struct amdtp_stream *s, u32 cycles, const __be32 *cip_header, unsigned int payload_length, unsigned int data_blocks, unsigned int index),
+       TP_ARGS(s, cycles, cip_header, payload_length, data_blocks, index),
        TP_STRUCT__entry(
                __field(unsigned int, second)
                __field(unsigned int, cycle)
                __field(int, channel)
                __field(int, src)
                __field(int, dest)
+               __dynamic_array(u8, cip_header, cip_header ? 8 : 0)
                __field(unsigned int, payload_quadlets)
                __field(unsigned int, data_blocks)
                __field(unsigned int, data_block_counter)
@@ -165,17 +34,26 @@ TRACE_EVENT(out_packet_without_header,
                __entry->second = cycles / CYCLES_PER_SECOND;
                __entry->cycle = cycles % CYCLES_PER_SECOND;
                __entry->channel = s->context->channel;
-               __entry->src = fw_parent_device(s->unit)->card->node_id;
-               __entry->dest = fw_parent_device(s->unit)->node_id;
-               __entry->payload_quadlets = payload_length / 4;
-               __entry->data_blocks = data_blocks,
+               if (s->direction == AMDTP_IN_STREAM) {
+                       __entry->src = fw_parent_device(s->unit)->node_id;
+                       __entry->dest = fw_parent_device(s->unit)->card->node_id;
+               } else {
+                       __entry->src = fw_parent_device(s->unit)->card->node_id;
+                       __entry->dest = fw_parent_device(s->unit)->node_id;
+               }
+               if (cip_header) {
+                       memcpy(__get_dynamic_array(cip_header), cip_header,
+                              __get_dynamic_array_len(cip_header));
+               }
+               __entry->payload_quadlets = payload_length / sizeof(__be32);
+               __entry->data_blocks = data_blocks;
                __entry->data_block_counter = s->data_block_counter,
                __entry->packet_index = s->packet_index;
                __entry->irq = !!in_interrupt();
                __entry->index = index;
        ),
        TP_printk(
-               "%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
+               "%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u %s",
                __entry->second,
                __entry->cycle,
                __entry->src,
@@ -186,7 +64,10 @@ TRACE_EVENT(out_packet_without_header,
                __entry->data_block_counter,
                __entry->packet_index,
                __entry->irq,
-               __entry->index)
+               __entry->index,
+               __print_array(__get_dynamic_array(cip_header),
+                             __get_dynamic_array_len(cip_header),
+                             sizeof(u8)))
 );
 
 #endif
index 68f5fa4..4d71d74 100644 (file)
 #define INTERRUPT_INTERVAL     16
 #define QUEUE_LENGTH           48
 
-#define IR_HEADER_SIZE         8       // For header and timestamp.
-#define OUT_PACKET_HEADER_SIZE 0
+// For iso header, tstamp and 2 CIP header.
+#define IR_CTX_HEADER_SIZE_CIP         16
+// For iso header and tstamp.
+#define IR_CTX_HEADER_SIZE_NO_CIP      8
 #define HEADER_TSTAMP_MASK     0x0000ffff
 
+#define IT_PKT_HEADER_SIZE_CIP         8 // For 2 CIP header.
+#define IT_PKT_HEADER_SIZE_NO_CIP      0 // Nothing.
+
 static void pcm_period_tasklet(unsigned long data);
 
 /**
@@ -260,11 +265,18 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate,
        s->data_block_quadlets = data_block_quadlets;
        s->syt_interval = amdtp_syt_intervals[sfc];
 
-       /* default buffering in the device */
-       s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
-       if (s->flags & CIP_BLOCKING)
-               /* additional buffering needed to adjust for no-data packets */
-               s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate;
+       // default buffering in the device.
+       if (s->direction == AMDTP_OUT_STREAM) {
+               s->ctx_data.rx.transfer_delay =
+                                       TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
+
+               if (s->flags & CIP_BLOCKING) {
+                       // additional buffering needed to adjust for no-data
+                       // packets.
+                       s->ctx_data.rx.transfer_delay +=
+                               TICKS_PER_SECOND * s->syt_interval / rate;
+               }
+       }
 
        return 0;
 }
@@ -280,15 +292,15 @@ EXPORT_SYMBOL(amdtp_stream_set_parameters);
 unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s)
 {
        unsigned int multiplier = 1;
-       unsigned int header_size = 0;
+       unsigned int cip_header_size = 0;
 
        if (s->flags & CIP_JUMBO_PAYLOAD)
                multiplier = 5;
        if (!(s->flags & CIP_NO_HEADER))
-               header_size = 8;
+               cip_header_size = sizeof(__be32) * 2;
 
-       return header_size +
-               s->syt_interval * s->data_block_quadlets * 4 * multiplier;
+       return cip_header_size +
+               s->syt_interval * s->data_block_quadlets * sizeof(__be32) * multiplier;
 }
 EXPORT_SYMBOL(amdtp_stream_get_max_payload);
 
@@ -321,10 +333,10 @@ static unsigned int calculate_data_blocks(struct amdtp_stream *s,
        /* Non-blocking mode. */
        } else {
                if (!cip_sfc_is_base_44100(s->sfc)) {
-                       /* Sample_rate / 8000 is an integer, and precomputed. */
-                       data_blocks = s->data_block_state;
+                       // Sample_rate / 8000 is an integer, and precomputed.
+                       data_blocks = s->ctx_data.rx.data_block_state;
                } else {
-                       phase = s->data_block_state;
+                       phase = s->ctx_data.rx.data_block_state;
 
                /*
                 * This calculates the number of data blocks per packet so that
@@ -343,7 +355,7 @@ static unsigned int calculate_data_blocks(struct amdtp_stream *s,
                                data_blocks = 11 * (s->sfc >> 1) + (phase == 0);
                        if (++phase >= (80 >> (s->sfc >> 1)))
                                phase = 0;
-                       s->data_block_state = phase;
+                       s->ctx_data.rx.data_block_state = phase;
                }
        }
 
@@ -355,9 +367,10 @@ static unsigned int calculate_syt(struct amdtp_stream *s,
 {
        unsigned int syt_offset, phase, index, syt;
 
-       if (s->last_syt_offset < TICKS_PER_CYCLE) {
+       if (s->ctx_data.rx.last_syt_offset < TICKS_PER_CYCLE) {
                if (!cip_sfc_is_base_44100(s->sfc))
-                       syt_offset = s->last_syt_offset + s->syt_offset_state;
+                       syt_offset = s->ctx_data.rx.last_syt_offset +
+                                    s->ctx_data.rx.syt_offset_state;
                else {
                /*
                 * The time, in ticks, of the n'th SYT_INTERVAL sample is:
@@ -369,21 +382,21 @@ static unsigned int calculate_syt(struct amdtp_stream *s,
                 *   1386 1386 1387 1386 1386 1386 1387 1386 1386 1386 1387 ...
                 * This code generates _exactly_ the same sequence.
                 */
-                       phase = s->syt_offset_state;
+                       phase = s->ctx_data.rx.syt_offset_state;
                        index = phase % 13;
-                       syt_offset = s->last_syt_offset;
+                       syt_offset = s->ctx_data.rx.last_syt_offset;
                        syt_offset += 1386 + ((index && !(index & 3)) ||
                                              phase == 146);
                        if (++phase >= 147)
                                phase = 0;
-                       s->syt_offset_state = phase;
+                       s->ctx_data.rx.syt_offset_state = phase;
                }
        } else
-               syt_offset = s->last_syt_offset - TICKS_PER_CYCLE;
-       s->last_syt_offset = syt_offset;
+               syt_offset = s->ctx_data.rx.last_syt_offset - TICKS_PER_CYCLE;
+       s->ctx_data.rx.last_syt_offset = syt_offset;
 
        if (syt_offset < TICKS_PER_CYCLE) {
-               syt_offset += s->transfer_delay;
+               syt_offset += s->ctx_data.rx.transfer_delay;
                syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12;
                syt += syt_offset % TICKS_PER_CYCLE;
 
@@ -420,23 +433,15 @@ static void pcm_period_tasklet(unsigned long data)
                snd_pcm_period_elapsed(pcm);
 }
 
-static int queue_packet(struct amdtp_stream *s, unsigned int header_length,
-                       unsigned int payload_length)
+static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params)
 {
-       struct fw_iso_packet p = {0};
-       int err = 0;
+       int err;
 
-       if (IS_ERR(s->context))
-               goto end;
+       params->interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
+       params->tag = s->tag;
+       params->sy = 0;
 
-       p.interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
-       p.tag = s->tag;
-       p.header_length = header_length;
-       if (payload_length > 0)
-               p.payload_length = payload_length;
-       else
-               p.skip = true;
-       err = fw_iso_context_queue(s->context, &p, &s->buffer.iso_buffer,
+       err = fw_iso_context_queue(s->context, params, &s->buffer.iso_buffer,
                                   s->buffer.packets[s->packet_index].offset);
        if (err < 0) {
                dev_err(&s->unit->device, "queueing error: %d\n", err);
@@ -450,112 +455,83 @@ end:
 }
 
 static inline int queue_out_packet(struct amdtp_stream *s,
-                                  unsigned int payload_length)
+                                  struct fw_iso_packet *params)
 {
-       return queue_packet(s, OUT_PACKET_HEADER_SIZE, payload_length);
+       params->skip =
+               !!(params->header_length == 0 && params->payload_length == 0);
+       return queue_packet(s, params);
 }
 
-static inline int queue_in_packet(struct amdtp_stream *s)
+static inline int queue_in_packet(struct amdtp_stream *s,
+                                 struct fw_iso_packet *params)
 {
-       return queue_packet(s, IR_HEADER_SIZE, s->max_payload_length);
+       // Queue one packet for IR context.
+       params->header_length = s->ctx_data.tx.ctx_header_size;
+       params->payload_length = s->ctx_data.tx.max_ctx_payload_length;
+       params->skip = false;
+       return queue_packet(s, params);
 }
 
-static int handle_out_packet(struct amdtp_stream *s,
-                            unsigned int payload_length, unsigned int cycle,
-                            unsigned int index)
+static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2],
+                               unsigned int syt)
 {
-       __be32 *buffer;
-       unsigned int syt;
-       unsigned int data_blocks;
-       unsigned int pcm_frames;
-       struct snd_pcm_substream *pcm;
-
-       buffer = s->buffer.packets[s->packet_index].buffer;
-       syt = calculate_syt(s, cycle);
-       data_blocks = calculate_data_blocks(s, syt);
-       pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
-
-       if (s->flags & CIP_DBC_IS_END_EVENT)
-               s->data_block_counter =
-                               (s->data_block_counter + data_blocks) & 0xff;
-
-       buffer[0] = cpu_to_be32(READ_ONCE(s->source_node_id_field) |
+       cip_header[0] = cpu_to_be32(READ_ONCE(s->source_node_id_field) |
                                (s->data_block_quadlets << CIP_DBS_SHIFT) |
                                ((s->sph << CIP_SPH_SHIFT) & CIP_SPH_MASK) |
                                s->data_block_counter);
-       buffer[1] = cpu_to_be32(CIP_EOH |
-                               ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) |
-                               ((s->fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) |
-                               (syt & CIP_SYT_MASK));
-
-       if (!(s->flags & CIP_DBC_IS_END_EVENT))
-               s->data_block_counter =
-                               (s->data_block_counter + data_blocks) & 0xff;
-       payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
-
-       trace_out_packet(s, cycle, buffer, payload_length, index);
-
-       if (queue_out_packet(s, payload_length) < 0)
-               return -EIO;
-
-       pcm = READ_ONCE(s->pcm);
-       if (pcm && pcm_frames > 0)
-               update_pcm_pointers(s, pcm, pcm_frames);
-
-       /* No need to return the number of handled data blocks. */
-       return 0;
+       cip_header[1] = cpu_to_be32(CIP_EOH |
+                       ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) |
+                       ((s->ctx_data.rx.fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) |
+                       (syt & CIP_SYT_MASK));
 }
 
-static int handle_out_packet_without_header(struct amdtp_stream *s,
-                       unsigned int payload_length, unsigned int cycle,
-                       unsigned int index)
+static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle,
+                               struct fw_iso_packet *params,
+                               unsigned int data_blocks, unsigned int syt,
+                               unsigned int index)
 {
-       __be32 *buffer;
-       unsigned int syt;
-       unsigned int data_blocks;
-       unsigned int pcm_frames;
-       struct snd_pcm_substream *pcm;
-
-       buffer = s->buffer.packets[s->packet_index].buffer;
-       syt = calculate_syt(s, cycle);
-       data_blocks = calculate_data_blocks(s, syt);
-       pcm_frames = s->process_data_blocks(s, buffer, data_blocks, &syt);
-       s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
+       unsigned int payload_length;
+       __be32 *cip_header;
 
-       payload_length = data_blocks * 4 * s->data_block_quadlets;
+       payload_length = data_blocks * sizeof(__be32) * s->data_block_quadlets;
+       params->payload_length = payload_length;
 
-       trace_out_packet_without_header(s, cycle, payload_length, data_blocks,
-                                       index);
+       if (s->flags & CIP_DBC_IS_END_EVENT) {
+               s->data_block_counter =
+                               (s->data_block_counter + data_blocks) & 0xff;
+       }
 
-       if (queue_out_packet(s, payload_length) < 0)
-               return -EIO;
+       if (!(s->flags & CIP_NO_HEADER)) {
+               cip_header = (__be32 *)params->header;
+               generate_cip_header(s, cip_header, syt);
+               params->header_length = 2 * sizeof(__be32);
+               payload_length += params->header_length;
+       } else {
+               cip_header = NULL;
+       }
 
-       pcm = READ_ONCE(s->pcm);
-       if (pcm && pcm_frames > 0)
-               update_pcm_pointers(s, pcm, pcm_frames);
+       trace_amdtp_packet(s, cycle, cip_header, payload_length, data_blocks,
+                          index);
 
-       /* No need to return the number of handled data blocks. */
-       return 0;
+       if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
+               s->data_block_counter =
+                               (s->data_block_counter + data_blocks) & 0xff;
+       }
 }
 
-static int handle_in_packet(struct amdtp_stream *s,
-                           unsigned int payload_length, unsigned int cycle,
-                           unsigned int index)
+static int check_cip_header(struct amdtp_stream *s, const __be32 *buf,
+                           unsigned int payload_length,
+                           unsigned int *data_blocks, unsigned int *dbc,
+                           unsigned int *syt)
 {
-       __be32 *buffer;
        u32 cip_header[2];
-       unsigned int sph, fmt, fdf, syt;
-       unsigned int data_block_quadlets, data_block_counter, dbc_interval;
-       unsigned int data_blocks;
-       struct snd_pcm_substream *pcm;
-       unsigned int pcm_frames;
+       unsigned int sph;
+       unsigned int fmt;
+       unsigned int fdf;
        bool lost;
 
-       buffer = s->buffer.packets[s->packet_index].buffer;
-       cip_header[0] = be32_to_cpu(buffer[0]);
-       cip_header[1] = be32_to_cpu(buffer[1]);
-
-       trace_in_packet(s, cycle, cip_header, payload_length, index);
+       cip_header[0] = be32_to_cpu(buf[0]);
+       cip_header[1] = be32_to_cpu(buf[1]);
 
        /*
         * This module supports 'Two-quadlet CIP header with SYT field'.
@@ -567,9 +543,7 @@ static int handle_in_packet(struct amdtp_stream *s,
                dev_info_ratelimited(&s->unit->device,
                                "Invalid CIP header for AMDTP: %08X:%08X\n",
                                cip_header[0], cip_header[1]);
-               data_blocks = 0;
-               pcm_frames = 0;
-               goto end;
+               return -EAGAIN;
        }
 
        /* Check valid protocol or not. */
@@ -579,19 +553,17 @@ static int handle_in_packet(struct amdtp_stream *s,
                dev_info_ratelimited(&s->unit->device,
                                     "Detect unexpected protocol: %08x %08x\n",
                                     cip_header[0], cip_header[1]);
-               data_blocks = 0;
-               pcm_frames = 0;
-               goto end;
+               return -EAGAIN;
        }
 
        /* Calculate data blocks */
        fdf = (cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SHIFT;
-       if (payload_length < 12 ||
+       if (payload_length < sizeof(__be32) * 2 ||
            (fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) {
-               data_blocks = 0;
+               *data_blocks = 0;
        } else {
-               data_block_quadlets =
-                       (cip_header[0] & CIP_DBS_MASK) >> CIP_DBS_SHIFT;
+               unsigned int data_block_quadlets =
+                               (cip_header[0] & CIP_DBS_MASK) >> CIP_DBS_SHIFT;
                /* avoid division by zero */
                if (data_block_quadlets == 0) {
                        dev_err(&s->unit->device,
@@ -602,95 +574,97 @@ static int handle_in_packet(struct amdtp_stream *s,
                if (s->flags & CIP_WRONG_DBS)
                        data_block_quadlets = s->data_block_quadlets;
 
-               data_blocks = (payload_length / 4 - 2) /
+               *data_blocks = (payload_length / sizeof(__be32) - 2) /
                                                        data_block_quadlets;
        }
 
        /* Check data block counter continuity */
-       data_block_counter = cip_header[0] & CIP_DBC_MASK;
-       if (data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
+       *dbc = cip_header[0] & CIP_DBC_MASK;
+       if (*data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
            s->data_block_counter != UINT_MAX)
-               data_block_counter = s->data_block_counter;
+               *dbc = s->data_block_counter;
 
        if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) &&
-            data_block_counter == s->tx_first_dbc) ||
+            *dbc == s->ctx_data.tx.first_dbc) ||
            s->data_block_counter == UINT_MAX) {
                lost = false;
        } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
-               lost = data_block_counter != s->data_block_counter;
+               lost = *dbc != s->data_block_counter;
        } else {
-               if (data_blocks > 0 && s->tx_dbc_interval > 0)
-                       dbc_interval = s->tx_dbc_interval;
+               unsigned int dbc_interval;
+
+               if (*data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0)
+                       dbc_interval = s->ctx_data.tx.dbc_interval;
                else
-                       dbc_interval = data_blocks;
+                       dbc_interval = *data_blocks;
 
-               lost = data_block_counter !=
-                      ((s->data_block_counter + dbc_interval) & 0xff);
+               lost = *dbc != ((s->data_block_counter + dbc_interval) & 0xff);
        }
 
        if (lost) {
                dev_err(&s->unit->device,
                        "Detect discontinuity of CIP: %02X %02X\n",
-                       s->data_block_counter, data_block_counter);
+                       s->data_block_counter, *dbc);
                return -EIO;
        }
 
-       syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK;
-       pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
-
-       if (s->flags & CIP_DBC_IS_END_EVENT)
-               s->data_block_counter = data_block_counter;
-       else
-               s->data_block_counter =
-                               (data_block_counter + data_blocks) & 0xff;
-end:
-       if (queue_in_packet(s) < 0)
-               return -EIO;
-
-       pcm = READ_ONCE(s->pcm);
-       if (pcm && pcm_frames > 0)
-               update_pcm_pointers(s, pcm, pcm_frames);
+       *syt = cip_header[1] & CIP_SYT_MASK;
 
        return 0;
 }
 
-static int handle_in_packet_without_header(struct amdtp_stream *s,
-                       unsigned int payload_length, unsigned int cycle,
-                       unsigned int index)
+static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle,
+                              const __be32 *ctx_header,
+                              unsigned int *payload_length,
+                              unsigned int *data_blocks, unsigned int *syt,
+                              unsigned int index)
 {
-       __be32 *buffer;
-       unsigned int payload_quadlets;
-       unsigned int data_blocks;
-       struct snd_pcm_substream *pcm;
-       unsigned int pcm_frames;
-
-       buffer = s->buffer.packets[s->packet_index].buffer;
-       payload_quadlets = payload_length / 4;
-       data_blocks = payload_quadlets / s->data_block_quadlets;
+       unsigned int dbc;
+       const __be32 *cip_header;
+       int err;
 
-       trace_in_packet_without_header(s, cycle, payload_quadlets, data_blocks,
-                                      index);
+       *payload_length = be32_to_cpu(ctx_header[0]) >> ISO_DATA_LENGTH_SHIFT;
+       if (*payload_length > s->ctx_data.tx.ctx_header_size +
+                                       s->ctx_data.tx.max_ctx_payload_length) {
+               dev_err(&s->unit->device,
+                       "Detect jumbo payload: %04x %04x\n",
+                       *payload_length, s->ctx_data.tx.max_ctx_payload_length);
+               return -EIO;
+       }
 
-       pcm_frames = s->process_data_blocks(s, buffer, data_blocks, NULL);
-       s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
+       if (!(s->flags & CIP_NO_HEADER)) {
+               cip_header = ctx_header + 2;
+               err = check_cip_header(s, cip_header, *payload_length,
+                                      data_blocks, &dbc, syt);
+               if (err < 0)
+                       return err;
+       } else {
+               cip_header = NULL;
+               err = 0;
+               *data_blocks = *payload_length / sizeof(__be32) /
+                              s->data_block_quadlets;
+               *syt = 0;
+
+               if (s->data_block_counter != UINT_MAX)
+                       dbc = s->data_block_counter;
+               else
+                       dbc = 0;
+       }
 
-       if (queue_in_packet(s) < 0)
-               return -EIO;
+       s->data_block_counter = dbc;
 
-       pcm = READ_ONCE(s->pcm);
-       if (pcm && pcm_frames > 0)
-               update_pcm_pointers(s, pcm, pcm_frames);
+       trace_amdtp_packet(s, cycle, cip_header, *payload_length, *data_blocks,
+                          index);
 
-       return 0;
+       return err;
 }
 
-/*
- * In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On
- * the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent
- * it. Thus, via Linux firewire subsystem, we can get the 3 bits for second.
- */
-static inline u32 compute_cycle_count(u32 tstamp)
+// In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On
+// the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent
+// it. Thus, via Linux firewire subsystem, we can get the 3 bits for second.
+static inline u32 compute_cycle_count(__be32 ctx_header_tstamp)
 {
+       u32 tstamp = be32_to_cpu(ctx_header_tstamp) & HEADER_TSTAMP_MASK;
        return (((tstamp >> 13) & 0x07) * 8000) + (tstamp & 0x1fff);
 }
 
@@ -702,31 +676,68 @@ static inline u32 increment_cycle_count(u32 cycle, unsigned int addend)
        return cycle;
 }
 
+// Align to actual cycle count for the packet which is going to be scheduled.
+// This module queued the same number of isochronous cycle as QUEUE_LENGTH to
+// skip isochronous cycle, therefore it's OK to just increment the cycle by
+// QUEUE_LENGTH for scheduled cycle.
+static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp)
+{
+       u32 cycle = compute_cycle_count(ctx_header_tstamp);
+       return increment_cycle_count(cycle, QUEUE_LENGTH);
+}
+
+static inline void cancel_stream(struct amdtp_stream *s)
+{
+       s->packet_index = -1;
+       if (in_interrupt())
+               amdtp_stream_pcm_abort(s);
+       WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN);
+}
+
 static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
                                size_t header_length, void *header,
                                void *private_data)
 {
        struct amdtp_stream *s = private_data;
-       unsigned int i, packets = header_length / 4;
-       u32 cycle;
+       const __be32 *ctx_header = header;
+       unsigned int packets = header_length / sizeof(*ctx_header);
+       int i;
 
        if (s->packet_index < 0)
                return;
 
-       cycle = compute_cycle_count(tstamp);
-
-       /* Align to actual cycle count for the last packet. */
-       cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets);
-
        for (i = 0; i < packets; ++i) {
-               cycle = increment_cycle_count(cycle, 1);
-               if (s->handle_packet(s, 0, cycle, i) < 0) {
-                       s->packet_index = -1;
-                       if (in_interrupt())
-                               amdtp_stream_pcm_abort(s);
-                       WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN);
+               u32 cycle;
+               unsigned int syt;
+               unsigned int data_blocks;
+               __be32 *buffer;
+               unsigned int pcm_frames;
+               struct {
+                       struct fw_iso_packet params;
+                       __be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)];
+               } template = { {0}, {0} };
+               struct snd_pcm_substream *pcm;
+
+               cycle = compute_it_cycle(*ctx_header);
+               syt = calculate_syt(s, cycle);
+               data_blocks = calculate_data_blocks(s, syt);
+               buffer = s->buffer.packets[s->packet_index].buffer;
+               pcm_frames = s->process_data_blocks(s, buffer, data_blocks,
+                                                   &syt);
+
+               build_it_pkt_header(s, cycle, &template.params, data_blocks,
+                                   syt, i);
+
+               if (queue_out_packet(s, &template.params) < 0) {
+                       cancel_stream(s);
                        return;
                }
+
+               pcm = READ_ONCE(s->pcm);
+               if (pcm && pcm_frames > 0)
+                       update_pcm_pointers(s, pcm, pcm_frames);
+
+               ++ctx_header;
        }
 
        fw_iso_context_queue_flush(s->context);
@@ -738,46 +749,55 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
 {
        struct amdtp_stream *s = private_data;
        unsigned int i, packets;
-       unsigned int payload_length, max_payload_length;
        __be32 *ctx_header = header;
 
        if (s->packet_index < 0)
                return;
 
-       /* The number of packets in buffer */
-       packets = header_length / IR_HEADER_SIZE;
-
-       /* For buffer-over-run prevention. */
-       max_payload_length = s->max_payload_length;
+       // The number of packets in buffer.
+       packets = header_length / s->ctx_data.tx.ctx_header_size;
 
        for (i = 0; i < packets; i++) {
-               u32 iso_header = be32_to_cpu(ctx_header[0]);
-               unsigned int cycle;
+               u32 cycle;
+               unsigned int payload_length;
+               unsigned int data_blocks;
+               unsigned int syt;
+               __be32 *buffer;
+               unsigned int pcm_frames = 0;
+               struct fw_iso_packet params = {0};
+               struct snd_pcm_substream *pcm;
+               int err;
+
+               cycle = compute_cycle_count(ctx_header[1]);
+               err = parse_ir_ctx_header(s, cycle, ctx_header, &payload_length,
+                                         &data_blocks, &syt, i);
+               if (err < 0 && err != -EAGAIN)
+                       break;
 
-               tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
-               cycle = compute_cycle_count(tstamp);
+               if (err >= 0) {
+                       buffer = s->buffer.packets[s->packet_index].buffer;
+                       pcm_frames = s->process_data_blocks(s, buffer,
+                                                           data_blocks, &syt);
 
-               /* The number of bytes in this packet */
-               payload_length = iso_header >> ISO_DATA_LENGTH_SHIFT;
-               if (payload_length > max_payload_length) {
-                       dev_err(&s->unit->device,
-                               "Detect jumbo payload: %04x %04x\n",
-                               payload_length, max_payload_length);
-                       break;
+                       if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
+                               s->data_block_counter += data_blocks;
+                               s->data_block_counter &= 0xff;
+                       }
                }
 
-               if (s->handle_packet(s, payload_length, cycle, i) < 0)
+               if (queue_in_packet(s, &params) < 0)
                        break;
 
-               ctx_header += IR_HEADER_SIZE / sizeof(__be32);
+               pcm = READ_ONCE(s->pcm);
+               if (pcm && pcm_frames > 0)
+                       update_pcm_pointers(s, pcm, pcm_frames);
+
+               ctx_header += s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header);
        }
 
        /* Queueing error or detecting invalid payload. */
        if (i < packets) {
-               s->packet_index = -1;
-               if (in_interrupt())
-                       amdtp_stream_pcm_abort(s);
-               WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN);
+               cancel_stream(s);
                return;
        }
 
@@ -790,9 +810,8 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
                                        void *header, void *private_data)
 {
        struct amdtp_stream *s = private_data;
-       __be32 *ctx_header = header;
+       const __be32 *ctx_header = header;
        u32 cycle;
-       unsigned int packets;
 
        /*
         * For in-stream, first packet has come.
@@ -802,23 +821,13 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
        wake_up(&s->callback_wait);
 
        if (s->direction == AMDTP_IN_STREAM) {
-               tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
-               cycle = compute_cycle_count(tstamp);
+               cycle = compute_cycle_count(ctx_header[1]);
 
                context->callback.sc = in_stream_callback;
-               if (s->flags & CIP_NO_HEADER)
-                       s->handle_packet = handle_in_packet_without_header;
-               else
-                       s->handle_packet = handle_in_packet;
        } else {
-               packets = header_length / 4;
-               cycle = compute_cycle_count(tstamp);
-               cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets);
+               cycle = compute_it_cycle(*ctx_header);
+
                context->callback.sc = out_stream_callback;
-               if (s->flags & CIP_NO_HEADER)
-                       s->handle_packet = handle_out_packet_without_header;
-               else
-                       s->handle_packet = handle_out_packet;
        }
 
        s->start_cycle = cycle;
@@ -841,7 +850,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
        static const struct {
                unsigned int data_block;
                unsigned int syt_offset;
-       } initial_state[] = {
+       } *entry, initial_state[] = {
                [CIP_SFC_32000]  = {  4, 3072 },
                [CIP_SFC_48000]  = {  6, 1024 },
                [CIP_SFC_96000]  = { 12, 1024 },
@@ -850,7 +859,8 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
                [CIP_SFC_88200]  = {  0,   67 },
                [CIP_SFC_176400] = {  0,   67 },
        };
-       unsigned int header_size;
+       unsigned int ctx_header_size;
+       unsigned int max_ctx_payload_size;
        enum dma_data_direction dir;
        int type, tag, err;
 
@@ -862,32 +872,46 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
                goto err_unlock;
        }
 
-       if (s->direction == AMDTP_IN_STREAM)
+       if (s->direction == AMDTP_IN_STREAM) {
                s->data_block_counter = UINT_MAX;
-       else
+       } else {
+               entry = &initial_state[s->sfc];
+
                s->data_block_counter = 0;
-       s->data_block_state = initial_state[s->sfc].data_block;
-       s->syt_offset_state = initial_state[s->sfc].syt_offset;
-       s->last_syt_offset = TICKS_PER_CYCLE;
+               s->ctx_data.rx.data_block_state = entry->data_block;
+               s->ctx_data.rx.syt_offset_state = entry->syt_offset;
+               s->ctx_data.rx.last_syt_offset = TICKS_PER_CYCLE;
+       }
 
        /* initialize packet buffer */
        if (s->direction == AMDTP_IN_STREAM) {
                dir = DMA_FROM_DEVICE;
                type = FW_ISO_CONTEXT_RECEIVE;
-               header_size = IR_HEADER_SIZE;
+               if (!(s->flags & CIP_NO_HEADER))
+                       ctx_header_size = IR_CTX_HEADER_SIZE_CIP;
+               else
+                       ctx_header_size = IR_CTX_HEADER_SIZE_NO_CIP;
+
+               max_ctx_payload_size = amdtp_stream_get_max_payload(s) -
+                                      ctx_header_size;
        } else {
                dir = DMA_TO_DEVICE;
                type = FW_ISO_CONTEXT_TRANSMIT;
-               header_size = OUT_PACKET_HEADER_SIZE;
+               ctx_header_size = 0;    // No effect for IT context.
+
+               max_ctx_payload_size = amdtp_stream_get_max_payload(s);
+               if (!(s->flags & CIP_NO_HEADER))
+                       max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP;
        }
+
        err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH,
-                                     amdtp_stream_get_max_payload(s), dir);
+                                     max_ctx_payload_size, dir);
        if (err < 0)
                goto err_unlock;
 
        s->context = fw_iso_context_create(fw_parent_device(s->unit)->card,
-                                          type, channel, speed, header_size,
-                                          amdtp_stream_first_callback, s);
+                                         type, channel, speed, ctx_header_size,
+                                         amdtp_stream_first_callback, s);
        if (IS_ERR(s->context)) {
                err = PTR_ERR(s->context);
                if (err == -EBUSY)
@@ -898,8 +922,10 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
 
        amdtp_stream_update(s);
 
-       if (s->direction == AMDTP_IN_STREAM)
-               s->max_payload_length = amdtp_stream_get_max_payload(s);
+       if (s->direction == AMDTP_IN_STREAM) {
+               s->ctx_data.tx.max_ctx_payload_length = max_ctx_payload_size;
+               s->ctx_data.tx.ctx_header_size = ctx_header_size;
+       }
 
        if (s->flags & CIP_NO_HEADER)
                s->tag = TAG_NO_CIP_HEADER;
@@ -908,10 +934,14 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
 
        s->packet_index = 0;
        do {
-               if (s->direction == AMDTP_IN_STREAM)
-                       err = queue_in_packet(s);
-               else
-                       err = queue_out_packet(s, 0);
+               struct fw_iso_packet params;
+               if (s->direction == AMDTP_IN_STREAM) {
+                       err = queue_in_packet(s, &params);
+               } else {
+                       params.header_length = 0;
+                       params.payload_length = 0;
+                       err = queue_out_packet(s, &params);
+               }
                if (err < 0)
                        goto err_context;
        } while (s->packet_index > 0);
index e45de3e..3942894 100644 (file)
@@ -108,10 +108,31 @@ struct amdtp_stream {
        struct iso_packets_buffer buffer;
        int packet_index;
        int tag;
-       int (*handle_packet)(struct amdtp_stream *s,
-                       unsigned int payload_quadlets, unsigned int cycle,
-                       unsigned int index);
-       unsigned int max_payload_length;
+       union {
+               struct {
+                       unsigned int ctx_header_size;
+
+                       // limit for payload of iso packet.
+                       unsigned int max_ctx_payload_length;
+
+                       // For quirks of CIP headers.
+                       // Fixed interval of dbc between previos/current
+                       // packets.
+                       unsigned int dbc_interval;
+                       // Indicate the value of dbc field in a first packet.
+                       unsigned int first_dbc;
+               } tx;
+               struct {
+                       // To calculate CIP data blocks and tstamp.
+                       unsigned int transfer_delay;
+                       unsigned int data_block_state;
+                       unsigned int last_syt_offset;
+                       unsigned int syt_offset_state;
+
+                       // To generate CIP header.
+                       unsigned int fdf;
+               } rx;
+       } ctx_data;
 
        /* For CIP headers. */
        unsigned int source_node_id_field;
@@ -119,19 +140,10 @@ struct amdtp_stream {
        unsigned int data_block_counter;
        unsigned int sph;
        unsigned int fmt;
-       unsigned int fdf;
-       /* quirk: fixed interval of dbc between previos/current packets. */
-       unsigned int tx_dbc_interval;
-       /* quirk: indicate the value of dbc field in a first packet. */
-       unsigned int tx_first_dbc;
 
        /* Internal flags. */
        enum cip_sfc sfc;
        unsigned int syt_interval;
-       unsigned int transfer_delay;
-       unsigned int data_block_state;
-       unsigned int last_syt_offset;
-       unsigned int syt_offset_state;
 
        /* For a PCM substream processing. */
        struct snd_pcm_substream *pcm;
index af71dac..9e0b689 100644 (file)
@@ -92,8 +92,6 @@ struct snd_bebob {
        unsigned int midi_input_ports;
        unsigned int midi_output_ports;
 
-       bool connected;
-
        struct amdtp_stream tx_stream;
        struct amdtp_stream rx_stream;
        struct cmp_connection out_conn;
@@ -217,7 +215,8 @@ int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
                                   enum snd_bebob_clock_type *src);
 int snd_bebob_stream_discover(struct snd_bebob *bebob);
 int snd_bebob_stream_init_duplex(struct snd_bebob *bebob);
-int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate);
+int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate);
+int snd_bebob_stream_start_duplex(struct snd_bebob *bebob);
 void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob);
 void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);
 
index c54ac42..4d8805f 100644 (file)
@@ -7,58 +7,31 @@
 
 #include "bebob.h"
 
-static int midi_capture_open(struct snd_rawmidi_substream *substream)
+static int midi_open(struct snd_rawmidi_substream *substream)
 {
        struct snd_bebob *bebob = substream->rmidi->private_data;
        int err;
 
        err = snd_bebob_stream_lock_try(bebob);
        if (err < 0)
-               goto end;
+               return err;
 
        mutex_lock(&bebob->mutex);
-       bebob->substreams_counter++;
-       err = snd_bebob_stream_start_duplex(bebob, 0);
+       err = snd_bebob_stream_reserve_duplex(bebob, 0);
+       if (err >= 0) {
+               ++bebob->substreams_counter;
+               err = snd_bebob_stream_start_duplex(bebob);
+               if (err < 0)
+                       --bebob->substreams_counter;
+       }
        mutex_unlock(&bebob->mutex);
        if (err < 0)
                snd_bebob_stream_lock_release(bebob);
-end:
-       return err;
-}
-
-static int midi_playback_open(struct snd_rawmidi_substream *substream)
-{
-       struct snd_bebob *bebob = substream->rmidi->private_data;
-       int err;
-
-       err = snd_bebob_stream_lock_try(bebob);
-       if (err < 0)
-               goto end;
 
-       mutex_lock(&bebob->mutex);
-       bebob->substreams_counter++;
-       err = snd_bebob_stream_start_duplex(bebob, 0);
-       mutex_unlock(&bebob->mutex);
-       if (err < 0)
-               snd_bebob_stream_lock_release(bebob);
-end:
        return err;
 }
 
-static int midi_capture_close(struct snd_rawmidi_substream *substream)
-{
-       struct snd_bebob *bebob = substream->rmidi->private_data;
-
-       mutex_lock(&bebob->mutex);
-       bebob->substreams_counter--;
-       snd_bebob_stream_stop_duplex(bebob);
-       mutex_unlock(&bebob->mutex);
-
-       snd_bebob_stream_lock_release(bebob);
-       return 0;
-}
-
-static int midi_playback_close(struct snd_rawmidi_substream *substream)
+static int midi_close(struct snd_rawmidi_substream *substream)
 {
        struct snd_bebob *bebob = substream->rmidi->private_data;
 
@@ -120,13 +93,13 @@ static void set_midi_substream_names(struct snd_bebob *bebob,
 int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
 {
        static const struct snd_rawmidi_ops capture_ops = {
-               .open           = midi_capture_open,
-               .close          = midi_capture_close,
+               .open           = midi_open,
+               .close          = midi_close,
                .trigger        = midi_capture_trigger,
        };
        static const struct snd_rawmidi_ops playback_ops = {
-               .open           = midi_playback_open,
-               .close          = midi_playback_close,
+               .open           = midi_open,
+               .close          = midi_close,
                .trigger        = midi_playback_trigger,
        };
        struct snd_rawmidi *rmidi;
index 2f50ec7..0fb9eed 100644 (file)
@@ -184,9 +184,8 @@ pcm_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int
-pcm_capture_hw_params(struct snd_pcm_substream *substream,
-                     struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
 {
        struct snd_bebob *bebob = substream->private_data;
        int err;
@@ -197,62 +196,31 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&bebob->mutex);
-               bebob->substreams_counter++;
-               mutex_unlock(&bebob->mutex);
-       }
+               unsigned int rate = params_rate(hw_params);
 
-       return 0;
-}
-static int
-pcm_playback_hw_params(struct snd_pcm_substream *substream,
-                      struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_bebob *bebob = substream->private_data;
-       int err;
-
-       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
-                                              params_buffer_bytes(hw_params));
-       if (err < 0)
-               return err;
-
-       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                mutex_lock(&bebob->mutex);
-               bebob->substreams_counter++;
+               err = snd_bebob_stream_reserve_duplex(bebob, rate);
+               if (err >= 0)
+                       ++bebob->substreams_counter;
                mutex_unlock(&bebob->mutex);
        }
 
-       return 0;
+       return err;
 }
 
-static int
-pcm_capture_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_bebob *bebob = substream->private_data;
 
-       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&bebob->mutex);
-               bebob->substreams_counter--;
-               mutex_unlock(&bebob->mutex);
-       }
-
-       snd_bebob_stream_stop_duplex(bebob);
+       mutex_lock(&bebob->mutex);
 
-       return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-static int
-pcm_playback_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_bebob *bebob = substream->private_data;
-
-       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&bebob->mutex);
+       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
                bebob->substreams_counter--;
-               mutex_unlock(&bebob->mutex);
-       }
 
        snd_bebob_stream_stop_duplex(bebob);
 
+       mutex_unlock(&bebob->mutex);
+
        return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
 
@@ -260,10 +228,9 @@ static int
 pcm_capture_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_bebob *bebob = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
-       err = snd_bebob_stream_start_duplex(bebob, runtime->rate);
+       err = snd_bebob_stream_start_duplex(bebob);
        if (err >= 0)
                amdtp_stream_pcm_prepare(&bebob->tx_stream);
 
@@ -273,10 +240,9 @@ static int
 pcm_playback_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_bebob *bebob = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
-       err = snd_bebob_stream_start_duplex(bebob, runtime->rate);
+       err = snd_bebob_stream_start_duplex(bebob);
        if (err >= 0)
                amdtp_stream_pcm_prepare(&bebob->rx_stream);
 
@@ -353,8 +319,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_capture_hw_params,
-               .hw_free        = pcm_capture_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_capture_prepare,
                .trigger        = pcm_capture_trigger,
                .pointer        = pcm_capture_pointer,
@@ -365,8 +331,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_playback_hw_params,
-               .hw_free        = pcm_playback_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_playback_prepare,
                .trigger        = pcm_playback_trigger,
                .pointer        = pcm_playback_pointer,
index 0c93a82..334dc7c 100644 (file)
@@ -376,24 +376,6 @@ end:
 }
 
 static int
-init_both_connections(struct snd_bebob *bebob)
-{
-       int err;
-
-       err = cmp_connection_init(&bebob->in_conn,
-                                 bebob->unit, CMP_INPUT, 0);
-       if (err < 0)
-               goto end;
-
-       err = cmp_connection_init(&bebob->out_conn,
-                                 bebob->unit, CMP_OUTPUT, 0);
-       if (err < 0)
-               cmp_connection_destroy(&bebob->in_conn);
-end:
-       return err;
-}
-
-static int
 check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s)
 {
        struct cmp_connection *conn;
@@ -417,49 +399,21 @@ check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s)
        return err;
 }
 
-static int
-make_both_connections(struct snd_bebob *bebob, unsigned int rate)
+static int make_both_connections(struct snd_bebob *bebob)
 {
-       int index, pcm_channels, midi_channels, err = 0;
-
-       if (bebob->connected)
-               goto end;
-
-       /* confirm params for both streams */
-       err = get_formation_index(rate, &index);
-       if (err < 0)
-               goto end;
-       pcm_channels = bebob->tx_stream_formations[index].pcm;
-       midi_channels = bebob->tx_stream_formations[index].midi;
-       err = amdtp_am824_set_parameters(&bebob->tx_stream, rate,
-                                        pcm_channels, midi_channels * 8,
-                                        false);
-       if (err < 0)
-               goto end;
+       int err = 0;
 
-       pcm_channels = bebob->rx_stream_formations[index].pcm;
-       midi_channels = bebob->rx_stream_formations[index].midi;
-       err = amdtp_am824_set_parameters(&bebob->rx_stream, rate,
-                                        pcm_channels, midi_channels * 8,
-                                        false);
+       err = cmp_connection_establish(&bebob->out_conn);
        if (err < 0)
-               goto end;
+               return err;
 
-       /* establish connections for both streams */
-       err = cmp_connection_establish(&bebob->out_conn,
-                       amdtp_stream_get_max_payload(&bebob->tx_stream));
-       if (err < 0)
-               goto end;
-       err = cmp_connection_establish(&bebob->in_conn,
-                       amdtp_stream_get_max_payload(&bebob->rx_stream));
+       err = cmp_connection_establish(&bebob->in_conn);
        if (err < 0) {
                cmp_connection_break(&bebob->out_conn);
-               goto end;
+               return err;
        }
 
-       bebob->connected = true;
-end:
-       return err;
+       return 0;
 }
 
 static void
@@ -468,23 +422,13 @@ break_both_connections(struct snd_bebob *bebob)
        cmp_connection_break(&bebob->in_conn);
        cmp_connection_break(&bebob->out_conn);
 
-       bebob->connected = false;
-
        /* These models seems to be in transition state for a longer time. */
        if (bebob->maudio_special_quirk != NULL)
                msleep(200);
 }
 
-static void
-destroy_both_connections(struct snd_bebob *bebob)
-{
-       cmp_connection_destroy(&bebob->in_conn);
-       cmp_connection_destroy(&bebob->out_conn);
-}
-
 static int
-start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream,
-            unsigned int rate)
+start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
 {
        struct cmp_connection *conn;
        int err = 0;
@@ -509,190 +453,252 @@ end:
        return err;
 }
 
-int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
+static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
 {
+       enum amdtp_stream_direction dir_stream;
+       struct cmp_connection *conn;
+       enum cmp_direction dir_conn;
        int err;
 
-       err = init_both_connections(bebob);
+       if (stream == &bebob->tx_stream) {
+               dir_stream = AMDTP_IN_STREAM;
+               conn = &bebob->out_conn;
+               dir_conn = CMP_OUTPUT;
+       } else {
+               dir_stream = AMDTP_OUT_STREAM;
+               conn = &bebob->in_conn;
+               dir_conn = CMP_INPUT;
+       }
+
+       err = cmp_connection_init(conn, bebob->unit, dir_conn, 0);
        if (err < 0)
-               goto end;
+               return err;
 
-       err = amdtp_am824_init(&bebob->tx_stream, bebob->unit,
-                              AMDTP_IN_STREAM, CIP_BLOCKING);
+       err = amdtp_am824_init(stream, bebob->unit, dir_stream, CIP_BLOCKING);
        if (err < 0) {
-               amdtp_stream_destroy(&bebob->tx_stream);
-               destroy_both_connections(bebob);
-               goto end;
+               cmp_connection_destroy(conn);
+               return err;
        }
 
-       /*
-        * BeBoB v3 transfers packets with these qurks:
-        *  - In the beginning of streaming, the value of dbc is incremented
-        *    even if no data blocks are transferred.
-        *  - The value of dbc is reset suddenly.
-        */
-       if (bebob->version > 2)
-               bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC |
-                                         CIP_SKIP_DBC_ZERO_CHECK;
+       if (stream == &bebob->tx_stream) {
+               // BeBoB v3 transfers packets with these qurks:
+               //  - In the beginning of streaming, the value of dbc is
+               //    incremented even if no data blocks are transferred.
+               //  - The value of dbc is reset suddenly.
+               if (bebob->version > 2)
+                       bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC |
+                                                 CIP_SKIP_DBC_ZERO_CHECK;
+
+               // At high sampling rate, M-Audio special firmware transmits
+               // empty packet with the value of dbc incremented by 8 but the
+               // others are valid to IEC 61883-1.
+               if (bebob->maudio_special_quirk)
+                       bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
+       }
 
-       /*
-        * At high sampling rate, M-Audio special firmware transmits empty
-        * packet with the value of dbc incremented by 8 but the others are
-        * valid to IEC 61883-1.
-        */
-       if (bebob->maudio_special_quirk)
-               bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
+       return 0;
+}
+
+static void destroy_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
+{
+       amdtp_stream_destroy(stream);
+
+       if (stream == &bebob->tx_stream)
+               cmp_connection_destroy(&bebob->out_conn);
+       else
+               cmp_connection_destroy(&bebob->in_conn);
+}
+
+int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
+{
+       int err;
 
-       err = amdtp_am824_init(&bebob->rx_stream, bebob->unit,
-                              AMDTP_OUT_STREAM, CIP_BLOCKING);
+       err = init_stream(bebob, &bebob->tx_stream);
+       if (err < 0)
+               return err;
+
+       err = init_stream(bebob, &bebob->rx_stream);
        if (err < 0) {
-               amdtp_stream_destroy(&bebob->tx_stream);
-               amdtp_stream_destroy(&bebob->rx_stream);
-               destroy_both_connections(bebob);
+               destroy_stream(bebob, &bebob->tx_stream);
+               return err;
        }
-end:
-       return err;
+
+       return 0;
 }
 
-int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
+static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream,
+                         unsigned int rate, unsigned int index)
 {
-       const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
-       unsigned int curr_rate;
-       int err = 0;
+       struct snd_bebob_stream_formation *formation;
+       struct cmp_connection *conn;
+       int err;
 
-       /* Need no substreams */
-       if (bebob->substreams_counter == 0)
-               goto end;
+       if (stream == &bebob->tx_stream) {
+               formation = bebob->tx_stream_formations + index;
+               conn = &bebob->out_conn;
+       } else {
+               formation = bebob->rx_stream_formations + index;
+               conn = &bebob->in_conn;
+       }
 
-       /*
-        * Considering JACK/FFADO streaming:
-        * TODO: This can be removed hwdep functionality becomes popular.
-        */
+       err = amdtp_am824_set_parameters(stream, rate, formation->pcm,
+                                        formation->midi, false);
+       if (err < 0)
+               return err;
+
+       return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
+}
+
+int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate)
+{
+       unsigned int curr_rate;
+       int err;
+
+       // Considering JACK/FFADO streaming:
+       // TODO: This can be removed hwdep functionality becomes popular.
        err = check_connection_used_by_others(bebob, &bebob->rx_stream);
        if (err < 0)
-               goto end;
+               return err;
 
-       /*
-        * packet queueing error or detecting discontinuity
-        *
-        * At bus reset, connections should not be broken here. So streams need
-        * to be re-started. This is a reason to use SKIP_INIT_DBC_CHECK flag.
-        */
-       if (amdtp_streaming_error(&bebob->rx_stream))
-               amdtp_stream_stop(&bebob->rx_stream);
-       if (amdtp_streaming_error(&bebob->tx_stream))
+       err = bebob->spec->rate->get(bebob, &curr_rate);
+       if (err < 0)
+               return err;
+       if (rate == 0)
+               rate = curr_rate;
+       if (curr_rate != rate) {
                amdtp_stream_stop(&bebob->tx_stream);
-       if (!amdtp_stream_running(&bebob->rx_stream) &&
-           !amdtp_stream_running(&bebob->tx_stream))
+               amdtp_stream_stop(&bebob->rx_stream);
+
                break_both_connections(bebob);
 
-       /* stop streams if rate is different */
-       err = rate_spec->get(bebob, &curr_rate);
-       if (err < 0) {
-               dev_err(&bebob->unit->device,
-                       "fail to get sampling rate: %d\n", err);
-               goto end;
+               cmp_connection_release(&bebob->out_conn);
+               cmp_connection_release(&bebob->in_conn);
        }
-       if (rate == 0)
-               rate = curr_rate;
-       if (rate != curr_rate) {
+
+       if (bebob->substreams_counter == 0 || curr_rate != rate) {
+               unsigned int index;
+
+               // NOTE:
+               // If establishing connections at first, Yamaha GO46
+               // (and maybe Terratec X24) don't generate sound.
+               //
+               // For firmware customized by M-Audio, refer to next NOTE.
+               err = bebob->spec->rate->set(bebob, rate);
+               if (err < 0) {
+                       dev_err(&bebob->unit->device,
+                               "fail to set sampling rate: %d\n",
+                               err);
+                       return err;
+               }
+
+               err = get_formation_index(rate, &index);
+               if (err < 0)
+                       return err;
+
+               err = keep_resources(bebob, &bebob->tx_stream, rate, index);
+               if (err < 0)
+                       return err;
+
+               err = keep_resources(bebob, &bebob->rx_stream, rate, index);
+               if (err < 0) {
+                       cmp_connection_release(&bebob->out_conn);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
+{
+       int err;
+
+       // Need no substreams.
+       if (bebob->substreams_counter == 0)
+               return -EIO;
+
+       // packet queueing error or detecting discontinuity
+       if (amdtp_streaming_error(&bebob->rx_stream) ||
+           amdtp_streaming_error(&bebob->tx_stream)) {
                amdtp_stream_stop(&bebob->rx_stream);
                amdtp_stream_stop(&bebob->tx_stream);
+
                break_both_connections(bebob);
        }
 
-       /* master should be always running */
        if (!amdtp_stream_running(&bebob->rx_stream)) {
-               /*
-                * NOTE:
-                * If establishing connections at first, Yamaha GO46
-                * (and maybe Terratec X24) don't generate sound.
-                *
-                * For firmware customized by M-Audio, refer to next NOTE.
-                */
-               if (bebob->maudio_special_quirk == NULL) {
-                       err = rate_spec->set(bebob, rate);
-                       if (err < 0) {
-                               dev_err(&bebob->unit->device,
-                                       "fail to set sampling rate: %d\n",
-                                       err);
-                               goto end;
-                       }
+               unsigned int curr_rate;
+
+               if (bebob->maudio_special_quirk) {
+                       err = bebob->spec->rate->get(bebob, &curr_rate);
+                       if (err < 0)
+                               return err;
                }
 
-               err = make_both_connections(bebob, rate);
+               err = make_both_connections(bebob);
                if (err < 0)
-                       goto end;
+                       return err;
 
-               err = start_stream(bebob, &bebob->rx_stream, rate);
+               err = start_stream(bebob, &bebob->rx_stream);
                if (err < 0) {
                        dev_err(&bebob->unit->device,
                                "fail to run AMDTP master stream:%d\n", err);
-                       break_both_connections(bebob);
-                       goto end;
+                       goto error;
                }
 
-               /*
-                * NOTE:
-                * The firmware customized by M-Audio uses these commands to
-                * start transmitting stream. This is not usual way.
-                */
-               if (bebob->maudio_special_quirk != NULL) {
-                       err = rate_spec->set(bebob, rate);
+               // NOTE:
+               // The firmware customized by M-Audio uses these commands to
+               // start transmitting stream. This is not usual way.
+               if (bebob->maudio_special_quirk) {
+                       err = bebob->spec->rate->set(bebob, curr_rate);
                        if (err < 0) {
                                dev_err(&bebob->unit->device,
                                        "fail to ensure sampling rate: %d\n",
                                        err);
-                               amdtp_stream_stop(&bebob->rx_stream);
-                               break_both_connections(bebob);
-                               goto end;
+                               goto error;
                        }
                }
 
-               /* wait first callback */
                if (!amdtp_stream_wait_callback(&bebob->rx_stream,
                                                CALLBACK_TIMEOUT)) {
-                       amdtp_stream_stop(&bebob->rx_stream);
-                       break_both_connections(bebob);
                        err = -ETIMEDOUT;
-                       goto end;
+                       goto error;
                }
        }
 
-       /* start slave if needed */
        if (!amdtp_stream_running(&bebob->tx_stream)) {
-               err = start_stream(bebob, &bebob->tx_stream, rate);
+               err = start_stream(bebob, &bebob->tx_stream);
                if (err < 0) {
                        dev_err(&bebob->unit->device,
                                "fail to run AMDTP slave stream:%d\n", err);
-                       amdtp_stream_stop(&bebob->rx_stream);
-                       break_both_connections(bebob);
-                       goto end;
+                       goto error;
                }
 
-               /* wait first callback */
                if (!amdtp_stream_wait_callback(&bebob->tx_stream,
                                                CALLBACK_TIMEOUT)) {
-                       amdtp_stream_stop(&bebob->tx_stream);
-                       amdtp_stream_stop(&bebob->rx_stream);
-                       break_both_connections(bebob);
                        err = -ETIMEDOUT;
+                       goto error;
                }
        }
-end:
+
+       return 0;
+error:
+       amdtp_stream_stop(&bebob->tx_stream);
+       amdtp_stream_stop(&bebob->rx_stream);
+       break_both_connections(bebob);
        return err;
 }
 
 void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
 {
        if (bebob->substreams_counter == 0) {
-               amdtp_stream_pcm_abort(&bebob->rx_stream);
                amdtp_stream_stop(&bebob->rx_stream);
-
-               amdtp_stream_pcm_abort(&bebob->tx_stream);
                amdtp_stream_stop(&bebob->tx_stream);
 
                break_both_connections(bebob);
+
+               cmp_connection_release(&bebob->out_conn);
+               cmp_connection_release(&bebob->in_conn);
        }
 }
 
@@ -702,10 +708,8 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
  */
 void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
 {
-       amdtp_stream_destroy(&bebob->rx_stream);
-       amdtp_stream_destroy(&bebob->tx_stream);
-
-       destroy_both_connections(bebob);
+       destroy_stream(bebob, &bebob->tx_stream);
+       destroy_stream(bebob, &bebob->rx_stream);
 }
 
 /*
index 13f8abc..14abbe7 100644 (file)
@@ -185,6 +185,37 @@ void cmp_connection_destroy(struct cmp_connection *c)
 }
 EXPORT_SYMBOL(cmp_connection_destroy);
 
+int cmp_connection_reserve(struct cmp_connection *c,
+                          unsigned int max_payload_bytes)
+{
+       int err;
+
+       mutex_lock(&c->mutex);
+
+       if (WARN_ON(c->resources.allocated)) {
+               err = -EBUSY;
+               goto end;
+       }
+
+       c->speed = min(c->max_speed,
+                      fw_parent_device(c->resources.unit)->max_speed);
+
+       err = fw_iso_resources_allocate(&c->resources, max_payload_bytes,
+                                       c->speed);
+end:
+       mutex_unlock(&c->mutex);
+
+       return err;
+}
+EXPORT_SYMBOL(cmp_connection_reserve);
+
+void cmp_connection_release(struct cmp_connection *c)
+{
+       mutex_lock(&c->mutex);
+       fw_iso_resources_free(&c->resources);
+       mutex_unlock(&c->mutex);
+}
+EXPORT_SYMBOL(cmp_connection_release);
 
 static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr)
 {
@@ -270,25 +301,18 @@ static int pcr_set_check(struct cmp_connection *c, __be32 pcr)
  * When this function succeeds, the caller is responsible for starting
  * transmitting packets.
  */
-int cmp_connection_establish(struct cmp_connection *c,
-                            unsigned int max_payload_bytes)
+int cmp_connection_establish(struct cmp_connection *c)
 {
        int err;
 
-       if (WARN_ON(c->connected))
-               return -EISCONN;
-
-       c->speed = min(c->max_speed,
-                      fw_parent_device(c->resources.unit)->max_speed);
-
        mutex_lock(&c->mutex);
 
-retry_after_bus_reset:
-       err = fw_iso_resources_allocate(&c->resources,
-                                       max_payload_bytes, c->speed);
-       if (err < 0)
-               goto err_mutex;
+       if (WARN_ON(c->connected)) {
+               mutex_unlock(&c->mutex);
+               return -EISCONN;
+       }
 
+retry_after_bus_reset:
        if (c->direction == CMP_OUTPUT)
                err = pcr_modify(c, opcr_set_modify, pcr_set_check,
                                 ABORT_ON_BUS_RESET);
@@ -297,21 +321,13 @@ retry_after_bus_reset:
                                 ABORT_ON_BUS_RESET);
 
        if (err == -EAGAIN) {
-               fw_iso_resources_free(&c->resources);
-               goto retry_after_bus_reset;
+               err = fw_iso_resources_update(&c->resources);
+               if (err >= 0)
+                       goto retry_after_bus_reset;
        }
-       if (err < 0)
-               goto err_resources;
-
-       c->connected = true;
-
-       mutex_unlock(&c->mutex);
-
-       return 0;
+       if (err >= 0)
+               c->connected = true;
 
-err_resources:
-       fw_iso_resources_free(&c->resources);
-err_mutex:
        mutex_unlock(&c->mutex);
 
        return err;
@@ -351,14 +367,12 @@ int cmp_connection_update(struct cmp_connection *c)
                                 SUCCEED_ON_BUS_RESET);
 
        if (err < 0)
-               goto err_resources;
+               goto err_unconnect;
 
        mutex_unlock(&c->mutex);
 
        return 0;
 
-err_resources:
-       fw_iso_resources_free(&c->resources);
 err_unconnect:
        c->connected = false;
        mutex_unlock(&c->mutex);
@@ -395,8 +409,6 @@ void cmp_connection_break(struct cmp_connection *c)
        if (err < 0)
                cmp_error(c, "plug is still connected\n");
 
-       fw_iso_resources_free(&c->resources);
-
        c->connected = false;
 
        mutex_unlock(&c->mutex);
index b60b415..26ab880 100644 (file)
@@ -42,8 +42,11 @@ int cmp_connection_init(struct cmp_connection *connection,
 int cmp_connection_check_used(struct cmp_connection *connection, bool *used);
 void cmp_connection_destroy(struct cmp_connection *connection);
 
-int cmp_connection_establish(struct cmp_connection *connection,
-                            unsigned int max_payload);
+int cmp_connection_reserve(struct cmp_connection *connection,
+                          unsigned int max_payload);
+void cmp_connection_release(struct cmp_connection *connection);
+
+int cmp_connection_establish(struct cmp_connection *connection);
 int cmp_connection_update(struct cmp_connection *connection);
 void cmp_connection_break(struct cmp_connection *connection);
 
index 115eadd..7a62daf 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
                 dice-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \
-                dice-alesis.o dice-extension.o dice-mytek.o
+                dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.o
 obj-$(CONFIG_SND_DICE) += snd-dice.o
index ca7ae42..c9e19bd 100644 (file)
@@ -17,8 +17,13 @@ static int midi_open(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&dice->mutex);
 
-       dice->substreams_counter++;
-       err = snd_dice_stream_start_duplex(dice, 0);
+       err = snd_dice_stream_reserve_duplex(dice, 0);
+       if (err >= 0) {
+               ++dice->substreams_counter;
+               err = snd_dice_stream_start_duplex(dice);
+               if (err < 0)
+                       --dice->substreams_counter;
+       }
 
        mutex_unlock(&dice->mutex);
 
@@ -34,7 +39,7 @@ static int midi_close(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&dice->mutex);
 
-       dice->substreams_counter--;
+       --dice->substreams_counter;
        snd_dice_stream_stop_duplex(dice);
 
        mutex_unlock(&dice->mutex);
index 8a601be..94a4dcc 100644 (file)
@@ -230,8 +230,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int capture_hw_params(struct snd_pcm_substream *substream,
-                            struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
 {
        struct snd_dice *dice = substream->private_data;
        int err;
@@ -242,57 +242,26 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&dice->mutex);
-               dice->substreams_counter++;
-               mutex_unlock(&dice->mutex);
-       }
-
-       return 0;
-}
-static int playback_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_dice *dice = substream->private_data;
-       int err;
-
-       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
-                                              params_buffer_bytes(hw_params));
-       if (err < 0)
-               return err;
+               unsigned int rate = params_rate(hw_params);
 
-       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                mutex_lock(&dice->mutex);
-               dice->substreams_counter++;
+               err = snd_dice_stream_reserve_duplex(dice, rate);
+               if (err >= 0)
+                       ++dice->substreams_counter;
                mutex_unlock(&dice->mutex);
        }
 
-       return 0;
-}
-
-static int capture_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_dice *dice = substream->private_data;
-
-       mutex_lock(&dice->mutex);
-
-       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               dice->substreams_counter--;
-
-       snd_dice_stream_stop_duplex(dice);
-
-       mutex_unlock(&dice->mutex);
-
-       return snd_pcm_lib_free_vmalloc_buffer(substream);
+       return err;
 }
 
-static int playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_dice *dice = substream->private_data;
 
        mutex_lock(&dice->mutex);
 
        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               dice->substreams_counter--;
+               --dice->substreams_counter;
 
        snd_dice_stream_stop_duplex(dice);
 
@@ -308,7 +277,7 @@ static int capture_prepare(struct snd_pcm_substream *substream)
        int err;
 
        mutex_lock(&dice->mutex);
-       err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
+       err = snd_dice_stream_start_duplex(dice);
        mutex_unlock(&dice->mutex);
        if (err >= 0)
                amdtp_stream_pcm_prepare(stream);
@@ -322,7 +291,7 @@ static int playback_prepare(struct snd_pcm_substream *substream)
        int err;
 
        mutex_lock(&dice->mutex);
-       err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
+       err = snd_dice_stream_start_duplex(dice);
        mutex_unlock(&dice->mutex);
        if (err >= 0)
                amdtp_stream_pcm_prepare(stream);
@@ -404,8 +373,8 @@ int snd_dice_create_pcm(struct snd_dice *dice)
                .open      = pcm_open,
                .close     = pcm_close,
                .ioctl     = snd_pcm_lib_ioctl,
-               .hw_params = capture_hw_params,
-               .hw_free   = capture_hw_free,
+               .hw_params = pcm_hw_params,
+               .hw_free   = pcm_hw_free,
                .prepare   = capture_prepare,
                .trigger   = capture_trigger,
                .pointer   = capture_pointer,
@@ -416,8 +385,8 @@ int snd_dice_create_pcm(struct snd_dice *dice)
                .open      = pcm_open,
                .close     = pcm_close,
                .ioctl     = snd_pcm_lib_ioctl,
-               .hw_params = playback_hw_params,
-               .hw_free   = playback_hw_free,
+               .hw_params = pcm_hw_params,
+               .hw_free   = pcm_hw_free,
                .prepare   = playback_prepare,
                .trigger   = playback_trigger,
                .pointer   = playback_pointer,
diff --git a/sound/firewire/dice/dice-presonus.c b/sound/firewire/dice/dice-presonus.c
new file mode 100644 (file)
index 0000000..503f462
--- /dev/null
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+// dice-presonus.c - a part of driver for DICE based devices
+//
+// Copyright (c) 2019 Takashi Sakamoto
+//
+// Licensed under the terms of the GNU General Public License, version 2.
+
+#include "dice.h"
+
+struct dice_presonus_spec {
+       unsigned int tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
+       unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
+       bool has_midi;
+};
+
+static const struct dice_presonus_spec dice_presonus_firesutio = {
+       .tx_pcm_chs = {{16, 16, 0}, {10, 2, 0} },
+       .rx_pcm_chs = {{16, 16, 0}, {10, 2, 0} },
+       .has_midi = true,
+};
+
+int snd_dice_detect_presonus_formats(struct snd_dice *dice)
+{
+       static const struct {
+               u32 model_id;
+               const struct dice_presonus_spec *spec;
+       } *entry, entries[] = {
+               {0x000008, &dice_presonus_firesutio},
+       };
+       struct fw_csr_iterator it;
+       int key, val, model_id;
+       int i;
+
+       model_id = 0;
+       fw_csr_iterator_init(&it, dice->unit->directory);
+       while (fw_csr_iterator_next(&it, &key, &val)) {
+               if (key == CSR_MODEL) {
+                       model_id = val;
+                       break;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(entries); ++i) {
+               entry = entries + i;
+               if (entry->model_id == model_id)
+                       break;
+       }
+       if (i == ARRAY_SIZE(entries))
+               return -ENODEV;
+
+       memcpy(dice->tx_pcm_chs, entry->spec->tx_pcm_chs,
+              MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
+       memcpy(dice->rx_pcm_chs, entry->spec->rx_pcm_chs,
+              MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
+
+       if (entry->spec->has_midi) {
+               dice->tx_midi_ports[0] = 1;
+               dice->rx_midi_ports[0] = 1;
+       }
+
+       return 0;
+}
index 7a93ae3..a9f0c77 100644 (file)
@@ -137,18 +137,9 @@ static int get_register_params(struct snd_dice *dice,
 
 static void release_resources(struct snd_dice *dice)
 {
-       unsigned int i;
-
-       for (i = 0; i < MAX_STREAMS; i++) {
-               if (amdtp_stream_running(&dice->tx_stream[i])) {
-                       amdtp_stream_pcm_abort(&dice->tx_stream[i]);
-                       amdtp_stream_stop(&dice->tx_stream[i]);
-               }
-               if (amdtp_stream_running(&dice->rx_stream[i])) {
-                       amdtp_stream_pcm_abort(&dice->rx_stream[i]);
-                       amdtp_stream_stop(&dice->rx_stream[i]);
-               }
+       int i;
 
+       for (i = 0; i < MAX_STREAMS; ++i) {
                fw_iso_resources_free(&dice->tx_resources[i]);
                fw_iso_resources_free(&dice->rx_resources[i]);
        }
@@ -163,10 +154,14 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
        for (i = 0; i < params->count; i++) {
                reg = cpu_to_be32((u32)-1);
                if (dir == AMDTP_IN_STREAM) {
+                       amdtp_stream_stop(&dice->tx_stream[i]);
+
                        snd_dice_transaction_write_tx(dice,
                                        params->size * i + TX_ISOCHRONOUS,
                                        &reg, sizeof(reg));
                } else {
+                       amdtp_stream_stop(&dice->rx_stream[i]);
+
                        snd_dice_transaction_write_rx(dice,
                                        params->size * i + RX_ISOCHRONOUS,
                                        &reg, sizeof(reg));
@@ -174,35 +169,22 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
        }
 }
 
-static int keep_resources(struct snd_dice *dice,
-                         enum amdtp_stream_direction dir, unsigned int index,
-                         unsigned int rate, unsigned int pcm_chs,
-                         unsigned int midi_ports)
+static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
+                         struct fw_iso_resources *resources, unsigned int rate,
+                         unsigned int pcm_chs, unsigned int midi_ports)
 {
-       struct amdtp_stream *stream;
-       struct fw_iso_resources *resources;
        bool double_pcm_frames;
        unsigned int i;
        int err;
 
-       if (dir == AMDTP_IN_STREAM) {
-               stream = &dice->tx_stream[index];
-               resources = &dice->tx_resources[index];
-       } else {
-               stream = &dice->rx_stream[index];
-               resources = &dice->rx_resources[index];
-       }
-
-       /*
-        * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
-        * one data block of AMDTP packet. Thus sampling transfer frequency is
-        * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
-        * transferred on AMDTP packets at 96 kHz. Two successive samples of a
-        * channel are stored consecutively in the packet. This quirk is called
-        * as 'Dual Wire'.
-        * For this quirk, blocking mode is required and PCM buffer size should
-        * be aligned to SYT_INTERVAL.
-        */
+       // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
+       // one data block of AMDTP packet. Thus sampling transfer frequency is
+       // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
+       // transferred on AMDTP packets at 96 kHz. Two successive samples of a
+       // channel are stored consecutively in the packet. This quirk is called
+       // as 'Dual Wire'.
+       // For this quirk, blocking mode is required and PCM buffer size should
+       // be aligned to SYT_INTERVAL.
        double_pcm_frames = rate > 96000;
        if (double_pcm_frames) {
                rate /= 2;
@@ -229,40 +211,40 @@ static int keep_resources(struct snd_dice *dice,
                                fw_parent_device(dice->unit)->max_speed);
 }
 
-static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
-                        unsigned int rate, struct reg_params *params)
+static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
+                              enum amdtp_stream_direction dir,
+                              struct reg_params *params)
 {
-       __be32 reg[2];
        enum snd_dice_rate_mode mode;
-       unsigned int i, pcm_chs, midi_ports;
-       struct amdtp_stream *streams;
-       struct fw_iso_resources *resources;
-       struct fw_device *fw_dev = fw_parent_device(dice->unit);
-       int err = 0;
-
-       if (dir == AMDTP_IN_STREAM) {
-               streams = dice->tx_stream;
-               resources = dice->tx_resources;
-       } else {
-               streams = dice->rx_stream;
-               resources = dice->rx_resources;
-       }
+       int i;
+       int err;
 
        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
        if (err < 0)
                return err;
 
-       for (i = 0; i < params->count; i++) {
+       for (i = 0; i < params->count; ++i) {
+               __be32 reg[2];
+               struct amdtp_stream *stream;
+               struct fw_iso_resources *resources;
                unsigned int pcm_cache;
                unsigned int midi_cache;
+               unsigned int pcm_chs;
+               unsigned int midi_ports;
 
                if (dir == AMDTP_IN_STREAM) {
+                       stream = &dice->tx_stream[i];
+                       resources = &dice->tx_resources[i];
+
                        pcm_cache = dice->tx_pcm_chs[i][mode];
                        midi_cache = dice->tx_midi_ports[i];
                        err = snd_dice_transaction_read_tx(dice,
                                        params->size * i + TX_NUMBER_AUDIO,
                                        reg, sizeof(reg));
                } else {
+                       stream = &dice->rx_stream[i];
+                       resources = &dice->rx_resources[i];
+
                        pcm_cache = dice->rx_pcm_chs[i][mode];
                        midi_cache = dice->rx_midi_ports[i];
                        err = snd_dice_transaction_read_rx(dice,
@@ -274,7 +256,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
                pcm_chs = be32_to_cpu(reg[0]);
                midi_ports = be32_to_cpu(reg[1]);
 
-               /* These are important for developer of this driver. */
+               // These are important for developer of this driver.
                if (pcm_chs != pcm_cache || midi_ports != midi_cache) {
                        dev_info(&dice->unit->device,
                                 "cache mismatch: pcm: %u:%u, midi: %u:%u\n",
@@ -282,141 +264,170 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
                        return -EPROTO;
                }
 
-               err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports);
-               if (err < 0)
-                       return err;
-
-               reg[0] = cpu_to_be32(resources[i].channel);
-               if (dir == AMDTP_IN_STREAM) {
-                       err = snd_dice_transaction_write_tx(dice,
-                                       params->size * i + TX_ISOCHRONOUS,
-                                       reg, sizeof(reg[0]));
-               } else {
-                       err = snd_dice_transaction_write_rx(dice,
-                                       params->size * i + RX_ISOCHRONOUS,
-                                       reg, sizeof(reg[0]));
-               }
+               err = keep_resources(dice, stream, resources, rate, pcm_chs,
+                                    midi_ports);
                if (err < 0)
                        return err;
+       }
 
-               if (dir == AMDTP_IN_STREAM) {
-                       reg[0] = cpu_to_be32(fw_dev->max_speed);
-                       err = snd_dice_transaction_write_tx(dice,
-                                       params->size * i + TX_SPEED,
-                                       reg, sizeof(reg[0]));
-                       if (err < 0)
-                               return err;
-               }
+       return 0;
+}
 
-               err = amdtp_stream_start(&streams[i], resources[i].channel,
-                                        fw_dev->max_speed);
-               if (err < 0)
-                       return err;
-       }
+static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
+                          struct reg_params *rx_params)
+{
+       stop_streams(dice, AMDTP_IN_STREAM, tx_params);
+       stop_streams(dice, AMDTP_OUT_STREAM, rx_params);
 
-       return err;
+       snd_dice_transaction_clear_enable(dice);
 }
 
-static int start_duplex_streams(struct snd_dice *dice, unsigned int rate)
+int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate)
 {
-       struct reg_params tx_params, rx_params;
-       int i;
+       unsigned int curr_rate;
        int err;
 
-       err = get_register_params(dice, &tx_params, &rx_params);
+       // Check sampling transmission frequency.
+       err = snd_dice_transaction_get_rate(dice, &curr_rate);
        if (err < 0)
                return err;
+       if (rate == 0)
+               rate = curr_rate;
 
-       /* Stop transmission. */
-       stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
-       stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
-       snd_dice_transaction_clear_enable(dice);
-       release_resources(dice);
+       if (dice->substreams_counter == 0 || curr_rate != rate) {
+               struct reg_params tx_params, rx_params;
 
-       err = ensure_phase_lock(dice, rate);
-       if (err < 0) {
-               dev_err(&dice->unit->device, "fail to ensure phase lock\n");
-               return err;
-       }
+               err = get_register_params(dice, &tx_params, &rx_params);
+               if (err < 0)
+                       return err;
 
-       /* Likely to have changed stream formats. */
-       err = get_register_params(dice, &tx_params, &rx_params);
-       if (err < 0)
-               return err;
+               finish_session(dice, &tx_params, &rx_params);
 
-       /* Start both streams. */
-       err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
-       if (err < 0)
-               goto error;
-       err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
-       if (err < 0)
-               goto error;
+               release_resources(dice);
 
-       err = snd_dice_transaction_set_enable(dice);
-       if (err < 0) {
-               dev_err(&dice->unit->device, "fail to enable interface\n");
-               goto error;
-       }
+               // Just after owning the unit (GLOBAL_OWNER), the unit can
+               // return invalid stream formats. Selecting clock parameters
+               // have an effect for the unit to refine it.
+               err = ensure_phase_lock(dice, rate);
+               if (err < 0)
+                       return err;
 
-       for (i = 0; i < MAX_STREAMS; i++) {
-               if ((i < tx_params.count &&
-                   !amdtp_stream_wait_callback(&dice->tx_stream[i],
-                                               CALLBACK_TIMEOUT)) ||
-                   (i < rx_params.count &&
-                    !amdtp_stream_wait_callback(&dice->rx_stream[i],
-                                                CALLBACK_TIMEOUT))) {
-                       err = -ETIMEDOUT;
+               // After changing sampling transfer frequency, the value of
+               // register can be changed.
+               err = get_register_params(dice, &tx_params, &rx_params);
+               if (err < 0)
+                       return err;
+
+               err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,
+                                         &tx_params);
+               if (err < 0)
+                       goto error;
+
+               err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,
+                                         &rx_params);
+               if (err < 0)
                        goto error;
-               }
        }
 
        return 0;
 error:
-       stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
-       stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
-       snd_dice_transaction_clear_enable(dice);
        release_resources(dice);
        return err;
 }
 
+static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
+                        unsigned int rate, struct reg_params *params)
+{
+       unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
+       int i;
+       int err;
+
+       for (i = 0; i < params->count; i++) {
+               struct amdtp_stream *stream;
+               struct fw_iso_resources *resources;
+               __be32 reg;
+
+               if (dir == AMDTP_IN_STREAM) {
+                       stream = dice->tx_stream + i;
+                       resources = dice->tx_resources + i;
+               } else {
+                       stream = dice->rx_stream + i;
+                       resources = dice->rx_resources + i;
+               }
+
+               reg = cpu_to_be32(resources->channel);
+               if (dir == AMDTP_IN_STREAM) {
+                       err = snd_dice_transaction_write_tx(dice,
+                                       params->size * i + TX_ISOCHRONOUS,
+                                       &reg, sizeof(reg));
+               } else {
+                       err = snd_dice_transaction_write_rx(dice,
+                                       params->size * i + RX_ISOCHRONOUS,
+                                       &reg, sizeof(reg));
+               }
+               if (err < 0)
+                       return err;
+
+               if (dir == AMDTP_IN_STREAM) {
+                       reg = cpu_to_be32(max_speed);
+                       err = snd_dice_transaction_write_tx(dice,
+                                       params->size * i + TX_SPEED,
+                                       &reg, sizeof(reg));
+                       if (err < 0)
+                               return err;
+               }
+
+               err = amdtp_stream_start(stream, resources->channel, max_speed);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
 /*
  * MEMO: After this function, there're two states of streams:
  *  - None streams are running.
  *  - All streams are running.
  */
-int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
+int snd_dice_stream_start_duplex(struct snd_dice *dice)
 {
-       unsigned int curr_rate;
+       unsigned int generation = dice->rx_resources[0].generation;
+       struct reg_params tx_params, rx_params;
        unsigned int i;
+       unsigned int rate;
        enum snd_dice_rate_mode mode;
        int err;
 
        if (dice->substreams_counter == 0)
                return -EIO;
 
-       /* Check sampling transmission frequency. */
-       err = snd_dice_transaction_get_rate(dice, &curr_rate);
-       if (err < 0) {
-               dev_err(&dice->unit->device,
-                       "fail to get sampling rate\n");
+       err = get_register_params(dice, &tx_params, &rx_params);
+       if (err < 0)
                return err;
-       }
-       if (rate == 0)
-               rate = curr_rate;
-       if (rate != curr_rate)
-               goto restart;
 
-       /* Check error of packet streaming. */
+       // Check error of packet streaming.
        for (i = 0; i < MAX_STREAMS; ++i) {
-               if (amdtp_streaming_error(&dice->tx_stream[i]))
-                       break;
-               if (amdtp_streaming_error(&dice->rx_stream[i]))
+               if (amdtp_streaming_error(&dice->tx_stream[i]) ||
+                   amdtp_streaming_error(&dice->rx_stream[i])) {
+                       finish_session(dice, &tx_params, &rx_params);
                        break;
+               }
        }
-       if (i < MAX_STREAMS)
-               goto restart;
 
-       /* Check required streams are running or not. */
+       if (generation != fw_parent_device(dice->unit)->card->generation) {
+               for (i = 0; i < MAX_STREAMS; ++i) {
+                       if (i < tx_params.count)
+                               fw_iso_resources_update(dice->tx_resources + i);
+                       if (i < rx_params.count)
+                               fw_iso_resources_update(dice->rx_resources + i);
+               }
+       }
+
+       // Check required streams are running or not.
+       err = snd_dice_transaction_get_rate(dice, &rate);
+       if (err < 0)
+               return err;
        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
        if (err < 0)
                return err;
@@ -428,12 +439,40 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
                    !amdtp_stream_running(&dice->rx_stream[i]))
                        break;
        }
-       if (i < MAX_STREAMS)
-               goto restart;
+       if (i < MAX_STREAMS) {
+               // Start both streams.
+               err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
+               if (err < 0)
+                       goto error;
+
+               err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
+               if (err < 0)
+                       goto error;
+
+               err = snd_dice_transaction_set_enable(dice);
+               if (err < 0) {
+                       dev_err(&dice->unit->device,
+                               "fail to enable interface\n");
+                       goto error;
+               }
+
+               for (i = 0; i < MAX_STREAMS; i++) {
+                       if ((i < tx_params.count &&
+                           !amdtp_stream_wait_callback(&dice->tx_stream[i],
+                                                       CALLBACK_TIMEOUT)) ||
+                           (i < rx_params.count &&
+                            !amdtp_stream_wait_callback(&dice->rx_stream[i],
+                                                        CALLBACK_TIMEOUT))) {
+                               err = -ETIMEDOUT;
+                               goto error;
+                       }
+               }
+       }
 
        return 0;
-restart:
-       return start_duplex_streams(dice, rate);
+error:
+       finish_session(dice, &tx_params, &rx_params);
+       return err;
 }
 
 /*
@@ -445,17 +484,12 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice)
 {
        struct reg_params tx_params, rx_params;
 
-       if (dice->substreams_counter > 0)
-               return;
-
-       snd_dice_transaction_clear_enable(dice);
+       if (dice->substreams_counter == 0) {
+               if (get_register_params(dice, &tx_params, &rx_params) >= 0)
+                       finish_session(dice, &tx_params, &rx_params);
 
-       if (get_register_params(dice, &tx_params, &rx_params) == 0) {
-               stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
-               stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
+               release_resources(dice);
        }
-
-       release_resources(dice);
 }
 
 static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
index ea829ce..13eeb3f 100644 (file)
@@ -19,6 +19,7 @@ MODULE_LICENSE("GPL v2");
 #define OUI_MAUDIO             0x000d6c
 #define OUI_MYTEK              0x001ee8
 #define OUI_SSL                        0x0050c2        // Actually ID reserved by IEEE.
+#define OUI_PRESONUS           0x000a92
 
 #define DICE_CATEGORY_ID       0x04
 #define WEISS_CATEGORY_ID      0x00
@@ -371,6 +372,14 @@ static const struct ieee1394_device_id dice_id_table[] = {
                .vendor_id      = OUI_SSL,
                .model_id       = 0x000070,
        },
+       // Presonus FireStudio.
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = OUI_PRESONUS,
+               .model_id       = 0x000008,
+               .driver_data    = (kernel_ulong_t)snd_dice_detect_presonus_formats,
+       },
        {
                .match_flags = IEEE1394_MATCH_VERSION,
                .version     = DICE_INTERFACE,
index eb4fb8b..c6304e5 100644 (file)
@@ -204,10 +204,11 @@ extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT];
 
 int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
                                  enum snd_dice_rate_mode *mode);
-int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate);
+int snd_dice_stream_start_duplex(struct snd_dice *dice);
 void snd_dice_stream_stop_duplex(struct snd_dice *dice);
 int snd_dice_stream_init_duplex(struct snd_dice *dice);
 void snd_dice_stream_destroy_duplex(struct snd_dice *dice);
+int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate);
 void snd_dice_stream_update_duplex(struct snd_dice *dice);
 int snd_dice_stream_detect_current_formats(struct snd_dice *dice);
 
@@ -226,5 +227,6 @@ int snd_dice_detect_tcelectronic_formats(struct snd_dice *dice);
 int snd_dice_detect_alesis_formats(struct snd_dice *dice);
 int snd_dice_detect_extension_formats(struct snd_dice *dice);
 int snd_dice_detect_mytek_formats(struct snd_dice *dice);
+int snd_dice_detect_presonus_formats(struct snd_dice *dice);
 
 #endif
index 10c8803..45ff73d 100644 (file)
@@ -127,7 +127,7 @@ int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate,
        if (err < 0)
                return err;
 
-       s->fdf = AMDTP_FDF_AM824 | s->sfc;
+       s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc;
 
        p->pcm_channels = pcm_channels;
 
index bf50a16..2b57ece 100644 (file)
@@ -17,8 +17,13 @@ static int midi_open(struct snd_rawmidi_substream *substream)
                return err;
 
        mutex_lock(&dg00x->mutex);
-       dg00x->substreams_counter++;
-       err = snd_dg00x_stream_start_duplex(dg00x, 0);
+       err = snd_dg00x_stream_reserve_duplex(dg00x, 0);
+       if (err >= 0) {
+               ++dg00x->substreams_counter;
+               err = snd_dg00x_stream_start_duplex(dg00x);
+               if (err < 0)
+                       --dg00x->substreams_counter;
+       }
        mutex_unlock(&dg00x->mutex);
        if (err < 0)
                snd_dg00x_stream_lock_release(dg00x);
@@ -31,7 +36,7 @@ static int midi_close(struct snd_rawmidi_substream *substream)
        struct snd_dg00x *dg00x = substream->rmidi->private_data;
 
        mutex_lock(&dg00x->mutex);
-       dg00x->substreams_counter--;
+       --dg00x->substreams_counter;
        snd_dg00x_stream_stop_duplex(dg00x);
        mutex_unlock(&dg00x->mutex);
 
index 4f637f2..18e561b 100644 (file)
@@ -154,8 +154,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
 {
        struct snd_dg00x *dg00x = substream->private_data;
        int err;
@@ -166,58 +166,26 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&dg00x->mutex);
-               dg00x->substreams_counter++;
-               mutex_unlock(&dg00x->mutex);
-       }
+               unsigned int rate = params_rate(hw_params);
 
-       return 0;
-}
-
-static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_dg00x *dg00x = substream->private_data;
-       int err;
-
-       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
-                                              params_buffer_bytes(hw_params));
-       if (err < 0)
-               return err;
-
-       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                mutex_lock(&dg00x->mutex);
-               dg00x->substreams_counter++;
+               err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
+               if (err >= 0)
+                       ++dg00x->substreams_counter;
                mutex_unlock(&dg00x->mutex);
        }
 
-       return 0;
-}
-
-static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_dg00x *dg00x = substream->private_data;
-
-       mutex_lock(&dg00x->mutex);
-
-       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               dg00x->substreams_counter--;
-
-       snd_dg00x_stream_stop_duplex(dg00x);
-
-       mutex_unlock(&dg00x->mutex);
-
-       return snd_pcm_lib_free_vmalloc_buffer(substream);
+       return err;
 }
 
-static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_dg00x *dg00x = substream->private_data;
 
        mutex_lock(&dg00x->mutex);
 
        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               dg00x->substreams_counter--;
+               --dg00x->substreams_counter;
 
        snd_dg00x_stream_stop_duplex(dg00x);
 
@@ -229,12 +197,11 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_dg00x *dg00x = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
        mutex_lock(&dg00x->mutex);
 
-       err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+       err = snd_dg00x_stream_start_duplex(dg00x);
        if (err >= 0)
                amdtp_stream_pcm_prepare(&dg00x->tx_stream);
 
@@ -246,12 +213,11 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_dg00x *dg00x = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
        mutex_lock(&dg00x->mutex);
 
-       err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+       err = snd_dg00x_stream_start_duplex(dg00x);
        if (err >= 0) {
                amdtp_stream_pcm_prepare(&dg00x->rx_stream);
                amdtp_dot_reset(&dg00x->rx_stream);
@@ -332,8 +298,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_capture_hw_params,
-               .hw_free        = pcm_capture_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_capture_prepare,
                .trigger        = pcm_capture_trigger,
                .pointer        = pcm_capture_pointer,
@@ -344,8 +310,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_playback_hw_params,
-               .hw_free        = pcm_playback_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_playback_prepare,
                .trigger        = pcm_playback_trigger,
                .pointer        = pcm_playback_pointer,
index ac8052c..3e77dbd 100644 (file)
@@ -124,11 +124,25 @@ int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
 
 static void finish_session(struct snd_dg00x *dg00x)
 {
-       __be32 data = cpu_to_be32(0x00000003);
+       __be32 data;
+
+       amdtp_stream_stop(&dg00x->tx_stream);
+       amdtp_stream_stop(&dg00x->rx_stream);
 
+       data = cpu_to_be32(0x00000003);
        snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
                           DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
                           &data, sizeof(data), 0);
+
+       // Unregister isochronous channels for both direction.
+       data = 0;
+       snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
+                          &data, sizeof(data), 0);
+
+       // Just after finishing the session, the device may lost transmitting
+       // functionality for a short time.
+       msleep(50);
 }
 
 static int begin_session(struct snd_dg00x *dg00x)
@@ -137,11 +151,20 @@ static int begin_session(struct snd_dg00x *dg00x)
        u32 curr;
        int err;
 
+       // Register isochronous channels for both direction.
+       data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
+                          dg00x->rx_resources.channel);
+       err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
+                                &data, sizeof(data), 0);
+       if (err < 0)
+               return err;
+
        err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
                                 DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
                                 &data, sizeof(data), 0);
        if (err < 0)
-               goto error;
+               return err;
        curr = be32_to_cpu(data);
 
        if (curr == 0)
@@ -156,39 +179,23 @@ static int begin_session(struct snd_dg00x *dg00x)
                                         DG00X_OFFSET_STREAMING_SET,
                                         &data, sizeof(data), 0);
                if (err < 0)
-                       goto error;
+                       break;
 
                msleep(20);
                curr--;
        }
 
-       return 0;
-error:
-       finish_session(dg00x);
        return err;
 }
 
-static void release_resources(struct snd_dg00x *dg00x)
+static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
+                         unsigned int rate)
 {
-       __be32 data = 0;
-
-       /* Unregister isochronous channels for both direction. */
-       snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
-                          DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
-                          &data, sizeof(data), 0);
-
-       /* Release isochronous resources. */
-       fw_iso_resources_free(&dg00x->tx_resources);
-       fw_iso_resources_free(&dg00x->rx_resources);
-}
-
-static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
-{
-       unsigned int i;
-       __be32 data;
+       struct fw_iso_resources *resources;
+       int i;
        int err;
 
-       /* Check sampling rate. */
+       // Check sampling rate.
        for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
                if (snd_dg00x_stream_rates[i] == rate)
                        break;
@@ -196,41 +203,19 @@ static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
        if (i == SND_DG00X_RATE_COUNT)
                return -EINVAL;
 
-       /* Keep resources for out-stream. */
-       err = amdtp_dot_set_parameters(&dg00x->rx_stream, rate,
-                                      snd_dg00x_stream_pcm_channels[i]);
-       if (err < 0)
-               return err;
-       err = fw_iso_resources_allocate(&dg00x->rx_resources,
-                               amdtp_stream_get_max_payload(&dg00x->rx_stream),
-                               fw_parent_device(dg00x->unit)->max_speed);
-       if (err < 0)
-               return err;
+       if (stream == &dg00x->tx_stream)
+               resources = &dg00x->tx_resources;
+       else
+               resources = &dg00x->rx_resources;
 
-       /* Keep resources for in-stream. */
-       err = amdtp_dot_set_parameters(&dg00x->tx_stream, rate,
+       err = amdtp_dot_set_parameters(stream, rate,
                                       snd_dg00x_stream_pcm_channels[i]);
        if (err < 0)
                return err;
-       err = fw_iso_resources_allocate(&dg00x->tx_resources,
-                               amdtp_stream_get_max_payload(&dg00x->tx_stream),
-                               fw_parent_device(dg00x->unit)->max_speed);
-       if (err < 0)
-               goto error;
 
-       /* Register isochronous channels for both direction. */
-       data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
-                          dg00x->rx_resources.channel);
-       err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
-                                DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
-                                &data, sizeof(data), 0);
-       if (err < 0)
-               goto error;
-
-       return 0;
-error:
-       release_resources(dg00x);
-       return err;
+       return fw_iso_resources_allocate(resources,
+                               amdtp_stream_get_max_payload(stream),
+                               fw_parent_device(dg00x->unit)->max_speed);
 }
 
 int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
@@ -272,43 +257,68 @@ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
        fw_iso_resources_destroy(&dg00x->tx_resources);
 }
 
-int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)
 {
        unsigned int curr_rate;
-       int err = 0;
-
-       if (dg00x->substreams_counter == 0)
-               goto end;
+       int err;
 
-       /* Check current sampling rate. */
        err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
        if (err < 0)
-               goto error;
+               return err;
        if (rate == 0)
                rate = curr_rate;
-       if (curr_rate != rate ||
-           amdtp_streaming_error(&dg00x->tx_stream) ||
-           amdtp_streaming_error(&dg00x->rx_stream)) {
+
+       if (dg00x->substreams_counter == 0 || curr_rate != rate) {
                finish_session(dg00x);
 
-               amdtp_stream_stop(&dg00x->tx_stream);
-               amdtp_stream_stop(&dg00x->rx_stream);
-               release_resources(dg00x);
-       }
+               fw_iso_resources_free(&dg00x->tx_resources);
+               fw_iso_resources_free(&dg00x->rx_resources);
 
-       /*
-        * No packets are transmitted without receiving packets, reagardless of
-        * which source of clock is used.
-        */
-       if (!amdtp_stream_running(&dg00x->rx_stream)) {
                err = snd_dg00x_stream_set_local_rate(dg00x, rate);
                if (err < 0)
+                       return err;
+
+               err = keep_resources(dg00x, &dg00x->rx_stream, rate);
+               if (err < 0)
+                       return err;
+
+               err = keep_resources(dg00x, &dg00x->tx_stream, rate);
+               if (err < 0) {
+                       fw_iso_resources_free(&dg00x->rx_resources);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
+{
+       unsigned int generation = dg00x->rx_resources.generation;
+       int err = 0;
+
+       if (dg00x->substreams_counter == 0)
+               return 0;
+
+       if (amdtp_streaming_error(&dg00x->tx_stream) ||
+           amdtp_streaming_error(&dg00x->rx_stream))
+               finish_session(dg00x);
+
+       if (generation != fw_parent_device(dg00x->unit)->card->generation) {
+               err = fw_iso_resources_update(&dg00x->tx_resources);
+               if (err < 0)
                        goto error;
 
-               err = keep_resources(dg00x, rate);
+               err = fw_iso_resources_update(&dg00x->rx_resources);
                if (err < 0)
                        goto error;
+       }
 
+       /*
+        * No packets are transmitted without receiving packets, reagardless of
+        * which source of clock is used.
+        */
+       if (!amdtp_stream_running(&dg00x->rx_stream)) {
                err = begin_session(dg00x);
                if (err < 0)
                        goto error;
@@ -343,33 +353,22 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
                        goto error;
                }
        }
-end:
-       return err;
+
+       return 0;
 error:
        finish_session(dg00x);
 
-       amdtp_stream_stop(&dg00x->tx_stream);
-       amdtp_stream_stop(&dg00x->rx_stream);
-       release_resources(dg00x);
-
        return err;
 }
 
 void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
 {
-       if (dg00x->substreams_counter > 0)
-               return;
-
-       amdtp_stream_stop(&dg00x->tx_stream);
-       amdtp_stream_stop(&dg00x->rx_stream);
-       finish_session(dg00x);
-       release_resources(dg00x);
+       if (dg00x->substreams_counter == 0) {
+               finish_session(dg00x);
 
-       /*
-        * Just after finishing the session, the device may lost transmitting
-        * functionality for a short time.
-        */
-       msleep(50);
+               fw_iso_resources_free(&dg00x->tx_resources);
+               fw_iso_resources_free(&dg00x->rx_resources);
+       }
 }
 
 void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
index 464e6d3..0994d19 100644 (file)
@@ -139,7 +139,8 @@ int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
 int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x,
                                          bool *detect);
 int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x);
-int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x);
 void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x);
 void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);
 void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x);
index 0d40bb6..9eab3ad 100644 (file)
@@ -198,8 +198,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
 {
        struct snd_ff *ff = substream->private_data;
        int err;
@@ -210,58 +210,26 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&ff->mutex);
-               ff->substreams_counter++;
-               mutex_unlock(&ff->mutex);
-       }
-
-       return 0;
-}
-
-static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_ff *ff = substream->private_data;
-       int err;
-
-       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
-                                              params_buffer_bytes(hw_params));
-       if (err < 0)
-               return err;
+               unsigned int rate = params_rate(hw_params);
 
-       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                mutex_lock(&ff->mutex);
-               ff->substreams_counter++;
+               err = snd_ff_stream_reserve_duplex(ff, rate);
+               if (err >= 0)
+                       ++ff->substreams_counter;
                mutex_unlock(&ff->mutex);
        }
 
        return 0;
 }
 
-static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_ff *ff = substream->private_data;
-
-       mutex_lock(&ff->mutex);
-
-       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               ff->substreams_counter--;
-
-       snd_ff_stream_stop_duplex(ff);
-
-       mutex_unlock(&ff->mutex);
-
-       return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-
-static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_ff *ff = substream->private_data;
 
        mutex_lock(&ff->mutex);
 
        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               ff->substreams_counter--;
+               --ff->substreams_counter;
 
        snd_ff_stream_stop_duplex(ff);
 
@@ -374,8 +342,8 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_capture_hw_params,
-               .hw_free        = pcm_capture_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_capture_prepare,
                .trigger        = pcm_capture_trigger,
                .pointer        = pcm_capture_pointer,
@@ -386,8 +354,8 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_playback_hw_params,
-               .hw_free        = pcm_playback_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_playback_prepare,
                .trigger        = pcm_playback_trigger,
                .pointer        = pcm_playback_pointer,
index 8d1c2c6..bf44cad 100644 (file)
@@ -293,27 +293,6 @@ static int former_fill_midi_msg(struct snd_ff *ff,
 
 #define FF800_TX_PACKET_ISOC_CH        0x0000801c0008
 
-static int allocate_rx_resources(struct snd_ff *ff)
-{
-       u32 data;
-       __le32 reg;
-       int err;
-
-       // Controllers should allocate isochronous resources for rx stream.
-       err = fw_iso_resources_allocate(&ff->rx_resources,
-                               amdtp_stream_get_max_payload(&ff->rx_stream),
-                               fw_parent_device(ff->unit)->max_speed);
-       if (err < 0)
-               return err;
-
-       // Set isochronous channel and the number of quadlets of rx packets.
-       data = ff->rx_stream.data_block_quadlets << 3;
-       data = (data << 8) | ff->rx_resources.channel;
-       reg = cpu_to_le32(data);
-       return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-                               FF800_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
-}
-
 static int allocate_tx_resources(struct snd_ff *ff)
 {
        __le32 reg;
@@ -355,8 +334,9 @@ static int allocate_tx_resources(struct snd_ff *ff)
        return 0;
 }
 
-static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
+static int ff800_allocate_resources(struct snd_ff *ff, unsigned int rate)
 {
+       u32 data;
        __le32 reg;
        int err;
 
@@ -371,14 +351,38 @@ static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
        // Let's sleep for a bit.
        msleep(100);
 
-       err = allocate_rx_resources(ff);
+       // Controllers should allocate isochronous resources for rx stream.
+       err = fw_iso_resources_allocate(&ff->rx_resources,
+                               amdtp_stream_get_max_payload(&ff->rx_stream),
+                               fw_parent_device(ff->unit)->max_speed);
        if (err < 0)
                return err;
 
-       err = allocate_tx_resources(ff);
+       // Set isochronous channel and the number of quadlets of rx packets.
+       // This should be done before the allocation of tx resources to avoid
+       // periodical noise.
+       data = ff->rx_stream.data_block_quadlets << 3;
+       data = (data << 8) | ff->rx_resources.channel;
+       reg = cpu_to_le32(data);
+       err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                FF800_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
        if (err < 0)
                return err;
 
+       return allocate_tx_resources(ff);
+}
+
+static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
+{
+       unsigned int generation = ff->rx_resources.generation;
+       __le32 reg;
+
+       if (generation != fw_parent_device(ff->unit)->card->generation) {
+               int err = fw_iso_resources_update(&ff->rx_resources);
+               if (err < 0)
+                       return err;
+       }
+
        reg = cpu_to_le32(0x80000000);
        reg |= cpu_to_le32(ff->tx_stream.data_block_quadlets);
        if (fw_parent_device(ff->unit)->max_speed == SCODE_800)
@@ -420,6 +424,7 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = {
        .fill_midi_msg          = former_fill_midi_msg,
        .get_clock              = former_get_clock,
        .switch_fetching_mode   = former_switch_fetching_mode,
+       .allocate_resources     = ff800_allocate_resources,
        .begin_session          = ff800_begin_session,
        .finish_session         = ff800_finish_session,
        .dump_status            = former_dump_status,
@@ -431,12 +436,11 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = {
 #define FF400_TX_PACKET_FORMAT 0x00008010050cull
 #define FF400_ISOC_COMM_STOP   0x000080100510ull
 
-/*
- * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
- * we can allocate between 0 and 7 channel.
- */
-static int keep_resources(struct snd_ff *ff, unsigned int rate)
+// Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
+// we can allocate between 0 and 7 channel.
+static int ff400_allocate_resources(struct snd_ff *ff, unsigned int rate)
 {
+       __le32 reg;
        enum snd_ff_stream_mode mode;
        int i;
        int err;
@@ -449,11 +453,20 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
        if (i >= CIP_SFC_COUNT)
                return -EINVAL;
 
+       // Set the number of data blocks transferred in a second.
+       reg = cpu_to_le32(rate);
+       err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                FF400_STF, &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       msleep(100);
+
        err = snd_ff_stream_get_multiplier_mode(i, &mode);
        if (err < 0)
                return err;
 
-       /* Keep resources for in-stream. */
+       // Keep resources for in-stream.
        ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
        err = fw_iso_resources_allocate(&ff->tx_resources,
                        amdtp_stream_get_max_payload(&ff->tx_stream),
@@ -461,7 +474,7 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
        if (err < 0)
                return err;
 
-       /* Keep resources for out-stream. */
+       // Keep resources for out-stream.
        ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
        err = fw_iso_resources_allocate(&ff->rx_resources,
                        amdtp_stream_get_max_payload(&ff->rx_stream),
@@ -474,26 +487,22 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
 
 static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
 {
+       unsigned int generation = ff->rx_resources.generation;
        __le32 reg;
        int err;
 
-       err = keep_resources(ff, rate);
-       if (err < 0)
-               return err;
-
-       /* Set the number of data blocks transferred in a second. */
-       reg = cpu_to_le32(rate);
-       err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-                                FF400_STF, &reg, sizeof(reg), 0);
-       if (err < 0)
-               return err;
+       if (generation != fw_parent_device(ff->unit)->card->generation) {
+               err = fw_iso_resources_update(&ff->tx_resources);
+               if (err < 0)
+                       return err;
 
-       msleep(100);
+               err = fw_iso_resources_update(&ff->rx_resources);
+               if (err < 0)
+                       return err;
+       }
 
-       /*
-        * Set isochronous channel and the number of quadlets of received
-        * packets.
-        */
+       // Set isochronous channel and the number of quadlets of received
+       // packets.
        reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) |
                          ff->rx_resources.channel);
        err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
@@ -501,11 +510,9 @@ static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
        if (err < 0)
                return err;
 
-       /*
-        * Set isochronous channel and the number of quadlets of transmitted
-        * packet.
-        */
-       /* TODO: investigate the purpose of this 0x80. */
+       // Set isochronous channel and the number of quadlets of transmitted
+       // packet.
+       // TODO: investigate the purpose of this 0x80.
        reg = cpu_to_le32((0x80 << 24) |
                          (ff->tx_resources.channel << 5) |
                          (ff->tx_stream.data_block_quadlets));
@@ -514,7 +521,7 @@ static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
        if (err < 0)
                return err;
 
-       /* Allow to transmit packets. */
+       // Allow to transmit packets.
        reg = cpu_to_le32(0x00000001);
        return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
                                 FF400_ISOC_COMM_START, &reg, sizeof(reg), 0);
@@ -591,6 +598,7 @@ const struct snd_ff_protocol snd_ff_protocol_ff400 = {
        .fill_midi_msg          = former_fill_midi_msg,
        .get_clock              = former_get_clock,
        .switch_fetching_mode   = former_switch_fetching_mode,
+       .allocate_resources     = ff400_allocate_resources,
        .begin_session          = ff400_begin_session,
        .finish_session         = ff400_finish_session,
        .dump_status            = former_dump_status,
index b30d02d..0e4c3a9 100644 (file)
@@ -97,25 +97,64 @@ static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable)
                                  LATTER_FETCH_MODE, &reg, sizeof(reg), 0);
 }
 
-static int keep_resources(struct snd_ff *ff, unsigned int rate)
+static int latter_allocate_resources(struct snd_ff *ff, unsigned int rate)
 {
        enum snd_ff_stream_mode mode;
+       unsigned int code;
+       __le32 reg;
+       unsigned int count;
        int i;
        int err;
 
-       // Check whether the given value is supported or not.
-       for (i = 0; i < CIP_SFC_COUNT; i++) {
-               if (amdtp_rate_table[i] == rate)
+       // Set the number of data blocks transferred in a second.
+       if (rate % 32000 == 0)
+               code = 0x00;
+       else if (rate % 44100 == 0)
+               code = 0x02;
+       else if (rate % 48000 == 0)
+               code = 0x04;
+       else
+               return -EINVAL;
+
+       if (rate >= 64000 && rate < 128000)
+               code |= 0x08;
+       else if (rate >= 128000 && rate < 192000)
+               code |= 0x10;
+
+       reg = cpu_to_le32(code);
+       err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                LATTER_STF, &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       // Confirm to shift transmission clock.
+       count = 0;
+       while (count++ < 10) {
+               unsigned int curr_rate;
+               enum snd_ff_clock_src src;
+
+               err = latter_get_clock(ff, &curr_rate, &src);
+               if (err < 0)
+                       return err;
+
+               if (curr_rate == rate)
                        break;
        }
-       if (i >= CIP_SFC_COUNT)
+       if (count == 10)
+               return -ETIMEDOUT;
+
+       for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); ++i) {
+               if (rate == amdtp_rate_table[i])
+                       break;
+       }
+       if (i == ARRAY_SIZE(amdtp_rate_table))
                return -EINVAL;
 
        err = snd_ff_stream_get_multiplier_mode(i, &mode);
        if (err < 0)
                return err;
 
-       /* Keep resources for in-stream. */
+       // Keep resources for in-stream.
        ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
        err = fw_iso_resources_allocate(&ff->tx_resources,
                        amdtp_stream_get_max_payload(&ff->tx_stream),
@@ -123,7 +162,7 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
        if (err < 0)
                return err;
 
-       /* Keep resources for out-stream. */
+       // Keep resources for out-stream.
        ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
        err = fw_iso_resources_allocate(&ff->rx_resources,
                        amdtp_stream_get_max_payload(&ff->rx_stream),
@@ -136,60 +175,30 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
 
 static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
 {
-       static const struct {
-               unsigned int stf;
-               unsigned int code;
-               unsigned int flag;
-       } *entry, rate_table[] = {
-               { 32000,  0x00, 0x92, },
-               { 44100,  0x02, 0x92, },
-               { 48000,  0x04, 0x92, },
-               { 64000,  0x08, 0x8e, },
-               { 88200,  0x0a, 0x8e, },
-               { 96000,  0x0c, 0x8e, },
-               { 128000, 0x10, 0x8c, },
-               { 176400, 0x12, 0x8c, },
-               { 192000, 0x14, 0x8c, },
-       };
+       unsigned int generation = ff->rx_resources.generation;
+       unsigned int flag;
        u32 data;
        __le32 reg;
-       unsigned int count;
-       int i;
        int err;
 
-       for (i = 0; i < ARRAY_SIZE(rate_table); ++i) {
-               entry = rate_table + i;
-               if (entry->stf == rate)
-                       break;
-       }
-       if (i == ARRAY_SIZE(rate_table))
+       if (rate >= 32000 && rate <= 48000)
+               flag = 0x92;
+       else if (rate >= 64000 && rate <= 96000)
+               flag = 0x8e;
+       else if (rate >= 128000 && rate <= 192000)
+               flag = 0x8c;
+       else
                return -EINVAL;
 
-       reg = cpu_to_le32(entry->code);
-       err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-                                LATTER_STF, &reg, sizeof(reg), 0);
-       if (err < 0)
-               return err;
-
-       // Confirm to shift transmission clock.
-       count = 0;
-       while (count++ < 10) {
-               unsigned int curr_rate;
-               enum snd_ff_clock_src src;
-
-               err = latter_get_clock(ff, &curr_rate, &src);
+       if (generation != fw_parent_device(ff->unit)->card->generation) {
+               err = fw_iso_resources_update(&ff->tx_resources);
                if (err < 0)
                        return err;
 
-               if (curr_rate == rate)
-                       break;
+               err = fw_iso_resources_update(&ff->rx_resources);
+               if (err < 0)
+                       return err;
        }
-       if (count == 10)
-               return -ETIMEDOUT;
-
-       err = keep_resources(ff, rate);
-       if (err < 0)
-               return err;
 
        data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel;
        reg = cpu_to_le32(data);
@@ -200,7 +209,7 @@ static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
 
        // Always use the maximum number of data channels in data block of
        // packet.
-       reg = cpu_to_le32(entry->flag);
+       reg = cpu_to_le32(flag);
        return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
                                  LATTER_ISOC_START, &reg, sizeof(reg), 0);
 }
@@ -424,6 +433,7 @@ const struct snd_ff_protocol snd_ff_protocol_latter = {
        .fill_midi_msg          = latter_fill_midi_msg,
        .get_clock              = latter_get_clock,
        .switch_fetching_mode   = latter_switch_fetching_mode,
+       .allocate_resources     = latter_allocate_resources,
        .begin_session          = latter_begin_session,
        .finish_session         = latter_finish_session,
        .dump_status            = latter_dump_status,
index 6dfd2ef..4208b80 100644 (file)
@@ -30,14 +30,11 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
        return 0;
 }
 
-static void release_resources(struct snd_ff *ff)
-{
-       fw_iso_resources_free(&ff->tx_resources);
-       fw_iso_resources_free(&ff->rx_resources);
-}
-
 static inline void finish_session(struct snd_ff *ff)
 {
+       amdtp_stream_stop(&ff->tx_stream);
+       amdtp_stream_stop(&ff->rx_stream);
+
        ff->spec->protocol->finish_session(ff);
        ff->spec->protocol->switch_fetching_mode(ff, false);
 }
@@ -103,37 +100,25 @@ void snd_ff_stream_destroy_duplex(struct snd_ff *ff)
        destroy_stream(ff, AMDTP_OUT_STREAM);
 }
 
-int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
+int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate)
 {
        unsigned int curr_rate;
        enum snd_ff_clock_src src;
        int err;
 
-       if (ff->substreams_counter == 0)
-               return 0;
-
        err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
        if (err < 0)
                return err;
-       if (curr_rate != rate ||
-           amdtp_streaming_error(&ff->tx_stream) ||
-           amdtp_streaming_error(&ff->rx_stream)) {
-               finish_session(ff);
-
-               amdtp_stream_stop(&ff->tx_stream);
-               amdtp_stream_stop(&ff->rx_stream);
-
-               release_resources(ff);
-       }
 
-       /*
-        * Regardless of current source of clock signal, drivers transfer some
-        * packets. Then, the device transfers packets.
-        */
-       if (!amdtp_stream_running(&ff->rx_stream)) {
+       if (ff->substreams_counter == 0 || curr_rate != rate) {
                enum snd_ff_stream_mode mode;
                int i;
 
+               finish_session(ff);
+
+               fw_iso_resources_free(&ff->tx_resources);
+               fw_iso_resources_free(&ff->rx_resources);
+
                for (i = 0; i < CIP_SFC_COUNT; ++i) {
                        if (amdtp_rate_table[i] == rate)
                                break;
@@ -155,6 +140,30 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
                if (err < 0)
                        return err;
 
+               err = ff->spec->protocol->allocate_resources(ff, rate);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
+{
+       int err;
+
+       if (ff->substreams_counter == 0)
+               return 0;
+
+       if (amdtp_streaming_error(&ff->tx_stream) ||
+           amdtp_streaming_error(&ff->rx_stream))
+               finish_session(ff);
+
+       /*
+        * Regardless of current source of clock signal, drivers transfer some
+        * packets. Then, the device transfers packets.
+        */
+       if (!amdtp_stream_running(&ff->rx_stream)) {
                err = ff->spec->protocol->begin_session(ff, rate);
                if (err < 0)
                        goto error;
@@ -192,37 +201,29 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
 
        return 0;
 error:
-       amdtp_stream_stop(&ff->tx_stream);
-       amdtp_stream_stop(&ff->rx_stream);
-
        finish_session(ff);
-       release_resources(ff);
 
        return err;
 }
 
 void snd_ff_stream_stop_duplex(struct snd_ff *ff)
 {
-       if (ff->substreams_counter > 0)
-               return;
+       if (ff->substreams_counter == 0) {
+               finish_session(ff);
 
-       amdtp_stream_stop(&ff->tx_stream);
-       amdtp_stream_stop(&ff->rx_stream);
-       finish_session(ff);
-       release_resources(ff);
+               fw_iso_resources_free(&ff->tx_resources);
+               fw_iso_resources_free(&ff->rx_resources);
+       }
 }
 
 void snd_ff_stream_update_duplex(struct snd_ff *ff)
 {
-       /* The device discontinue to transfer packets.  */
+       // The device discontinue to transfer packets.
        amdtp_stream_pcm_abort(&ff->tx_stream);
        amdtp_stream_stop(&ff->tx_stream);
 
        amdtp_stream_pcm_abort(&ff->rx_stream);
        amdtp_stream_stop(&ff->rx_stream);
-
-       fw_iso_resources_update(&ff->tx_resources);
-       fw_iso_resources_update(&ff->rx_resources);
 }
 
 void snd_ff_stream_lock_changed(struct snd_ff *ff)
index 7fac241..36dd0c7 100644 (file)
@@ -112,6 +112,7 @@ struct snd_ff_protocol {
        int (*get_clock)(struct snd_ff *ff, unsigned int *rate,
                         enum snd_ff_clock_src *src);
        int (*switch_fetching_mode)(struct snd_ff *ff, bool enable);
+       int (*allocate_resources)(struct snd_ff *ff, unsigned int rate);
        int (*begin_session)(struct snd_ff *ff, unsigned int rate);
        void (*finish_session)(struct snd_ff *ff);
        void (*dump_status)(struct snd_ff *ff, struct snd_info_buffer *buffer);
@@ -136,6 +137,7 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
                                      enum snd_ff_stream_mode *mode);
 int snd_ff_stream_init_duplex(struct snd_ff *ff);
 void snd_ff_stream_destroy_duplex(struct snd_ff *ff);
+int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate);
 int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate);
 void snd_ff_stream_stop_duplex(struct snd_ff *ff);
 void snd_ff_stream_update_duplex(struct snd_ff *ff);
index 28df49c..31efd4b 100644 (file)
@@ -88,8 +88,7 @@ struct snd_efw {
        struct amdtp_stream rx_stream;
        struct cmp_connection out_conn;
        struct cmp_connection in_conn;
-       unsigned int capture_substreams;
-       unsigned int playback_substreams;
+       unsigned int substreams_counter;
 
        /* hardware metering parameters */
        unsigned int phys_out;
@@ -206,7 +205,8 @@ int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate);
 int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate);
 
 int snd_efw_stream_init_duplex(struct snd_efw *efw);
-int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate);
+int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate);
+int snd_efw_stream_start_duplex(struct snd_efw *efw);
 void snd_efw_stream_stop_duplex(struct snd_efw *efw);
 void snd_efw_stream_update_duplex(struct snd_efw *efw);
 void snd_efw_stream_destroy_duplex(struct snd_efw *efw);
index 14b985c..a9f4a96 100644 (file)
@@ -7,7 +7,7 @@
  */
 #include "fireworks.h"
 
-static int midi_capture_open(struct snd_rawmidi_substream *substream)
+static int midi_open(struct snd_rawmidi_substream *substream)
 {
        struct snd_efw *efw = substream->rmidi->private_data;
        int err;
@@ -17,28 +17,13 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
                goto end;
 
        mutex_lock(&efw->mutex);
-       efw->capture_substreams++;
-       err = snd_efw_stream_start_duplex(efw, 0);
-       mutex_unlock(&efw->mutex);
-       if (err < 0)
-               snd_efw_stream_lock_release(efw);
-
-end:
-       return err;
-}
-
-static int midi_playback_open(struct snd_rawmidi_substream *substream)
-{
-       struct snd_efw *efw = substream->rmidi->private_data;
-       int err;
-
-       err = snd_efw_stream_lock_try(efw);
-       if (err < 0)
-               goto end;
-
-       mutex_lock(&efw->mutex);
-       efw->playback_substreams++;
-       err = snd_efw_stream_start_duplex(efw, 0);
+       err = snd_efw_stream_reserve_duplex(efw, 0);
+       if (err >= 0) {
+               ++efw->substreams_counter;
+               err = snd_efw_stream_start_duplex(efw);
+               if (err < 0)
+                       --efw->substreams_counter;
+       }
        mutex_unlock(&efw->mutex);
        if (err < 0)
                snd_efw_stream_lock_release(efw);
@@ -46,25 +31,12 @@ end:
        return err;
 }
 
-static int midi_capture_close(struct snd_rawmidi_substream *substream)
-{
-       struct snd_efw *efw = substream->rmidi->private_data;
-
-       mutex_lock(&efw->mutex);
-       efw->capture_substreams--;
-       snd_efw_stream_stop_duplex(efw);
-       mutex_unlock(&efw->mutex);
-
-       snd_efw_stream_lock_release(efw);
-       return 0;
-}
-
-static int midi_playback_close(struct snd_rawmidi_substream *substream)
+static int midi_close(struct snd_rawmidi_substream *substream)
 {
        struct snd_efw *efw = substream->rmidi->private_data;
 
        mutex_lock(&efw->mutex);
-       efw->playback_substreams--;
+       --efw->substreams_counter;
        snd_efw_stream_stop_duplex(efw);
        mutex_unlock(&efw->mutex);
 
@@ -120,13 +92,13 @@ static void set_midi_substream_names(struct snd_efw *efw,
 int snd_efw_create_midi_devices(struct snd_efw *efw)
 {
        static const struct snd_rawmidi_ops capture_ops = {
-               .open           = midi_capture_open,
-               .close          = midi_capture_close,
+               .open           = midi_open,
+               .close          = midi_close,
                .trigger        = midi_capture_trigger,
        };
        static const struct snd_rawmidi_ops playback_ops = {
-               .open           = midi_playback_open,
-               .close          = midi_playback_close,
+               .open           = midi_open,
+               .close          = midi_close,
                .trigger        = midi_playback_trigger,
        };
        struct snd_rawmidi *rmidi;
index affc50f..a7025dc 100644 (file)
@@ -218,7 +218,7 @@ static int pcm_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
+static int pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *hw_params)
 {
        struct snd_efw *efw = substream->private_data;
@@ -230,69 +230,40 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&efw->mutex);
-               efw->capture_substreams++;
-               mutex_unlock(&efw->mutex);
-       }
-
-       return 0;
-}
-static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_efw *efw = substream->private_data;
-       int err;
+               unsigned int rate = params_rate(hw_params);
 
-       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
-                                              params_buffer_bytes(hw_params));
-       if (err < 0)
-               return err;
-
-       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                mutex_lock(&efw->mutex);
-               efw->playback_substreams++;
+               err = snd_efw_stream_reserve_duplex(efw, rate);
+               if (err >= 0)
+                       ++efw->substreams_counter;
                mutex_unlock(&efw->mutex);
        }
 
-       return 0;
+       return err;
 }
 
-static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_efw *efw = substream->private_data;
 
-       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&efw->mutex);
-               efw->capture_substreams--;
-               mutex_unlock(&efw->mutex);
-       }
-
-       snd_efw_stream_stop_duplex(efw);
-
-       return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_efw *efw = substream->private_data;
+       mutex_lock(&efw->mutex);
 
-       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&efw->mutex);
-               efw->playback_substreams--;
-               mutex_unlock(&efw->mutex);
-       }
+       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+               --efw->substreams_counter;
 
        snd_efw_stream_stop_duplex(efw);
 
+       mutex_unlock(&efw->mutex);
+
        return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
 
 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_efw *efw = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
-       err = snd_efw_stream_start_duplex(efw, runtime->rate);
+       err = snd_efw_stream_start_duplex(efw);
        if (err >= 0)
                amdtp_stream_pcm_prepare(&efw->tx_stream);
 
@@ -301,10 +272,9 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_efw *efw = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
-       err = snd_efw_stream_start_duplex(efw, runtime->rate);
+       err = snd_efw_stream_start_duplex(efw);
        if (err >= 0)
                amdtp_stream_pcm_prepare(&efw->rx_stream);
 
@@ -377,8 +347,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_capture_hw_params,
-               .hw_free        = pcm_capture_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_capture_prepare,
                .trigger        = pcm_capture_trigger,
                .pointer        = pcm_capture_pointer,
@@ -389,8 +359,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_playback_hw_params,
-               .hw_free        = pcm_playback_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_playback_prepare,
                .trigger        = pcm_playback_trigger,
                .pointer        = pcm_playback_pointer,
index 2d30954..e659a0b 100644 (file)
@@ -42,7 +42,6 @@ end:
 static void
 stop_stream(struct snd_efw *efw, struct amdtp_stream *stream)
 {
-       amdtp_stream_pcm_abort(stream);
        amdtp_stream_stop(stream);
 
        if (stream == &efw->tx_stream)
@@ -51,54 +50,37 @@ stop_stream(struct snd_efw *efw, struct amdtp_stream *stream)
                cmp_connection_break(&efw->in_conn);
 }
 
-static int
-start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
-            unsigned int sampling_rate)
+static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
+                       unsigned int rate)
 {
        struct cmp_connection *conn;
-       unsigned int mode, pcm_channels, midi_ports;
        int err;
 
-       err = snd_efw_get_multiplier_mode(sampling_rate, &mode);
-       if (err < 0)
-               goto end;
-       if (stream == &efw->tx_stream) {
+       if (stream == &efw->tx_stream)
                conn = &efw->out_conn;
-               pcm_channels = efw->pcm_capture_channels[mode];
-               midi_ports = efw->midi_out_ports;
-       } else {
+       else
                conn = &efw->in_conn;
-               pcm_channels = efw->pcm_playback_channels[mode];
-               midi_ports = efw->midi_in_ports;
-       }
-
-       err = amdtp_am824_set_parameters(stream, sampling_rate,
-                                        pcm_channels, midi_ports, false);
-       if (err < 0)
-               goto end;
 
-       /*  establish connection via CMP */
-       err = cmp_connection_establish(conn,
-                               amdtp_stream_get_max_payload(stream));
+       // Establish connection via CMP.
+       err = cmp_connection_establish(conn);
        if (err < 0)
-               goto end;
+               return err;
 
-       /* start amdtp stream */
-       err = amdtp_stream_start(stream,
-                                conn->resources.channel,
-                                conn->speed);
+       // Start amdtp stream.
+       err = amdtp_stream_start(stream, conn->resources.channel, conn->speed);
        if (err < 0) {
-               stop_stream(efw, stream);
-               goto end;
+               cmp_connection_break(conn);
+               return err;
        }
 
-       /* wait first callback */
+       // Wait first callback.
        if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
-               stop_stream(efw, stream);
-               err = -ETIMEDOUT;
+               amdtp_stream_stop(stream);
+               cmp_connection_break(conn);
+               return -ETIMEDOUT;
        }
-end:
-       return err;
+
+       return 0;
 }
 
 /*
@@ -164,13 +146,13 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw)
            (efw->firmware_version == 0x5070000 ||
             efw->firmware_version == 0x5070300 ||
             efw->firmware_version == 0x5080000))
-               efw->tx_stream.tx_first_dbc = 0x02;
+               efw->tx_stream.ctx_data.tx.first_dbc = 0x02;
        /* AudioFire9 always reports wrong dbs. */
        if (efw->is_af9)
                efw->tx_stream.flags |= CIP_WRONG_DBS;
        /* Firmware version 5.5 reports fixed interval for dbc. */
        if (efw->firmware_version == 0x5050000)
-               efw->tx_stream.tx_dbc_interval = 8;
+               efw->tx_stream.ctx_data.tx.dbc_interval = 8;
 
        err = init_stream(efw, &efw->rx_stream);
        if (err < 0) {
@@ -188,75 +170,135 @@ end:
        return err;
 }
 
-int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
+static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
+                         unsigned int rate, unsigned int mode)
 {
-       unsigned int curr_rate;
-       int err = 0;
+       unsigned int pcm_channels;
+       unsigned int midi_ports;
+       struct cmp_connection *conn;
+       int err;
 
-       /* Need no substreams */
-       if (efw->playback_substreams == 0 && efw->capture_substreams  == 0)
-               goto end;
+       if (stream == &efw->tx_stream) {
+               pcm_channels = efw->pcm_capture_channels[mode];
+               midi_ports = efw->midi_out_ports;
+               conn = &efw->out_conn;
+       } else {
+               pcm_channels = efw->pcm_playback_channels[mode];
+               midi_ports = efw->midi_in_ports;
+               conn = &efw->in_conn;
+       }
 
-       /*
-        * Considering JACK/FFADO streaming:
-        * TODO: This can be removed hwdep functionality becomes popular.
-        */
-       err = check_connection_used_by_others(efw, &efw->rx_stream);
+       err = amdtp_am824_set_parameters(stream, rate, pcm_channels,
+                                        midi_ports, false);
        if (err < 0)
-               goto end;
+               return err;
 
-       /* packet queueing error */
-       if (amdtp_streaming_error(&efw->tx_stream))
-               stop_stream(efw, &efw->tx_stream);
-       if (amdtp_streaming_error(&efw->rx_stream))
-               stop_stream(efw, &efw->rx_stream);
+       return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
+}
+
+int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate)
+{
+       unsigned int curr_rate;
+       int err;
 
-       /* stop streams if rate is different */
+       // Considering JACK/FFADO streaming:
+       // TODO: This can be removed hwdep functionality becomes popular.
+       err = check_connection_used_by_others(efw, &efw->rx_stream);
+       if (err < 0)
+               return err;
+
+       // stop streams if rate is different.
        err = snd_efw_command_get_sampling_rate(efw, &curr_rate);
        if (err < 0)
-               goto end;
+               return err;
        if (rate == 0)
                rate = curr_rate;
        if (rate != curr_rate) {
                stop_stream(efw, &efw->tx_stream);
                stop_stream(efw, &efw->rx_stream);
+
+               cmp_connection_release(&efw->out_conn);
+               cmp_connection_release(&efw->in_conn);
        }
 
-       /* master should be always running */
-       if (!amdtp_stream_running(&efw->rx_stream)) {
+       if (efw->substreams_counter == 0 || rate != curr_rate) {
+               unsigned int mode;
+
                err = snd_efw_command_set_sampling_rate(efw, rate);
                if (err < 0)
-                       goto end;
+                       return err;
+
+               err = snd_efw_get_multiplier_mode(rate, &mode);
+               if (err < 0)
+                       return err;
+
+               err = keep_resources(efw, &efw->tx_stream, rate, mode);
+               if (err < 0)
+                       return err;
 
+               err = keep_resources(efw, &efw->rx_stream, rate, mode);
+               if (err < 0) {
+                       cmp_connection_release(&efw->in_conn);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+int snd_efw_stream_start_duplex(struct snd_efw *efw)
+{
+       unsigned int rate;
+       int err = 0;
+
+       // Need no substreams.
+       if (efw->substreams_counter == 0)
+               return -EIO;
+
+       err = snd_efw_command_get_sampling_rate(efw, &rate);
+       if (err < 0)
+               return err;
+
+       if (amdtp_streaming_error(&efw->rx_stream) ||
+           amdtp_streaming_error(&efw->tx_stream)) {
+               stop_stream(efw, &efw->rx_stream);
+               stop_stream(efw, &efw->tx_stream);
+       }
+
+       /* master should be always running */
+       if (!amdtp_stream_running(&efw->rx_stream)) {
                err = start_stream(efw, &efw->rx_stream, rate);
                if (err < 0) {
                        dev_err(&efw->unit->device,
                                "fail to start AMDTP master stream:%d\n", err);
-                       goto end;
+                       goto error;
                }
        }
 
-       /* start slave if needed */
-       if (efw->capture_substreams > 0 &&
-           !amdtp_stream_running(&efw->tx_stream)) {
+       if (!amdtp_stream_running(&efw->tx_stream)) {
                err = start_stream(efw, &efw->tx_stream, rate);
                if (err < 0) {
                        dev_err(&efw->unit->device,
                                "fail to start AMDTP slave stream:%d\n", err);
-                       stop_stream(efw, &efw->rx_stream);
+                       goto error;
                }
        }
-end:
+
+       return 0;
+error:
+       stop_stream(efw, &efw->rx_stream);
+       stop_stream(efw, &efw->tx_stream);
        return err;
 }
 
 void snd_efw_stream_stop_duplex(struct snd_efw *efw)
 {
-       if (efw->capture_substreams == 0) {
+       if (efw->substreams_counter == 0) {
                stop_stream(efw, &efw->tx_stream);
+               stop_stream(efw, &efw->rx_stream);
 
-               if (efw->playback_substreams == 0)
-                       stop_stream(efw, &efw->rx_stream);
+               cmp_connection_release(&efw->out_conn);
+               cmp_connection_release(&efw->in_conn);
        }
 }
 
index 4d2351c..3d36f12 100644 (file)
@@ -18,7 +18,7 @@ static void copy_sph(u32 *frame, __be32 *buffer, unsigned int data_blocks,
 static void copy_message(u64 *frames, __be32 *buffer, unsigned int data_blocks,
                         unsigned int data_block_quadlets);
 
-TRACE_EVENT(in_data_block_sph,
+TRACE_EVENT(data_block_sph,
        TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
        TP_ARGS(s, data_blocks, buffer),
        TP_STRUCT__entry(
@@ -28,8 +28,13 @@ TRACE_EVENT(in_data_block_sph,
                __dynamic_array(u32, tstamps, data_blocks)
        ),
        TP_fast_assign(
-               __entry->src = fw_parent_device(s->unit)->node_id;
-               __entry->dst = fw_parent_device(s->unit)->card->node_id;
+               if (s->direction == AMDTP_IN_STREAM) {
+                       __entry->src = fw_parent_device(s->unit)->node_id;
+                       __entry->dst = fw_parent_device(s->unit)->card->node_id;
+               } else {
+                       __entry->src = fw_parent_device(s->unit)->card->node_id;
+                       __entry->dst = fw_parent_device(s->unit)->node_id;
+               }
                __entry->data_blocks = data_blocks;
                copy_sph(__get_dynamic_array(tstamps), buffer, data_blocks, s->data_block_quadlets);
        ),
@@ -42,55 +47,7 @@ TRACE_EVENT(in_data_block_sph,
        )
 );
 
-TRACE_EVENT(out_data_block_sph,
-       TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
-       TP_ARGS(s, data_blocks, buffer),
-       TP_STRUCT__entry(
-               __field(int, src)
-               __field(int, dst)
-               __field(unsigned int, data_blocks)
-               __dynamic_array(u32, tstamps, data_blocks)
-       ),
-       TP_fast_assign(
-               __entry->src = fw_parent_device(s->unit)->card->node_id;
-               __entry->dst = fw_parent_device(s->unit)->node_id;
-               __entry->data_blocks = data_blocks;
-               copy_sph(__get_dynamic_array(tstamps), buffer, data_blocks, s->data_block_quadlets);
-       ),
-       TP_printk(
-               "%04x %04x %u %s",
-               __entry->src,
-               __entry->dst,
-               __entry->data_blocks,
-               __print_array(__get_dynamic_array(tstamps), __entry->data_blocks, 4)
-       )
-);
-
-TRACE_EVENT(in_data_block_message,
-       TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
-       TP_ARGS(s, data_blocks, buffer),
-       TP_STRUCT__entry(
-               __field(int, src)
-               __field(int, dst)
-               __field(unsigned int, data_blocks)
-               __dynamic_array(u64, messages, data_blocks)
-       ),
-       TP_fast_assign(
-               __entry->src = fw_parent_device(s->unit)->node_id;
-               __entry->dst = fw_parent_device(s->unit)->card->node_id;
-               __entry->data_blocks = data_blocks;
-               copy_message(__get_dynamic_array(messages), buffer, data_blocks, s->data_block_quadlets);
-       ),
-       TP_printk(
-               "%04x %04x %u %s",
-               __entry->src,
-               __entry->dst,
-               __entry->data_blocks,
-               __print_array(__get_dynamic_array(messages), __entry->data_blocks, 8)
-       )
-);
-
-TRACE_EVENT(out_data_block_message,
+TRACE_EVENT(data_block_message,
        TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
        TP_ARGS(s, data_blocks, buffer),
        TP_STRUCT__entry(
@@ -100,8 +57,13 @@ TRACE_EVENT(out_data_block_message,
                __dynamic_array(u64, messages, data_blocks)
        ),
        TP_fast_assign(
-               __entry->src = fw_parent_device(s->unit)->card->node_id;
-               __entry->dst = fw_parent_device(s->unit)->node_id;
+               if (s->direction == AMDTP_IN_STREAM) {
+                       __entry->src = fw_parent_device(s->unit)->node_id;
+                       __entry->dst = fw_parent_device(s->unit)->card->node_id;
+               } else {
+                       __entry->src = fw_parent_device(s->unit)->card->node_id;
+                       __entry->dst = fw_parent_device(s->unit)->node_id;
+               }
                __entry->data_blocks = data_blocks;
                copy_message(__get_dynamic_array(messages), buffer, data_blocks, s->data_block_quadlets);
        ),
index 782d1fa..7973ded 100644 (file)
@@ -305,8 +305,8 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
        struct amdtp_motu *p = s->protocol;
        struct snd_pcm_substream *pcm;
 
-       trace_in_data_block_sph(s, data_blocks, buffer);
-       trace_in_data_block_message(s, data_blocks, buffer);
+       trace_data_block_sph(s, data_blocks, buffer);
+       trace_data_block_message(s, data_blocks, buffer);
 
        if (p->midi_ports)
                read_midi_messages(s, buffer, data_blocks);
@@ -383,8 +383,8 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
 
        write_sph(s, buffer, data_blocks);
 
-       trace_out_data_block_sph(s, data_blocks, buffer);
-       trace_out_data_block_message(s, data_blocks, buffer);
+       trace_data_block_sph(s, data_blocks, buffer);
+       trace_data_block_message(s, data_blocks, buffer);
 
        return data_blocks;
 }
@@ -428,7 +428,7 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
                return err;
 
        s->sph = 1;
-       s->fdf = MOTU_FDF_AM824;
+       s->ctx_data.rx.fdf = MOTU_FDF_AM824;
 
        return 0;
 }
index 75f6b2e..46a0035 100644 (file)
@@ -6,7 +6,7 @@
  */
 #include "motu.h"
 
-static int midi_capture_open(struct snd_rawmidi_substream *substream)
+static int midi_open(struct snd_rawmidi_substream *substream)
 {
        struct snd_motu *motu = substream->rmidi->private_data;
        int err;
@@ -17,30 +17,13 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&motu->mutex);
 
-       motu->capture_substreams++;
-       err = snd_motu_stream_start_duplex(motu, 0);
-
-       mutex_unlock(&motu->mutex);
-
-       if (err < 0)
-               snd_motu_stream_lock_release(motu);
-
-       return err;
-}
-
-static int midi_playback_open(struct snd_rawmidi_substream *substream)
-{
-       struct snd_motu *motu = substream->rmidi->private_data;
-       int err;
-
-       err = snd_motu_stream_lock_try(motu);
-       if (err < 0)
-               return err;
-
-       mutex_lock(&motu->mutex);
-
-       motu->playback_substreams++;
-       err = snd_motu_stream_start_duplex(motu, 0);
+       err = snd_motu_stream_reserve_duplex(motu, 0);
+       if (err >= 0) {
+               ++motu->substreams_counter;
+               err = snd_motu_stream_start_duplex(motu);
+               if (err < 0)
+                       --motu->substreams_counter;
+       }
 
        mutex_unlock(&motu->mutex);
 
@@ -50,28 +33,13 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
        return err;
 }
 
-static int midi_capture_close(struct snd_rawmidi_substream *substream)
-{
-       struct snd_motu *motu = substream->rmidi->private_data;
-
-       mutex_lock(&motu->mutex);
-
-       motu->capture_substreams--;
-       snd_motu_stream_stop_duplex(motu);
-
-       mutex_unlock(&motu->mutex);
-
-       snd_motu_stream_lock_release(motu);
-       return 0;
-}
-
-static int midi_playback_close(struct snd_rawmidi_substream *substream)
+static int midi_close(struct snd_rawmidi_substream *substream)
 {
        struct snd_motu *motu = substream->rmidi->private_data;
 
        mutex_lock(&motu->mutex);
 
-       motu->playback_substreams--;
+       --motu->substreams_counter;
        snd_motu_stream_stop_duplex(motu);
 
        mutex_unlock(&motu->mutex);
@@ -128,13 +96,13 @@ static void set_midi_substream_names(struct snd_motu *motu,
 int snd_motu_create_midi_devices(struct snd_motu *motu)
 {
        static const struct snd_rawmidi_ops capture_ops = {
-               .open           = midi_capture_open,
-               .close          = midi_capture_close,
+               .open           = midi_open,
+               .close          = midi_close,
                .trigger        = midi_capture_trigger,
        };
        static const struct snd_rawmidi_ops playback_ops = {
-               .open           = midi_playback_open,
-               .close          = midi_playback_close,
+               .open           = midi_open,
+               .close          = midi_close,
                .trigger        = midi_playback_trigger,
        };
        struct snd_rawmidi *rmidi;
index 5e7db7a..aa2e584 100644 (file)
@@ -189,8 +189,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int capture_hw_params(struct snd_pcm_substream *substream,
-                            struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
 {
        struct snd_motu *motu = substream->private_data;
        int err;
@@ -201,57 +201,26 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&motu->mutex);
-               motu->capture_substreams++;
-               mutex_unlock(&motu->mutex);
-       }
-
-       return 0;
-}
-static int playback_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_motu *motu = substream->private_data;
-       int err;
-
-       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
-                                              params_buffer_bytes(hw_params));
-       if (err < 0)
-               return err;
+               unsigned int rate = params_rate(hw_params);
 
-       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                mutex_lock(&motu->mutex);
-               motu->playback_substreams++;
+               err = snd_motu_stream_reserve_duplex(motu, rate);
+               if (err >= 0)
+                       ++motu->substreams_counter;
                mutex_unlock(&motu->mutex);
        }
 
-       return 0;
-}
-
-static int capture_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_motu *motu = substream->private_data;
-
-       mutex_lock(&motu->mutex);
-
-       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               motu->capture_substreams--;
-
-       snd_motu_stream_stop_duplex(motu);
-
-       mutex_unlock(&motu->mutex);
-
-       return snd_pcm_lib_free_vmalloc_buffer(substream);
+       return err;
 }
 
-static int playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_motu *motu = substream->private_data;
 
        mutex_lock(&motu->mutex);
 
        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               motu->playback_substreams--;
+               --motu->substreams_counter;
 
        snd_motu_stream_stop_duplex(motu);
 
@@ -266,7 +235,7 @@ static int capture_prepare(struct snd_pcm_substream *substream)
        int err;
 
        mutex_lock(&motu->mutex);
-       err = snd_motu_stream_start_duplex(motu, substream->runtime->rate);
+       err = snd_motu_stream_start_duplex(motu);
        mutex_unlock(&motu->mutex);
        if (err >= 0)
                amdtp_stream_pcm_prepare(&motu->tx_stream);
@@ -279,7 +248,7 @@ static int playback_prepare(struct snd_pcm_substream *substream)
        int err;
 
        mutex_lock(&motu->mutex);
-       err = snd_motu_stream_start_duplex(motu, substream->runtime->rate);
+       err = snd_motu_stream_start_duplex(motu);
        mutex_unlock(&motu->mutex);
        if (err >= 0)
                amdtp_stream_pcm_prepare(&motu->rx_stream);
@@ -355,8 +324,8 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
                .open      = pcm_open,
                .close     = pcm_close,
                .ioctl     = snd_pcm_lib_ioctl,
-               .hw_params = capture_hw_params,
-               .hw_free   = capture_hw_free,
+               .hw_params = pcm_hw_params,
+               .hw_free   = pcm_hw_free,
                .prepare   = capture_prepare,
                .trigger   = capture_trigger,
                .pointer   = capture_pointer,
@@ -367,8 +336,8 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
                .open      = pcm_open,
                .close     = pcm_close,
                .ioctl     = snd_pcm_lib_ioctl,
-               .hw_params = playback_hw_params,
-               .hw_free   = playback_hw_free,
+               .hw_params = pcm_hw_params,
+               .hw_free   = pcm_hw_free,
                .prepare   = playback_prepare,
                .trigger   = playback_trigger,
                .pointer   = playback_pointer,
index 81f7edc..2bbb335 100644 (file)
 #define  RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS        0x00000040
 #define  TX_PACKET_TRANSMISSION_SPEED_MASK     0x0000000f
 
-static int start_both_streams(struct snd_motu *motu, unsigned int rate)
+static int keep_resources(struct snd_motu *motu, unsigned int rate,
+                         struct amdtp_stream *stream)
 {
+       struct fw_iso_resources *resources;
+       struct snd_motu_packet_format *packet_format;
        unsigned int midi_ports = 0;
-       __be32 reg;
-       u32 data;
        int err;
 
-       if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
-           (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
-               midi_ports = 1;
+       if (stream == &motu->rx_stream) {
+               resources = &motu->rx_resources;
+               packet_format = &motu->rx_packet_formats;
 
-       /* Set packet formation to our packet streaming engine. */
-       err = amdtp_motu_set_parameters(&motu->rx_stream, rate, midi_ports,
-                                       &motu->rx_packet_formats);
-       if (err < 0)
-               return err;
+               if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
+                   (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
+                       midi_ports = 1;
+       } else {
+               resources = &motu->tx_resources;
+               packet_format = &motu->tx_packet_formats;
 
-       if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
-           (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
-               midi_ports = 1;
-       else
-               midi_ports = 0;
+               if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
+                   (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
+                       midi_ports = 1;
+       }
 
-       err = amdtp_motu_set_parameters(&motu->tx_stream, rate, midi_ports,
-                                       &motu->tx_packet_formats);
+       err = amdtp_motu_set_parameters(stream, rate, midi_ports,
+                                       packet_format);
        if (err < 0)
                return err;
 
-       /* Get isochronous resources on the bus. */
-       err = fw_iso_resources_allocate(&motu->rx_resources,
-                               amdtp_stream_get_max_payload(&motu->rx_stream),
+       return fw_iso_resources_allocate(resources,
+                               amdtp_stream_get_max_payload(stream),
                                fw_parent_device(motu->unit)->max_speed);
-       if (err < 0)
-               return err;
+}
 
-       err = fw_iso_resources_allocate(&motu->tx_resources,
-                               amdtp_stream_get_max_payload(&motu->tx_stream),
-                               fw_parent_device(motu->unit)->max_speed);
-       if (err < 0)
-               return err;
+static int begin_session(struct snd_motu *motu)
+{
+       __be32 reg;
+       u32 data;
+       int err;
 
-       /* Configure the unit to start isochronous communication. */
+       // Configure the unit to start isochronous communication.
        err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
                                        sizeof(reg));
        if (err < 0)
@@ -83,7 +82,7 @@ static int start_both_streams(struct snd_motu *motu, unsigned int rate)
                                          sizeof(reg));
 }
 
-static void stop_both_streams(struct snd_motu *motu)
+static void finish_session(struct snd_motu *motu)
 {
        __be32 reg;
        u32 data;
@@ -93,6 +92,9 @@ static void stop_both_streams(struct snd_motu *motu)
        if (err < 0)
                return;
 
+       amdtp_stream_stop(&motu->tx_stream);
+       amdtp_stream_stop(&motu->rx_stream);
+
        err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
                                        sizeof(reg));
        if (err < 0)
@@ -105,9 +107,6 @@ static void stop_both_streams(struct snd_motu *motu)
        reg = cpu_to_be32(data);
        snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
                                   sizeof(reg));
-
-       fw_iso_resources_free(&motu->tx_resources);
-       fw_iso_resources_free(&motu->rx_resources);
 }
 
 static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
@@ -125,28 +124,12 @@ static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
        if (err < 0)
                return err;
 
-       if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
-               amdtp_stream_stop(stream);
-               fw_iso_resources_free(resources);
+       if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT))
                return -ETIMEDOUT;
-       }
 
        return 0;
 }
 
-static void stop_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
-{
-       struct fw_iso_resources *resources;
-
-       if (stream == &motu->rx_stream)
-               resources = &motu->rx_resources;
-       else
-               resources = &motu->tx_resources;
-
-       amdtp_stream_stop(stream);
-       fw_iso_resources_free(resources);
-}
-
 int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
 {
        int err;
@@ -174,6 +157,48 @@ int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
        return 0;
 }
 
+int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate)
+{
+       unsigned int curr_rate;
+       int err;
+
+       err = motu->spec->protocol->get_clock_rate(motu, &curr_rate);
+       if (err < 0)
+               return err;
+       if (rate == 0)
+               rate = curr_rate;
+
+       if (motu->substreams_counter == 0 || curr_rate != rate) {
+               finish_session(motu);
+
+               fw_iso_resources_free(&motu->tx_resources);
+               fw_iso_resources_free(&motu->rx_resources);
+
+               err = motu->spec->protocol->set_clock_rate(motu, rate);
+               if (err < 0) {
+                       dev_err(&motu->unit->device,
+                               "fail to set sampling rate: %d\n", err);
+                       return err;
+               }
+
+               err = snd_motu_stream_cache_packet_formats(motu);
+               if (err < 0)
+                       return err;
+
+               err = keep_resources(motu, rate, &motu->tx_stream);
+               if (err < 0)
+                       return err;
+
+               err = keep_resources(motu, rate, &motu->rx_stream);
+               if (err < 0) {
+                       fw_iso_resources_free(&motu->tx_resources);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
 static int ensure_packet_formats(struct snd_motu *motu)
 {
        __be32 reg;
@@ -200,55 +225,34 @@ static int ensure_packet_formats(struct snd_motu *motu)
                                          sizeof(reg));
 }
 
-int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
+int snd_motu_stream_start_duplex(struct snd_motu *motu)
 {
-       const struct snd_motu_protocol *protocol = motu->spec->protocol;
-       unsigned int curr_rate;
+       unsigned int generation = motu->rx_resources.generation;
        int err = 0;
 
-       if (motu->capture_substreams == 0 && motu->playback_substreams == 0)
+       if (motu->substreams_counter == 0)
                return 0;
 
-       /* Some packet queueing errors. */
        if (amdtp_streaming_error(&motu->rx_stream) ||
-           amdtp_streaming_error(&motu->tx_stream)) {
-               amdtp_stream_stop(&motu->rx_stream);
-               amdtp_stream_stop(&motu->tx_stream);
-               stop_both_streams(motu);
-       }
+           amdtp_streaming_error(&motu->tx_stream))
+               finish_session(motu);
 
-       err = snd_motu_stream_cache_packet_formats(motu);
-       if (err < 0)
-               return err;
+       if (generation != fw_parent_device(motu->unit)->card->generation) {
+               err = fw_iso_resources_update(&motu->rx_resources);
+               if (err < 0)
+                       return err;
 
-       /* Stop stream if rate is different. */
-       err = protocol->get_clock_rate(motu, &curr_rate);
-       if (err < 0) {
-               dev_err(&motu->unit->device,
-                       "fail to get sampling rate: %d\n", err);
-               return err;
-       }
-       if (rate == 0)
-               rate = curr_rate;
-       if (rate != curr_rate) {
-               amdtp_stream_stop(&motu->rx_stream);
-               amdtp_stream_stop(&motu->tx_stream);
-               stop_both_streams(motu);
+               err = fw_iso_resources_update(&motu->tx_resources);
+               if (err < 0)
+                       return err;
        }
 
        if (!amdtp_stream_running(&motu->rx_stream)) {
-               err = protocol->set_clock_rate(motu, rate);
-               if (err < 0) {
-                       dev_err(&motu->unit->device,
-                               "fail to set sampling rate: %d\n", err);
-                       return err;
-               }
-
                err = ensure_packet_formats(motu);
                if (err < 0)
                        return err;
 
-               err = start_both_streams(motu, rate);
+               err = begin_session(motu);
                if (err < 0) {
                        dev_err(&motu->unit->device,
                                "fail to start isochronous comm: %d\n", err);
@@ -262,7 +266,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
                        goto stop_streams;
                }
 
-               err = protocol->switch_fetching_mode(motu, true);
+               err = motu->spec->protocol->switch_fetching_mode(motu, true);
                if (err < 0) {
                        dev_err(&motu->unit->device,
                                "fail to enable frame fetching: %d\n", err);
@@ -270,13 +274,11 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
                }
        }
 
-       if (!amdtp_stream_running(&motu->tx_stream) &&
-           motu->capture_substreams > 0) {
+       if (!amdtp_stream_running(&motu->tx_stream)) {
                err = start_isoc_ctx(motu, &motu->tx_stream);
                if (err < 0) {
                        dev_err(&motu->unit->device,
                                "fail to start IR context: %d", err);
-                       amdtp_stream_stop(&motu->rx_stream);
                        goto stop_streams;
                }
        }
@@ -284,21 +286,17 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
        return 0;
 
 stop_streams:
-       stop_both_streams(motu);
+       finish_session(motu);
        return err;
 }
 
 void snd_motu_stream_stop_duplex(struct snd_motu *motu)
 {
-       if (motu->capture_substreams == 0) {
-               if (amdtp_stream_running(&motu->tx_stream))
-                       stop_isoc_ctx(motu, &motu->tx_stream);
-
-               if (motu->playback_substreams == 0) {
-                       if (amdtp_stream_running(&motu->rx_stream))
-                               stop_isoc_ctx(motu, &motu->rx_stream);
-                       stop_both_streams(motu);
-               }
+       if (motu->substreams_counter == 0) {
+               finish_session(motu);
+
+               fw_iso_resources_free(&motu->tx_resources);
+               fw_iso_resources_free(&motu->rx_resources);
        }
 }
 
@@ -371,8 +369,7 @@ void snd_motu_stream_destroy_duplex(struct snd_motu *motu)
        destroy_stream(motu, AMDTP_IN_STREAM);
        destroy_stream(motu, AMDTP_OUT_STREAM);
 
-       motu->playback_substreams = 0;
-       motu->capture_substreams = 0;
+       motu->substreams_counter = 0;
 }
 
 static void motu_lock_changed(struct snd_motu *motu)
index 7c79529..09d1451 100644 (file)
@@ -59,8 +59,7 @@ struct snd_motu {
        struct amdtp_stream rx_stream;
        struct fw_iso_resources tx_resources;
        struct fw_iso_resources rx_resources;
-       unsigned int capture_substreams;
-       unsigned int playback_substreams;
+       unsigned int substreams_counter;
 
        /* For notification. */
        struct fw_address_handler async_handler;
@@ -153,7 +152,8 @@ void snd_motu_transaction_unregister(struct snd_motu *motu);
 int snd_motu_stream_init_duplex(struct snd_motu *motu);
 void snd_motu_stream_destroy_duplex(struct snd_motu *motu);
 int snd_motu_stream_cache_packet_formats(struct snd_motu *motu);
-int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate);
+int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate);
+int snd_motu_stream_start_duplex(struct snd_motu *motu);
 void snd_motu_stream_stop_duplex(struct snd_motu *motu);
 int snd_motu_stream_lock_try(struct snd_motu *motu);
 void snd_motu_stream_lock_release(struct snd_motu *motu);
index cbce013..9bdec08 100644 (file)
@@ -18,8 +18,13 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&oxfw->mutex);
 
-       oxfw->capture_substreams++;
-       err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream, 0, 0);
+       err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0);
+       if (err >= 0) {
+               ++oxfw->substreams_count;
+               err = snd_oxfw_stream_start_duplex(oxfw);
+               if (err < 0)
+                       --oxfw->substreams_count;
+       }
 
        mutex_unlock(&oxfw->mutex);
 
@@ -40,8 +45,11 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&oxfw->mutex);
 
-       oxfw->playback_substreams++;
-       err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream, 0, 0);
+       err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0);
+       if (err >= 0) {
+               ++oxfw->substreams_count;
+               err = snd_oxfw_stream_start_duplex(oxfw);
+       }
 
        mutex_unlock(&oxfw->mutex);
 
@@ -57,8 +65,8 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&oxfw->mutex);
 
-       oxfw->capture_substreams--;
-       snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
+       --oxfw->substreams_count;
+       snd_oxfw_stream_stop_duplex(oxfw);
 
        mutex_unlock(&oxfw->mutex);
 
@@ -72,8 +80,8 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
 
        mutex_lock(&oxfw->mutex);
 
-       oxfw->playback_substreams--;
-       snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
+       --oxfw->substreams_count;
+       snd_oxfw_stream_stop_duplex(oxfw);
 
        mutex_unlock(&oxfw->mutex);
 
index 94f367c..9ea3934 100644 (file)
@@ -219,12 +219,18 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+               unsigned int rate = params_rate(hw_params);
+               unsigned int channels = params_channels(hw_params);
+
                mutex_lock(&oxfw->mutex);
-               oxfw->capture_substreams++;
+               err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream,
+                                                    rate, channels);
+               if (err >= 0)
+                       ++oxfw->substreams_count;
                mutex_unlock(&oxfw->mutex);
        }
 
-       return 0;
+       return err;
 }
 static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *hw_params)
@@ -238,8 +244,14 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+               unsigned int rate = params_rate(hw_params);
+               unsigned int channels = params_channels(hw_params);
+
                mutex_lock(&oxfw->mutex);
-               oxfw->playback_substreams++;
+               err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream,
+                                                    rate, channels);
+               if (err >= 0)
+                       ++oxfw->substreams_count;
                mutex_unlock(&oxfw->mutex);
        }
 
@@ -253,9 +265,9 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
        mutex_lock(&oxfw->mutex);
 
        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               oxfw->capture_substreams--;
+               --oxfw->substreams_count;
 
-       snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
+       snd_oxfw_stream_stop_duplex(oxfw);
 
        mutex_unlock(&oxfw->mutex);
 
@@ -268,9 +280,9 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
        mutex_lock(&oxfw->mutex);
 
        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               oxfw->playback_substreams--;
+               --oxfw->substreams_count;
 
-       snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
+       snd_oxfw_stream_stop_duplex(oxfw);
 
        mutex_unlock(&oxfw->mutex);
 
@@ -280,12 +292,10 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_oxfw *oxfw = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
        mutex_lock(&oxfw->mutex);
-       err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream,
-                                           runtime->rate, runtime->channels);
+       err = snd_oxfw_stream_start_duplex(oxfw);
        mutex_unlock(&oxfw->mutex);
        if (err < 0)
                goto end;
@@ -297,12 +307,10 @@ end:
 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_oxfw *oxfw = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
        mutex_lock(&oxfw->mutex);
-       err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream,
-                                           runtime->rate, runtime->channels);
+       err = snd_oxfw_stream_start_duplex(oxfw);
        mutex_unlock(&oxfw->mutex);
        if (err < 0)
                goto end;
index 5ffedb0..74c972d 100644 (file)
@@ -100,85 +100,34 @@ static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
        return 0;
 }
 
-static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
+static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
 {
-       amdtp_stream_pcm_abort(stream);
-       amdtp_stream_stop(stream);
-
-       if (stream == &oxfw->tx_stream)
-               cmp_connection_break(&oxfw->out_conn);
-       else
-               cmp_connection_break(&oxfw->in_conn);
-}
-
-static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
-                       unsigned int rate, unsigned int pcm_channels)
-{
-       u8 **formats;
        struct cmp_connection *conn;
-       struct snd_oxfw_stream_formation formation;
-       unsigned int i, midi_ports;
        int err;
 
-       if (stream == &oxfw->rx_stream) {
-               formats = oxfw->rx_stream_formats;
+       if (stream == &oxfw->rx_stream)
                conn = &oxfw->in_conn;
-       } else {
-               formats = oxfw->tx_stream_formats;
+       else
                conn = &oxfw->out_conn;
-       }
-
-       /* Get stream format */
-       for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
-               if (formats[i] == NULL)
-                       break;
-
-               err = snd_oxfw_stream_parse_format(formats[i], &formation);
-               if (err < 0)
-                       goto end;
-               if (rate != formation.rate)
-                       continue;
-               if (pcm_channels == 0 ||  pcm_channels == formation.pcm)
-                       break;
-       }
-       if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) {
-               err = -EINVAL;
-               goto end;
-       }
-
-       pcm_channels = formation.pcm;
-       midi_ports = formation.midi * 8;
-
-       /* The stream should have one pcm channels at least */
-       if (pcm_channels == 0) {
-               err = -EINVAL;
-               goto end;
-       }
-       err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports,
-                                        false);
-       if (err < 0)
-               goto end;
 
-       err = cmp_connection_establish(conn,
-                                      amdtp_stream_get_max_payload(stream));
+       err = cmp_connection_establish(conn);
        if (err < 0)
-               goto end;
+               return err;
 
-       err = amdtp_stream_start(stream,
-                                conn->resources.channel,
-                                conn->speed);
+       err = amdtp_stream_start(stream, conn->resources.channel, conn->speed);
        if (err < 0) {
                cmp_connection_break(conn);
-               goto end;
+               return err;
        }
 
-       /* Wait first packet */
+       // Wait first packet.
        if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
-               stop_stream(oxfw, stream);
-               err = -ETIMEDOUT;
+               amdtp_stream_stop(stream);
+               cmp_connection_break(conn);
+               return -ETIMEDOUT;
        }
-end:
-       return err;
+
+       return 0;
 }
 
 static int check_connection_used_by_others(struct snd_oxfw *oxfw,
@@ -205,8 +154,7 @@ static int check_connection_used_by_others(struct snd_oxfw *oxfw,
        return err;
 }
 
-int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
-                                struct amdtp_stream *stream)
+static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
 {
        struct cmp_connection *conn;
        enum cmp_direction c_dir;
@@ -225,13 +173,12 @@ int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
 
        err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
        if (err < 0)
-               goto end;
+               return err;
 
        err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
        if (err < 0) {
-               amdtp_stream_destroy(stream);
                cmp_connection_destroy(conn);
-               goto end;
+               return err;
        }
 
        /*
@@ -245,115 +192,195 @@ int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
                if (oxfw->wrong_dbs)
                        oxfw->tx_stream.flags |= CIP_WRONG_DBS;
        }
-end:
-       return err;
+
+       return 0;
 }
 
-int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
-                                 struct amdtp_stream *stream,
-                                 unsigned int rate, unsigned int pcm_channels)
+static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
 {
-       struct amdtp_stream *opposite;
-       struct snd_oxfw_stream_formation formation;
        enum avc_general_plug_dir dir;
-       unsigned int substreams, opposite_substreams;
-       int err = 0;
+       u8 **formats;
+       struct snd_oxfw_stream_formation formation;
+       struct cmp_connection *conn;
+       int i;
+       int err;
 
-       if (stream == &oxfw->tx_stream) {
-               substreams = oxfw->capture_substreams;
-               opposite = &oxfw->rx_stream;
-               opposite_substreams = oxfw->playback_substreams;
-               dir = AVC_GENERAL_PLUG_DIR_OUT;
+       if (stream == &oxfw->rx_stream) {
+               dir = AVC_GENERAL_PLUG_DIR_IN;
+               formats = oxfw->rx_stream_formats;
+               conn = &oxfw->in_conn;
        } else {
-               substreams = oxfw->playback_substreams;
-               opposite_substreams = oxfw->capture_substreams;
+               dir = AVC_GENERAL_PLUG_DIR_OUT;
+               formats = oxfw->tx_stream_formats;
+               conn = &oxfw->out_conn;
+       }
 
-               if (oxfw->has_output)
-                       opposite = &oxfw->rx_stream;
-               else
-                       opposite = NULL;
+       err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
+       if (err < 0)
+               return err;
 
-               dir = AVC_GENERAL_PLUG_DIR_IN;
+       for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+               struct snd_oxfw_stream_formation fmt;
+
+               if (formats[i] == NULL)
+                       break;
+
+               err = snd_oxfw_stream_parse_format(formats[i], &fmt);
+               if (err < 0)
+                       return err;
+
+               if (fmt.rate == formation.rate && fmt.pcm == formation.pcm &&
+                   fmt.midi == formation.midi)
+                       break;
        }
+       if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
+               return -EINVAL;
 
-       if (substreams == 0)
-               goto end;
+       // The stream should have one pcm channels at least.
+       if (formation.pcm == 0)
+               return -EINVAL;
 
-       /*
-        * Considering JACK/FFADO streaming:
-        * TODO: This can be removed hwdep functionality becomes popular.
-        */
-       err = check_connection_used_by_others(oxfw, stream);
+       err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm,
+                                        formation.midi * 8, false);
        if (err < 0)
-               goto end;
+               return err;
 
-       /* packet queueing error */
-       if (amdtp_streaming_error(stream))
-               stop_stream(oxfw, stream);
+       return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
+}
+
+int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
+                                  struct amdtp_stream *stream,
+                                  unsigned int rate, unsigned int pcm_channels)
+{
+       struct snd_oxfw_stream_formation formation;
+       enum avc_general_plug_dir dir;
+       int err;
+
+       // Considering JACK/FFADO streaming:
+       // TODO: This can be removed hwdep functionality becomes popular.
+       err = check_connection_used_by_others(oxfw, &oxfw->rx_stream);
+       if (err < 0)
+               return err;
+       if (oxfw->has_output) {
+               err = check_connection_used_by_others(oxfw, &oxfw->tx_stream);
+               if (err < 0)
+                       return err;
+       }
+
+       if (stream == &oxfw->tx_stream)
+               dir = AVC_GENERAL_PLUG_DIR_OUT;
+       else
+               dir = AVC_GENERAL_PLUG_DIR_IN;
 
        err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
        if (err < 0)
-               goto end;
-       if (rate == 0)
+               return err;
+       if (rate == 0) {
                rate = formation.rate;
-       if (pcm_channels == 0)
                pcm_channels = formation.pcm;
+       }
+       if (formation.rate != rate || formation.pcm != pcm_channels) {
+               amdtp_stream_stop(&oxfw->rx_stream);
+               cmp_connection_break(&oxfw->in_conn);
+               cmp_connection_release(&oxfw->in_conn);
 
-       if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
-               if (opposite != NULL) {
-                       err = check_connection_used_by_others(oxfw, opposite);
-                       if (err < 0)
-                               goto end;
-                       stop_stream(oxfw, opposite);
+               if (oxfw->has_output) {
+                       amdtp_stream_stop(&oxfw->tx_stream);
+                       cmp_connection_break(&oxfw->out_conn);
+                       cmp_connection_release(&oxfw->out_conn);
                }
-               stop_stream(oxfw, stream);
+       }
 
+       if (oxfw->substreams_count == 0 ||
+           formation.rate != rate || formation.pcm != pcm_channels) {
                err = set_stream_format(oxfw, stream, rate, pcm_channels);
                if (err < 0) {
                        dev_err(&oxfw->unit->device,
                                "fail to set stream format: %d\n", err);
-                       goto end;
+                       return err;
                }
 
-               /* Start opposite stream if needed. */
-               if (opposite && !amdtp_stream_running(opposite) &&
-                   (opposite_substreams > 0)) {
-                       err = start_stream(oxfw, opposite, rate, 0);
+               err = keep_resources(oxfw, &oxfw->rx_stream);
+               if (err < 0)
+                       return err;
+
+               if (oxfw->has_output) {
+                       err = keep_resources(oxfw, &oxfw->tx_stream);
                        if (err < 0) {
-                               dev_err(&oxfw->unit->device,
-                                       "fail to restart stream: %d\n", err);
-                               goto end;
+                               cmp_connection_release(&oxfw->in_conn);
+                               return err;
                        }
                }
        }
 
-       /* Start requested stream. */
-       if (!amdtp_stream_running(stream)) {
-               err = start_stream(oxfw, stream, rate, pcm_channels);
-               if (err < 0)
+       return 0;
+}
+
+int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
+{
+       int err;
+
+       if (oxfw->substreams_count == 0)
+               return -EIO;
+
+       if (amdtp_streaming_error(&oxfw->rx_stream) ||
+           amdtp_streaming_error(&oxfw->tx_stream)) {
+               amdtp_stream_stop(&oxfw->rx_stream);
+               cmp_connection_break(&oxfw->in_conn);
+
+               if (oxfw->has_output) {
+                       amdtp_stream_stop(&oxfw->tx_stream);
+                       cmp_connection_break(&oxfw->out_conn);
+               }
+       }
+
+       if (!amdtp_stream_running(&oxfw->rx_stream)) {
+               err = start_stream(oxfw, &oxfw->rx_stream);
+               if (err < 0) {
                        dev_err(&oxfw->unit->device,
-                               "fail to start stream: %d\n", err);
+                               "fail to start rx stream: %d\n", err);
+                       goto error;
+               }
+       }
+
+       if (oxfw->has_output) {
+               if (!amdtp_stream_running(&oxfw->tx_stream)) {
+                       err = start_stream(oxfw, &oxfw->tx_stream);
+                       if (err < 0) {
+                               dev_err(&oxfw->unit->device,
+                                       "fail to start tx stream: %d\n", err);
+                               goto error;
+                       }
+               }
+       }
+
+       return 0;
+error:
+       amdtp_stream_stop(&oxfw->rx_stream);
+       cmp_connection_break(&oxfw->in_conn);
+       if (oxfw->has_output) {
+               amdtp_stream_stop(&oxfw->tx_stream);
+               cmp_connection_break(&oxfw->out_conn);
        }
-end:
        return err;
 }
 
-void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
-                                 struct amdtp_stream *stream)
+void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw)
 {
-       if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
-           ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
-               return;
+       if (oxfw->substreams_count == 0) {
+               amdtp_stream_stop(&oxfw->rx_stream);
+               cmp_connection_break(&oxfw->in_conn);
+               cmp_connection_release(&oxfw->in_conn);
 
-       stop_stream(oxfw, stream);
+               if (oxfw->has_output) {
+                       amdtp_stream_stop(&oxfw->tx_stream);
+                       cmp_connection_break(&oxfw->out_conn);
+                       cmp_connection_release(&oxfw->out_conn);
+               }
+       }
 }
 
-/*
- * This function should be called before starting the stream or after stopping
- * the streams.
- */
-void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
-                                    struct amdtp_stream *stream)
+static void destroy_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
 {
        struct cmp_connection *conn;
 
@@ -366,20 +393,48 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
        cmp_connection_destroy(conn);
 }
 
-void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
-                                   struct amdtp_stream *stream)
+int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw)
 {
-       struct cmp_connection *conn;
+       int err;
 
-       if (stream == &oxfw->tx_stream)
-               conn = &oxfw->out_conn;
-       else
-               conn = &oxfw->in_conn;
+       err = init_stream(oxfw, &oxfw->rx_stream);
+       if (err < 0)
+               return err;
 
-       if (cmp_connection_update(conn) < 0)
-               stop_stream(oxfw, stream);
-       else
-               amdtp_stream_update(stream);
+       if (oxfw->has_output) {
+               err = init_stream(oxfw, &oxfw->tx_stream);
+               if (err < 0) {
+                       destroy_stream(oxfw, &oxfw->rx_stream);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+// This function should be called before starting the stream or after stopping
+// the streams.
+void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw)
+{
+       destroy_stream(oxfw, &oxfw->rx_stream);
+
+       if (oxfw->has_output)
+               destroy_stream(oxfw, &oxfw->tx_stream);
+}
+
+void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw)
+{
+       amdtp_stream_stop(&oxfw->rx_stream);
+       cmp_connection_break(&oxfw->in_conn);
+
+       amdtp_stream_pcm_abort(&oxfw->rx_stream);
+
+       if (oxfw->has_output) {
+               amdtp_stream_stop(&oxfw->tx_stream);
+               cmp_connection_break(&oxfw->out_conn);
+
+               amdtp_stream_pcm_abort(&oxfw->tx_stream);
+       }
 }
 
 int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
index 9fd145c..fb6df3f 100644 (file)
@@ -118,9 +118,7 @@ static void oxfw_card_free(struct snd_card *card)
 {
        struct snd_oxfw *oxfw = card->private_data;
 
-       snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
-       if (oxfw->has_output)
-               snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+       snd_oxfw_stream_destroy_duplex(oxfw);
 }
 
 static int detect_quirks(struct snd_oxfw *oxfw)
@@ -208,14 +206,9 @@ static void do_registration(struct work_struct *work)
        if (err < 0)
                goto error;
 
-       err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream);
+       err = snd_oxfw_stream_init_duplex(oxfw);
        if (err < 0)
                goto error;
-       if (oxfw->has_output) {
-               err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream);
-               if (err < 0)
-                       goto error;
-       }
 
        err = snd_oxfw_create_pcm(oxfw);
        if (err < 0)
@@ -282,11 +275,7 @@ static void oxfw_bus_reset(struct fw_unit *unit)
 
        if (oxfw->registered) {
                mutex_lock(&oxfw->mutex);
-
-               snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream);
-               if (oxfw->has_output)
-                       snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream);
-
+               snd_oxfw_stream_update_duplex(oxfw);
                mutex_unlock(&oxfw->mutex);
 
                if (oxfw->entry->vendor_id == OUI_STANTON)
index 3611285..cb69ab8 100644 (file)
@@ -52,8 +52,7 @@ struct snd_oxfw {
        struct cmp_connection in_conn;
        struct amdtp_stream tx_stream;
        struct amdtp_stream rx_stream;
-       unsigned int capture_substreams;
-       unsigned int playback_substreams;
+       unsigned int substreams_count;
 
        unsigned int midi_input_ports;
        unsigned int midi_output_ports;
@@ -99,17 +98,14 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
                                enum avc_general_plug_dir dir,
                                unsigned short pid);
 
-int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
-                                struct amdtp_stream *stream);
-int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
-                                 struct amdtp_stream *stream,
-                                 unsigned int rate, unsigned int pcm_channels);
-void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
-                                 struct amdtp_stream *stream);
-void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
-                                    struct amdtp_stream *stream);
-void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
-                                   struct amdtp_stream *stream);
+int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw);
+int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
+                                  struct amdtp_stream *stream,
+                                  unsigned int rate, unsigned int pcm_channels);
+int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw);
 
 struct snd_oxfw_stream_formation {
        unsigned int rate;
index d9d20ef..95fb10b 100644 (file)
@@ -223,7 +223,7 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
                return 0;
 
        /* Use fixed value for FDF field. */
-       s->fdf = 0x00;
+       s->ctx_data.rx.fdf = 0x00;
 
        /* This protocol uses fixed number of data channels for PCM samples. */
        p = s->protocol;
index a8cd9b1..b5ced54 100644 (file)
@@ -83,8 +83,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
 {
        struct snd_tscm *tscm = substream->private_data;
        int err;
@@ -95,58 +95,26 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-               mutex_lock(&tscm->mutex);
-               tscm->substreams_counter++;
-               mutex_unlock(&tscm->mutex);
-       }
-
-       return 0;
-}
-
-static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_tscm *tscm = substream->private_data;
-       int err;
-
-       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
-                                              params_buffer_bytes(hw_params));
-       if (err < 0)
-               return err;
+               unsigned int rate = params_rate(hw_params);
 
-       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                mutex_lock(&tscm->mutex);
-               tscm->substreams_counter++;
+               err = snd_tscm_stream_reserve_duplex(tscm, rate);
+               if (err >= 0)
+                       ++tscm->substreams_counter;
                mutex_unlock(&tscm->mutex);
        }
 
-       return 0;
-}
-
-static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_tscm *tscm = substream->private_data;
-
-       mutex_lock(&tscm->mutex);
-
-       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               tscm->substreams_counter--;
-
-       snd_tscm_stream_stop_duplex(tscm);
-
-       mutex_unlock(&tscm->mutex);
-
-       return snd_pcm_lib_free_vmalloc_buffer(substream);
+       return err;
 }
 
-static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_tscm *tscm = substream->private_data;
 
        mutex_lock(&tscm->mutex);
 
        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-               tscm->substreams_counter--;
+               --tscm->substreams_counter;
 
        snd_tscm_stream_stop_duplex(tscm);
 
@@ -259,8 +227,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_capture_hw_params,
-               .hw_free        = pcm_capture_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_capture_prepare,
                .trigger        = pcm_capture_trigger,
                .pointer        = pcm_capture_pointer,
@@ -271,8 +239,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
                .open           = pcm_open,
                .close          = pcm_close,
                .ioctl          = snd_pcm_lib_ioctl,
-               .hw_params      = pcm_playback_hw_params,
-               .hw_free        = pcm_playback_hw_free,
+               .hw_params      = pcm_hw_params,
+               .hw_free        = pcm_hw_free,
                .prepare        = pcm_playback_prepare,
                .trigger        = pcm_playback_trigger,
                .pointer        = pcm_playback_pointer,
index e6fcd9e..e852e46 100644 (file)
@@ -165,7 +165,7 @@ static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)
        __be32 reg;
        int err;
 
-       /* Set an option for unknown purpose. */
+       // Set an option for unknown purpose.
        reg = cpu_to_be32(0x00200000);
        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
                                 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
@@ -173,17 +173,16 @@ static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)
        if (err < 0)
                return err;
 
-       err = enable_data_channels(tscm);
-       if (err < 0)
-               return err;
-
-       return set_clock(tscm, rate, INT_MAX);
+       return enable_data_channels(tscm);
 }
 
 static void finish_session(struct snd_tscm *tscm)
 {
        __be32 reg;
 
+       amdtp_stream_stop(&tscm->rx_stream);
+       amdtp_stream_stop(&tscm->tx_stream);
+
        reg = 0;
        snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
                           TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
@@ -194,6 +193,19 @@ static void finish_session(struct snd_tscm *tscm)
                           TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,
                           &reg, sizeof(reg), 0);
 
+       // Unregister channels.
+       reg = cpu_to_be32(0x00000000);
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
+                          &reg, sizeof(reg), 0);
+       reg = cpu_to_be32(0x00000000);
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
+                          &reg, sizeof(reg), 0);
+       reg = cpu_to_be32(0x00000000);
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
+                          &reg, sizeof(reg), 0);
 }
 
 static int begin_session(struct snd_tscm *tscm)
@@ -201,6 +213,30 @@ static int begin_session(struct snd_tscm *tscm)
        __be32 reg;
        int err;
 
+       // Register the isochronous channel for transmitting stream.
+       reg = cpu_to_be32(tscm->tx_resources.channel);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       // Unknown.
+       reg = cpu_to_be32(0x00000002);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       // Register the isochronous channel for receiving stream.
+       reg = cpu_to_be32(tscm->rx_resources.channel);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
        reg = cpu_to_be32(0x00000001);
        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
                                 TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
@@ -215,7 +251,7 @@ static int begin_session(struct snd_tscm *tscm)
        if (err < 0)
                return err;
 
-       /* Set an option for unknown purpose. */
+       // Set an option for unknown purpose.
        reg = cpu_to_be32(0x00002000);
        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
                                 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
@@ -223,7 +259,7 @@ static int begin_session(struct snd_tscm *tscm)
        if (err < 0)
                return err;
 
-       /* Start multiplexing PCM samples on packets. */
+       // Start multiplexing PCM samples on packets.
        reg = cpu_to_be32(0x00000001);
        return snd_fw_transaction(tscm->unit,
                                  TCODE_WRITE_QUADLET_REQUEST,
@@ -231,82 +267,24 @@ static int begin_session(struct snd_tscm *tscm)
                                  &reg, sizeof(reg), 0);
 }
 
-static void release_resources(struct snd_tscm *tscm)
+static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
+                         struct amdtp_stream *stream)
 {
-       __be32 reg;
-
-       /* Unregister channels. */
-       reg = cpu_to_be32(0x00000000);
-       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
-                          TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
-                          &reg, sizeof(reg), 0);
-       reg = cpu_to_be32(0x00000000);
-       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
-                          TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
-                          &reg, sizeof(reg), 0);
-       reg = cpu_to_be32(0x00000000);
-       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
-                          TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
-                          &reg, sizeof(reg), 0);
-
-       /* Release isochronous resources. */
-       fw_iso_resources_free(&tscm->tx_resources);
-       fw_iso_resources_free(&tscm->rx_resources);
-}
-
-static int keep_resources(struct snd_tscm *tscm, unsigned int rate)
-{
-       __be32 reg;
+       struct fw_iso_resources *resources;
        int err;
 
-       /* Keep resources for in-stream. */
-       err = amdtp_tscm_set_parameters(&tscm->tx_stream, rate);
-       if (err < 0)
-               return err;
-       err = fw_iso_resources_allocate(&tscm->tx_resources,
-                       amdtp_stream_get_max_payload(&tscm->tx_stream),
-                       fw_parent_device(tscm->unit)->max_speed);
-       if (err < 0)
-               goto error;
+       if (stream == &tscm->tx_stream)
+               resources = &tscm->tx_resources;
+       else
+               resources = &tscm->rx_resources;
 
-       /* Keep resources for out-stream. */
-       err = amdtp_tscm_set_parameters(&tscm->rx_stream, rate);
-       if (err < 0)
-               return err;
-       err = fw_iso_resources_allocate(&tscm->rx_resources,
-                       amdtp_stream_get_max_payload(&tscm->rx_stream),
-                       fw_parent_device(tscm->unit)->max_speed);
+       err = amdtp_tscm_set_parameters(stream, rate);
        if (err < 0)
                return err;
 
-       /* Register the isochronous channel for transmitting stream. */
-       reg = cpu_to_be32(tscm->tx_resources.channel);
-       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
-                                TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
-                                &reg, sizeof(reg), 0);
-       if (err < 0)
-               goto error;
-
-       /* Unknown */
-       reg = cpu_to_be32(0x00000002);
-       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
-                                TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
-                                &reg, sizeof(reg), 0);
-       if (err < 0)
-               goto error;
-
-       /* Register the isochronous channel for receiving stream. */
-       reg = cpu_to_be32(tscm->rx_resources.channel);
-       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
-                                TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
-                                &reg, sizeof(reg), 0);
-       if (err < 0)
-               goto error;
-
-       return 0;
-error:
-       release_resources(tscm);
-       return err;
+       return fw_iso_resources_allocate(resources,
+                               amdtp_stream_get_max_payload(stream),
+                               fw_parent_device(tscm->unit)->max_speed);
 }
 
 int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
@@ -345,7 +323,7 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
        return err;
 }
 
-/* At bus reset, streaming is stopped and some registers are clear. */
+// At bus reset, streaming is stopped and some registers are clear.
 void snd_tscm_stream_update_duplex(struct snd_tscm *tscm)
 {
        amdtp_stream_pcm_abort(&tscm->tx_stream);
@@ -368,33 +346,62 @@ void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
        fw_iso_resources_destroy(&tscm->tx_resources);
 }
 
-int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
+int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate)
 {
        unsigned int curr_rate;
        int err;
 
-       if (tscm->substreams_counter == 0)
-               return 0;
-
        err = snd_tscm_stream_get_rate(tscm, &curr_rate);
        if (err < 0)
                return err;
-       if (curr_rate != rate ||
-           amdtp_streaming_error(&tscm->rx_stream) ||
-           amdtp_streaming_error(&tscm->tx_stream)) {
+
+       if (tscm->substreams_counter == 0 || rate != curr_rate) {
                finish_session(tscm);
 
-               amdtp_stream_stop(&tscm->rx_stream);
-               amdtp_stream_stop(&tscm->tx_stream);
+               fw_iso_resources_free(&tscm->tx_resources);
+               fw_iso_resources_free(&tscm->rx_resources);
 
-               release_resources(tscm);
+               err = set_clock(tscm, rate, INT_MAX);
+               if (err < 0)
+                       return err;
+
+               err = keep_resources(tscm, rate, &tscm->tx_stream);
+               if (err < 0)
+                       return err;
+
+               err = keep_resources(tscm, rate, &tscm->rx_stream);
+               if (err < 0) {
+                       fw_iso_resources_free(&tscm->tx_resources);
+                       return err;
+               }
        }
 
-       if (!amdtp_stream_running(&tscm->rx_stream)) {
-               err = keep_resources(tscm, rate);
+       return 0;
+}
+
+int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
+{
+       unsigned int generation = tscm->rx_resources.generation;
+       int err;
+
+       if (tscm->substreams_counter == 0)
+               return 0;
+
+       if (amdtp_streaming_error(&tscm->rx_stream) ||
+           amdtp_streaming_error(&tscm->tx_stream))
+               finish_session(tscm);
+
+       if (generation != fw_parent_device(tscm->unit)->card->generation) {
+               err = fw_iso_resources_update(&tscm->tx_resources);
+               if (err < 0)
+                       goto error;
+
+               err = fw_iso_resources_update(&tscm->rx_resources);
                if (err < 0)
                        goto error;
+       }
 
+       if (!amdtp_stream_running(&tscm->rx_stream)) {
                err = set_stream_formats(tscm, rate);
                if (err < 0)
                        goto error;
@@ -432,25 +439,19 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
 
        return 0;
 error:
-       amdtp_stream_stop(&tscm->rx_stream);
-       amdtp_stream_stop(&tscm->tx_stream);
-
        finish_session(tscm);
-       release_resources(tscm);
 
        return err;
 }
 
 void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)
 {
-       if (tscm->substreams_counter > 0)
-               return;
-
-       amdtp_stream_stop(&tscm->tx_stream);
-       amdtp_stream_stop(&tscm->rx_stream);
+       if (tscm->substreams_counter == 0) {
+               finish_session(tscm);
 
-       finish_session(tscm);
-       release_resources(tscm);
+               fw_iso_resources_free(&tscm->tx_resources);
+               fw_iso_resources_free(&tscm->rx_resources);
+       }
 }
 
 void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)
index 1d003d4..734e5bb 100644 (file)
@@ -146,6 +146,7 @@ int snd_tscm_stream_get_clock(struct snd_tscm *tscm,
 int snd_tscm_stream_init_duplex(struct snd_tscm *tscm);
 void snd_tscm_stream_update_duplex(struct snd_tscm *tscm);
 void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm);
+int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate);
 int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate);
 void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm);
 
index b02f745..3b01105 100644 (file)
@@ -79,6 +79,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
        snd_hdac_chip_writew(bus, RINTCNT, 1);
        /* enable rirb dma and response irq */
        snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
+       /* Accept unsolicited responses */
+       snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
        spin_unlock_irq(&bus->reg_lock);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_init_cmd_io);
@@ -241,6 +243,8 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
 
        for (loopcounter = 0;; loopcounter++) {
                spin_lock_irq(&bus->reg_lock);
+               if (bus->polling_mode)
+                       snd_hdac_bus_update_rirb(bus);
                if (!bus->rirb.cmds[addr]) {
                        if (res)
                                *res = bus->rirb.res[addr]; /* the last value */
@@ -415,9 +419,6 @@ int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset)
                return -EBUSY;
        }
 
-       /* Accept unsolicited responses */
-       snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
-
        /* detect codecs */
        if (!bus->codec_mask) {
                bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
index 6907dbe..b26cc93 100644 (file)
@@ -90,7 +90,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus,
 
        fg = codec->afg ? codec->afg : codec->mfg;
 
-       err = snd_hdac_refresh_widgets(codec, false);
+       err = snd_hdac_refresh_widgets(codec);
        if (err < 0)
                goto error;
 
@@ -395,32 +395,35 @@ static void setup_fg_nodes(struct hdac_device *codec)
 /**
  * snd_hdac_refresh_widgets - Reset the widget start/end nodes
  * @codec: the codec object
- * @sysfs: re-initialize sysfs tree, too
  */
-int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs)
+int snd_hdac_refresh_widgets(struct hdac_device *codec)
 {
        hda_nid_t start_nid;
-       int nums, err;
+       int nums, err = 0;
 
+       /*
+        * Serialize against multiple threads trying to update the sysfs
+        * widgets array.
+        */
+       mutex_lock(&codec->widget_lock);
        nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid);
        if (!start_nid || nums <= 0 || nums >= 0xff) {
                dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n",
                        codec->afg);
-               return -EINVAL;
+               err = -EINVAL;
+               goto unlock;
        }
 
-       if (sysfs) {
-               mutex_lock(&codec->widget_lock);
-               err = hda_widget_sysfs_reinit(codec, start_nid, nums);
-               mutex_unlock(&codec->widget_lock);
-               if (err < 0)
-                       return err;
-       }
+       err = hda_widget_sysfs_reinit(codec, start_nid, nums);
+       if (err < 0)
+               goto unlock;
 
        codec->num_nodes = nums;
        codec->start_nid = start_nid;
        codec->end_nid = start_nid + nums;
-       return 0;
+unlock:
+       mutex_unlock(&codec->widget_lock);
+       return err;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets);
 
index 1192c75..3c2db38 100644 (file)
@@ -136,10 +136,12 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
        if (!acomp)
                return -ENODEV;
        if (!acomp->ops) {
-               request_module("i915");
-               /* 60s timeout */
-               wait_for_completion_timeout(&bind_complete,
-                                           msecs_to_jiffies(60 * 1000));
+               if (!IS_ENABLED(CONFIG_MODULES) ||
+                   !request_module("i915")) {
+                       /* 60s timeout */
+                       wait_for_completion_timeout(&bind_complete,
+                                                  msecs_to_jiffies(60 * 1000));
+               }
        }
        if (!acomp->ops) {
                dev_info(bus->dev, "couldn't bind with audio component\n");
index 909d5ef..e56e833 100644 (file)
@@ -428,7 +428,7 @@ int hda_widget_sysfs_reinit(struct hdac_device *codec,
        int i;
 
        if (!codec->widgets)
-               return hda_widget_sysfs_init(codec);
+               return 0;
 
        tree = kmemdup(codec->widgets, sizeof(*tree), GFP_KERNEL);
        if (!tree)
index e7234f3..2a21a3d 100644 (file)
@@ -1519,7 +1519,6 @@ static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
 static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
-       int change;
        u32 h_control = kcontrol->private_value;
        short an_gain_mB[HPI_MAX_CHANNELS];
 
@@ -1530,9 +1529,8 @@ static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
        /*  change = asihpi->mixer_volume[addr][0] != left ||
           asihpi->mixer_volume[addr][1] != right;
         */
-       change = 1;
        hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));
-       return change;
+       return 1;
 }
 
 static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
@@ -1555,13 +1553,12 @@ static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
        u32 h_control = kcontrol->private_value;
-       int change = 1;
        /* HPI currently only supports all or none muting of multichannel volume
        ALSA Switch element has opposite sense to HPI mute: on==unmuted, off=muted
        */
        int mute =  ucontrol->value.integer.value[0] ? 0 : HPI_BITMASK_ALL_CHANNELS;
        hpi_handle_error(hpi_volume_set_mute(h_control, mute));
-       return change;
+       return 1;
 }
 
 static int snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
index 7347103..2db183f 100644 (file)
@@ -765,7 +765,7 @@ snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
        a3dsrc_t *a = kcontrol->private_data;
-       int changed = 1, i;
+       int i;
        int coord[6];
        for (i = 0; i < 6; i++)
                coord[i] = ucontrol->value.integer.value[i];
@@ -774,7 +774,7 @@ snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol,
        vortex_a3d_coord2hrtf(a->hrtf[1], coord);
        a3dsrc_SetHrtfTarget(a, a->hrtf[0], a->hrtf[1]);
        a3dsrc_SetHrtfCurrent(a, a->hrtf[0], a->hrtf[1]);
-       return changed;
+       return 1;
 }
 
 static int
@@ -783,7 +783,7 @@ snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol,
 {
        a3dsrc_t *a = kcontrol->private_data;
        int coord[6];
-       int i, changed = 1;
+       int i;
        for (i = 0; i < 6; i++)
                coord[i] = ucontrol->value.integer.value[i];
        /* Translate orientation coordinates to a3d params. */
@@ -793,7 +793,7 @@ snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol,
        a3dsrc_SetItdTarget(a, a->itd[0], a->itd[1]);
        a3dsrc_SetItdCurrent(a, a->itd[0], a->itd[1]);
        a3dsrc_SetItdDline(a, a->dline);
-       return changed;
+       return 1;
 }
 
 static int
@@ -801,7 +801,6 @@ snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_value *ucontrol)
 {
        a3dsrc_t *a = kcontrol->private_data;
-       int changed = 1;
        int l, r;
        /* There may be some scale tranlation needed here. */
        l = ucontrol->value.integer.value[0];
@@ -810,7 +809,7 @@ snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol,
        /* Left Right panning. */
        a3dsrc_SetGainTarget(a, l, r);
        a3dsrc_SetGainCurrent(a, l, r);
-       return changed;
+       return 1;
 }
 
 static int
@@ -818,7 +817,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        a3dsrc_t *a = kcontrol->private_data;
-       int i, changed = 1;
+       int i;
        int params[6];
        for (i = 0; i < 6; i++)
                params[i] = ucontrol->value.integer.value[i];
@@ -831,7 +830,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,
        a3dsrc_SetAtmosCurrent(a, a->filter[0],
                               a->filter[1], a->filter[2],
                               a->filter[3], a->filter[4]);
-       return changed;
+       return 1;
 }
 
 static const struct snd_kcontrol_new vortex_a3d_kcontrol = {
index a2cce3e..04c7126 100644 (file)
@@ -694,7 +694,7 @@ static int snd_cs4281_trigger(struct snd_pcm_substream *substream, int cmd)
 
 static unsigned int snd_cs4281_rate(unsigned int rate, unsigned int *real_rate)
 {
-       unsigned int val = ~0;
+       unsigned int val;
        
        if (real_rate)
                *real_rate = rate;
@@ -707,9 +707,8 @@ static unsigned int snd_cs4281_rate(unsigned int rate, unsigned int *real_rate)
        case 44100:     return 1;
        case 48000:     return 0;
        default:
-               goto __variable;
+               break;
        }
-      __variable:
        val = 1536000 / rate;
        if (real_rate)
                *real_rate = 1536000 / val;
index b181752..50d4a87 100644 (file)
@@ -1058,7 +1058,6 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
 {
        int i;
        u32 channel_mask;
-       char is_cyclic;
 
        dev_dbg(chip->card->dev,
                "allocate_pipes: ch=%d int=%d\n", pipe_index, interleave);
@@ -1066,8 +1065,6 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
        if (chip->bad_board)
                return -EIO;
 
-       is_cyclic = 1;  /* This driver uses cyclic buffers only */
-
        for (channel_mask = i = 0; i < interleave; i++)
                channel_mask |= 1 << (pipe_index + i);
        if (chip->pipe_alloc_mask & channel_mask) {
@@ -1078,8 +1075,8 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
 
        chip->comm_page->position[pipe_index] = 0;
        chip->pipe_alloc_mask |= channel_mask;
-       if (is_cyclic)
-               chip->pipe_cyclic_mask |= channel_mask;
+       /* This driver uses cyclic buffers only */
+       chip->pipe_cyclic_mask |= channel_mask;
        pipe->index = pipe_index;
        pipe->interleave = interleave;
        pipe->state = PIPE_STATE_STOPPED;
index 67d6473..9cf8183 100644 (file)
@@ -1074,7 +1074,6 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol,
 {
        struct emu10k1x *emu = snd_kcontrol_chip(kcontrol);
        unsigned int val;
-       int change = 0;
 
        val = ucontrol->value.integer.value[0] ;
 
@@ -1089,7 +1088,7 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol,
                snd_emu10k1x_ptr_write(emu, ROUTING, 0, 0x1003F);
                snd_emu10k1x_gpio_write(emu, 0x1080);
        }
-       return change;
+       return 0;
 }
 
 static const struct snd_kcontrol_new snd_emu10k1x_shared_spdif =
index 6c51b83..51f10ed 100644 (file)
@@ -108,7 +108,7 @@ static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
 {
        struct hda_conn_list *p;
 
-       p = kmalloc(sizeof(*p) + len * sizeof(hda_nid_t), GFP_KERNEL);
+       p = kmalloc(struct_size(p, conns, len), GFP_KERNEL);
        if (!p)
                return -ENOMEM;
        p->len = len;
@@ -1002,7 +1002,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
        hda_nid_t fg;
        int err;
 
-       err = snd_hdac_refresh_widgets(&codec->core, true);
+       err = snd_hdac_refresh_widgets(&codec->core);
        if (err < 0)
                return err;
 
@@ -2941,15 +2941,19 @@ static int hda_codec_runtime_resume(struct device *dev)
 #ifdef CONFIG_PM_SLEEP
 static int hda_codec_force_resume(struct device *dev)
 {
+       struct hda_codec *codec = dev_to_hda_codec(dev);
+       bool forced_resume = !codec->relaxed_resume && codec->jacktbl.used;
        int ret;
 
        /* The get/put pair below enforces the runtime resume even if the
         * device hasn't been used at suspend time.  This trick is needed to
         * update the jack state change during the sleep.
         */
-       pm_runtime_get_noresume(dev);
+       if (forced_resume)
+               pm_runtime_get_noresume(dev);
        ret = pm_runtime_force_resume(dev);
-       pm_runtime_put(dev);
+       if (forced_resume)
+               pm_runtime_put(dev);
        return ret;
 }
 
index 232a192..c8d1b43 100644 (file)
@@ -795,11 +795,11 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
 
        for (loopcounter = 0;; loopcounter++) {
                spin_lock_irq(&bus->reg_lock);
-               if (chip->polling_mode || do_poll)
+               if (bus->polling_mode || do_poll)
                        snd_hdac_bus_update_rirb(bus);
                if (!bus->rirb.cmds[addr]) {
                        if (!do_poll)
-                               chip->poll_count = 0;
+                               bus->poll_count = 0;
                        if (res)
                                *res = bus->rirb.res[addr]; /* the last value */
                        spin_unlock_irq(&bus->reg_lock);
@@ -819,21 +819,21 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
        if (hbus->no_response_fallback)
                return -EIO;
 
-       if (!chip->polling_mode && chip->poll_count < 2) {
+       if (!bus->polling_mode && bus->poll_count < 2) {
                dev_dbg(chip->card->dev,
                        "azx_get_response timeout, polling the codec once: last cmd=0x%08x\n",
                        bus->last_cmd[addr]);
                do_poll = 1;
-               chip->poll_count++;
+               bus->poll_count++;
                goto again;
        }
 
 
-       if (!chip->polling_mode) {
+       if (!bus->polling_mode) {
                dev_warn(chip->card->dev,
                         "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n",
                         bus->last_cmd[addr]);
-               chip->polling_mode = 1;
+               bus->polling_mode = 1;
                goto again;
        }
 
index 3aa5c95..baa1537 100644 (file)
@@ -133,11 +133,9 @@ struct azx {
 
        /* flags */
        int bdl_pos_adj;
-       int poll_count;
        unsigned int running:1;
        unsigned int fallback_to_single_cmd:1;
        unsigned int single_cmd:1;
-       unsigned int polling_mode:1;
        unsigned int msi:1;
        unsigned int probing:1; /* codec probing phase */
        unsigned int snoop:1;
index 50f86f4..1e14d72 100644 (file)
@@ -313,11 +313,10 @@ enum {
 
 #define AZX_DCAPS_INTEL_SKYLAKE \
        (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
+        AZX_DCAPS_SYNC_WRITE |\
         AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
 
-#define AZX_DCAPS_INTEL_BROXTON \
-       (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
-        AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
+#define AZX_DCAPS_INTEL_BROXTON                AZX_DCAPS_INTEL_SKYLAKE
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -1687,10 +1686,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
        else
                chip->bdl_pos_adj = bdl_pos_adj[dev];
 
-       /* Workaround for a communication error on CFL (bko#199007) and CNL */
-       if (IS_CFL(pci) || IS_CNL(pci))
-               chip->polling_mode = 1;
-
        err = azx_bus_init(chip, model[dev], &pci_hda_io_ops);
        if (err < 0) {
                kfree(hda);
@@ -1698,6 +1693,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
                return err;
        }
 
+       /* Workaround for a communication error on CFL (bko#199007) and CNL */
+       if (IS_CFL(pci) || IS_CNL(pci))
+               azx_bus(chip)->polling_mode = 1;
+
        if (chip->driver_type == AZX_DRIVER_NVIDIA) {
                dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
                chip->bus.needs_damn_long_delay = 1;
@@ -2374,6 +2373,9 @@ static const struct pci_device_id azx_ids[] = {
        /* Icelake */
        { PCI_DEVICE(0x8086, 0x34c8),
          .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       /* Elkhart Lake */
+       { PCI_DEVICE(0x8086, 0x4b55),
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
        /* Broxton-P(Apollolake) */
        { PCI_DEVICE(0x8086, 0x5a98),
          .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
index 6d9acd5..1fb7b06 100644 (file)
@@ -559,7 +559,7 @@ static void call_jack_callback(struct hda_codec *codec, unsigned int res,
 void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
 {
        struct hda_jack_tbl *event;
-       int tag = (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x7f;
+       int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT;
 
        event = snd_hda_jack_tbl_get_from_tag(codec, tag);
        if (!event)
index c309679..0d51823 100644 (file)
@@ -2718,7 +2718,7 @@ static bool is_last(const struct dsp_image_seg *p)
 
 static size_t dsp_sizeof(const struct dsp_image_seg *p)
 {
-       return sizeof(*p) + p->count*sizeof(u32);
+       return struct_size(p, data, p->count);
 }
 
 static const struct dsp_image_seg *get_next_seg_ptr(
@@ -5980,7 +5980,7 @@ static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol,
        int ch = get_amp_channels(kcontrol);
        long *valp = ucontrol->value.integer.value;
        hda_nid_t vnid = 0;
-       int changed = 1;
+       int changed;
 
        switch (nid) {
        case 0x02:
index 4f8d084..f299f13 100644 (file)
@@ -1083,6 +1083,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
  */
 
 static const struct hda_device_id snd_hda_id_conexant[] = {
+       HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
index b7bde55..bea7b09 100644 (file)
@@ -1614,7 +1614,8 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
        if (jack == NULL)
                goto unlock;
        snd_jack_report(jack,
-                       eld->monitor_present ? SND_JACK_AVOUT : 0);
+                       (eld->monitor_present && eld->eld_valid) ?
+                               SND_JACK_AVOUT : 0);
  unlock:
        mutex_unlock(&per_pin->lock);
 }
@@ -2291,8 +2292,10 @@ static void generic_hdmi_free(struct hda_codec *codec)
        struct hdmi_spec *spec = codec->spec;
        int pin_idx, pcm_idx;
 
-       if (codec_has_acomp(codec))
+       if (codec_has_acomp(codec)) {
                snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
+               codec->relaxed_resume = 0;
+       }
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
                struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
@@ -2416,7 +2419,6 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
 }
 
 #define INTEL_GET_VENDOR_VERB  0xf81
-#define INTEL_GET_VENDOR_VERB  0xf81
 #define INTEL_SET_VENDOR_VERB  0x781
 #define INTEL_EN_DP12          0x02    /* enable DP 1.2 features */
 #define INTEL_EN_ALL_PIN_CVTS  0x01    /* enable 2nd & 3rd pins and convertors */
@@ -2524,18 +2526,32 @@ static int intel_pin2port(void *audio_ptr, int pin_nid)
        return -1;
 }
 
+static int intel_port2pin(struct hda_codec *codec, int port)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (!spec->port_num) {
+               /* we assume only from port-B to port-D */
+               if (port < 1 || port > 3)
+                       return 0;
+               /* intel port is 1-based */
+               return port + intel_base_nid(codec) - 1;
+       }
+
+       if (port < 1 || port > spec->port_num)
+               return 0;
+       return spec->port_map[port - 1];
+}
+
 static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
 {
        struct hda_codec *codec = audio_ptr;
        int pin_nid;
        int dev_id = pipe;
 
-       /* we assume only from port-B to port-D */
-       if (port < 1 || port > 3)
+       pin_nid = intel_port2pin(codec, port);
+       if (!pin_nid)
                return;
-
-       pin_nid = port + intel_base_nid(codec) - 1; /* intel port is 1-based */
-
        /* skip notification during system suspend (but not in runtime PM);
         * the state will be updated at resume
         */
@@ -2565,6 +2581,8 @@ static void register_i915_notifier(struct hda_codec *codec)
        spec->drm_audio_ops.pin_eld_notify = intel_pin_eld_notify;
        snd_hdac_acomp_register_notifier(&codec->bus->core,
                                        &spec->drm_audio_ops);
+       /* no need for forcible resume for jack check thanks to notifier */
+       codec->relaxed_resume = 1;
 }
 
 /* setup_stream ops override for HSW+ */
index 5b3c269..de224cb 100644 (file)
@@ -2448,9 +2448,10 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x96e1, "System76 Oryx Pro (oryp5)", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x97e1, "System76 Oryx Pro (oryp5)", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x65d1, "Tuxedo Book XC1509", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
@@ -3254,6 +3255,7 @@ static void alc256_init(struct hda_codec *codec)
        alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
        alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */
        alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15);
+       alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
 }
 
 static void alc256_shutup(struct hda_codec *codec)
@@ -7074,6 +7076,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+       SND_PCI_QUIRK(0x17aa, 0x3111, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
        SND_PCI_QUIRK(0x17aa, 0x312a, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
        SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
        SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
@@ -7654,9 +7657,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x12, 0x90a60130},
                {0x17, 0x90170110},
                {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
                {0x14, 0x90170110},
                {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+               {0x14, 0x90170110},
+               {0x21, 0x04211030}),
        SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC295_STANDARD_PINS,
                {0x17, 0x21014020},
@@ -7823,7 +7829,6 @@ static int patch_alc269(struct hda_codec *codec)
                spec->shutup = alc256_shutup;
                spec->init_hook = alc256_init;
                spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
-               alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
                break;
        case 0x10ec0257:
                spec->codec_variant = ALC269_TYPE_ALC257;
@@ -8798,6 +8803,11 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
                {0x18, 0x01a19030},
                {0x1a, 0x01813040},
                {0x21, 0x01014020}),
+       SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+               {0x16, 0x01813030},
+               {0x17, 0x02211010},
+               {0x18, 0x01a19040},
+               {0x21, 0x01014020}),
        SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
                {0x14, 0x01014010},
                {0x18, 0x01a19020},
index 1771a6d..583ca73 100644 (file)
@@ -253,9 +253,8 @@ exit:
 
 static int lx_pcm_close(struct snd_pcm_substream *substream)
 {
-       int err = 0;
        dev_dbg(substream->pcm->card->dev, "->lx_pcm_close\n");
-       return err;
+       return 0;
 }
 
 static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
index 9236a1a..dd3a873 100644 (file)
@@ -986,8 +986,6 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
         * Stat[8]      LSB overrun
         * */
 
-       u64 orun_mask;
-       u64 urun_mask;
        int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0;
        int eb_pending_in  = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0;
 
@@ -1010,9 +1008,6 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
                            *r_notified_out_pipe_mask);
        }
 
-       orun_mask = ((u64)stat[7] << 32) + stat[8];
-       urun_mask = ((u64)stat[5] << 32) + stat[6];
-
        /* todo: handle xrun notification */
 
        return err;
index 6f5eaa5..81a6f4b 100644 (file)
@@ -23,6 +23,9 @@
  *      Modified 2011-01-14 added S/PDIF input on RayDATs by Adrian Knoth
  *
  *     Modified 2011-01-25 variable period sizes on RayDAT/AIO by Adrian Knoth
+ *
+ *      Modified 2019-05-23 fix AIO single speed ADAT capture and playback
+ *      by Philippe.Bekaert@uhasselt.be
  */
 
 /* *************    Register Documentation   *******************************************************
@@ -1091,9 +1094,9 @@ static int hdspm_autosync_ref(struct hdspm *hdspm);
 static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out);
 static int snd_hdspm_set_defaults(struct hdspm *hdspm);
 static int hdspm_system_clock_mode(struct hdspm *hdspm);
-static void hdspm_set_sgbuf(struct hdspm *hdspm,
-                           struct snd_pcm_substream *substream,
-                            unsigned int reg, int channels);
+static void hdspm_set_channel_dma_addr(struct hdspm *hdspm,
+                                      struct snd_pcm_substream *substream,
+                                      unsigned int reg, int channels);
 
 static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx);
 static int hdspm_wc_sync_check(struct hdspm *hdspm);
@@ -5574,11 +5577,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 
-               hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferOut,
-                               params_channels(params));
+               for (i = 0; i < params_channels(params); ++i) {
+                       int c = hdspm->channel_map_out[i];
 
-               for (i = 0; i < params_channels(params); ++i)
-                       snd_hdspm_enable_out(hdspm, i, 1);
+                       if (c < 0)
+                               continue;      /* just make sure */
+                       hdspm_set_channel_dma_addr(hdspm, substream,
+                                                  HDSPM_pageAddressBufferOut,
+                                                  c);
+                       snd_hdspm_enable_out(hdspm, c, 1);
+               }
 
                hdspm->playback_buffer =
                        (unsigned char *) substream->runtime->dma_area;
@@ -5586,11 +5594,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
                        "Allocated sample buffer for playback at %p\n",
                                hdspm->playback_buffer);
        } else {
-               hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn,
-                               params_channels(params));
-
-               for (i = 0; i < params_channels(params); ++i)
-                       snd_hdspm_enable_in(hdspm, i, 1);
+               for (i = 0; i < params_channels(params); ++i) {
+                       int c = hdspm->channel_map_in[i];
+
+                       if (c < 0)
+                               continue;
+                       hdspm_set_channel_dma_addr(hdspm, substream,
+                                                  HDSPM_pageAddressBufferIn,
+                                                  c);
+                       snd_hdspm_enable_in(hdspm, c, 1);
+               }
 
                hdspm->capture_buffer =
                        (unsigned char *) substream->runtime->dma_area;
@@ -5651,19 +5664,17 @@ static int snd_hdspm_hw_free(struct snd_pcm_substream *substream)
        struct hdspm *hdspm = snd_pcm_substream_chip(substream);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-
-               /* params_channels(params) should be enough,
-                  but to get sure in case of error */
-               for (i = 0; i < hdspm->max_channels_out; ++i)
+               /* Just disable all channels. The saving when disabling a */
+               /* smaller set is not worth the trouble. */
+               for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
                        snd_hdspm_enable_out(hdspm, i, 0);
 
                hdspm->playback_buffer = NULL;
        } else {
-               for (i = 0; i < hdspm->max_channels_in; ++i)
+               for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
                        snd_hdspm_enable_in(hdspm, i, 0);
 
                hdspm->capture_buffer = NULL;
-
        }
 
        snd_pcm_lib_free_pages(substream);
@@ -6402,17 +6413,17 @@ static int snd_hdspm_preallocate_memory(struct hdspm *hdspm)
        return 0;
 }
 
-
-static void hdspm_set_sgbuf(struct hdspm *hdspm,
-                           struct snd_pcm_substream *substream,
-                            unsigned int reg, int channels)
+/* Inform the card what DMA addresses to use for the indicated channel. */
+/* Each channel got 16 4K pages allocated for DMA transfers. */
+static void hdspm_set_channel_dma_addr(struct hdspm *hdspm,
+                                      struct snd_pcm_substream *substream,
+                                      unsigned int reg, int channel)
 {
        int i;
 
-       /* continuous memory segment */
-       for (i = 0; i < (channels * 16); i++)
+       for (i = channel * 16; i < channel * 16 + 16; i++)
                hdspm_write(hdspm, reg + 4 * i,
-                               snd_pcm_sgbuf_get_addr(substream, 4096 * i));
+                           snd_pcm_sgbuf_get_addr(substream, 4096 * i));
 }
 
 
index cb9818a..4c851f8 100644 (file)
@@ -2158,13 +2158,12 @@ static int snd_rme9652_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
        unsigned long flags;
-       int result = 0;
 
        spin_lock_irqsave(&rme9652->lock, flags);
        if (!rme9652->running)
                rme9652_reset_hw_pointer(rme9652);
        spin_unlock_irqrestore(&rme9652->lock, flags);
-       return result;
+       return 0;
 }
 
 static const struct snd_pcm_hardware snd_rme9652_playback_subinfo =
index 71b7fd3..c213eb7 100644 (file)
@@ -628,7 +628,6 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
                               int cmd)
 {
        struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
-       int ret = 0;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -665,7 +664,7 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
 
        }
 
-       return ret;
+       return 0;
 };
 
 /*
index 9615e78..80dab5d 100644 (file)
@@ -240,10 +240,8 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
        }
 
        /* For DSP_*, LRCLK's polarity must be inverted */
-       if (fmt & SND_SOC_DAIFMT_DSP_A) {
-               change_bit(ffs(AD193X_DAC_LEFT_HIGH) - 1,
-                          (unsigned long *)&dac_fmt);
-       }
+       if (fmt & SND_SOC_DAIFMT_DSP_A)
+               dac_fmt ^= AD193X_DAC_LEFT_HIGH;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
index 47eee18..2991895 100644 (file)
@@ -539,6 +539,29 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
 }
 
 /*
+ * Go through all converters and ensure connection is set to
+ * the correct pin as set via kcontrols.
+ */
+static void hdac_hdmi_verify_connect_sel_all_pins(struct hdac_device *hdev)
+{
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+       struct hdac_hdmi_port *port;
+       struct hdac_hdmi_cvt *cvt;
+       int cvt_idx = 0;
+
+       list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+               port = hdac_hdmi_get_port_from_cvt(hdev, hdmi, cvt);
+               if (port && port->pin) {
+                       snd_hdac_codec_write(hdev, port->pin->nid, 0,
+                                            AC_VERB_SET_CONNECT_SEL, cvt_idx);
+                       dev_dbg(&hdev->dev, "%s: %s set connect %d -> %d\n",
+                               __func__, cvt->name, port->pin->nid, cvt_idx);
+               }
+               ++cvt_idx;
+       }
+}
+
+/*
  * This tries to get a valid pin and set the HW constraints based on the
  * ELD. Even if a valid pin is not found return success so that device open
  * doesn't fail.
@@ -798,6 +821,14 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
                                AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag);
                snd_hdac_codec_write(hdev, cvt->nid, 0,
                                AC_VERB_SET_STREAM_FORMAT, pcm->format);
+
+               /*
+                * The connection indices are shared by all converters and
+                * may interfere with each other. Ensure correct
+                * routing for all converters at stream start.
+                */
+               hdac_hdmi_verify_connect_sel_all_pins(hdev);
+
                break;
 
        case SND_SOC_DAPM_POST_PMD:
@@ -2041,7 +2072,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
                        "Failed in parse and map nid with err: %d\n", ret);
                return ret;
        }
-       snd_hdac_refresh_widgets(hdev, true);
+       snd_hdac_refresh_widgets(hdev);
 
        /* ASoC specific initialization */
        ret = devm_snd_soc_register_component(&hdev->dev, &hdmi_hda_codec,
index e5dd05c..9f5aee7 100644 (file)
@@ -1880,6 +1880,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
                NAU8825_JACK_EJECT_DEBOUNCE_MASK,
                nau8825->jack_eject_debounce << NAU8825_JACK_EJECT_DEBOUNCE_SFT);
 
+       /* Pull up IRQ pin */
+       regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+               NAU8825_IRQ_PIN_PULLUP | NAU8825_IRQ_PIN_PULL_EN,
+               NAU8825_IRQ_PIN_PULLUP | NAU8825_IRQ_PIN_PULL_EN);
        /* Mask unneeded IRQs: 1 - disable, 0 - enable */
        regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, 0x7ff, 0x7ff);
 
index 5e60696..887bbff 100644 (file)
 #define NAU8825_JACK_POLARITY  (1 << 1) /* 0 - active low, 1 - active high */
 
 /* INTERRUPT_MASK (0xf) */
+#define NAU8825_IRQ_PIN_PULLUP (1 << 14)
+#define NAU8825_IRQ_PIN_PULL_EN (1 << 13)
 #define NAU8825_IRQ_OUTPUT_EN (1 << 11)
 #define NAU8825_IRQ_HEADSET_COMPLETE_EN (1 << 10)
 #define NAU8825_IRQ_RMS_EN (1 << 8)
index ebf2ca3..288df24 100644 (file)
@@ -423,9 +423,6 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
                        codec_ep = of_graph_get_remote_endpoint(cpu_ep);
                        codec_port = of_get_parent(codec_ep);
 
-                       of_node_put(codec_ep);
-                       of_node_put(codec_port);
-
                        /* get convert-xxx property */
                        memset(&adata, 0, sizeof(adata));
                        graph_parse_convert(dev, codec_ep, &adata);
@@ -445,6 +442,9 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
                        else
                                ret = func_noml(priv, cpu_ep, codec_ep, li);
 
+                       of_node_put(codec_ep);
+                       of_node_put(codec_port);
+
                        if (ret < 0)
                                return ret;
 
index 64db003..daeaa39 100644 (file)
@@ -551,7 +551,7 @@ static int sof_audio_probe(struct platform_device *pdev)
        int dmic_be_num, hdmi_num;
        int ret, ssp_amp, ssp_codec;
 
-       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
index 7e093fb..3362e71 100644 (file)
@@ -184,6 +184,25 @@ void skl_update_d0i3c(struct device *dev, bool enable)
                        snd_hdac_chip_readb(bus, VS_D0I3C));
 }
 
+/**
+ * skl_dum_set - set DUM bit in EM2 register
+ * @bus: HD-audio core bus
+ *
+ * Addresses incorrect position reporting for capture streams.
+ * Used on device power up.
+ */
+static void skl_dum_set(struct hdac_bus *bus)
+{
+       /* For the DUM bit to be set, CRST needs to be out of reset state */
+       if (!(snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)) {
+               skl_enable_miscbdcge(bus->dev, false);
+               snd_hdac_bus_exit_link_reset(bus);
+               skl_enable_miscbdcge(bus->dev, true);
+       }
+
+       snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM);
+}
+
 /* called from IRQ */
 static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
 {
@@ -291,6 +310,7 @@ static int _skl_resume(struct hdac_bus *bus)
        struct skl *skl = bus_to_skl(bus);
 
        skl_init_pci(skl);
+       skl_dum_set(bus);
        skl_init_chip(bus, true);
 
        return skl_resume_dsp(skl);
@@ -950,6 +970,7 @@ static int skl_first_init(struct hdac_bus *bus)
 
        /* initialize chip */
        skl_init_pci(skl);
+       skl_dum_set(bus);
 
        return skl_init_chip(bus, true);
 }
index 6fab1a2..6070666 100644 (file)
@@ -37,6 +37,7 @@
 #define DMA_TRANSMITION_START  2
 #define DMA_TRANSMITION_STOP   3
 
+#define AZX_VS_EM2_DUM                 BIT(23)
 #define AZX_REG_VS_EM2_L1SEN           BIT(13)
 
 struct skl_dsp_resource {
index e578b6f..5774ce0 100644 (file)
@@ -40,7 +40,7 @@ struct axg_tdm_iface {
 
 static inline bool axg_tdm_lrclk_invert(unsigned int fmt)
 {
-       return (fmt & SND_SOC_DAIFMT_I2S) ^
+       return ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) ^
                !!(fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_NB_IF));
 }
 
index a790f92..cb87f17 100644 (file)
@@ -121,7 +121,6 @@ static int axg_tdmin_prepare(struct regmap *map,
                break;
 
        case SND_SOC_DAIFMT_LEFT_J:
-       case SND_SOC_DAIFMT_RIGHT_J:
        case SND_SOC_DAIFMT_DSP_B:
                break;
 
index 527bfc4..86537fc 100644 (file)
@@ -137,7 +137,6 @@ static int axg_tdmout_prepare(struct regmap *map,
                break;
 
        case SND_SOC_DAIFMT_LEFT_J:
-       case SND_SOC_DAIFMT_RIGHT_J:
        case SND_SOC_DAIFMT_DSP_B:
                skew += 1;
                break;
index 97488b5..2c7348d 100644 (file)
@@ -116,6 +116,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
                        goto err;
                }
 
+               link->nonatomic = 1;
                link->dpcm_playback = 1;
                link->dpcm_capture = 1;
                link->stream_name = link->name;
index 1486fb2..44f899b 100644 (file)
@@ -165,9 +165,10 @@ static void soc_init_component_debugfs(struct snd_soc_component *component)
                                component->card->debugfs_card_root);
        }
 
-       if (!component->debugfs_root) {
+       if (IS_ERR(component->debugfs_root)) {
                dev_warn(component->dev,
-                       "ASoC: Failed to create component debugfs directory\n");
+                       "ASoC: Failed to create component debugfs directory: %ld\n",
+                       PTR_ERR(component->debugfs_root));
                return;
        }
 
@@ -219,18 +220,21 @@ static void soc_init_card_debugfs(struct snd_soc_card *card)
 
        card->debugfs_card_root = debugfs_create_dir(card->name,
                                                     snd_soc_debugfs_root);
-       if (!card->debugfs_card_root) {
+       if (IS_ERR(card->debugfs_card_root)) {
                dev_warn(card->dev,
-                        "ASoC: Failed to create card debugfs directory\n");
+                        "ASoC: Failed to create card debugfs directory: %ld\n",
+                        PTR_ERR(card->debugfs_card_root));
+               card->debugfs_card_root = NULL;
                return;
        }
 
        card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644,
                                                    card->debugfs_card_root,
                                                    &card->pop_time);
-       if (!card->debugfs_pop_time)
+       if (IS_ERR(card->debugfs_pop_time))
                dev_warn(card->dev,
-                        "ASoC: Failed to create pop time debugfs file\n");
+                        "ASoC: Failed to create pop time debugfs file: %ld\n",
+                        PTR_ERR(card->debugfs_pop_time));
 }
 
 static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
@@ -2748,14 +2752,12 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
                snd_soc_dapm_shutdown(card);
                snd_soc_flush_all_delayed_work(card);
 
-               mutex_lock(&client_mutex);
                /* remove all components used by DAI links on this card */
                for_each_comp_order(order) {
                        for_each_card_rtds(card, rtd) {
                                soc_remove_link_components(card, rtd, order);
                        }
                }
-               mutex_unlock(&client_mutex);
 
                soc_cleanup_card_resources(card);
                if (!unregister)
@@ -2774,7 +2776,9 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
  */
 int snd_soc_unregister_card(struct snd_soc_card *card)
 {
+       mutex_lock(&client_mutex);
        snd_soc_unbind_card(card, true);
+       mutex_unlock(&client_mutex);
        dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
 
        return 0;
index 656cb5c..2790c00 100644 (file)
@@ -2156,23 +2156,25 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
 {
        struct dentry *d;
 
-       if (!parent)
+       if (!parent || IS_ERR(parent))
                return;
 
        dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
 
-       if (!dapm->debugfs_dapm) {
+       if (IS_ERR(dapm->debugfs_dapm)) {
                dev_warn(dapm->dev,
-                      "ASoC: Failed to create DAPM debugfs directory\n");
+                        "ASoC: Failed to create DAPM debugfs directory %ld\n",
+                        PTR_ERR(dapm->debugfs_dapm));
                return;
        }
 
        d = debugfs_create_file("bias_level", 0444,
                                dapm->debugfs_dapm, dapm,
                                &dapm_bias_fops);
-       if (!d)
+       if (IS_ERR(d))
                dev_warn(dapm->dev,
-                        "ASoC: Failed to create bias level debugfs file\n");
+                        "ASoC: Failed to create bias level debugfs file: %ld\n",
+                        PTR_ERR(d));
 }
 
 static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
@@ -2186,10 +2188,10 @@ static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
        d = debugfs_create_file(w->name, 0444,
                                dapm->debugfs_dapm, w,
                                &dapm_widget_power_fops);
-       if (!d)
+       if (IS_ERR(d))
                dev_warn(w->dapm->dev,
-                       "ASoC: Failed to create %s debugfs file\n",
-                       w->name);
+                        "ASoC: Failed to create %s debugfs file: %ld\n",
+                        w->name, PTR_ERR(d));
 }
 
 static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
index 136f98b..7f66539 100644 (file)
@@ -34,6 +34,9 @@
 /* platform specific devices */
 #include "shim.h"
 
+#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348)
+#define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8)
+
 /*
  * Debug
  */
@@ -245,6 +248,11 @@ static int hda_init(struct snd_sof_dev *sdev)
        ext_ops = snd_soc_hdac_hda_get_ops();
 #endif
        sof_hda_bus_init(bus, &pci->dev, ext_ops);
+
+       /* Workaround for a communication error on CFL (bko#199007) and CNL */
+       if (IS_CFL(pci) || IS_CNL(pci))
+               bus->polling_mode = 1;
+
        bus->use_posbuf = 1;
        bus->bdl_pos_adj = 0;
 
index 44708c8..bc7bf15 100644 (file)
@@ -2297,7 +2297,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                ret = edma_pcm_platform_register(&pdev->dev);
                break;
        case PCM_SDMA:
-               ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
+               ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
                break;
        default:
                dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
index 1ab3c7d..26b503b 100644 (file)
@@ -1424,7 +1424,7 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       return sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
+       return sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
 }
 
 static int asoc_mcbsp_remove(struct platform_device *pdev)
index c02b51a..d79db71 100644 (file)
@@ -285,6 +285,33 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
        return nr_rates;
 }
 
+/* Line6 Helix series don't support the UAC2_CS_RANGE usb function
+ * call. Return a static table of known clock rates.
+ */
+static int line6_parse_audio_format_rates_quirk(struct snd_usb_audio *chip,
+                                               struct audioformat *fp)
+{
+       switch (chip->usb_id) {
+       case USB_ID(0x0E41, 0x4241): /* Line6 Helix */
+       case USB_ID(0x0E41, 0x4242): /* Line6 Helix Rack */
+       case USB_ID(0x0E41, 0x4244): /* Line6 Helix LT */
+       case USB_ID(0x0E41, 0x4246): /* Line6 HX-Stomp */
+               /* supported rates: 48Khz */
+               kfree(fp->rate_table);
+               fp->rate_table = kmalloc(sizeof(int), GFP_KERNEL);
+               if (!fp->rate_table)
+                       return -ENOMEM;
+               fp->nr_rates = 1;
+               fp->rate_min = 48000;
+               fp->rate_max = 48000;
+               fp->rates = SNDRV_PCM_RATE_48000;
+               fp->rate_table[0] = 48000;
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
 /*
  * parse the format descriptor and stores the possible sample rates
  * on the audioformat table (audio class v2 and v3).
@@ -294,7 +321,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
 {
        struct usb_device *dev = chip->dev;
        unsigned char tmp[2], *data;
-       int nr_triplets, data_size, ret = 0;
+       int nr_triplets, data_size, ret = 0, ret_l6;
        int clock = snd_usb_clock_find_source(chip, fp->protocol,
                                              fp->clock, false);
 
@@ -313,9 +340,22 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
                              tmp, sizeof(tmp));
 
        if (ret < 0) {
-               dev_err(&dev->dev,
-                       "%s(): unable to retrieve number of sample rates (clock %d)\n",
+               /* line6 helix devices don't support UAC2_CS_CONTROL_SAM_FREQ call */
+               ret_l6 = line6_parse_audio_format_rates_quirk(chip, fp);
+               if (ret_l6 == -ENODEV) {
+                       /* no line6 device found continue showing the error */
+                       dev_err(&dev->dev,
+                               "%s(): unable to retrieve number of sample rates (clock %d)\n",
+                               __func__, clock);
+                       goto err;
+               }
+               if (ret_l6 == 0) {
+                       dev_info(&dev->dev,
+                               "%s(): unable to retrieve number of sample rates: set it to a predefined value (clock %d).\n",
                                __func__, clock);
+                       return 0;
+               }
+               ret = ret_l6;
                goto err;
        }
 
index 84aa265..4c12cc5 100644 (file)
@@ -63,6 +63,20 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype
        return NULL;
 }
 
+/* check the validity of pipe and EP types */
+int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe)
+{
+       static const int pipetypes[4] = {
+               PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+       };
+       struct usb_host_endpoint *ep;
+
+       ep = usb_pipe_endpoint(dev, pipe);
+       if (!ep || usb_pipetype(pipe) != pipetypes[usb_endpoint_type(&ep->desc)])
+               return -EINVAL;
+       return 0;
+}
+
 /*
  * Wrapper for usb_control_msg().
  * Allocates a temp buffer to prevent dmaing from/to the stack.
@@ -75,6 +89,9 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
        void *buf = NULL;
        int timeout;
 
+       if (snd_usb_pipe_sanity_check(dev, pipe))
+               return -EINVAL;
+
        if (size > 0) {
                buf = kmemdup(data, size, GFP_KERNEL);
                if (!buf)
index d338bd0..6afb701 100644 (file)
@@ -7,6 +7,7 @@ unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size);
 void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype);
 void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype);
 
+int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe);
 int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe,
                    __u8 request, __u8 requesttype, __u16 value, __u16 index,
                    void *data, __u16 size);
index e63a245..ab2ec89 100644 (file)
@@ -192,17 +192,6 @@ static int line6_send_raw_message_async_part(struct message *msg,
 }
 
 /*
-       Setup and start timer.
-*/
-void line6_start_timer(struct timer_list *timer, unsigned long msecs,
-                      void (*function)(struct timer_list *t))
-{
-       timer->function = function;
-       mod_timer(timer, jiffies + msecs_to_jiffies(msecs));
-}
-EXPORT_SYMBOL_GPL(line6_start_timer);
-
-/*
        Asynchronously send raw message.
 */
 int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
index a9f7b4a..e5e572e 100644 (file)
 
 #define LINE6_CHANNEL_MASK 0x0f
 
-#define CHECK_STARTUP_PROGRESS(x, n)   \
-do {                                   \
-       if ((x) >= (n))                 \
-               return;                 \
-       x = (n);                        \
-} while (0)
-
 extern const unsigned char line6_midi_id[3];
 
 static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
@@ -197,8 +190,6 @@ extern int line6_send_sysex_message(struct usb_line6 *line6,
                                    const char *buffer, int size);
 extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count);
-extern void line6_start_timer(struct timer_list *timer, unsigned long msecs,
-                             void (*function)(struct timer_list *t));
 extern int line6_version_request_async(struct usb_line6 *line6);
 extern int line6_write_data(struct usb_line6 *line6, unsigned address,
                            void *data, unsigned datalen);
index 21127e4..2c03e0f 100644 (file)
@@ -556,6 +556,11 @@ int line6_init_pcm(struct usb_line6 *line6,
        line6pcm->max_packet_size_out =
                usb_maxpacket(line6->usbdev,
                        usb_sndisocpipe(line6->usbdev, ep_write), 1);
+       if (!line6pcm->max_packet_size_in || !line6pcm->max_packet_size_out) {
+               dev_err(line6pcm->line6->ifcdev,
+                       "cannot get proper max packet size\n");
+               return -EINVAL;
+       }
 
        spin_lock_init(&line6pcm->out.lock);
        spin_lock_init(&line6pcm->in.lock);
index 200ae53..ee4c9d2 100644 (file)
        Stages of POD startup procedure
 */
 enum {
-       POD_STARTUP_INIT = 1,
        POD_STARTUP_VERSIONREQ,
-       POD_STARTUP_WORKQUEUE,
        POD_STARTUP_SETUP,
-       POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
+       POD_STARTUP_DONE,
 };
 
 enum {
@@ -59,12 +57,6 @@ struct usb_line6_pod {
        /* Instrument monitor level */
        int monitor_level;
 
-       /* Timer for device initialization */
-       struct timer_list startup_timer;
-
-       /* Work handler for device initialization */
-       struct work_struct startup_work;
-
        /* Current progress in startup procedure */
        int startup_progress;
 
@@ -78,6 +70,8 @@ struct usb_line6_pod {
        int device_id;
 };
 
+#define line6_to_pod(x)                container_of(x, struct usb_line6_pod, line6)
+
 #define POD_SYSEX_CODE 3
 
 /* *INDENT-OFF* */
@@ -169,10 +163,6 @@ static const char pod_version_header[] = {
        0xf2, 0x7e, 0x7f, 0x06, 0x02
 };
 
-/* forward declarations: */
-static void pod_startup2(struct timer_list *t);
-static void pod_startup3(struct usb_line6_pod *pod);
-
 static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
                                    int size)
 {
@@ -185,14 +175,17 @@ static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
 */
 static void line6_pod_process_message(struct usb_line6 *line6)
 {
-       struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+       struct usb_line6_pod *pod = line6_to_pod(line6);
        const unsigned char *buf = pod->line6.buffer_message;
 
        if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
                pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
                pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
                                 (int) buf[10];
-               pod_startup3(pod);
+               if (pod->startup_progress == POD_STARTUP_VERSIONREQ) {
+                       pod->startup_progress = POD_STARTUP_SETUP;
+                       schedule_delayed_work(&line6->startup_work, 0);
+               }
                return;
        }
 
@@ -277,47 +270,27 @@ static ssize_t device_id_show(struct device *dev,
        context). After the last one has finished, the device is ready to use.
 */
 
-static void pod_startup1(struct usb_line6_pod *pod)
-{
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
-
-       /* delay startup procedure: */
-       line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2);
-}
-
-static void pod_startup2(struct timer_list *t)
-{
-       struct usb_line6_pod *pod = from_timer(pod, t, startup_timer);
-       struct usb_line6 *line6 = &pod->line6;
-
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
-
-       /* request firmware version: */
-       line6_version_request_async(line6);
-}
-
-static void pod_startup3(struct usb_line6_pod *pod)
-{
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
-
-       /* schedule work for global work queue: */
-       schedule_work(&pod->startup_work);
-}
-
-static void pod_startup4(struct work_struct *work)
+static void pod_startup(struct usb_line6 *line6)
 {
-       struct usb_line6_pod *pod =
-           container_of(work, struct usb_line6_pod, startup_work);
-       struct usb_line6 *line6 = &pod->line6;
-
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
-
-       /* serial number: */
-       line6_read_serial_number(&pod->line6, &pod->serial_number);
-
-       /* ALSA audio interface: */
-       if (snd_card_register(line6->card))
-               dev_err(line6->ifcdev, "Failed to register POD card.\n");
+       struct usb_line6_pod *pod = line6_to_pod(line6);
+
+       switch (pod->startup_progress) {
+       case POD_STARTUP_VERSIONREQ:
+               /* request firmware version: */
+               line6_version_request_async(line6);
+               break;
+       case POD_STARTUP_SETUP:
+               /* serial number: */
+               line6_read_serial_number(&pod->line6, &pod->serial_number);
+
+               /* ALSA audio interface: */
+               if (snd_card_register(line6->card))
+                       dev_err(line6->ifcdev, "Failed to register POD card.\n");
+               pod->startup_progress = POD_STARTUP_DONE;
+               break;
+       default:
+               break;
+       }
 }
 
 /* POD special files: */
@@ -353,7 +326,7 @@ static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+       struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6);
 
        ucontrol->value.integer.value[0] = pod->monitor_level;
        return 0;
@@ -364,7 +337,7 @@ static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+       struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6);
 
        if (ucontrol->value.integer.value[0] == pod->monitor_level)
                return 0;
@@ -387,30 +360,16 @@ static const struct snd_kcontrol_new pod_control_monitor = {
 };
 
 /*
-       POD device disconnected.
-*/
-static void line6_pod_disconnect(struct usb_line6 *line6)
-{
-       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6;
-
-       del_timer_sync(&pod->startup_timer);
-       cancel_work_sync(&pod->startup_work);
-}
-
-/*
         Try to init POD device.
 */
 static int pod_init(struct usb_line6 *line6,
                    const struct usb_device_id *id)
 {
        int err;
-       struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+       struct usb_line6_pod *pod = line6_to_pod(line6);
 
        line6->process_message = line6_pod_process_message;
-       line6->disconnect = line6_pod_disconnect;
-
-       timer_setup(&pod->startup_timer, NULL, 0);
-       INIT_WORK(&pod->startup_work, pod_startup4);
+       line6->startup = pod_startup;
 
        /* create sysfs entries: */
        err = snd_card_add_dev_attr(line6->card, &pod_dev_attr_group);
@@ -443,7 +402,8 @@ static int pod_init(struct usb_line6 *line6,
                pod->monitor_level = POD_SYSTEM_INVALID;
 
                /* initiate startup procedure: */
-               pod_startup1(pod);
+               schedule_delayed_work(&line6->startup_work,
+                                     msecs_to_jiffies(POD_STARTUP_DELAY));
        }
 
        return 0;
index 77a1d55..27bf61c 100644 (file)
 
 #define PODHD_STARTUP_DELAY 500
 
-/*
- * Stages of POD startup procedure
- */
-enum {
-       PODHD_STARTUP_INIT = 1,
-       PODHD_STARTUP_SCHEDULE_WORKQUEUE,
-       PODHD_STARTUP_SETUP,
-       PODHD_STARTUP_LAST = PODHD_STARTUP_SETUP - 1
-};
-
 enum {
        LINE6_PODHD300,
        LINE6_PODHD400,
@@ -43,15 +33,6 @@ struct usb_line6_podhd {
        /* Generic Line 6 USB data */
        struct usb_line6 line6;
 
-       /* Timer for device initialization */
-       struct timer_list startup_timer;
-
-       /* Work handler for device initialization */
-       struct work_struct startup_work;
-
-       /* Current progress in startup procedure */
-       int startup_progress;
-
        /* Serial number of device */
        u32 serial_number;
 
@@ -59,6 +40,8 @@ struct usb_line6_podhd {
        int firmware_version;
 };
 
+#define line6_to_podhd(x)      container_of(x, struct usb_line6_podhd, line6)
+
 static struct snd_ratden podhd_ratden = {
        .num_min = 48000,
        .num_max = 48000,
@@ -154,10 +137,6 @@ static struct line6_pcm_properties podx3_pcm_properties = {
 };
 static struct usb_driver podhd_driver;
 
-static void podhd_startup_start_workqueue(struct timer_list *t);
-static void podhd_startup_workqueue(struct work_struct *work);
-static int podhd_startup_finalize(struct usb_line6_podhd *pod);
-
 static ssize_t serial_number_show(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
@@ -198,26 +177,6 @@ static const struct attribute_group podhd_dev_attr_group = {
  * audio nor bulk interfaces to work.
  */
 
-static void podhd_startup(struct usb_line6_podhd *pod)
-{
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, PODHD_STARTUP_INIT);
-
-       /* delay startup procedure: */
-       line6_start_timer(&pod->startup_timer, PODHD_STARTUP_DELAY,
-               podhd_startup_start_workqueue);
-}
-
-static void podhd_startup_start_workqueue(struct timer_list *t)
-{
-       struct usb_line6_podhd *pod = from_timer(pod, t, startup_timer);
-
-       CHECK_STARTUP_PROGRESS(pod->startup_progress,
-               PODHD_STARTUP_SCHEDULE_WORKQUEUE);
-
-       /* schedule work for global work queue: */
-       schedule_work(&pod->startup_work);
-}
-
 static int podhd_dev_start(struct usb_line6_podhd *pod)
 {
        int ret;
@@ -268,37 +227,23 @@ exit:
        return ret;
 }
 
-static void podhd_startup_workqueue(struct work_struct *work)
+static void podhd_startup(struct usb_line6 *line6)
 {
-       struct usb_line6_podhd *pod =
-           container_of(work, struct usb_line6_podhd, startup_work);
-
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, PODHD_STARTUP_SETUP);
+       struct usb_line6_podhd *pod = line6_to_podhd(line6);
 
        podhd_dev_start(pod);
        line6_read_serial_number(&pod->line6, &pod->serial_number);
-
-       podhd_startup_finalize(pod);
-}
-
-static int podhd_startup_finalize(struct usb_line6_podhd *pod)
-{
-       struct usb_line6 *line6 = &pod->line6;
-
-       /* ALSA audio interface: */
-       return snd_card_register(line6->card);
+       if (snd_card_register(line6->card))
+               dev_err(line6->ifcdev, "Failed to register POD HD card.\n");
 }
 
 static void podhd_disconnect(struct usb_line6 *line6)
 {
-       struct usb_line6_podhd *pod = (struct usb_line6_podhd *)line6;
+       struct usb_line6_podhd *pod = line6_to_podhd(line6);
 
        if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
                struct usb_interface *intf;
 
-               del_timer_sync(&pod->startup_timer);
-               cancel_work_sync(&pod->startup_work);
-
                intf = usb_ifnum_to_if(line6->usbdev,
                                        pod->line6.properties->ctrl_if);
                if (intf)
@@ -313,13 +258,11 @@ static int podhd_init(struct usb_line6 *line6,
                      const struct usb_device_id *id)
 {
        int err;
-       struct usb_line6_podhd *pod = (struct usb_line6_podhd *) line6;
+       struct usb_line6_podhd *pod = line6_to_podhd(line6);
        struct usb_interface *intf;
 
        line6->disconnect = podhd_disconnect;
-
-       timer_setup(&pod->startup_timer, NULL, 0);
-       INIT_WORK(&pod->startup_work, podhd_startup_workqueue);
+       line6->startup = podhd_startup;
 
        if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
                /* claim the data interface */
@@ -358,11 +301,12 @@ static int podhd_init(struct usb_line6 *line6,
 
        if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) {
                /* register USB audio system directly */
-               return podhd_startup_finalize(pod);
+               return snd_card_register(line6->card);
        }
 
        /* init device and delay registering */
-       podhd_startup(pod);
+       schedule_delayed_work(&line6->startup_work,
+                             msecs_to_jiffies(PODHD_STARTUP_DELAY));
        return 0;
 }
 
@@ -424,7 +368,7 @@ static const struct line6_properties podhd_properties_table[] = {
                .name = "POD HD500",
                .capabilities   = LINE6_CAP_PCM
                                | LINE6_CAP_HWMON,
-               .altsetting = 1,
+               .altsetting = 0,
                .ep_ctrl_r = 0x81,
                .ep_ctrl_w = 0x01,
                .ep_audio_r = 0x86,
index 974ab3e..d0a555d 100644 (file)
@@ -57,6 +57,8 @@ struct usb_line6_toneport {
        struct toneport_led leds[2];
 };
 
+#define line6_to_toneport(x) container_of(x, struct usb_line6_toneport, line6)
+
 static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
 
 #define TONEPORT_PCM_DELAY 1
@@ -207,8 +209,8 @@ static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_toneport *toneport =
-           (struct usb_line6_toneport *)line6pcm->line6;
+       struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);
+
        ucontrol->value.enumerated.item[0] = toneport->source;
        return 0;
 }
@@ -218,8 +220,7 @@ static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_toneport *toneport =
-           (struct usb_line6_toneport *)line6pcm->line6;
+       struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);
        unsigned int source;
 
        source = ucontrol->value.enumerated.item[0];
@@ -393,8 +394,7 @@ static int toneport_setup(struct usb_line6_toneport *toneport)
 */
 static void line6_toneport_disconnect(struct usb_line6 *line6)
 {
-       struct usb_line6_toneport *toneport =
-               (struct usb_line6_toneport *)line6;
+       struct usb_line6_toneport *toneport = line6_to_toneport(line6);
 
        if (toneport_has_led(toneport))
                toneport_remove_leds(toneport);
@@ -408,7 +408,7 @@ static int toneport_init(struct usb_line6 *line6,
                         const struct usb_device_id *id)
 {
        int err;
-       struct usb_line6_toneport *toneport =  (struct usb_line6_toneport *) line6;
+       struct usb_line6_toneport *toneport = line6_to_toneport(line6);
 
        toneport->type = id->driver_info;
 
index e59b974..ed158f0 100644 (file)
        Stages of Variax startup procedure
 */
 enum {
-       VARIAX_STARTUP_INIT = 1,
        VARIAX_STARTUP_VERSIONREQ,
-       VARIAX_STARTUP_WAIT,
        VARIAX_STARTUP_ACTIVATE,
-       VARIAX_STARTUP_WORKQUEUE,
        VARIAX_STARTUP_SETUP,
-       VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
 };
 
 enum {
@@ -43,17 +39,12 @@ struct usb_line6_variax {
        /* Buffer for activation code */
        unsigned char *buffer_activate;
 
-       /* Handler for device initialization */
-       struct work_struct startup_work;
-
-       /* Timers for device initialization */
-       struct timer_list startup_timer1;
-       struct timer_list startup_timer2;
-
        /* Current progress in startup procedure */
        int startup_progress;
 };
 
+#define line6_to_variax(x)     container_of(x, struct usb_line6_variax, line6)
+
 #define VARIAX_OFFSET_ACTIVATE 7
 
 /*
@@ -77,11 +68,6 @@ static const char variax_activate[] = {
        0xf7
 };
 
-/* forward declarations: */
-static void variax_startup2(struct timer_list *t);
-static void variax_startup4(struct timer_list *t);
-static void variax_startup5(struct timer_list *t);
-
 static void variax_activate_async(struct usb_line6_variax *variax, int a)
 {
        variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
@@ -96,74 +82,30 @@ static void variax_activate_async(struct usb_line6_variax *variax, int a)
        context). After the last one has finished, the device is ready to use.
 */
 
-static void variax_startup1(struct usb_line6_variax *variax)
-{
-       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
-
-       /* delay startup procedure: */
-       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
-                         variax_startup2);
-}
-
-static void variax_startup2(struct timer_list *t)
-{
-       struct usb_line6_variax *variax = from_timer(variax, t, startup_timer1);
-       struct usb_line6 *line6 = &variax->line6;
-
-       /* schedule another startup procedure until startup is complete: */
-       if (variax->startup_progress >= VARIAX_STARTUP_LAST)
-               return;
-
-       variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
-       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
-                         variax_startup2);
-
-       /* request firmware version: */
-       line6_version_request_async(line6);
-}
-
-static void variax_startup3(struct usb_line6_variax *variax)
-{
-       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
-
-       /* delay startup procedure: */
-       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
-                         variax_startup4);
-}
-
-static void variax_startup4(struct timer_list *t)
+static void variax_startup(struct usb_line6 *line6)
 {
-       struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2);
-
-       CHECK_STARTUP_PROGRESS(variax->startup_progress,
-                              VARIAX_STARTUP_ACTIVATE);
-
-       /* activate device: */
-       variax_activate_async(variax, 1);
-       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
-                         variax_startup5);
-}
-
-static void variax_startup5(struct timer_list *t)
-{
-       struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2);
-
-       CHECK_STARTUP_PROGRESS(variax->startup_progress,
-                              VARIAX_STARTUP_WORKQUEUE);
-
-       /* schedule work for global work queue: */
-       schedule_work(&variax->startup_work);
-}
-
-static void variax_startup6(struct work_struct *work)
-{
-       struct usb_line6_variax *variax =
-           container_of(work, struct usb_line6_variax, startup_work);
-
-       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
-
-       /* ALSA audio interface: */
-       snd_card_register(variax->line6.card);
+       struct usb_line6_variax *variax = line6_to_variax(line6);
+
+       switch (variax->startup_progress) {
+       case VARIAX_STARTUP_VERSIONREQ:
+               /* repeat request until getting the response */
+               schedule_delayed_work(&line6->startup_work,
+                                     msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
+               /* request firmware version: */
+               line6_version_request_async(line6);
+               break;
+       case VARIAX_STARTUP_ACTIVATE:
+               /* activate device: */
+               variax_activate_async(variax, 1);
+               variax->startup_progress = VARIAX_STARTUP_SETUP;
+               schedule_delayed_work(&line6->startup_work,
+                                     msecs_to_jiffies(VARIAX_STARTUP_DELAY4));
+               break;
+       case VARIAX_STARTUP_SETUP:
+               /* ALSA audio interface: */
+               snd_card_register(variax->line6.card);
+               break;
+       }
 }
 
 /*
@@ -171,7 +113,7 @@ static void variax_startup6(struct work_struct *work)
 */
 static void line6_variax_process_message(struct usb_line6 *line6)
 {
-       struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+       struct usb_line6_variax *variax = line6_to_variax(line6);
        const unsigned char *buf = variax->line6.buffer_message;
 
        switch (buf[0]) {
@@ -182,11 +124,19 @@ static void line6_variax_process_message(struct usb_line6 *line6)
        case LINE6_SYSEX_BEGIN:
                if (memcmp(buf + 1, variax_init_version + 1,
                           sizeof(variax_init_version) - 1) == 0) {
-                       variax_startup3(variax);
+                       if (variax->startup_progress >= VARIAX_STARTUP_ACTIVATE)
+                               break;
+                       variax->startup_progress = VARIAX_STARTUP_ACTIVATE;
+                       cancel_delayed_work(&line6->startup_work);
+                       schedule_delayed_work(&line6->startup_work,
+                                             msecs_to_jiffies(VARIAX_STARTUP_DELAY3));
                } else if (memcmp(buf + 1, variax_init_done + 1,
                                  sizeof(variax_init_done) - 1) == 0) {
                        /* notify of complete initialization: */
-                       variax_startup4(&variax->startup_timer2);
+                       if (variax->startup_progress >= VARIAX_STARTUP_SETUP)
+                               break;
+                       cancel_delayed_work(&line6->startup_work);
+                       schedule_delayed_work(&line6->startup_work, 0);
                }
                break;
        }
@@ -197,11 +147,7 @@ static void line6_variax_process_message(struct usb_line6 *line6)
 */
 static void line6_variax_disconnect(struct usb_line6 *line6)
 {
-       struct usb_line6_variax *variax = (struct usb_line6_variax *)line6;
-
-       del_timer(&variax->startup_timer1);
-       del_timer(&variax->startup_timer2);
-       cancel_work_sync(&variax->startup_work);
+       struct usb_line6_variax *variax = line6_to_variax(line6);
 
        kfree(variax->buffer_activate);
 }
@@ -212,15 +158,12 @@ static void line6_variax_disconnect(struct usb_line6 *line6)
 static int variax_init(struct usb_line6 *line6,
                       const struct usb_device_id *id)
 {
-       struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+       struct usb_line6_variax *variax = line6_to_variax(line6);
        int err;
 
        line6->process_message = line6_variax_process_message;
        line6->disconnect = line6_variax_disconnect;
-
-       timer_setup(&variax->startup_timer1, NULL, 0);
-       timer_setup(&variax->startup_timer2, NULL, 0);
-       INIT_WORK(&variax->startup_work, variax_startup6);
+       line6->startup = variax_startup;
 
        /* initialize USB buffers: */
        variax->buffer_activate = kmemdup(variax_activate,
@@ -235,7 +178,8 @@ static int variax_init(struct usb_line6 *line6,
                return err;
 
        /* initiate startup procedure: */
-       variax_startup1(variax);
+       schedule_delayed_work(&line6->startup_work,
+                             msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
        return 0;
 }
 
@@ -300,5 +244,5 @@ static struct usb_driver variax_driver = {
 
 module_usb_driver(variax_driver);
 
-MODULE_DESCRIPTION("Vairax Workbench USB driver");
+MODULE_DESCRIPTION("Variax Workbench USB driver");
 MODULE_LICENSE("GPL");
index c703f85..7498b51 100644 (file)
@@ -2303,7 +2303,7 @@ static struct procunit_info extunits[] = {
  */
 static int build_audio_procunit(struct mixer_build *state, int unitid,
                                void *raw_desc, struct procunit_info *list,
-                               char *name)
+                               bool extension_unit)
 {
        struct uac_processing_unit_descriptor *desc = raw_desc;
        int num_ins;
@@ -2320,6 +2320,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
        static struct procunit_info default_info = {
                0, NULL, default_value_info
        };
+       const char *name = extension_unit ?
+               "Extension Unit" : "Processing Unit";
 
        if (desc->bLength < 13) {
                usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
@@ -2433,7 +2435,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
                } else if (info->name) {
                        strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
                } else {
-                       nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol);
+                       if (extension_unit)
+                               nameid = uac_extension_unit_iExtension(desc, state->mixer->protocol);
+                       else
+                               nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol);
                        len = 0;
                        if (nameid)
                                len = snd_usb_copy_string_desc(state->chip,
@@ -2466,10 +2471,10 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid,
        case UAC_VERSION_2:
        default:
                return build_audio_procunit(state, unitid, raw_desc,
-                               procunits, "Processing Unit");
+                                           procunits, false);
        case UAC_VERSION_3:
                return build_audio_procunit(state, unitid, raw_desc,
-                               uac3_procunits, "Processing Unit");
+                                           uac3_procunits, false);
        }
 }
 
@@ -2480,8 +2485,7 @@ static int parse_audio_extension_unit(struct mixer_build *state, int unitid,
         * Note that we parse extension units with processing unit descriptors.
         * That's ok as the layout is the same.
         */
-       return build_audio_procunit(state, unitid, raw_desc,
-                                   extunits, "Extension Unit");
+       return build_audio_procunit(state, unitid, raw_desc, extunits, true);
 }
 
 /*
index 1f6011f..199fa15 100644 (file)
@@ -741,7 +741,7 @@ static int snd_ni_control_init_val(struct usb_mixer_interface *mixer,
                return err;
        }
 
-       kctl->private_value |= (value << 24);
+       kctl->private_value |= ((unsigned int)value << 24);
        return 0;
 }
 
@@ -902,7 +902,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
        if (err < 0)
                return err;
 
-       kctl->private_value |= value[0] << 24;
+       kctl->private_value |= (unsigned int)value[0] << 24;
        return 0;
 }
 
index 9e049f6..e918ce3 100644 (file)
@@ -2408,7 +2408,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        USB_DEVICE(0x086a, 0x0001),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                .vendor_name = "Emagic",
-               /* .product_name = "Unitor8", */
+               .product_name = "Unitor8",
                .ifnum = 2,
                .type = QUIRK_MIDI_EMAGIC,
                .data = & (const struct snd_usb_midi_endpoint_info) {
index cf5cff1..7885891 100644 (file)
@@ -828,11 +828,13 @@ static int snd_usb_novation_boot_quirk(struct usb_device *dev)
 static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
 {
        int err, actual_length;
-
        /* "midi send" enable */
        static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 };
+       void *buf;
 
-       void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
+       if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x05)))
+               return -EINVAL;
+       buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
        err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf,
@@ -857,7 +859,11 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
 
 static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
 {
-       int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+       int ret;
+
+       if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0)))
+               return -EINVAL;
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                                  0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                  1, 0, NULL, 0, 1000);
 
@@ -964,6 +970,8 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev)
 
        dev_dbg(&dev->dev, "Waiting for Axe-Fx III to boot up...\n");
 
+       if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0)))
+               return -EINVAL;
        /* If the Axe-Fx III has not fully booted, it will timeout when trying
         * to enable the audio streaming interface. A more generous timeout is
         * used here to detect when the Axe-Fx III has finished booting as the
@@ -996,6 +1004,8 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf,
 {
        int err, actual_length;
 
+       if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x01)))
+               return -EINVAL;
        err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x01), buf, *length,
                                &actual_length, 1000);
        if (err < 0)
@@ -1006,6 +1016,8 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf,
 
        memset(buf, 0, buf_size);
 
+       if (snd_usb_pipe_sanity_check(dev, usb_rcvintpipe(dev, 0x82)))
+               return -EINVAL;
        err = usb_interrupt_msg(dev, usb_rcvintpipe(dev, 0x82), buf, buf_size,
                                &actual_length, 1000);
        if (err < 0)
index b14ab51..e016319 100644 (file)
@@ -196,7 +196,7 @@ static u64 to_sndif_formats_mask(u64 alsa_formats)
        mask = 0;
        for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++)
                if (pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa) & alsa_formats)
-                       mask |= 1 << ALSA_SNDIF_FORMATS[i].sndif;
+                       mask |= BIT_ULL(ALSA_SNDIF_FORMATS[i].sndif);
 
        return mask;
 }
@@ -208,7 +208,7 @@ static u64 to_alsa_formats_mask(u64 sndif_formats)
 
        mask = 0;
        for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++)
-               if (1 << ALSA_SNDIF_FORMATS[i].sndif & sndif_formats)
+               if (BIT_ULL(ALSA_SNDIF_FORMATS[i].sndif) & sndif_formats)
                        mask |= pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa);
 
        return mask;
index ac67bbe..7c9d2bb 100644 (file)
@@ -52,4 +52,7 @@ enum perf_event_x86_regs {
        /* These include both GPRs and XMMX registers */
        PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2,
 };
+
+#define PERF_REG_EXTENDED_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
+
 #endif /* _ASM_X86_PERF_REGS_H */
index b7cd91a..b732133 100644 (file)
@@ -9,7 +9,6 @@
 void perf_regs_load(u64 *regs);
 
 #define PERF_REGS_MAX PERF_REG_X86_XMM_MAX
-#define PERF_XMM_REGS_MASK     (~((1ULL << PERF_REG_X86_XMM0) - 1))
 #ifndef HAVE_ARCH_X86_64_SUPPORT
 #define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
 #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
index 7886ca5..3666c00 100644 (file)
@@ -277,7 +277,7 @@ uint64_t arch__intr_reg_mask(void)
                .type                   = PERF_TYPE_HARDWARE,
                .config                 = PERF_COUNT_HW_CPU_CYCLES,
                .sample_type            = PERF_SAMPLE_REGS_INTR,
-               .sample_regs_intr       = PERF_XMM_REGS_MASK,
+               .sample_regs_intr       = PERF_REG_EXTENDED_MASK,
                .precise_ip             = 1,
                .disabled               = 1,
                .exclude_kernel         = 1,
@@ -293,7 +293,7 @@ uint64_t arch__intr_reg_mask(void)
        fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
        if (fd != -1) {
                close(fd);
-               return (PERF_XMM_REGS_MASK | PERF_REGS_MASK);
+               return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
        }
 
        return PERF_REGS_MASK;
index 698c08f..8995092 100644 (file)
@@ -279,6 +279,51 @@ static void idr_align_test(struct idr *idr)
        }
 }
 
+DEFINE_IDR(find_idr);
+
+static void *idr_throbber(void *arg)
+{
+       time_t start = time(NULL);
+       int id = *(int *)arg;
+
+       rcu_register_thread();
+       do {
+               idr_alloc(&find_idr, xa_mk_value(id), id, id + 1, GFP_KERNEL);
+               idr_remove(&find_idr, id);
+       } while (time(NULL) < start + 10);
+       rcu_unregister_thread();
+
+       return NULL;
+}
+
+void idr_find_test_1(int anchor_id, int throbber_id)
+{
+       pthread_t throbber;
+       time_t start = time(NULL);
+
+       pthread_create(&throbber, NULL, idr_throbber, &throbber_id);
+
+       BUG_ON(idr_alloc(&find_idr, xa_mk_value(anchor_id), anchor_id,
+                               anchor_id + 1, GFP_KERNEL) != anchor_id);
+
+       do {
+               int id = 0;
+               void *entry = idr_get_next(&find_idr, &id);
+               BUG_ON(entry != xa_mk_value(id));
+       } while (time(NULL) < start + 11);
+
+       pthread_join(throbber, NULL);
+
+       idr_remove(&find_idr, anchor_id);
+       BUG_ON(!idr_is_empty(&find_idr));
+}
+
+void idr_find_test(void)
+{
+       idr_find_test_1(100000, 0);
+       idr_find_test_1(0, 100000);
+}
+
 void idr_checks(void)
 {
        unsigned long i;
@@ -360,6 +405,7 @@ void idr_checks(void)
        idr_u32_test(1);
        idr_u32_test(0);
        idr_align_test(&idr);
+       idr_find_test();
 }
 
 #define module_init(x)
index ba91930..d503b87 100644 (file)
@@ -3,4 +3,5 @@ subpage_prot
 tempfile
 prot_sao
 segv_errors
-wild_bctr
\ No newline at end of file
+wild_bctr
+large_vm_fork_separation
\ No newline at end of file
index 43d6842..f1fbc15 100644 (file)
@@ -2,7 +2,8 @@
 noarg:
        $(MAKE) -C ../
 
-TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors wild_bctr
+TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors wild_bctr \
+                 large_vm_fork_separation
 TEST_GEN_FILES := tempfile
 
 top_srcdir = ../../../../..
@@ -13,6 +14,7 @@ $(TEST_GEN_PROGS): ../harness.c
 $(OUTPUT)/prot_sao: ../utils.c
 
 $(OUTPUT)/wild_bctr: CFLAGS += -m64
+$(OUTPUT)/large_vm_fork_separation: CFLAGS += -m64
 
 $(OUTPUT)/tempfile:
        dd if=/dev/zero of=$@ bs=64k count=1
diff --git a/tools/testing/selftests/powerpc/mm/large_vm_fork_separation.c b/tools/testing/selftests/powerpc/mm/large_vm_fork_separation.c
new file mode 100644 (file)
index 0000000..2363a7f
--- /dev/null
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2019, Michael Ellerman, IBM Corp.
+//
+// Test that allocating memory beyond the memory limit and then forking is
+// handled correctly, ie. the child is able to access the mappings beyond the
+// memory limit and the child's writes are not visible to the parent.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+
+#ifndef MAP_FIXED_NOREPLACE
+#define MAP_FIXED_NOREPLACE    MAP_FIXED       // "Should be safe" above 512TB
+#endif
+
+
+static int test(void)
+{
+       int p2c[2], c2p[2], rc, status, c, *p;
+       unsigned long page_size;
+       pid_t pid;
+
+       page_size = sysconf(_SC_PAGESIZE);
+       SKIP_IF(page_size != 65536);
+
+       // Create a mapping at 512TB to allocate an extended_id
+       p = mmap((void *)(512ul << 40), page_size, PROT_READ | PROT_WRITE,
+               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE, -1, 0);
+       if (p == MAP_FAILED) {
+               perror("mmap");
+               printf("Error: couldn't mmap(), confirm kernel has 4TB support?\n");
+               return 1;
+       }
+
+       printf("parent writing %p = 1\n", p);
+       *p = 1;
+
+       FAIL_IF(pipe(p2c) == -1 || pipe(c2p) == -1);
+
+       pid = fork();
+       if (pid == 0) {
+               FAIL_IF(read(p2c[0], &c, 1) != 1);
+
+               pid = getpid();
+               printf("child writing  %p = %d\n", p, pid);
+               *p = pid;
+
+               FAIL_IF(write(c2p[1], &c, 1) != 1);
+               FAIL_IF(read(p2c[0], &c, 1) != 1);
+               exit(0);
+       }
+
+       c = 0;
+       FAIL_IF(write(p2c[1], &c, 1) != 1);
+       FAIL_IF(read(c2p[0], &c, 1) != 1);
+
+       // Prevent compiler optimisation
+       barrier();
+
+       rc = 0;
+       printf("parent reading %p = %d\n", p, *p);
+       if (*p != 1) {
+               printf("Error: BUG! parent saw child's write! *p = %d\n", *p);
+               rc = 1;
+       }
+
+       FAIL_IF(write(p2c[1], &c, 1) != 1);
+       FAIL_IF(waitpid(pid, &status, 0) == -1);
+       FAIL_IF(!WIFEXITED(status) || WEXITSTATUS(status));
+
+       if (rc == 0)
+               printf("success: test completed OK\n");
+
+       return rc;
+}
+
+int main(void)
+{
+       return test_harness(test, "large_vm_fork_separation");
+}