50929 lines
1.7 MiB
50929 lines
1.7 MiB
From 04452c8ab94f043e3ab8032dbaf2bf6ee0549bc0 Mon Sep 17 00:00:00 2001
|
||
From: Tad <tad@spotco.us>
|
||
Date: Wed, 28 Oct 2015 10:25:43 -0400
|
||
Subject: [PATCH] Linux 3.4.67 -> 3.4.105
|
||
|
||
---
|
||
Documentation/cgroups/cpusets.txt | 6 +-
|
||
.../devicetree/bindings/mmc/fsl-imx-esdhc.txt | 8 +-
|
||
.../devicetree/bindings/tty/serial/of-serial.txt | 3 +
|
||
Documentation/hwmon/coretemp | 12 +-
|
||
Documentation/i2c/busses/i2c-i801 | 1 +
|
||
Documentation/i2c/busses/i2c-piix4 | 2 +-
|
||
Documentation/ja_JP/HOWTO | 2 +-
|
||
Documentation/ja_JP/stable_kernel_rules.txt | 6 +-
|
||
Documentation/kernel-parameters.txt | 20 +
|
||
Documentation/stable_kernel_rules.txt | 3 +
|
||
Documentation/sysctl/kernel.txt | 25 +-
|
||
Documentation/x86/x86_64/mm.txt | 2 +
|
||
Documentation/zh_CN/HOWTO | 2 +-
|
||
Documentation/zh_CN/stable_kernel_rules.txt | 2 +-
|
||
Makefile | 2 +-
|
||
arch/alpha/include/asm/io.h | 5 +
|
||
arch/alpha/oprofile/common.c | 1 +
|
||
arch/arm/Kconfig | 1 -
|
||
arch/arm/boot/dts/imx51-babbage.dts | 4 +-
|
||
arch/arm/include/asm/a.out-core.h | 45 ---
|
||
arch/arm/include/asm/a.out.h | 34 --
|
||
arch/arm/include/asm/cacheflush.h | 1 +
|
||
arch/arm/include/asm/div64.h | 2 +-
|
||
arch/arm/include/asm/outercache.h | 4 +-
|
||
arch/arm/include/asm/processor.h | 4 -
|
||
arch/arm/include/asm/uaccess.h | 3 +-
|
||
arch/arm/kernel/crash_dump.c | 2 +-
|
||
arch/arm/kernel/entry-header.S | 29 +-
|
||
arch/arm/kernel/head.S | 3 +
|
||
arch/arm/kernel/machine_kexec.c | 7 +
|
||
arch/arm/kernel/process.c | 7 +-
|
||
arch/arm/kernel/stacktrace.c | 20 +-
|
||
arch/arm/kernel/topology.c | 2 +
|
||
arch/arm/mach-at91/sam9_smc.c | 2 +-
|
||
arch/arm/mach-dove/common.c | 2 +-
|
||
arch/arm/mach-footbridge/common.c | 3 +
|
||
arch/arm/mach-footbridge/dc21285.c | 2 -
|
||
arch/arm/mach-integrator/integrator_cp.c | 3 +-
|
||
arch/arm/mach-kirkwood/common.c | 4 +-
|
||
arch/arm/mach-mv78xx0/common.c | 6 +-
|
||
arch/arm/mach-omap2/irq.c | 8 +
|
||
arch/arm/mach-omap2/mux.c | 6 +-
|
||
arch/arm/mach-omap2/omap_hwmod.c | 43 ++-
|
||
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 17 +-
|
||
arch/arm/mach-orion5x/common.c | 3 +-
|
||
arch/arm/mach-pxa/reset.c | 8 +-
|
||
arch/arm/mach-pxa/tosa.c | 102 ++---
|
||
arch/arm/mach-sa1100/assabet.c | 3 +
|
||
arch/arm/mach-sa1100/include/mach/collie.h | 2 +
|
||
arch/arm/mach-shmobile/board-mackerel.c | 4 +-
|
||
arch/arm/mach-u300/include/mach/u300-regs.h | 2 +-
|
||
arch/arm/mach-w90x900/include/mach/entry-macro.S | 4 +-
|
||
arch/arm/mm/abort-ev6.S | 6 -
|
||
arch/arm/mm/abort-ev7.S | 6 -
|
||
arch/arm/mm/idmap.c | 7 +
|
||
arch/arm/plat-orion/common.c | 8 +-
|
||
arch/arm/plat-orion/include/plat/common.h | 6 +-
|
||
arch/avr32/Makefile | 2 +-
|
||
arch/avr32/boards/mimc200/fram.c | 1 +
|
||
arch/avr32/boot/u-boot/head.S | 35 +-
|
||
arch/avr32/kernel/entry-avr32b.S | 3 +-
|
||
arch/avr32/kernel/head.S | 20 -
|
||
arch/cris/include/asm/io.h | 1 +
|
||
arch/ia64/include/asm/processor.h | 2 +-
|
||
arch/mips/boot/compressed/decompress.c | 1 +
|
||
arch/mips/cavium-octeon/setup.c | 18 +-
|
||
arch/mips/include/asm/jump_label.h | 2 +-
|
||
arch/mips/kernel/irq-msc01.c | 2 +-
|
||
arch/mips/kernel/mcount.S | 12 +
|
||
arch/mips/kernel/perf_event_mipsxx.c | 5 -
|
||
arch/mips/mm/c-r4k.c | 5 +
|
||
arch/mips/mm/dma-default.c | 16 +-
|
||
arch/mips/power/hibernate.S | 1 +
|
||
arch/openrisc/kernel/head.S | 1 +
|
||
arch/parisc/Makefile | 7 +-
|
||
arch/parisc/kernel/head.S | 4 +
|
||
arch/parisc/kernel/syscall_table.S | 2 +-
|
||
arch/powerpc/Makefile | 4 +-
|
||
arch/powerpc/include/asm/exception-64s.h | 2 +-
|
||
arch/powerpc/include/asm/jump_label.h | 2 +-
|
||
arch/powerpc/include/asm/ppc_asm.h | 7 +-
|
||
arch/powerpc/kernel/cacheinfo.c | 3 +
|
||
arch/powerpc/kernel/crash_dump.c | 8 +-
|
||
arch/powerpc/kernel/exceptions-64s.S | 2 +-
|
||
arch/powerpc/kernel/head_64.S | 1 +
|
||
arch/powerpc/kernel/lparcfg.c | 24 +-
|
||
arch/powerpc/kernel/reloc_64.S | 1 +
|
||
arch/powerpc/kernel/setup_64.c | 2 +-
|
||
arch/powerpc/kernel/signal_32.c | 6 +
|
||
arch/powerpc/kernel/signal_64.c | 6 +
|
||
arch/powerpc/kernel/sysfs.c | 18 +-
|
||
arch/powerpc/kernel/time.c | 6 +-
|
||
arch/powerpc/kernel/traps.c | 10 +
|
||
arch/powerpc/kernel/vio.c | 4 +-
|
||
arch/powerpc/kvm/book3s_64_mmu_hv.c | 6 +-
|
||
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 4 +
|
||
arch/powerpc/kvm/emulate.c | 2 +
|
||
arch/powerpc/lib/checksum_64.S | 54 ++-
|
||
arch/powerpc/lib/crtsavres.S | 186 +++++++++
|
||
arch/powerpc/lib/sstep.c | 2 +-
|
||
arch/powerpc/perf/core-book3s.c | 17 +-
|
||
arch/powerpc/platforms/powernv/pci-ioda.c | 12 +-
|
||
arch/powerpc/platforms/pseries/eeh_pseries.c | 1 +
|
||
arch/s390/crypto/aes_s390.c | 50 +--
|
||
arch/s390/include/asm/jump_label.h | 2 +-
|
||
arch/s390/include/asm/lowcore.h | 11 +-
|
||
arch/s390/kernel/head64.S | 7 +-
|
||
arch/s390/kernel/ptrace.c | 9 +-
|
||
arch/s390/kvm/kvm-s390.c | 25 +-
|
||
arch/s390/mm/page-states.c | 10 +
|
||
arch/sh/kernel/dumpstack.c | 2 +-
|
||
arch/sh/lib/Makefile | 2 +-
|
||
arch/sparc/Kconfig | 2 +-
|
||
arch/sparc/include/asm/jump_label.h | 2 +-
|
||
arch/sparc/include/asm/pgtable_64.h | 6 +-
|
||
arch/sparc/include/asm/tlbflush_64.h | 12 +-
|
||
arch/sparc/include/asm/uaccess_64.h | 4 +-
|
||
arch/sparc/kernel/ldc.c | 2 +-
|
||
arch/sparc/kernel/pci.c | 4 +-
|
||
arch/sparc/kernel/smp_64.c | 6 +-
|
||
arch/sparc/kernel/sys32.S | 2 +-
|
||
arch/sparc/kernel/syscalls.S | 4 +-
|
||
arch/sparc/kernel/unaligned_64.c | 12 +-
|
||
arch/sparc/lib/NG2memcpy.S | 1 +
|
||
arch/sparc/math-emu/math_32.c | 2 +-
|
||
arch/sparc/mm/fault_64.c | 102 ++---
|
||
arch/sparc/mm/init_64.c | 27 ++
|
||
arch/sparc/mm/tsb.c | 14 +-
|
||
arch/um/kernel/exitcode.c | 4 +-
|
||
arch/unicore32/Kconfig | 1 +
|
||
arch/unicore32/include/asm/bug.h | 5 -
|
||
arch/unicore32/include/asm/cmpxchg.h | 2 +-
|
||
arch/unicore32/kernel/setup.h | 6 +
|
||
arch/x86/Kconfig | 26 +-
|
||
arch/x86/boot/Makefile | 6 +-
|
||
arch/x86/boot/compressed/Makefile | 1 +
|
||
arch/x86/crypto/ghash-clmulni-intel_asm.S | 28 --
|
||
arch/x86/crypto/ghash-clmulni-intel_glue.c | 14 +-
|
||
arch/x86/include/asm/cpufeature.h | 2 +-
|
||
arch/x86/include/asm/espfix.h | 16 +
|
||
arch/x86/include/asm/fpu-internal.h | 13 +-
|
||
arch/x86/include/asm/hugetlb.h | 1 +
|
||
arch/x86/include/asm/irqflags.h | 2 +-
|
||
arch/x86/include/asm/jump_label.h | 2 +-
|
||
arch/x86/include/asm/kvm_host.h | 4 +-
|
||
arch/x86/include/asm/pgtable_64_types.h | 2 +
|
||
arch/x86/include/asm/ptrace.h | 16 +
|
||
arch/x86/include/asm/setup.h | 2 +
|
||
arch/x86/include/asm/topology.h | 3 +-
|
||
arch/x86/kernel/Makefile | 1 +
|
||
arch/x86/kernel/cpu/perf_event.c | 3 +
|
||
arch/x86/kernel/cpu/perf_event_amd_ibs.c | 53 ++-
|
||
arch/x86/kernel/cpu/perf_event_intel.c | 9 +
|
||
arch/x86/kernel/crash.c | 2 +-
|
||
arch/x86/kernel/entry_32.S | 30 +-
|
||
arch/x86/kernel/entry_64.S | 80 +++-
|
||
arch/x86/kernel/espfix_64.c | 208 +++++++++++
|
||
arch/x86/kernel/ldt.c | 5 +
|
||
arch/x86/kernel/microcode_amd.c | 2 +-
|
||
arch/x86/kernel/paravirt_patch_64.c | 2 -
|
||
arch/x86/kernel/quirks.c | 2 +-
|
||
arch/x86/kernel/reboot.c | 11 +-
|
||
arch/x86/kernel/setup.c | 4 +-
|
||
arch/x86/kernel/smpboot.c | 10 +
|
||
arch/x86/kernel/step.c | 53 ++-
|
||
arch/x86/kernel/sys_x86_64.c | 2 +-
|
||
arch/x86/kvm/lapic.c | 27 +-
|
||
arch/x86/kvm/lapic.h | 4 +-
|
||
arch/x86/kvm/mmu.c | 3 +
|
||
arch/x86/kvm/svm.c | 6 +-
|
||
arch/x86/kvm/vmx.c | 2 +-
|
||
arch/x86/kvm/x86.c | 33 +-
|
||
arch/x86/mm/dump_pagetables.c | 39 +-
|
||
arch/x86/mm/ioremap.c | 26 +-
|
||
arch/x86/mm/mmap.c | 6 +-
|
||
arch/x86/net/bpf_jit.S | 2 +-
|
||
arch/x86/platform/efi/efi.c | 112 +++++-
|
||
arch/x86/syscalls/syscall_64.tbl | 6 +-
|
||
arch/x86/xen/enlighten.c | 4 +
|
||
arch/x86/xen/smp.c | 2 +
|
||
arch/xtensa/include/asm/ioctls.h | 19 +-
|
||
arch/xtensa/include/asm/pgtable.h | 7 +-
|
||
arch/xtensa/kernel/entry.S | 14 +-
|
||
arch/xtensa/kernel/pci-dma.c | 12 +-
|
||
arch/xtensa/kernel/signal.c | 2 +-
|
||
block/blk-core.c | 7 +-
|
||
block/blk-exec.c | 12 +-
|
||
block/blk-settings.c | 1 +
|
||
block/blk-tag.c | 33 +-
|
||
block/blk-timeout.c | 3 +-
|
||
block/elevator.c | 16 +-
|
||
block/genhd.c | 20 +-
|
||
block/partition-generic.c | 2 +-
|
||
crypto/af_alg.c | 2 +
|
||
crypto/algif_hash.c | 5 +-
|
||
crypto/algif_skcipher.c | 4 +-
|
||
crypto/ansi_cprng.c | 4 +-
|
||
crypto/authenc.c | 7 +-
|
||
crypto/ccm.c | 3 +-
|
||
crypto/crypto_wq.c | 2 +-
|
||
crypto/testmgr.h | 38 +-
|
||
drivers/acpi/acpica/exoparg1.c | 48 ++-
|
||
drivers/acpi/acpica/exstore.c | 151 +++++---
|
||
drivers/acpi/battery.c | 27 +-
|
||
drivers/acpi/blacklist.c | 13 +
|
||
drivers/acpi/bus.c | 16 +
|
||
drivers/acpi/processor_idle.c | 4 +-
|
||
drivers/acpi/processor_throttling.c | 69 ++--
|
||
drivers/acpi/video.c | 24 +-
|
||
drivers/acpi/video_detect.c | 45 +++
|
||
drivers/ata/ahci.c | 52 +++
|
||
drivers/ata/ata_piix.c | 16 +
|
||
drivers/ata/libahci.c | 16 +
|
||
drivers/ata/libata-core.c | 34 +-
|
||
drivers/ata/libata-eh.c | 6 +-
|
||
drivers/ata/libata-pmp.c | 7 +-
|
||
drivers/ata/libata-transport.c | 16 +-
|
||
drivers/ata/pata_at91.c | 11 +-
|
||
drivers/ata/pata_scc.c | 15 +-
|
||
drivers/ata/sata_sil.c | 1 +
|
||
drivers/atm/ambassador.c | 2 +-
|
||
drivers/atm/idt77252.c | 4 +-
|
||
drivers/base/dd.c | 17 +
|
||
drivers/base/regmap/regmap.c | 2 +-
|
||
drivers/block/brd.c | 2 +-
|
||
drivers/block/floppy.c | 22 +-
|
||
drivers/block/loop.c | 6 +-
|
||
drivers/block/nbd.c | 17 +-
|
||
drivers/block/virtio_blk.c | 29 +-
|
||
drivers/block/xen-blkback/blkback.c | 16 +-
|
||
drivers/block/xen-blkback/common.h | 2 +
|
||
drivers/block/xen-blkback/xenbus.c | 2 +
|
||
drivers/block/xen-blkfront.c | 5 +-
|
||
drivers/bluetooth/ath3k.c | 8 +
|
||
drivers/bluetooth/btusb.c | 7 +
|
||
drivers/char/applicom.c | 1 -
|
||
drivers/char/i8k.c | 7 +
|
||
drivers/char/ipmi/ipmi_bt_sm.c | 2 +-
|
||
drivers/char/ipmi/ipmi_kcs_sm.c | 5 +-
|
||
drivers/char/ipmi/ipmi_si_intf.c | 46 ++-
|
||
drivers/char/raw.c | 2 +-
|
||
drivers/char/virtio_console.c | 22 +-
|
||
drivers/connector/cn_proc.c | 90 +++--
|
||
drivers/connector/connector.c | 7 +-
|
||
drivers/cpufreq/powernow-k6.c | 147 ++++++--
|
||
drivers/crypto/caam/error.c | 10 +-
|
||
drivers/dma/Kconfig | 1 +
|
||
drivers/dma/ste_dma40.c | 4 +-
|
||
drivers/edac/e752x_edac.c | 4 +-
|
||
drivers/edac/i7300_edac.c | 38 +-
|
||
drivers/edac/i7core_edac.c | 9 +-
|
||
drivers/edac/i82975x_edac.c | 11 +-
|
||
drivers/edac/sb_edac.c | 7 +-
|
||
drivers/firewire/core-device.c | 22 +-
|
||
drivers/firewire/net.c | 6 +-
|
||
drivers/firewire/sbp2.c | 17 +-
|
||
drivers/firmware/Kconfig | 18 +
|
||
drivers/firmware/efivars.c | 256 +++++++++----
|
||
drivers/gpio/gpio-mpc8xxx.c | 8 +-
|
||
drivers/gpio/gpio-mxs.c | 3 +-
|
||
drivers/gpu/drm/drm_crtc_helper.c | 4 +-
|
||
drivers/gpu/drm/drm_drv.c | 9 +-
|
||
drivers/gpu/drm/drm_edid.c | 8 +
|
||
drivers/gpu/drm/i915/i915_debugfs.c | 6 +-
|
||
drivers/gpu/drm/i915/i915_dma.c | 37 +-
|
||
drivers/gpu/drm/i915/i915_drv.h | 4 +-
|
||
drivers/gpu/drm/i915/i915_gem.c | 23 +-
|
||
drivers/gpu/drm/i915/i915_irq.c | 4 +-
|
||
drivers/gpu/drm/i915/intel_bios.c | 2 +-
|
||
drivers/gpu/drm/i915/intel_crt.c | 10 +-
|
||
drivers/gpu/drm/i915/intel_display.c | 118 +++++-
|
||
drivers/gpu/drm/i915/intel_dp.c | 5 -
|
||
drivers/gpu/drm/i915/intel_drv.h | 5 +-
|
||
drivers/gpu/drm/i915/intel_lvds.c | 5 +-
|
||
drivers/gpu/drm/i915/intel_opregion.c | 2 +-
|
||
drivers/gpu/drm/i915/intel_panel.c | 31 +-
|
||
drivers/gpu/drm/i915/intel_sdvo.c | 22 +-
|
||
drivers/gpu/drm/nouveau/nouveau_acpi.c | 3 -
|
||
drivers/gpu/drm/nouveau/nouveau_bo.c | 2 +-
|
||
drivers/gpu/drm/nouveau/nouveau_gem.c | 3 +-
|
||
drivers/gpu/drm/radeon/atombios_crtc.c | 53 +--
|
||
drivers/gpu/drm/radeon/atombios_encoders.c | 9 +-
|
||
drivers/gpu/drm/radeon/evergreen.c | 9 +-
|
||
drivers/gpu/drm/radeon/evergreen_cs.c | 5 +-
|
||
drivers/gpu/drm/radeon/ni.c | 23 +-
|
||
drivers/gpu/drm/radeon/r600.c | 16 +-
|
||
drivers/gpu/drm/radeon/r600_cs.c | 5 +-
|
||
drivers/gpu/drm/radeon/r600_hdmi.c | 4 +-
|
||
drivers/gpu/drm/radeon/r600d.h | 1 +
|
||
drivers/gpu/drm/radeon/radeon_atombios.c | 11 +
|
||
drivers/gpu/drm/radeon/radeon_atpx_handler.c | 7 +
|
||
drivers/gpu/drm/radeon/radeon_combios.c | 125 ++++++-
|
||
drivers/gpu/drm/radeon/radeon_connectors.c | 36 +-
|
||
drivers/gpu/drm/radeon/radeon_display.c | 6 +
|
||
drivers/gpu/drm/radeon/radeon_i2c.c | 3 +
|
||
drivers/gpu/drm/radeon/radeon_kms.c | 4 +
|
||
drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 28 ++
|
||
drivers/gpu/drm/radeon/radeon_mode.h | 2 +
|
||
drivers/gpu/drm/radeon/radeon_pm.c | 6 +-
|
||
drivers/gpu/drm/radeon/rs600.c | 6 +-
|
||
drivers/gpu/drm/radeon/rv770.c | 3 +-
|
||
drivers/gpu/drm/radeon/si.c | 14 +-
|
||
drivers/gpu/drm/radeon/sid.h | 2 +-
|
||
drivers/gpu/drm/ttm/ttm_bo.c | 40 +-
|
||
drivers/gpu/drm/ttm/ttm_bo_util.c | 4 +-
|
||
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 +-
|
||
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 3 +-
|
||
drivers/hid/hid-apple.c | 25 ++
|
||
drivers/hid/hid-cherry.c | 2 +-
|
||
drivers/hid/hid-core.c | 38 +-
|
||
drivers/hid/hid-ids.h | 10 +
|
||
drivers/hid/hid-input.c | 12 +-
|
||
drivers/hid/hid-kye.c | 2 +-
|
||
drivers/hid/hid-lg.c | 4 +-
|
||
drivers/hid/hid-logitech-dj.c | 92 +++--
|
||
drivers/hid/hid-logitech-dj.h | 1 +
|
||
drivers/hid/hid-magicmouse.c | 10 +
|
||
drivers/hid/hid-monterey.c | 2 +-
|
||
drivers/hid/hid-multitouch.c | 4 +-
|
||
drivers/hid/hid-petalynx.c | 2 +-
|
||
drivers/hid/hid-picolcd.c | 8 +-
|
||
drivers/hid/hid-roccat-kovaplus.c | 4 +
|
||
drivers/hid/hid-sony.c | 18 +-
|
||
drivers/hid/hid-sunplus.c | 2 +-
|
||
drivers/hid/hidraw.c | 98 ++---
|
||
drivers/hid/usbhid/hid-quirks.c | 3 +
|
||
drivers/hv/ring_buffer.c | 4 +-
|
||
drivers/hv/vmbus_drv.c | 2 +-
|
||
drivers/hwmon/adm1029.c | 3 +
|
||
drivers/hwmon/amc6821.c | 2 +-
|
||
drivers/hwmon/applesmc.c | 13 +
|
||
drivers/hwmon/coretemp.c | 36 +-
|
||
drivers/hwmon/emc1403.c | 4 +-
|
||
drivers/hwmon/lm78.c | 2 +
|
||
drivers/hwmon/lm90.c | 11 +-
|
||
drivers/hwmon/max1668.c | 2 +-
|
||
drivers/hwmon/sis5595.c | 2 +
|
||
drivers/hwmon/vt8231.c | 2 +-
|
||
drivers/hwmon/w83l786ng.c | 13 +-
|
||
drivers/i2c/busses/Kconfig | 2 +
|
||
drivers/i2c/busses/i2c-designware-core.c | 3 +
|
||
drivers/i2c/busses/i2c-i801.c | 3 +
|
||
drivers/i2c/busses/i2c-piix4.c | 3 +-
|
||
drivers/i2c/busses/i2c-tegra.c | 13 +-
|
||
drivers/idle/intel_idle.c | 48 ++-
|
||
drivers/infiniband/core/user_mad.c | 75 ++--
|
||
drivers/infiniband/hw/ehca/ehca_cq.c | 1 +
|
||
drivers/infiniband/hw/ipath/ipath_diag.c | 68 ++--
|
||
drivers/infiniband/hw/ipath/ipath_user_sdma.c | 7 +-
|
||
drivers/infiniband/hw/mthca/mthca_provider.c | 1 +
|
||
drivers/infiniband/hw/nes/nes_verbs.c | 2 +-
|
||
drivers/infiniband/hw/qib/qib_iba7322.c | 5 +
|
||
drivers/infiniband/hw/qib/qib_mad.c | 2 +-
|
||
drivers/infiniband/hw/qib/qib_ud.c | 9 +-
|
||
drivers/infiniband/hw/qib/qib_user_sdma.c | 6 +-
|
||
drivers/infiniband/ulp/srp/ib_srp.c | 6 +
|
||
drivers/infiniband/ulp/srpt/ib_srpt.c | 16 +-
|
||
drivers/input/Kconfig | 2 +-
|
||
drivers/input/input.c | 4 +
|
||
drivers/input/keyboard/Kconfig | 4 +-
|
||
drivers/input/mouse/elantech.c | 72 +++-
|
||
drivers/input/mouse/synaptics.c | 161 +++++++-
|
||
drivers/input/mouse/synaptics.h | 11 +
|
||
drivers/input/serio/Kconfig | 6 +-
|
||
drivers/input/serio/i8042-x86ia64io.h | 17 +
|
||
drivers/input/serio/serport.c | 45 ++-
|
||
drivers/input/touchscreen/usbtouchscreen.c | 22 +-
|
||
drivers/iommu/amd_iommu.c | 10 +-
|
||
drivers/iommu/dmar.c | 11 +-
|
||
drivers/iommu/intel-iommu.c | 23 +-
|
||
drivers/isdn/isdnloop/isdnloop.c | 31 +-
|
||
drivers/isdn/mISDN/socket.c | 13 +-
|
||
drivers/md/Kconfig | 4 +
|
||
drivers/md/Makefile | 1 +
|
||
drivers/md/dm-bufio.c | 31 +-
|
||
drivers/md/dm-builtin.c | 50 +++
|
||
drivers/md/dm-crypt.c | 20 +-
|
||
drivers/md/dm-delay.c | 23 +-
|
||
drivers/md/dm-mpath.c | 25 +-
|
||
drivers/md/dm-snap-persistent.c | 18 +-
|
||
drivers/md/dm-snap.c | 73 +++-
|
||
drivers/md/dm-sysfs.c | 5 +-
|
||
drivers/md/dm-table.c | 23 +-
|
||
drivers/md/dm-thin.c | 6 +-
|
||
drivers/md/dm.c | 15 +-
|
||
drivers/md/dm.h | 17 +
|
||
drivers/md/md.c | 21 +-
|
||
drivers/md/persistent-data/dm-btree-remove.c | 46 +--
|
||
drivers/md/persistent-data/dm-space-map-common.c | 6 +-
|
||
drivers/md/raid1.c | 1 +
|
||
drivers/md/raid10.c | 21 +-
|
||
drivers/md/raid5.c | 93 ++---
|
||
drivers/media/media-device.c | 1 +
|
||
drivers/media/video/gspca/kinect.c | 1 +
|
||
drivers/media/video/hdpvr/hdpvr-core.c | 22 +-
|
||
drivers/media/video/omap/omap_vout.c | 12 +-
|
||
drivers/media/video/saa7134/saa7134-alsa.c | 2 +
|
||
drivers/media/video/saa7164/saa7164-core.c | 4 +-
|
||
drivers/media/video/v4l2-device.c | 30 +-
|
||
drivers/mfd/max8925-i2c.c | 9 +
|
||
drivers/mfd/max8997.c | 18 +
|
||
drivers/mfd/max8998.c | 4 +
|
||
drivers/misc/enclosure.c | 7 +
|
||
drivers/misc/hpilo.c | 11 +-
|
||
drivers/mmc/host/atmel-mci.c | 13 +-
|
||
drivers/mmc/host/mxs-mmc.c | 8 +-
|
||
drivers/mtd/devices/m25p80.c | 19 +-
|
||
drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 4 +-
|
||
drivers/mtd/nand/mxc_nand.c | 1 -
|
||
drivers/mtd/nand/nand_base.c | 15 +-
|
||
drivers/mtd/nand/nuc900_nand.c | 2 +-
|
||
drivers/mtd/nand/pxa3xx_nand.c | 4 +-
|
||
drivers/mtd/sm_ftl.c | 11 +-
|
||
drivers/mtd/ubi/scan.c | 2 +-
|
||
drivers/net/bonding/bond_3ad.c | 6 +-
|
||
drivers/net/bonding/bond_3ad.h | 1 +
|
||
drivers/net/bonding/bond_main.c | 1 +
|
||
drivers/net/bonding/bond_sysfs.c | 11 +-
|
||
drivers/net/can/at91_can.c | 8 +-
|
||
drivers/net/can/c_can/c_can.c | 12 +-
|
||
drivers/net/can/dev.c | 10 +-
|
||
drivers/net/can/flexcan.c | 59 ++-
|
||
drivers/net/can/sja1000/peak_pci.c | 14 +-
|
||
drivers/net/can/sja1000/sja1000.c | 17 +-
|
||
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 14 +-
|
||
drivers/net/ethernet/broadcom/tg3.c | 88 ++++-
|
||
drivers/net/ethernet/broadcom/tg3.h | 14 +-
|
||
drivers/net/ethernet/calxeda/xgmac.c | 2 +-
|
||
drivers/net/ethernet/emulex/benet/be_main.c | 2 +-
|
||
drivers/net/ethernet/ibm/ehea/ehea_main.c | 2 +-
|
||
drivers/net/ethernet/ibm/ibmveth.c | 18 +-
|
||
drivers/net/ethernet/intel/e1000e/e1000.h | 1 +
|
||
drivers/net/ethernet/intel/e1000e/netdev.c | 48 ++-
|
||
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 7 +-
|
||
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 12 -
|
||
drivers/net/ethernet/marvell/mv643xx_eth.c | 6 +-
|
||
drivers/net/ethernet/mellanox/mlx4/en_cq.c | 1 -
|
||
drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 6 +-
|
||
drivers/net/ethernet/mellanox/mlx4/main.c | 172 +++++----
|
||
drivers/net/ethernet/mellanox/mlx4/mlx4.h | 7 +
|
||
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 -
|
||
drivers/net/ethernet/realtek/8139cp.c | 1 +
|
||
drivers/net/ethernet/sun/sunvnet.c | 20 +-
|
||
drivers/net/ethernet/tehuti/tehuti.c | 1 -
|
||
drivers/net/ethernet/ti/davinci_emac.c | 3 +-
|
||
drivers/net/ethernet/via/via-rhine.c | 1 +
|
||
drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
|
||
drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 2 +-
|
||
drivers/net/hamradio/hdlcdrv.c | 2 +
|
||
drivers/net/hamradio/yam.c | 1 +
|
||
drivers/net/hyperv/netvsc_drv.c | 1 -
|
||
drivers/net/macvlan.c | 4 +-
|
||
drivers/net/macvtap.c | 20 +-
|
||
drivers/net/ppp/pppoe.c | 4 +-
|
||
drivers/net/team/team.c | 7 +-
|
||
drivers/net/tun.c | 2 +
|
||
drivers/net/usb/asix.c | 128 +++++--
|
||
drivers/net/usb/dm9601.c | 34 +-
|
||
drivers/net/usb/gl620a.c | 4 +
|
||
drivers/net/usb/mcs7830.c | 5 +-
|
||
drivers/net/usb/net1080.c | 4 +
|
||
drivers/net/usb/qmi_wwan.c | 8 +-
|
||
drivers/net/usb/rndis_host.c | 4 +
|
||
drivers/net/usb/smsc75xx.c | 4 +
|
||
drivers/net/usb/smsc95xx.c | 4 +
|
||
drivers/net/usb/usbnet.c | 25 +-
|
||
drivers/net/virtio_net.c | 3 +-
|
||
drivers/net/vmxnet3/vmxnet3_drv.c | 19 +-
|
||
drivers/net/wan/farsync.c | 1 +
|
||
drivers/net/wan/wanxl.c | 1 +
|
||
drivers/net/wimax/i2400m/usb-rx.c | 2 +-
|
||
drivers/net/wireless/ath/ath9k/ar9002_mac.c | 52 ++-
|
||
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 8 +-
|
||
drivers/net/wireless/ath/ath9k/ar9003_hw.c | 15 +-
|
||
drivers/net/wireless/ath/ath9k/ar9003_phy.c | 27 +-
|
||
drivers/net/wireless/ath/ath9k/ar9003_phy.h | 2 +
|
||
.../net/wireless/ath/ath9k/ar9462_2p0_initvals.h | 4 +-
|
||
drivers/net/wireless/ath/ath9k/calib.c | 1 +
|
||
drivers/net/wireless/ath/ath9k/htc.h | 1 +
|
||
drivers/net/wireless/ath/ath9k/htc_drv_main.c | 25 +-
|
||
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 18 +-
|
||
drivers/net/wireless/ath/ath9k/hw.c | 3 +-
|
||
drivers/net/wireless/ath/ath9k/hw.h | 1 +
|
||
drivers/net/wireless/ath/ath9k/main.c | 12 +-
|
||
drivers/net/wireless/ath/ath9k/xmit.c | 8 +-
|
||
drivers/net/wireless/b43/Kconfig | 4 +-
|
||
drivers/net/wireless/b43/b43.h | 4 +-
|
||
drivers/net/wireless/b43/main.c | 27 +-
|
||
drivers/net/wireless/b43/phy_n.c | 14 +-
|
||
drivers/net/wireless/b43/xmit.c | 14 +-
|
||
drivers/net/wireless/b43legacy/main.c | 1 +
|
||
drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +
|
||
drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +-
|
||
drivers/net/wireless/iwlwifi/iwl-cfg.h | 1 +
|
||
drivers/net/wireless/iwlwifi/iwl-core.c | 5 +-
|
||
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 3 +
|
||
drivers/net/wireless/iwlwifi/iwl-pci.c | 10 +
|
||
drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h | 11 +-
|
||
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 37 +-
|
||
drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c | 72 +++-
|
||
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 27 +-
|
||
drivers/net/wireless/libertas/debugfs.c | 6 +-
|
||
drivers/net/wireless/mwifiex/11n.c | 3 +-
|
||
drivers/net/wireless/mwifiex/main.c | 1 +
|
||
drivers/net/wireless/mwifiex/sdio.c | 3 +
|
||
drivers/net/wireless/p54/txrx.c | 2 +-
|
||
drivers/net/wireless/prism54/islpci_dev.c | 7 +-
|
||
drivers/net/wireless/rt2x00/rt2400pci.c | 2 +-
|
||
drivers/net/wireless/rt2x00/rt2500pci.c | 7 +-
|
||
drivers/net/wireless/rt2x00/rt2500usb.c | 2 +-
|
||
drivers/net/wireless/rt2x00/rt2800usb.c | 14 +-
|
||
drivers/net/wireless/rt2x00/rt2x00.h | 1 +
|
||
drivers/net/wireless/rt2x00/rt2x00dev.c | 24 +-
|
||
drivers/net/wireless/rt2x00/rt2x00mac.c | 27 +-
|
||
drivers/net/wireless/rt2x00/rt73usb.c | 1 +
|
||
drivers/net/wireless/rtl818x/rtl8187/rtl8187.h | 10 +-
|
||
drivers/net/wireless/rtlwifi/base.c | 89 ++---
|
||
drivers/net/wireless/rtlwifi/core.c | 1 +
|
||
drivers/net/wireless/rtlwifi/pci.c | 4 +-
|
||
drivers/net/wireless/rtlwifi/ps.c | 2 +-
|
||
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 3 +
|
||
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 18 +-
|
||
drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 17 +-
|
||
drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 6 +-
|
||
drivers/net/wireless/rtlwifi/rtl8192cu/rf.c | 29 +-
|
||
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 2 +
|
||
drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 11 +-
|
||
drivers/net/wireless/rtlwifi/rtl8192de/trx.c | 2 +-
|
||
drivers/net/wireless/rtlwifi/rtl8192se/hw.c | 27 +-
|
||
drivers/net/wireless/rtlwifi/rtl8192se/rf.c | 2 +-
|
||
drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 2 +-
|
||
drivers/net/wireless/rtlwifi/wifi.h | 6 +-
|
||
drivers/net/xen-netback/common.h | 1 +
|
||
drivers/net/xen-netback/interface.c | 3 +-
|
||
drivers/net/xen-netback/netback.c | 303 ++++++++++++---
|
||
drivers/net/xen-netfront.c | 17 +-
|
||
drivers/parport/parport_pc.c | 10 +-
|
||
drivers/pci/hotplug/shpchp.h | 2 +-
|
||
drivers/pci/hotplug/shpchp_core.c | 26 +-
|
||
drivers/pci/hotplug/shpchp_ctrl.c | 10 +-
|
||
drivers/pci/pci-driver.c | 4 +
|
||
drivers/pci/pci.c | 16 +-
|
||
drivers/pci/pcie/aspm.c | 3 +
|
||
drivers/pci/pcie/portdrv_pci.c | 1 -
|
||
drivers/pci/quirks.c | 1 +
|
||
drivers/pci/setup-res.c | 3 +-
|
||
drivers/platform/x86/hp_accel.c | 1 +
|
||
drivers/platform/x86/msi-wmi.c | 4 +-
|
||
drivers/platform/x86/thinkpad_acpi.c | 2 +-
|
||
drivers/power/max17040_battery.c | 5 +-
|
||
drivers/pps/clients/pps-ldisc.c | 10 +-
|
||
drivers/pps/pps.c | 47 ++-
|
||
drivers/rapidio/devices/tsi721.c | 11 +
|
||
drivers/regulator/max8997.c | 36 +-
|
||
drivers/regulator/max8998.c | 2 +-
|
||
drivers/rtc/rtc-at91rm9200.c | 2 +
|
||
drivers/rtc/rtc-cmos.c | 52 ++-
|
||
drivers/rtc/rtc-pl031.c | 10 +-
|
||
drivers/s390/net/qeth_core_main.c | 6 +-
|
||
drivers/sbus/char/bbc_envctrl.c | 6 +
|
||
drivers/sbus/char/bbc_i2c.c | 11 +-
|
||
drivers/scsi/aacraid/commctrl.c | 3 +-
|
||
drivers/scsi/aacraid/linit.c | 2 +
|
||
drivers/scsi/arcmsr/arcmsr_hba.c | 7 +-
|
||
drivers/scsi/bfa/bfad.c | 6 +-
|
||
drivers/scsi/hpsa.c | 36 +-
|
||
drivers/scsi/ibmvscsi/ibmvscsi.c | 3 +-
|
||
drivers/scsi/isci/host.h | 5 +-
|
||
drivers/scsi/isci/port_config.c | 7 -
|
||
drivers/scsi/isci/task.c | 11 +-
|
||
drivers/scsi/libiscsi.c | 10 +
|
||
drivers/scsi/libsas/sas_ata.c | 2 +-
|
||
drivers/scsi/megaraid/megaraid_mm.c | 2 +
|
||
drivers/scsi/megaraid/megaraid_sas.h | 1 -
|
||
drivers/scsi/megaraid/megaraid_sas_base.c | 5 +-
|
||
drivers/scsi/mpt2sas/mpt2sas_base.c | 13 +-
|
||
drivers/scsi/mpt2sas/mpt2sas_base.h | 3 +
|
||
drivers/scsi/mpt2sas/mpt2sas_scsih.c | 127 ++++++-
|
||
drivers/scsi/qla2xxx/qla_def.h | 3 +-
|
||
drivers/scsi/scsi_error.c | 9 +
|
||
drivers/scsi/scsi_lib.c | 8 +
|
||
drivers/scsi/storvsc_drv.c | 3 +
|
||
drivers/scsi/sym53c8xx_2/sym_hipd.c | 4 +
|
||
drivers/staging/bcm/Bcmchar.c | 1 +
|
||
drivers/staging/bcm/InterfaceInit.c | 4 +-
|
||
drivers/staging/bcm/InterfaceInit.h | 5 +-
|
||
drivers/staging/comedi/comedi_fops.c | 25 +-
|
||
drivers/staging/comedi/drivers/cb_pcidio.c | 21 +-
|
||
drivers/staging/comedi/drivers/das08.c | 2 +-
|
||
drivers/staging/comedi/drivers/pcmuio.c | 12 +-
|
||
drivers/staging/comedi/drivers/ssv_dnp.c | 6 +-
|
||
drivers/staging/et131x/et131x.c | 78 ++--
|
||
drivers/staging/iio/adc/ad799x_core.c | 3 +-
|
||
drivers/staging/line6/pcm.c | 5 +-
|
||
drivers/staging/media/lirc/lirc_zilog.c | 12 +-
|
||
drivers/staging/octeon/ethernet-tx.c | 2 +-
|
||
drivers/staging/ozwpan/ozcdev.c | 3 +
|
||
drivers/staging/rtl8712/rtl871x_recv.c | 13 +-
|
||
drivers/staging/rtl8712/usb_intf.c | 5 +
|
||
drivers/staging/serqt_usb2/serqt_usb2.c | 2 +-
|
||
drivers/staging/speakup/i18n.c | 12 +-
|
||
drivers/staging/speakup/i18n.h | 12 +-
|
||
drivers/staging/speakup/keyhelp.c | 36 +-
|
||
drivers/staging/speakup/kobjects.c | 80 ++--
|
||
drivers/staging/speakup/main.c | 367 +++++++++---------
|
||
drivers/staging/speakup/selection.c | 52 ++-
|
||
drivers/staging/speakup/serialio.c | 6 +-
|
||
drivers/staging/speakup/speakup.h | 73 ++--
|
||
drivers/staging/speakup/speakup_acntpc.c | 6 +-
|
||
drivers/staging/speakup/speakup_acntsa.c | 2 +-
|
||
drivers/staging/speakup/speakup_apollo.c | 8 +-
|
||
drivers/staging/speakup/speakup_audptr.c | 2 +-
|
||
drivers/staging/speakup/speakup_bns.c | 2 +-
|
||
drivers/staging/speakup/speakup_decext.c | 6 +-
|
||
drivers/staging/speakup/speakup_decpc.c | 4 +-
|
||
drivers/staging/speakup/speakup_dectlk.c | 6 +-
|
||
drivers/staging/speakup/speakup_dtlk.c | 4 +-
|
||
drivers/staging/speakup/speakup_dummy.c | 2 +-
|
||
drivers/staging/speakup/speakup_keypc.c | 6 +-
|
||
drivers/staging/speakup/speakup_ltlk.c | 2 +-
|
||
drivers/staging/speakup/speakup_soft.c | 2 +-
|
||
drivers/staging/speakup/speakup_spkout.c | 2 +-
|
||
drivers/staging/speakup/speakup_txprt.c | 2 +-
|
||
drivers/staging/speakup/spk_priv.h | 8 +-
|
||
drivers/staging/speakup/synth.c | 38 +-
|
||
drivers/staging/speakup/thread.c | 4 +-
|
||
drivers/staging/speakup/varhandlers.c | 66 ++--
|
||
drivers/staging/tidspbridge/Kconfig | 2 +-
|
||
drivers/staging/tidspbridge/core/dsp-clock.c | 4 +-
|
||
drivers/staging/vt6656/baseband.c | 14 +-
|
||
drivers/staging/vt6656/rndis.h | 1 +
|
||
drivers/staging/wlags49_h2/wl_priv.c | 9 +-
|
||
drivers/target/iscsi/iscsi_target.c | 42 ++-
|
||
drivers/target/iscsi/iscsi_target_auth.c | 15 +-
|
||
drivers/target/iscsi/iscsi_target_login.c | 8 +-
|
||
drivers/target/iscsi/iscsi_target_nego.c | 12 +-
|
||
drivers/target/iscsi/iscsi_target_parameters.c | 2 +-
|
||
drivers/target/target_core_alua.c | 6 +-
|
||
drivers/target/target_core_file.c | 90 +++--
|
||
drivers/target/target_core_file.h | 2 +-
|
||
drivers/target/target_core_pscsi.c | 8 +-
|
||
drivers/target/target_core_rd.c | 2 +-
|
||
drivers/target/target_core_transport.c | 5 +-
|
||
drivers/target/tcm_fc/tfc_sess.c | 1 +
|
||
drivers/tty/hvc/hvc_console.c | 8 +-
|
||
drivers/tty/n_gsm.c | 89 +++--
|
||
drivers/tty/serial/8250/8250.c | 36 +-
|
||
drivers/tty/serial/8250/8250.h | 1 +
|
||
drivers/tty/serial/8250/8250_pci.c | 59 ++-
|
||
drivers/tty/serial/atmel_serial.c | 20 +-
|
||
drivers/tty/serial/imx.c | 18 +-
|
||
drivers/tty/serial/of_serial.c | 6 +
|
||
drivers/tty/serial/pch_uart.c | 5 +-
|
||
drivers/tty/serial/pmac_zilog.c | 3 +
|
||
drivers/tty/serial/sunsab.c | 9 +
|
||
drivers/tty/tty_buffer.c | 11 +-
|
||
drivers/usb/class/cdc-acm.c | 126 ++++---
|
||
drivers/usb/class/cdc-acm.h | 2 +-
|
||
drivers/usb/class/cdc-wdm.c | 8 +-
|
||
drivers/usb/core/config.c | 7 -
|
||
drivers/usb/core/driver.c | 103 +++--
|
||
drivers/usb/core/hcd-pci.c | 2 +-
|
||
drivers/usb/core/hub.c | 81 ++--
|
||
drivers/usb/core/quirks.c | 9 +
|
||
drivers/usb/core/usb.h | 2 +-
|
||
drivers/usb/dwc3/core.c | 5 +-
|
||
drivers/usb/dwc3/core.h | 6 +-
|
||
drivers/usb/dwc3/dwc3-pci.c | 4 +
|
||
drivers/usb/dwc3/gadget.c | 20 +-
|
||
drivers/usb/gadget/at91_udc.c | 10 -
|
||
drivers/usb/gadget/composite.c | 1 +
|
||
drivers/usb/gadget/f_fs.c | 12 +-
|
||
drivers/usb/gadget/inode.c | 2 +-
|
||
drivers/usb/host/ehci-pci.c | 2 +-
|
||
drivers/usb/host/ehci-q.c | 16 +-
|
||
drivers/usb/host/ehci-sched.c | 4 +-
|
||
drivers/usb/host/ohci-pci.c | 2 +-
|
||
drivers/usb/host/pci-quirks.c | 19 +-
|
||
drivers/usb/host/uhci-pci.c | 2 +-
|
||
drivers/usb/host/xhci-hub.c | 8 +-
|
||
drivers/usb/host/xhci-mem.c | 20 +-
|
||
drivers/usb/host/xhci-pci.c | 9 +-
|
||
drivers/usb/host/xhci-ring.c | 5 +-
|
||
drivers/usb/host/xhci.c | 13 +-
|
||
drivers/usb/misc/adutux.c | 2 +-
|
||
drivers/usb/misc/sisusbvga/sisusb.c | 1 +
|
||
drivers/usb/misc/usbtest.c | 40 +-
|
||
drivers/usb/musb/musb_gadget.c | 22 +-
|
||
drivers/usb/serial/ark3116.c | 10 +-
|
||
drivers/usb/serial/ch341.c | 11 +-
|
||
drivers/usb/serial/cp210x.c | 2 +
|
||
drivers/usb/serial/cypress_m8.c | 14 +-
|
||
drivers/usb/serial/cypress_m8.h | 2 +-
|
||
drivers/usb/serial/ftdi_sio.c | 125 +++++--
|
||
drivers/usb/serial/ftdi_sio_ids.h | 83 ++++-
|
||
drivers/usb/serial/generic.c | 9 +-
|
||
drivers/usb/serial/io_edgeport.c | 12 +-
|
||
drivers/usb/serial/io_ti.c | 64 ++--
|
||
drivers/usb/serial/io_usbvend.h | 2 +-
|
||
drivers/usb/serial/keyspan.c | 2 +-
|
||
drivers/usb/serial/mct_u232.c | 13 +-
|
||
drivers/usb/serial/mos7840.c | 96 +++--
|
||
drivers/usb/serial/option.c | 415 ++++++++++++++++++++-
|
||
drivers/usb/serial/oti6858.c | 10 +-
|
||
drivers/usb/serial/pl2303.c | 57 +--
|
||
drivers/usb/serial/pl2303.h | 6 +-
|
||
drivers/usb/serial/sierra.c | 64 +++-
|
||
drivers/usb/serial/spcp8x5.c | 49 ++-
|
||
drivers/usb/serial/ssu100.c | 12 +-
|
||
drivers/usb/serial/ti_usb_3410_5052.c | 20 +-
|
||
drivers/usb/serial/usb-serial.c | 36 +-
|
||
drivers/usb/serial/usb_wwan.c | 80 ++--
|
||
drivers/usb/serial/whiteheat.c | 7 +-
|
||
drivers/usb/storage/Kconfig | 4 +-
|
||
drivers/usb/storage/scsiglue.c | 6 +
|
||
drivers/usb/storage/shuttle_usbat.c | 2 +-
|
||
drivers/usb/storage/unusual_cypress.h | 2 +-
|
||
drivers/usb/storage/unusual_devs.h | 66 ++++
|
||
drivers/usb/wusbcore/wa-rpipe.c | 5 +-
|
||
drivers/usb/wusbcore/wa-xfer.c | 5 +-
|
||
drivers/uwb/lc-dev.c | 13 +-
|
||
drivers/vhost/net.c | 20 +-
|
||
drivers/video/aty/mach64_accel.c | 3 +-
|
||
drivers/video/aty/mach64_cursor.c | 22 +-
|
||
drivers/video/backlight/atmel-pwm-bl.c | 7 +-
|
||
drivers/video/cfbcopyarea.c | 153 ++++----
|
||
drivers/video/console/vgacon.c | 17 +-
|
||
drivers/video/kyro/fbdev.c | 6 +-
|
||
drivers/video/matrox/matroxfb_accel.c | 38 +-
|
||
drivers/video/matrox/matroxfb_base.h | 4 +-
|
||
drivers/video/omap2/omapfb/omapfb-main.c | 2 +-
|
||
drivers/video/tgafb.c | 279 ++++----------
|
||
drivers/virtio/virtio_balloon.c | 6 +
|
||
drivers/w1/w1_netlink.c | 25 +-
|
||
drivers/watchdog/sc1200wdt.c | 3 +-
|
||
drivers/watchdog/sp805_wdt.c | 4 +-
|
||
drivers/xen/events.c | 11 +
|
||
drivers/xen/manage.c | 7 -
|
||
fs/btrfs/backref.c | 2 +-
|
||
fs/btrfs/compression.c | 2 +
|
||
fs/btrfs/extent-tree.c | 2 +-
|
||
fs/btrfs/extent_io.c | 3 +-
|
||
fs/btrfs/volumes.c | 5 +-
|
||
fs/buffer.c | 12 +-
|
||
fs/cachefiles/rdwr.c | 2 +-
|
||
fs/ceph/addr.c | 8 +-
|
||
fs/ceph/mds_client.c | 8 +-
|
||
fs/ceph/snap.c | 2 +-
|
||
fs/cifs/cifs_unicode.c | 7 +-
|
||
fs/cifs/cifsfs.c | 24 ++
|
||
fs/cifs/cifsfs.h | 4 +
|
||
fs/cifs/cifssmb.c | 8 +-
|
||
fs/cifs/file.c | 45 ++-
|
||
fs/cifs/inode.c | 6 +
|
||
fs/cifs/readdir.c | 8 +
|
||
fs/cifs/transport.c | 7 +
|
||
fs/configfs/dir.c | 16 +-
|
||
fs/dcache.c | 16 +-
|
||
fs/devpts/inode.c | 1 +
|
||
fs/ecryptfs/keystore.c | 3 +-
|
||
fs/exec.c | 9 +
|
||
fs/exofs/ore.c | 37 +-
|
||
fs/ext2/inode.c | 2 +
|
||
fs/ext2/xip.c | 1 +
|
||
fs/ext3/dir.c | 167 ++++++---
|
||
fs/ext3/ext3.h | 6 +-
|
||
fs/ext3/hash.c | 4 +-
|
||
fs/ext4/ext4.h | 4 +-
|
||
fs/ext4/extents.c | 44 ++-
|
||
fs/ext4/file.c | 2 +-
|
||
fs/ext4/fsync.c | 3 +-
|
||
fs/ext4/indirect.c | 9 +-
|
||
fs/ext4/inode.c | 29 +-
|
||
fs/ext4/mballoc.c | 13 +-
|
||
fs/ext4/mmp.c | 2 +
|
||
fs/ext4/namei.c | 32 +-
|
||
fs/ext4/page-io.c | 9 +-
|
||
fs/ext4/resize.c | 12 +-
|
||
fs/ext4/super.c | 27 +-
|
||
fs/ext4/xattr.c | 4 +-
|
||
fs/file.c | 2 +-
|
||
fs/fuse/dir.c | 9 +-
|
||
fs/fuse/file.c | 8 +-
|
||
fs/fuse/fuse_i.h | 9 +
|
||
fs/fuse/inode.c | 4 +-
|
||
fs/gfs2/aops.c | 30 ++
|
||
fs/gfs2/ops_fstype.c | 12 +-
|
||
fs/hpfs/dir.c | 10 +-
|
||
fs/hpfs/file.c | 5 +-
|
||
fs/isofs/inode.c | 15 +-
|
||
fs/isofs/isofs.h | 23 +-
|
||
fs/isofs/rock.c | 39 +-
|
||
fs/jbd2/journal.c | 31 ++
|
||
fs/jbd2/transaction.c | 6 +-
|
||
fs/jffs2/compr_rtime.c | 4 +-
|
||
fs/jffs2/nodelist.h | 2 +-
|
||
fs/jffs2/nodemgmt.c | 14 +-
|
||
fs/jfs/jfs_inode.c | 3 +-
|
||
fs/lockd/svclock.c | 8 +
|
||
fs/locks.c | 7 +-
|
||
fs/namei.c | 30 +-
|
||
fs/namespace.c | 4 +-
|
||
fs/ncpfs/dir.c | 9 -
|
||
fs/nfs/blocklayout/extents.c | 2 +-
|
||
fs/nfs/callback_xdr.c | 6 +-
|
||
fs/nfs/delegation.c | 11 +-
|
||
fs/nfs/inode.c | 2 +
|
||
fs/nfs/nfs3proc.c | 6 +-
|
||
fs/nfs/nfs4filelayout.c | 1 -
|
||
fs/nfs/nfs4proc.c | 87 ++---
|
||
fs/nfs/nfs4state.c | 35 +-
|
||
fs/nfs/nfs4xdr.c | 47 ++-
|
||
fs/nfs/pnfs.c | 19 +-
|
||
fs/nfs/proc.c | 43 ---
|
||
fs/nfs/write.c | 10 +-
|
||
fs/nfsd/nfs4acl.c | 17 +-
|
||
fs/nfsd/nfs4proc.c | 26 +-
|
||
fs/nfsd/nfs4state.c | 15 +-
|
||
fs/nfsd/nfs4xdr.c | 24 +-
|
||
fs/nfsd/nfsctl.c | 62 ++-
|
||
fs/nfsd/nfsd.h | 6 +-
|
||
fs/nfsd/nfssvc.c | 42 +--
|
||
fs/nfsd/vfs.c | 188 ++++++----
|
||
fs/nilfs2/inode.c | 7 +-
|
||
fs/nilfs2/page.c | 2 +
|
||
fs/nilfs2/segment.c | 21 +-
|
||
fs/ocfs2/buffer_head_io.c | 2 -
|
||
fs/ocfs2/dlm/dlmmaster.c | 18 +-
|
||
fs/ocfs2/dlm/dlmrecovery.c | 29 +-
|
||
fs/ocfs2/file.c | 8 +-
|
||
fs/ocfs2/quota_global.c | 27 +-
|
||
fs/ocfs2/quota_local.c | 4 -
|
||
fs/pnode.c | 4 +-
|
||
fs/posix_acl.c | 6 +
|
||
fs/proc/array.c | 2 +-
|
||
fs/proc/base.c | 1 +
|
||
fs/proc/inode.c | 12 +-
|
||
fs/quota/dquot.c | 14 +-
|
||
fs/reiserfs/dir.c | 6 +-
|
||
fs/stat.c | 5 +-
|
||
fs/ubifs/orphan.c | 5 +-
|
||
fs/ubifs/shrinker.c | 1 -
|
||
fs/ubifs/ubifs.h | 2 +
|
||
fs/xfs/xfs_ioctl.c | 3 +-
|
||
fs/xfs/xfs_ioctl32.c | 3 +-
|
||
include/crypto/scatterwalk.h | 3 +-
|
||
include/drm/drm_mem_util.h | 4 +-
|
||
include/drm/drm_mode.h | 2 +
|
||
include/drm/drm_pciids.h | 2 +-
|
||
include/linux/audit.h | 2 +-
|
||
include/linux/binfmts.h | 3 -
|
||
include/linux/bitops.h | 15 +
|
||
include/linux/cgroup.h | 53 ++-
|
||
include/linux/compiler-gcc.h | 3 +
|
||
include/linux/compiler-gcc4.h | 16 +
|
||
include/linux/compiler-intel.h | 2 -
|
||
include/linux/cpuset.h | 4 +-
|
||
include/linux/efi.h | 16 +-
|
||
include/linux/firewire.h | 1 +
|
||
include/linux/fs.h | 2 +
|
||
include/linux/ftrace.h | 2 +
|
||
include/linux/hid.h | 2 +-
|
||
include/linux/hidraw.h | 4 +-
|
||
include/linux/idr.h | 11 +
|
||
include/linux/if_team.h | 1 +
|
||
include/linux/irqdesc.h | 4 +
|
||
include/linux/jbd2.h | 1 +
|
||
include/linux/jiffies.h | 20 +-
|
||
include/linux/kernel.h | 1 +
|
||
include/linux/libata.h | 2 +
|
||
include/linux/mempolicy.h | 2 +-
|
||
include/linux/mm_types.h | 1 +
|
||
include/linux/msg.h | 6 +-
|
||
include/linux/mtd/map.h | 4 +-
|
||
include/linux/mv643xx_eth.h | 2 +
|
||
include/linux/nbd.h | 1 +
|
||
include/linux/net.h | 56 ++-
|
||
include/linux/netdevice.h | 9 +
|
||
include/linux/pci_ids.h | 1 +
|
||
include/linux/perf_event.h | 12 +-
|
||
include/linux/pps_kernel.h | 17 +-
|
||
include/linux/printk.h | 6 +-
|
||
include/linux/ptrace.h | 3 +
|
||
include/linux/random.h | 6 +-
|
||
include/linux/sched.h | 47 ++-
|
||
include/linux/serial_core.h | 6 +-
|
||
include/linux/skbuff.h | 45 ++-
|
||
include/linux/slab.h | 2 +-
|
||
include/linux/sunrpc/svcsock.h | 1 +
|
||
include/linux/tracepoint.h | 6 +
|
||
include/linux/usb.h | 16 +
|
||
include/linux/usb/hcd.h | 2 +-
|
||
include/linux/usb/serial.h | 2 +
|
||
include/linux/virtio_console.h | 2 +-
|
||
include/net/cipso_ipv4.h | 6 +-
|
||
include/net/dst.h | 12 +
|
||
include/net/inetpeer.h | 9 +-
|
||
include/net/mac80211.h | 5 +
|
||
include/net/regulatory.h | 2 +-
|
||
include/scsi/osd_ore.h | 1 +
|
||
include/sound/memalloc.h | 2 +-
|
||
include/trace/events/block.h | 33 +-
|
||
include/trace/events/module.h | 2 +-
|
||
include/trace/ftrace.h | 5 +-
|
||
include/trace/syscall.h | 15 +
|
||
include/xen/interface/io/netif.h | 19 +
|
||
include/xen/interface/io/ring.h | 5 +
|
||
init/Kconfig | 1 +
|
||
init/main.c | 4 +
|
||
ipc/msg.c | 2 +
|
||
ipc/msgutil.c | 12 +-
|
||
ipc/util.h | 4 +-
|
||
kernel/audit.c | 7 +-
|
||
kernel/auditsc.c | 27 +-
|
||
kernel/cgroup.c | 55 ++-
|
||
kernel/cgroup_freezer.c | 13 +-
|
||
kernel/cpuset.c | 27 +-
|
||
kernel/events/core.c | 65 +++-
|
||
kernel/events/ring_buffer.c | 31 +-
|
||
kernel/exit.c | 15 +-
|
||
kernel/fork.c | 16 +-
|
||
kernel/futex.c | 8 +-
|
||
kernel/hrtimer.c | 30 +-
|
||
kernel/irq/irqdesc.c | 1 +
|
||
kernel/irq/manage.c | 4 +-
|
||
kernel/irq/spurious.c | 106 +++++-
|
||
kernel/module.c | 3 +
|
||
kernel/power/process.c | 1 +
|
||
kernel/power/snapshot.c | 6 +-
|
||
kernel/printk.c | 4 +-
|
||
kernel/ptrace.c | 3 +-
|
||
kernel/rtmutex-debug.h | 5 +
|
||
kernel/rtmutex.c | 252 +++++++++++--
|
||
kernel/rtmutex.h | 5 +
|
||
kernel/sched/core.c | 134 +++++--
|
||
kernel/sched/cpupri.c | 3 +-
|
||
kernel/sched/debug.c | 8 +
|
||
kernel/sched/fair.c | 60 ++-
|
||
kernel/sched/rt.c | 35 +-
|
||
kernel/sched/sched.h | 5 +-
|
||
kernel/sysctl.c | 6 +
|
||
kernel/time.c | 54 +--
|
||
kernel/time/alarmtimer.c | 21 +-
|
||
kernel/time/clockevents.c | 75 +++-
|
||
kernel/time/jiffies.c | 6 +
|
||
kernel/time/tick-sched.c | 1 +
|
||
kernel/time/timekeeping.c | 12 +-
|
||
kernel/timer.c | 2 +-
|
||
kernel/trace/blktrace.c | 20 +-
|
||
kernel/trace/ftrace.c | 274 +++++++++-----
|
||
kernel/trace/ring_buffer.c | 7 +
|
||
kernel/trace/trace.c | 13 +-
|
||
kernel/trace/trace_event_perf.c | 2 +-
|
||
kernel/trace/trace_events.c | 10 +
|
||
kernel/tracepoint.c | 13 +-
|
||
kernel/workqueue.c | 16 +
|
||
lib/Makefile | 1 +
|
||
lib/btree.c | 1 +
|
||
lib/idr.c | 36 +-
|
||
lib/lzo/lzo1x_decompress_safe.c | 62 +--
|
||
lib/nlattr.c | 15 +-
|
||
lib/random32.c | 14 +-
|
||
lib/scatterlist.c | 3 +-
|
||
lib/vsprintf.c | 36 +-
|
||
mm/hugetlb.c | 72 ++--
|
||
mm/kmemleak.c | 4 +-
|
||
mm/memory-failure.c | 58 +--
|
||
mm/memory.c | 5 +
|
||
mm/mempolicy.c | 63 ++--
|
||
mm/migrate.c | 5 +-
|
||
mm/mlock.c | 2 +
|
||
mm/page-writeback.c | 15 +-
|
||
mm/page_alloc.c | 49 ++-
|
||
mm/percpu-vm.c | 22 +-
|
||
mm/percpu.c | 4 +-
|
||
mm/rmap.c | 29 +-
|
||
mm/shmem.c | 143 ++++++-
|
||
mm/slab.c | 8 +-
|
||
mm/slub.c | 2 +-
|
||
mm/swap.c | 31 +-
|
||
mm/truncate.c | 25 --
|
||
mm/vmalloc.c | 14 +-
|
||
mm/vmscan.c | 3 +
|
||
net/8021q/vlan_core.c | 5 +-
|
||
net/8021q/vlan_dev.c | 22 +-
|
||
net/8021q/vlan_netlink.c | 2 +-
|
||
net/9p/trans_virtio.c | 3 +-
|
||
net/appletalk/ddp.c | 19 +-
|
||
net/atm/common.c | 2 -
|
||
net/ax25/af_ax25.c | 4 +-
|
||
net/bluetooth/af_bluetooth.c | 2 -
|
||
net/bluetooth/hci_sock.c | 2 -
|
||
net/bridge/br_if.c | 2 +
|
||
net/bridge/br_multicast.c | 10 +-
|
||
net/bridge/br_stp_if.c | 2 +-
|
||
net/bridge/netfilter/ebtables.c | 5 +-
|
||
net/caif/caif_socket.c | 4 -
|
||
net/ceph/auth_x.c | 256 +++++++------
|
||
net/ceph/mon_client.c | 8 +
|
||
net/ceph/osd_client.c | 30 +-
|
||
net/compat.c | 17 +-
|
||
net/core/dev.c | 8 +-
|
||
net/core/drop_monitor.c | 1 -
|
||
net/core/fib_rules.c | 7 +
|
||
net/core/filter.c | 6 +-
|
||
net/core/iovec.c | 7 +-
|
||
net/core/pktgen.c | 7 +
|
||
net/core/rtnetlink.c | 33 +-
|
||
net/core/skbuff.c | 43 ++-
|
||
net/core/sock.c | 2 +-
|
||
net/dns_resolver/dns_query.c | 4 +-
|
||
net/ieee802154/6lowpan.c | 4 +-
|
||
net/ipv4/datagram.c | 2 +-
|
||
net/ipv4/fib_semantics.c | 2 +-
|
||
net/ipv4/igmp.c | 10 +-
|
||
net/ipv4/inet_diag.c | 20 +-
|
||
net/ipv4/inet_hashtables.c | 2 +-
|
||
net/ipv4/ip_options.c | 4 +
|
||
net/ipv4/ip_output.c | 2 +-
|
||
net/ipv4/ipip.c | 1 +
|
||
net/ipv4/ipmr.c | 7 +-
|
||
net/ipv4/netfilter/arp_tables.c | 6 +-
|
||
net/ipv4/netfilter/ip_tables.c | 6 +-
|
||
net/ipv4/netfilter/nf_defrag_ipv4.c | 5 +-
|
||
net/ipv4/ping.c | 2 +-
|
||
net/ipv4/route.c | 62 ++-
|
||
net/ipv4/tcp_cubic.c | 2 +-
|
||
net/ipv4/tcp_input.c | 15 +-
|
||
net/ipv4/tcp_ipv4.c | 2 +-
|
||
net/ipv4/tcp_output.c | 15 +-
|
||
net/ipv4/tcp_vegas.c | 3 +-
|
||
net/ipv4/tcp_veno.c | 2 +-
|
||
net/ipv4/udp.c | 5 +-
|
||
net/ipv6/addrconf.c | 19 +-
|
||
net/ipv6/datagram.c | 1 +
|
||
net/ipv6/icmp.c | 2 +-
|
||
net/ipv6/inet6_hashtables.c | 2 +-
|
||
net/ipv6/ip6_output.c | 35 +-
|
||
net/ipv6/ip6_tunnel.c | 1 +
|
||
net/ipv6/ip6mr.c | 7 +-
|
||
net/ipv6/mcast.c | 11 +-
|
||
net/ipv6/netfilter/ip6_tables.c | 6 +-
|
||
net/ipv6/route.c | 21 +-
|
||
net/ipv6/sit.c | 1 +
|
||
net/ipv6/udp.c | 2 +-
|
||
net/ipx/af_ipx.c | 3 +-
|
||
net/irda/af_irda.c | 4 -
|
||
net/iucv/af_iucv.c | 2 -
|
||
net/key/af_key.c | 1 -
|
||
net/l2tp/l2tp_ppp.c | 11 +-
|
||
net/llc/af_llc.c | 7 +-
|
||
net/mac80211/debugfs_netdev.c | 6 +-
|
||
net/mac80211/ieee80211_i.h | 3 +
|
||
net/mac80211/rx.c | 6 +-
|
||
net/mac80211/scan.c | 19 +
|
||
net/mac80211/sta_info.c | 4 +
|
||
net/mac80211/sta_info.h | 7 +-
|
||
net/mac80211/status.c | 9 +-
|
||
net/mac80211/tx.c | 17 +-
|
||
net/netfilter/nf_conntrack_sip.c | 2 +-
|
||
net/netlink/af_netlink.c | 2 -
|
||
net/netrom/af_netrom.c | 3 +-
|
||
net/nfc/rawsock.c | 2 -
|
||
net/packet/af_packet.c | 96 ++---
|
||
net/rds/ib.c | 3 +-
|
||
net/rds/ib_send.c | 5 +-
|
||
net/rds/iw.c | 3 +-
|
||
net/rds/recv.c | 2 -
|
||
net/rose/af_rose.c | 24 +-
|
||
net/rxrpc/ar-recvmsg.c | 9 +-
|
||
net/sched/act_mirred.c | 11 +-
|
||
net/sctp/associola.c | 3 +-
|
||
net/sctp/output.c | 5 +-
|
||
net/sctp/sm_make_chunk.c | 4 +-
|
||
net/sctp/sm_statefuns.c | 10 +-
|
||
net/sctp/socket.c | 83 ++++-
|
||
net/sctp/ulpevent.c | 122 +-----
|
||
net/socket.c | 50 ++-
|
||
net/sunrpc/clnt.c | 9 +-
|
||
net/sunrpc/sched.c | 13 +-
|
||
net/sunrpc/svcsock.c | 16 +
|
||
net/sunrpc/xprtsock.c | 34 +-
|
||
net/tipc/bcast.c | 1 +
|
||
net/tipc/socket.c | 6 -
|
||
net/unix/af_unix.c | 48 ++-
|
||
net/unix/diag.c | 1 +
|
||
net/wireless/radiotap.c | 11 +-
|
||
net/wireless/sme.c | 3 +
|
||
net/x25/af_x25.c | 3 +-
|
||
scripts/mod/file2alias.c | 4 +-
|
||
scripts/mod/modpost.c | 8 +-
|
||
scripts/package/builddeb | 9 +-
|
||
scripts/recordmcount.h | 4 +-
|
||
scripts/tags.sh | 10 +-
|
||
security/integrity/evm/evm_main.c | 12 +-
|
||
security/integrity/ima/ima_policy.c | 1 -
|
||
security/selinux/hooks.c | 182 +++++++--
|
||
security/selinux/include/xfrm.h | 9 +-
|
||
security/selinux/netlabel.c | 6 +-
|
||
security/selinux/ss/policydb.c | 22 +-
|
||
security/selinux/xfrm.c | 53 ++-
|
||
sound/arm/pxa2xx-pcm-lib.c | 2 +
|
||
sound/core/compress_offload.c | 2 +-
|
||
sound/core/pcm_lib.c | 8 +-
|
||
sound/drivers/aloop.c | 5 +-
|
||
sound/drivers/pcsp/pcsp.c | 2 +-
|
||
sound/i2c/other/ak4xxx-adda.c | 2 +-
|
||
sound/isa/msnd/msnd_pinnacle.c | 4 +-
|
||
sound/pci/Kconfig | 12 +
|
||
sound/pci/asihpi/asihpi.c | 3 +
|
||
sound/pci/atiixp.c | 2 +
|
||
sound/pci/atiixp_modem.c | 2 +
|
||
sound/pci/hda/hda_intel.c | 40 +-
|
||
sound/pci/hda/patch_conexant.c | 134 +++++--
|
||
sound/pci/hda/patch_hdmi.c | 57 ++-
|
||
sound/pci/hda/patch_realtek.c | 34 +-
|
||
sound/pci/ice1712/ice1712.c | 15 +-
|
||
sound/pci/oxygen/xonar_dg.c | 12 +-
|
||
sound/pci/rme9652/rme9652.c | 2 +-
|
||
sound/soc/blackfin/bf5xx-i2s.c | 1 +
|
||
sound/soc/codecs/adau1701.c | 2 +-
|
||
sound/soc/codecs/ak4642.c | 2 +-
|
||
sound/soc/codecs/cs42l73.c | 6 +-
|
||
sound/soc/codecs/sgtl5000.c | 2 +-
|
||
sound/soc/codecs/sta32x.c | 74 ++--
|
||
sound/soc/codecs/wm8731.c | 4 +-
|
||
sound/soc/codecs/wm8770.c | 4 +-
|
||
sound/soc/codecs/wm8904.c | 2 +-
|
||
sound/soc/codecs/wm8958-dsp2.c | 2 +-
|
||
sound/soc/codecs/wm8962.c | 17 +-
|
||
sound/soc/codecs/wm8962.h | 4 +
|
||
sound/soc/codecs/wm8990.c | 2 +
|
||
sound/soc/codecs/wm_hubs.c | 1 +
|
||
sound/soc/imx/imx-ssi.c | 5 +
|
||
sound/soc/pxa/pxa-ssp.c | 4 +-
|
||
sound/soc/s6000/s6000-pcm.c | 2 +
|
||
sound/soc/samsung/i2s.c | 2 +-
|
||
sound/soc/soc-dapm.c | 2 +-
|
||
sound/usb/6fire/chip.c | 2 +-
|
||
sound/usb/6fire/midi.c | 16 +-
|
||
sound/usb/6fire/midi.h | 6 +-
|
||
sound/usb/6fire/pcm.c | 53 ++-
|
||
sound/usb/6fire/pcm.h | 2 +-
|
||
sound/usb/mixer.c | 1 +
|
||
sound/usb/usx2y/usbusx2yaudio.c | 4 +
|
||
tools/perf/util/parse-events.c | 2 +-
|
||
tools/power/x86/turbostat/turbostat.c | 11 +-
|
||
tools/usb/ffs-test.c | 4 +-
|
||
virt/kvm/coalesced_mmio.c | 8 +-
|
||
virt/kvm/iommu.c | 23 +-
|
||
virt/kvm/irq_comm.c | 1 +
|
||
virt/kvm/kvm_main.c | 28 +-
|
||
1152 files changed, 13814 insertions(+), 6068 deletions(-)
|
||
delete mode 100644 arch/arm/include/asm/a.out-core.h
|
||
delete mode 100644 arch/arm/include/asm/a.out.h
|
||
create mode 100644 arch/x86/include/asm/espfix.h
|
||
create mode 100644 arch/x86/kernel/espfix_64.c
|
||
create mode 100644 drivers/md/dm-builtin.c
|
||
|
||
diff --git a/Documentation/cgroups/cpusets.txt b/Documentation/cgroups/cpusets.txt
|
||
index cefd3d8..a52a39f 100644
|
||
--- a/Documentation/cgroups/cpusets.txt
|
||
+++ b/Documentation/cgroups/cpusets.txt
|
||
@@ -345,14 +345,14 @@ the named feature on.
|
||
The implementation is simple.
|
||
|
||
Setting the flag 'cpuset.memory_spread_page' turns on a per-process flag
|
||
-PF_SPREAD_PAGE for each task that is in that cpuset or subsequently
|
||
+PFA_SPREAD_PAGE for each task that is in that cpuset or subsequently
|
||
joins that cpuset. The page allocation calls for the page cache
|
||
-is modified to perform an inline check for this PF_SPREAD_PAGE task
|
||
+is modified to perform an inline check for this PFA_SPREAD_PAGE task
|
||
flag, and if set, a call to a new routine cpuset_mem_spread_node()
|
||
returns the node to prefer for the allocation.
|
||
|
||
Similarly, setting 'cpuset.memory_spread_slab' turns on the flag
|
||
-PF_SPREAD_SLAB, and appropriately marked slab caches will allocate
|
||
+PFA_SPREAD_SLAB, and appropriately marked slab caches will allocate
|
||
pages from the node returned by cpuset_mem_spread_node().
|
||
|
||
The cpuset_mem_spread_node() routine is also simple. It uses the
|
||
diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
|
||
index ab22fe6..e39a0c0 100644
|
||
--- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
|
||
+++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
|
||
@@ -10,8 +10,8 @@ Required properties:
|
||
|
||
Optional properties:
|
||
- fsl,card-wired : Indicate the card is wired to host permanently
|
||
-- fsl,cd-internal : Indicate to use controller internal card detection
|
||
-- fsl,wp-internal : Indicate to use controller internal write protection
|
||
+- fsl,cd-controller : Indicate to use controller internal card detection
|
||
+- fsl,wp-controller : Indicate to use controller internal write protection
|
||
- cd-gpios : Specify GPIOs for card detection
|
||
- wp-gpios : Specify GPIOs for write protection
|
||
|
||
@@ -21,8 +21,8 @@ esdhc@70004000 {
|
||
compatible = "fsl,imx51-esdhc";
|
||
reg = <0x70004000 0x4000>;
|
||
interrupts = <1>;
|
||
- fsl,cd-internal;
|
||
- fsl,wp-internal;
|
||
+ fsl,cd-controller;
|
||
+ fsl,wp-controller;
|
||
};
|
||
|
||
esdhc@70008000 {
|
||
diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
|
||
index b8b27b0..3f89cbd 100644
|
||
--- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt
|
||
+++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
|
||
@@ -10,6 +10,9 @@ Required properties:
|
||
- "ns16850"
|
||
- "nvidia,tegra20-uart"
|
||
- "ibm,qpace-nwp-serial"
|
||
+ - "altr,16550-FIFO32"
|
||
+ - "altr,16550-FIFO64"
|
||
+ - "altr,16550-FIFO128"
|
||
- "serial" if the port type is unknown.
|
||
- reg : offset and length of the register set for the device.
|
||
- interrupts : should contain uart interrupt.
|
||
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
|
||
index 84d46c0..eb5502e 100644
|
||
--- a/Documentation/hwmon/coretemp
|
||
+++ b/Documentation/hwmon/coretemp
|
||
@@ -6,7 +6,9 @@ Supported chips:
|
||
Prefix: 'coretemp'
|
||
CPUID: family 0x6, models 0xe (Pentium M DC), 0xf (Core 2 DC 65nm),
|
||
0x16 (Core 2 SC 65nm), 0x17 (Penryn 45nm),
|
||
- 0x1a (Nehalem), 0x1c (Atom), 0x1e (Lynnfield)
|
||
+ 0x1a (Nehalem), 0x1c (Atom), 0x1e (Lynnfield),
|
||
+ 0x26 (Tunnel Creek Atom), 0x27 (Medfield Atom),
|
||
+ 0x36 (Cedar Trail Atom)
|
||
Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual
|
||
Volume 3A: System Programming Guide
|
||
http://softwarecommunity.intel.com/Wiki/Mobility/720.htm
|
||
@@ -65,6 +67,11 @@ Process Processor TjMax(C)
|
||
U3400 105
|
||
P4505/P4500 90
|
||
|
||
+32nm Atom Processors
|
||
+ Z2460 90
|
||
+ D2700/2550/2500 100
|
||
+ N2850/2800/2650/2600 100
|
||
+
|
||
45nm Xeon Processors 5400 Quad-Core
|
||
X5492, X5482, X5472, X5470, X5460, X5450 85
|
||
E5472, E5462, E5450/40/30/20/10/05 85
|
||
@@ -85,6 +92,9 @@ Process Processor TjMax(C)
|
||
N475/470/455/450 100
|
||
N280/270 90
|
||
330/230 125
|
||
+ E680/660/640/620 90
|
||
+ E680T/660T/640T/620T 110
|
||
+ CE4170/4150/4110 110
|
||
|
||
45nm Core2 Processors
|
||
Solo ULV SU3500/3300 100
|
||
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
|
||
index 99d4e44..8bb57d7 100644
|
||
--- a/Documentation/i2c/busses/i2c-i801
|
||
+++ b/Documentation/i2c/busses/i2c-i801
|
||
@@ -22,6 +22,7 @@ Supported adapters:
|
||
* Intel Panther Point (PCH)
|
||
* Intel Lynx Point (PCH)
|
||
* Intel Lynx Point-LP (PCH)
|
||
+ * Intel Avoton (SOC)
|
||
Datasheets: Publicly available at the Intel website
|
||
|
||
On Intel Patsburg and later chipsets, both the normal host SMBus controller
|
||
diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4
|
||
index 475bb4a..65da157 100644
|
||
--- a/Documentation/i2c/busses/i2c-piix4
|
||
+++ b/Documentation/i2c/busses/i2c-piix4
|
||
@@ -8,7 +8,7 @@ Supported adapters:
|
||
Datasheet: Only available via NDA from ServerWorks
|
||
* ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges
|
||
Datasheet: Not publicly available
|
||
- * AMD Hudson-2
|
||
+ * AMD Hudson-2, CZ
|
||
Datasheet: Not publicly available
|
||
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
|
||
Datasheet: Publicly available at the SMSC website http://www.smsc.com
|
||
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
|
||
index 050d37f..46ed735 100644
|
||
--- a/Documentation/ja_JP/HOWTO
|
||
+++ b/Documentation/ja_JP/HOWTO
|
||
@@ -315,7 +315,7 @@ Andrew Morton が Linux-kernel メーリングリストにカーネルリリー
|
||
もし、2.6.x.y カーネルが存在しない場合には、番号が一番大きい 2.6.x が
|
||
最新の安定版カーネルです。
|
||
|
||
-2.6.x.y は "stable" チーム <stable@kernel.org> でメンテされており、必
|
||
+2.6.x.y は "stable" チーム <stable@vger.kernel.org> でメンテされており、必
|
||
要に応じてリリースされます。通常のリリース期間は 2週間毎ですが、差し迫っ
|
||
た問題がなければもう少し長くなることもあります。セキュリティ関連の問題
|
||
の場合はこれに対してだいたいの場合、すぐにリリースがされます。
|
||
diff --git a/Documentation/ja_JP/stable_kernel_rules.txt b/Documentation/ja_JP/stable_kernel_rules.txt
|
||
index 1426583..9dbda9b 100644
|
||
--- a/Documentation/ja_JP/stable_kernel_rules.txt
|
||
+++ b/Documentation/ja_JP/stable_kernel_rules.txt
|
||
@@ -50,16 +50,16 @@ linux-2.6.29/Documentation/stable_kernel_rules.txt
|
||
|
||
-stable ツリーにパッチを送付する手続き-
|
||
|
||
- - 上記の規則に従っているかを確認した後に、stable@kernel.org にパッチ
|
||
+ - 上記の規則に従っているかを確認した後に、stable@vger.kernel.org にパッチ
|
||
を送る。
|
||
- 送信者はパッチがキューに受け付けられた際には ACK を、却下された場合
|
||
には NAK を受け取る。この反応は開発者たちのスケジュールによって、数
|
||
日かかる場合がある。
|
||
- もし受け取られたら、パッチは他の開発者たちと関連するサブシステムの
|
||
メンテナーによるレビューのために -stable キューに追加される。
|
||
- - パッチに stable@kernel.org のアドレスが付加されているときには、それ
|
||
+ - パッチに stable@vger.kernel.org のアドレスが付加されているときには、それ
|
||
が Linus のツリーに入る時に自動的に stable チームに email される。
|
||
- - セキュリティパッチはこのエイリアス (stable@kernel.org) に送られるべ
|
||
+ - セキュリティパッチはこのエイリアス (stable@vger.kernel.org) に送られるべ
|
||
きではなく、代わりに security@kernel.org のアドレスに送られる。
|
||
|
||
レビューサイクル-
|
||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
|
||
index ae6c99a..719a853 100644
|
||
--- a/Documentation/kernel-parameters.txt
|
||
+++ b/Documentation/kernel-parameters.txt
|
||
@@ -782,6 +782,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||
edd= [EDD]
|
||
Format: {"off" | "on" | "skip[mbr]"}
|
||
|
||
+ efi_no_storage_paranoia [EFI; X86]
|
||
+ Using this parameter you can use more than 50% of
|
||
+ your efi variable storage. Use this parameter only if
|
||
+ you are really sure that your UEFI does sane gc and
|
||
+ fulfills the spec otherwise your board may brick.
|
||
+
|
||
eisa_irq_edge= [PARISC,HW]
|
||
See header of drivers/parisc/eisa.c.
|
||
|
||
@@ -996,6 +1002,20 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||
i8k.restricted [HW] Allow controlling fans only if SYS_ADMIN
|
||
capability is set.
|
||
|
||
+ i915.invert_brightness=
|
||
+ [DRM] Invert the sense of the variable that is used to
|
||
+ set the brightness of the panel backlight. Normally a
|
||
+ brightness value of 0 indicates backlight switched off,
|
||
+ and the maximum of the brightness value sets the backlight
|
||
+ to maximum brightness. If this parameter is set to 0
|
||
+ (default) and the machine requires it, or this parameter
|
||
+ is set to 1, a brightness value of 0 sets the backlight
|
||
+ to maximum brightness, and the maximum of the brightness
|
||
+ value switches the backlight off.
|
||
+ -1 -- never invert brightness
|
||
+ 0 -- machine default
|
||
+ 1 -- force brightness inversion
|
||
+
|
||
icn= [HW,ISDN]
|
||
Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]]
|
||
|
||
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
|
||
index b0714d8..8dfb6a5 100644
|
||
--- a/Documentation/stable_kernel_rules.txt
|
||
+++ b/Documentation/stable_kernel_rules.txt
|
||
@@ -29,6 +29,9 @@ Rules on what kind of patches are accepted, and which ones are not, into the
|
||
|
||
Procedure for submitting patches to the -stable tree:
|
||
|
||
+ - If the patch covers files in net/ or drivers/net please follow netdev stable
|
||
+ submission guidelines as described in
|
||
+ Documentation/networking/netdev-FAQ.txt
|
||
- Send the patch, after verifying that it follows the above rules, to
|
||
stable@vger.kernel.org. You must note the upstream commit ID in the
|
||
changelog of your submission, as well as the kernel version you wish
|
||
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
|
||
index 8a20b47..839572d 100644
|
||
--- a/Documentation/sysctl/kernel.txt
|
||
+++ b/Documentation/sysctl/kernel.txt
|
||
@@ -309,13 +309,24 @@ Default value is "/sbin/hotplug".
|
||
kptr_restrict:
|
||
|
||
This toggle indicates whether restrictions are placed on
|
||
-exposing kernel addresses via /proc and other interfaces. When
|
||
-kptr_restrict is set to (0), there are no restrictions. When
|
||
-kptr_restrict is set to (1), the default, kernel pointers
|
||
-printed using the %pK format specifier will be replaced with 0's
|
||
-unless the user has CAP_SYSLOG. When kptr_restrict is set to
|
||
-(2), kernel pointers printed using %pK will be replaced with 0's
|
||
-regardless of privileges.
|
||
+exposing kernel addresses via /proc and other interfaces.
|
||
+
|
||
+When kptr_restrict is set to (0), the default, there are no restrictions.
|
||
+
|
||
+When kptr_restrict is set to (1), kernel pointers printed using the %pK
|
||
+format specifier will be replaced with 0's unless the user has CAP_SYSLOG
|
||
+and effective user and group ids are equal to the real ids. This is
|
||
+because %pK checks are done at read() time rather than open() time, so
|
||
+if permissions are elevated between the open() and the read() (e.g via
|
||
+a setuid binary) then %pK will not leak kernel pointers to unprivileged
|
||
+users. Note, this is a temporary solution only. The correct long-term
|
||
+solution is to do the permission checks at open() time. Consider removing
|
||
+world read permissions from files that use %pK, and using dmesg_restrict
|
||
+to protect against uses of %pK in dmesg(8) if leaking kernel pointer
|
||
+values to unprivileged users is a concern.
|
||
+
|
||
+When kptr_restrict is set to (2), kernel pointers printed using
|
||
+%pK will be replaced with 0's regardless of privileges.
|
||
|
||
==============================================================
|
||
|
||
diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt
|
||
index d6498e3..f33a936 100644
|
||
--- a/Documentation/x86/x86_64/mm.txt
|
||
+++ b/Documentation/x86/x86_64/mm.txt
|
||
@@ -12,6 +12,8 @@ ffffc90000000000 - ffffe8ffffffffff (=45 bits) vmalloc/ioremap space
|
||
ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole
|
||
ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB)
|
||
... unused hole ...
|
||
+ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks
|
||
+... unused hole ...
|
||
ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0
|
||
ffffffffa0000000 - fffffffffff00000 (=1536 MB) module mapping space
|
||
|
||
diff --git a/Documentation/zh_CN/HOWTO b/Documentation/zh_CN/HOWTO
|
||
index 7fba5aa..7599eb3 100644
|
||
--- a/Documentation/zh_CN/HOWTO
|
||
+++ b/Documentation/zh_CN/HOWTO
|
||
@@ -237,7 +237,7 @@ kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循
|
||
如果没有2.6.x.y版本内核存在,那么最新的2.6.x版本内核就相当于是当前的稳定
|
||
版内核。
|
||
|
||
-2.6.x.y版本由“稳定版”小组(邮件地址<stable@kernel.org>)维护,一般隔周发
|
||
+2.6.x.y版本由“稳定版”小组(邮件地址<stable@vger.kernel.org>)维护,一般隔周发
|
||
布新版本。
|
||
|
||
内核源码中的Documentation/stable_kernel_rules.txt文件具体描述了可被稳定
|
||
diff --git a/Documentation/zh_CN/stable_kernel_rules.txt b/Documentation/zh_CN/stable_kernel_rules.txt
|
||
index b5b9b0a..26ea5ed 100644
|
||
--- a/Documentation/zh_CN/stable_kernel_rules.txt
|
||
+++ b/Documentation/zh_CN/stable_kernel_rules.txt
|
||
@@ -42,7 +42,7 @@ Documentation/stable_kernel_rules.txt 的中文翻译
|
||
|
||
向稳定版代码树提交补丁的过程:
|
||
|
||
- - 在确认了补丁符合以上的规则后,将补丁发送到stable@kernel.org。
|
||
+ - 在确认了补丁符合以上的规则后,将补丁发送到stable@vger.kernel.org。
|
||
- 如果补丁被接受到队列里,发送者会收到一个ACK回复,如果没有被接受,收
|
||
到的是NAK回复。回复需要几天的时间,这取决于开发者的时间安排。
|
||
- 被接受的补丁会被加到稳定版本队列里,等待其他开发者的审查。
|
||
diff --git a/Makefile b/Makefile
|
||
index f790197..2029ca8 100644
|
||
--- a/Makefile
|
||
+++ b/Makefile
|
||
@@ -1,6 +1,6 @@
|
||
VERSION = 3
|
||
PATCHLEVEL = 4
|
||
-SUBLEVEL = 67
|
||
+SUBLEVEL = 105
|
||
EXTRAVERSION =
|
||
NAME = Saber-toothed Squirrel
|
||
|
||
diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h
|
||
index 7a3d38d..5ebab58 100644
|
||
--- a/arch/alpha/include/asm/io.h
|
||
+++ b/arch/alpha/include/asm/io.h
|
||
@@ -489,6 +489,11 @@ extern inline void writeq(u64 b, volatile void __iomem *addr)
|
||
}
|
||
#endif
|
||
|
||
+#define ioread16be(p) be16_to_cpu(ioread16(p))
|
||
+#define ioread32be(p) be32_to_cpu(ioread32(p))
|
||
+#define iowrite16be(v,p) iowrite16(cpu_to_be16(v), (p))
|
||
+#define iowrite32be(v,p) iowrite32(cpu_to_be32(v), (p))
|
||
+
|
||
#define inb_p inb
|
||
#define inw_p inw
|
||
#define inl_p inl
|
||
diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c
|
||
index a0a5d27..b8ce18f 100644
|
||
--- a/arch/alpha/oprofile/common.c
|
||
+++ b/arch/alpha/oprofile/common.c
|
||
@@ -12,6 +12,7 @@
|
||
#include <linux/smp.h>
|
||
#include <linux/errno.h>
|
||
#include <asm/ptrace.h>
|
||
+#include <asm/special_insns.h>
|
||
|
||
#include "op_impl.h"
|
||
|
||
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
|
||
index 272e4a6..37d3c6d 100644
|
||
--- a/arch/arm/Kconfig
|
||
+++ b/arch/arm/Kconfig
|
||
@@ -1,7 +1,6 @@
|
||
config ARM
|
||
bool
|
||
default y
|
||
- select HAVE_AOUT
|
||
select HAVE_DMA_API_DEBUG
|
||
select HAVE_IDE if PCI || ISA || PCMCIA
|
||
select HAVE_DMA_CONTIGUOUS if (CPU_V6 || CPU_V6K || CPU_V7)
|
||
diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
|
||
index 9949e60..6b34b23 100644
|
||
--- a/arch/arm/boot/dts/imx51-babbage.dts
|
||
+++ b/arch/arm/boot/dts/imx51-babbage.dts
|
||
@@ -29,8 +29,8 @@
|
||
aips@70000000 { /* aips-1 */
|
||
spba@70000000 {
|
||
esdhc@70004000 { /* ESDHC1 */
|
||
- fsl,cd-internal;
|
||
- fsl,wp-internal;
|
||
+ fsl,cd-controller;
|
||
+ fsl,wp-controller;
|
||
status = "okay";
|
||
};
|
||
|
||
diff --git a/arch/arm/include/asm/a.out-core.h b/arch/arm/include/asm/a.out-core.h
|
||
deleted file mode 100644
|
||
index 92f10cb..0000000
|
||
--- a/arch/arm/include/asm/a.out-core.h
|
||
+++ /dev/null
|
||
@@ -1,45 +0,0 @@
|
||
-/* a.out coredump register dumper
|
||
- *
|
||
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||
- * Written by David Howells (dhowells@redhat.com)
|
||
- *
|
||
- * This program is free software; you can redistribute it and/or
|
||
- * modify it under the terms of the GNU General Public Licence
|
||
- * as published by the Free Software Foundation; either version
|
||
- * 2 of the Licence, or (at your option) any later version.
|
||
- */
|
||
-
|
||
-#ifndef _ASM_A_OUT_CORE_H
|
||
-#define _ASM_A_OUT_CORE_H
|
||
-
|
||
-#ifdef __KERNEL__
|
||
-
|
||
-#include <linux/user.h>
|
||
-#include <linux/elfcore.h>
|
||
-
|
||
-/*
|
||
- * fill in the user structure for an a.out core dump
|
||
- */
|
||
-static inline void aout_dump_thread(struct pt_regs *regs, struct user *dump)
|
||
-{
|
||
- struct task_struct *tsk = current;
|
||
-
|
||
- dump->magic = CMAGIC;
|
||
- dump->start_code = tsk->mm->start_code;
|
||
- dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1);
|
||
-
|
||
- dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT;
|
||
- dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||
- dump->u_ssize = 0;
|
||
-
|
||
- memset(dump->u_debugreg, 0, sizeof(dump->u_debugreg));
|
||
-
|
||
- if (dump->start_stack < 0x04000000)
|
||
- dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT;
|
||
-
|
||
- dump->regs = *regs;
|
||
- dump->u_fpvalid = dump_fpu (regs, &dump->u_fp);
|
||
-}
|
||
-
|
||
-#endif /* __KERNEL__ */
|
||
-#endif /* _ASM_A_OUT_CORE_H */
|
||
diff --git a/arch/arm/include/asm/a.out.h b/arch/arm/include/asm/a.out.h
|
||
deleted file mode 100644
|
||
index 083894b..0000000
|
||
--- a/arch/arm/include/asm/a.out.h
|
||
+++ /dev/null
|
||
@@ -1,34 +0,0 @@
|
||
-#ifndef __ARM_A_OUT_H__
|
||
-#define __ARM_A_OUT_H__
|
||
-
|
||
-#include <linux/personality.h>
|
||
-#include <linux/types.h>
|
||
-
|
||
-struct exec
|
||
-{
|
||
- __u32 a_info; /* Use macros N_MAGIC, etc for access */
|
||
- __u32 a_text; /* length of text, in bytes */
|
||
- __u32 a_data; /* length of data, in bytes */
|
||
- __u32 a_bss; /* length of uninitialized data area for file, in bytes */
|
||
- __u32 a_syms; /* length of symbol table data in file, in bytes */
|
||
- __u32 a_entry; /* start address */
|
||
- __u32 a_trsize; /* length of relocation info for text, in bytes */
|
||
- __u32 a_drsize; /* length of relocation info for data, in bytes */
|
||
-};
|
||
-
|
||
-/*
|
||
- * This is always the same
|
||
- */
|
||
-#define N_TXTADDR(a) (0x00008000)
|
||
-
|
||
-#define N_TRSIZE(a) ((a).a_trsize)
|
||
-#define N_DRSIZE(a) ((a).a_drsize)
|
||
-#define N_SYMSIZE(a) ((a).a_syms)
|
||
-
|
||
-#define M_ARM 103
|
||
-
|
||
-#ifndef LIBRARY_START_TEXT
|
||
-#define LIBRARY_START_TEXT (0x00c00000)
|
||
-#endif
|
||
-
|
||
-#endif /* __A_OUT_GNU_H__ */
|
||
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
|
||
index 6e023f7..1a417b3 100644
|
||
--- a/arch/arm/include/asm/cacheflush.h
|
||
+++ b/arch/arm/include/asm/cacheflush.h
|
||
@@ -233,6 +233,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
|
||
static inline void __flush_icache_all(void)
|
||
{
|
||
__flush_icache_preferred();
|
||
+ dsb();
|
||
}
|
||
|
||
/*
|
||
diff --git a/arch/arm/include/asm/div64.h b/arch/arm/include/asm/div64.h
|
||
index fe92ccf..a66061a 100644
|
||
--- a/arch/arm/include/asm/div64.h
|
||
+++ b/arch/arm/include/asm/div64.h
|
||
@@ -156,7 +156,7 @@
|
||
/* Select the best insn combination to perform the */ \
|
||
/* actual __m * __n / (__p << 64) operation. */ \
|
||
if (!__c) { \
|
||
- asm ( "umull %Q0, %R0, %1, %Q2\n\t" \
|
||
+ asm ( "umull %Q0, %R0, %Q1, %Q2\n\t" \
|
||
"mov %Q0, #0" \
|
||
: "=&r" (__res) \
|
||
: "r" (__m), "r" (__n) \
|
||
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
|
||
index 12f71a1..f94784f 100644
|
||
--- a/arch/arm/include/asm/outercache.h
|
||
+++ b/arch/arm/include/asm/outercache.h
|
||
@@ -37,10 +37,10 @@ struct outer_cache_fns {
|
||
void (*resume)(void);
|
||
};
|
||
|
||
-#ifdef CONFIG_OUTER_CACHE
|
||
-
|
||
extern struct outer_cache_fns outer_cache;
|
||
|
||
+#ifdef CONFIG_OUTER_CACHE
|
||
+
|
||
static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
|
||
{
|
||
if (outer_cache.inv_range)
|
||
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
|
||
index 3a2cd22..a587d4f 100644
|
||
--- a/arch/arm/include/asm/processor.h
|
||
+++ b/arch/arm/include/asm/processor.h
|
||
@@ -57,7 +57,6 @@ struct thread_struct {
|
||
|
||
#define start_thread(regs,pc,sp) \
|
||
({ \
|
||
- unsigned long *stack = (unsigned long *)sp; \
|
||
memset(regs->uregs, 0, sizeof(regs->uregs)); \
|
||
if (current->personality & ADDR_LIMIT_32BIT) \
|
||
regs->ARM_cpsr = USR_MODE; \
|
||
@@ -68,9 +67,6 @@ struct thread_struct {
|
||
regs->ARM_cpsr |= PSR_ENDSTATE; \
|
||
regs->ARM_pc = pc & ~1; /* pc */ \
|
||
regs->ARM_sp = sp; /* sp */ \
|
||
- regs->ARM_r2 = stack[2]; /* r2 (envp) */ \
|
||
- regs->ARM_r1 = stack[1]; /* r1 (argv) */ \
|
||
- regs->ARM_r0 = stack[0]; /* r0 (argc) */ \
|
||
nommu_start_thread(regs); \
|
||
})
|
||
|
||
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
|
||
index 6f83ad6..508ad5d 100644
|
||
--- a/arch/arm/include/asm/uaccess.h
|
||
+++ b/arch/arm/include/asm/uaccess.h
|
||
@@ -158,8 +158,9 @@ extern int __put_user_8(void *, unsigned long long);
|
||
#define put_user(x,p) \
|
||
({ \
|
||
unsigned long __limit = current_thread_info()->addr_limit - 1; \
|
||
+ const typeof(*(p)) __user *__tmp_p = (p); \
|
||
register const typeof(*(p)) __r2 asm("r2") = (x); \
|
||
- register const typeof(*(p)) __user *__p asm("r0") = (p);\
|
||
+ register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \
|
||
register unsigned long __l asm("r1") = __limit; \
|
||
register int __e asm("r0"); \
|
||
switch (sizeof(*(__p))) { \
|
||
diff --git a/arch/arm/kernel/crash_dump.c b/arch/arm/kernel/crash_dump.c
|
||
index 90c50d4..5d1286d 100644
|
||
--- a/arch/arm/kernel/crash_dump.c
|
||
+++ b/arch/arm/kernel/crash_dump.c
|
||
@@ -39,7 +39,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
|
||
if (!csize)
|
||
return 0;
|
||
|
||
- vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
|
||
+ vaddr = ioremap(__pfn_to_phys(pfn), PAGE_SIZE);
|
||
if (!vaddr)
|
||
return -ENOMEM;
|
||
|
||
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
|
||
index 9a8531e..9d95a46 100644
|
||
--- a/arch/arm/kernel/entry-header.S
|
||
+++ b/arch/arm/kernel/entry-header.S
|
||
@@ -76,26 +76,21 @@
|
||
#ifndef CONFIG_THUMB2_KERNEL
|
||
.macro svc_exit, rpsr
|
||
msr spsr_cxsf, \rpsr
|
||
-#if defined(CONFIG_CPU_V6)
|
||
- ldr r0, [sp]
|
||
- strex r1, r2, [sp] @ clear the exclusive monitor
|
||
- ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr
|
||
-#elif defined(CONFIG_CPU_32v6K)
|
||
- clrex @ clear the exclusive monitor
|
||
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
|
||
-#else
|
||
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
|
||
+#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K)
|
||
+ @ We must avoid clrex due to Cortex-A15 erratum #830321
|
||
+ sub r0, sp, #4 @ uninhabited address
|
||
+ strex r1, r2, [r0] @ clear the exclusive monitor
|
||
#endif
|
||
+ ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
|
||
.endm
|
||
|
||
.macro restore_user_regs, fast = 0, offset = 0
|
||
ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr
|
||
ldr lr, [sp, #\offset + S_PC]! @ get pc
|
||
msr spsr_cxsf, r1 @ save in spsr_svc
|
||
-#if defined(CONFIG_CPU_V6)
|
||
+#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K)
|
||
+ @ We must avoid clrex due to Cortex-A15 erratum #830321
|
||
strex r1, r2, [sp] @ clear the exclusive monitor
|
||
-#elif defined(CONFIG_CPU_32v6K)
|
||
- clrex @ clear the exclusive monitor
|
||
#endif
|
||
.if \fast
|
||
ldmdb sp, {r1 - lr}^ @ get calling r1 - lr
|
||
@@ -123,7 +118,10 @@
|
||
.macro svc_exit, rpsr
|
||
ldr lr, [sp, #S_SP] @ top of the stack
|
||
ldrd r0, r1, [sp, #S_LR] @ calling lr and pc
|
||
- clrex @ clear the exclusive monitor
|
||
+
|
||
+ @ We must avoid clrex due to Cortex-A15 erratum #830321
|
||
+ strex r2, r1, [sp, #S_LR] @ clear the exclusive monitor
|
||
+
|
||
stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context
|
||
ldmia sp, {r0 - r12}
|
||
mov sp, lr
|
||
@@ -132,13 +130,16 @@
|
||
.endm
|
||
|
||
.macro restore_user_regs, fast = 0, offset = 0
|
||
- clrex @ clear the exclusive monitor
|
||
mov r2, sp
|
||
load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr
|
||
ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr
|
||
ldr lr, [sp, #\offset + S_PC] @ get pc
|
||
add sp, sp, #\offset + S_SP
|
||
msr spsr_cxsf, r1 @ save in spsr_svc
|
||
+
|
||
+ @ We must avoid clrex due to Cortex-A15 erratum #830321
|
||
+ strex r1, r2, [sp] @ clear the exclusive monitor
|
||
+
|
||
.if \fast
|
||
ldmdb sp, {r1 - r12} @ get calling r1 - r12
|
||
.else
|
||
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
|
||
index ba79688..f4ea736 100644
|
||
--- a/arch/arm/kernel/head.S
|
||
+++ b/arch/arm/kernel/head.S
|
||
@@ -254,6 +254,7 @@ __create_page_tables:
|
||
/*
|
||
* Then map boot params address in r2 or the first 1MB (2MB with LPAE)
|
||
* of ram if boot params address is not specified.
|
||
+ * We map 2 sections in case the ATAGs/DTB crosses a section boundary.
|
||
*/
|
||
mov r0, r2, lsr #SECTION_SHIFT
|
||
movs r0, r0, lsl #SECTION_SHIFT
|
||
@@ -262,6 +263,8 @@ __create_page_tables:
|
||
add r3, r3, #PAGE_OFFSET
|
||
add r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
|
||
orr r6, r7, r0
|
||
+ str r6, [r3], #1 << PMD_ORDER
|
||
+ add r6, r6, #1 << SECTION_SHIFT
|
||
str r6, [r3]
|
||
|
||
#ifdef CONFIG_DEBUG_LL
|
||
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
|
||
index fa27058..357b651 100644
|
||
--- a/arch/arm/kernel/machine_kexec.c
|
||
+++ b/arch/arm/kernel/machine_kexec.c
|
||
@@ -142,3 +142,10 @@ void machine_kexec(struct kimage *image)
|
||
|
||
soft_restart(reboot_code_buffer_phys);
|
||
}
|
||
+
|
||
+void arch_crash_save_vmcoreinfo(void)
|
||
+{
|
||
+#ifdef CONFIG_ARM_LPAE
|
||
+ VMCOREINFO_CONFIG(ARM_LPAE);
|
||
+#endif
|
||
+}
|
||
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
|
||
index 6d69561..ddc9618 100644
|
||
--- a/arch/arm/kernel/process.c
|
||
+++ b/arch/arm/kernel/process.c
|
||
@@ -676,6 +676,7 @@ EXPORT_SYMBOL(kernel_thread);
|
||
unsigned long get_wchan(struct task_struct *p)
|
||
{
|
||
struct stackframe frame;
|
||
+ unsigned long stack_page;
|
||
int count = 0;
|
||
if (!p || p == current || p->state == TASK_RUNNING)
|
||
return 0;
|
||
@@ -684,9 +685,11 @@ unsigned long get_wchan(struct task_struct *p)
|
||
frame.sp = thread_saved_sp(p);
|
||
frame.lr = 0; /* recovered from the stack */
|
||
frame.pc = thread_saved_pc(p);
|
||
+ stack_page = (unsigned long)task_stack_page(p);
|
||
do {
|
||
- int ret = unwind_frame(&frame);
|
||
- if (ret < 0)
|
||
+ if (frame.sp < stack_page ||
|
||
+ frame.sp >= stack_page + THREAD_SIZE ||
|
||
+ unwind_frame(&frame) < 0)
|
||
return 0;
|
||
if (!in_sched_functions(frame.pc))
|
||
return frame.pc;
|
||
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
|
||
index 00f79e5..6582c4a 100644
|
||
--- a/arch/arm/kernel/stacktrace.c
|
||
+++ b/arch/arm/kernel/stacktrace.c
|
||
@@ -31,7 +31,7 @@ int notrace unwind_frame(struct stackframe *frame)
|
||
high = ALIGN(low, THREAD_SIZE);
|
||
|
||
/* check current frame pointer is within bounds */
|
||
- if (fp < (low + 12) || fp + 4 >= high)
|
||
+ if (fp < low + 12 || fp > high - 4)
|
||
return -EINVAL;
|
||
|
||
/* restore the registers from the stack frame */
|
||
@@ -83,13 +83,16 @@ static int save_trace(struct stackframe *frame, void *d)
|
||
return trace->nr_entries >= trace->max_entries;
|
||
}
|
||
|
||
-void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||
+/* This must be noinline to so that our skip calculation works correctly */
|
||
+static noinline void __save_stack_trace(struct task_struct *tsk,
|
||
+ struct stack_trace *trace, unsigned int nosched)
|
||
{
|
||
struct stack_trace_data data;
|
||
struct stackframe frame;
|
||
|
||
data.trace = trace;
|
||
data.skip = trace->skip;
|
||
+ data.no_sched_functions = nosched;
|
||
|
||
if (tsk != current) {
|
||
#ifdef CONFIG_SMP
|
||
@@ -102,7 +105,6 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||
return;
|
||
#else
|
||
- data.no_sched_functions = 1;
|
||
frame.fp = thread_saved_fp(tsk);
|
||
frame.sp = thread_saved_sp(tsk);
|
||
frame.lr = 0; /* recovered from the stack */
|
||
@@ -111,11 +113,12 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||
} else {
|
||
register unsigned long current_sp asm ("sp");
|
||
|
||
- data.no_sched_functions = 0;
|
||
+ /* We don't want this function nor the caller */
|
||
+ data.skip += 2;
|
||
frame.fp = (unsigned long)__builtin_frame_address(0);
|
||
frame.sp = current_sp;
|
||
frame.lr = (unsigned long)__builtin_return_address(0);
|
||
- frame.pc = (unsigned long)save_stack_trace_tsk;
|
||
+ frame.pc = (unsigned long)__save_stack_trace;
|
||
}
|
||
|
||
walk_stackframe(&frame, save_trace, &data);
|
||
@@ -123,9 +126,14 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||
}
|
||
|
||
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||
+{
|
||
+ __save_stack_trace(tsk, trace, 1);
|
||
+}
|
||
+
|
||
void save_stack_trace(struct stack_trace *trace)
|
||
{
|
||
- save_stack_trace_tsk(current, trace);
|
||
+ __save_stack_trace(current, trace, 0);
|
||
}
|
||
EXPORT_SYMBOL_GPL(save_stack_trace);
|
||
#endif
|
||
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
|
||
index 8200dea..140c817 100644
|
||
--- a/arch/arm/kernel/topology.c
|
||
+++ b/arch/arm/kernel/topology.c
|
||
@@ -13,6 +13,7 @@
|
||
|
||
#include <linux/cpu.h>
|
||
#include <linux/cpumask.h>
|
||
+#include <linux/export.h>
|
||
#include <linux/init.h>
|
||
#include <linux/percpu.h>
|
||
#include <linux/node.h>
|
||
@@ -42,6 +43,7 @@
|
||
#define MPIDR_LEVEL2_SHIFT 16
|
||
|
||
struct cputopo_arm cpu_topology[NR_CPUS];
|
||
+EXPORT_SYMBOL_GPL(cpu_topology);
|
||
|
||
const struct cpumask *cpu_coregroup_mask(int cpu)
|
||
{
|
||
diff --git a/arch/arm/mach-at91/sam9_smc.c b/arch/arm/mach-at91/sam9_smc.c
|
||
index 99a0a1d2..b26156b 100644
|
||
--- a/arch/arm/mach-at91/sam9_smc.c
|
||
+++ b/arch/arm/mach-at91/sam9_smc.c
|
||
@@ -101,7 +101,7 @@ static void sam9_smc_cs_read(void __iomem *base,
|
||
/* Pulse register */
|
||
val = __raw_readl(base + AT91_SMC_PULSE);
|
||
|
||
- config->nwe_setup = val & AT91_SMC_NWEPULSE;
|
||
+ config->nwe_pulse = val & AT91_SMC_NWEPULSE;
|
||
config->ncs_write_pulse = (val & AT91_SMC_NCS_WRPULSE) >> 8;
|
||
config->nrd_pulse = (val & AT91_SMC_NRDPULSE) >> 16;
|
||
config->ncs_read_pulse = (val & AT91_SMC_NCS_RDPULSE) >> 24;
|
||
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
|
||
index bda7aca..18f9e71 100644
|
||
--- a/arch/arm/mach-dove/common.c
|
||
+++ b/arch/arm/mach-dove/common.c
|
||
@@ -90,7 +90,7 @@ void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data)
|
||
{
|
||
orion_ge00_init(eth_data,
|
||
DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM,
|
||
- 0, get_tclk());
|
||
+ 0, get_tclk(), 1600);
|
||
}
|
||
|
||
/*****************************************************************************
|
||
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
|
||
index 3e6aaa6..909e866 100644
|
||
--- a/arch/arm/mach-footbridge/common.c
|
||
+++ b/arch/arm/mach-footbridge/common.c
|
||
@@ -15,6 +15,7 @@
|
||
#include <linux/init.h>
|
||
#include <linux/io.h>
|
||
#include <linux/spinlock.h>
|
||
+#include <video/vga.h>
|
||
|
||
#include <asm/pgtable.h>
|
||
#include <asm/page.h>
|
||
@@ -198,6 +199,8 @@ void __init footbridge_map_io(void)
|
||
*/
|
||
if (footbridge_cfn_mode())
|
||
iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc));
|
||
+
|
||
+ vga_base = PCIMEM_BASE;
|
||
}
|
||
|
||
void footbridge_restart(char mode, const char *cmd)
|
||
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
|
||
index e17e11de..cdc82ae 100644
|
||
--- a/arch/arm/mach-footbridge/dc21285.c
|
||
+++ b/arch/arm/mach-footbridge/dc21285.c
|
||
@@ -18,7 +18,6 @@
|
||
#include <linux/irq.h>
|
||
#include <linux/io.h>
|
||
#include <linux/spinlock.h>
|
||
-#include <video/vga.h>
|
||
|
||
#include <asm/irq.h>
|
||
#include <asm/mach/pci.h>
|
||
@@ -298,7 +297,6 @@ void __init dc21285_preinit(void)
|
||
int cfn_mode;
|
||
|
||
pcibios_min_mem = 0x81000000;
|
||
- vga_base = PCIMEM_BASE;
|
||
|
||
mem_size = (unsigned int)high_memory - PAGE_OFFSET;
|
||
for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
|
||
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
|
||
index 48a115a..ecc33bc 100644
|
||
--- a/arch/arm/mach-integrator/integrator_cp.c
|
||
+++ b/arch/arm/mach-integrator/integrator_cp.c
|
||
@@ -366,7 +366,8 @@ static AMBA_APB_DEVICE(aaci, "mb:1d", 0, INTEGRATOR_CP_AACI_BASE,
|
||
static void cp_clcd_enable(struct clcd_fb *fb)
|
||
{
|
||
struct fb_var_screeninfo *var = &fb->fb.var;
|
||
- u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2;
|
||
+ u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2
|
||
+ | CM_CTRL_LCDEN0 | CM_CTRL_LCDEN1;
|
||
|
||
if (var->bits_per_pixel <= 8 ||
|
||
(var->bits_per_pixel == 16 && var->green.length == 5))
|
||
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
|
||
index a02cae8..d275802 100644
|
||
--- a/arch/arm/mach-kirkwood/common.c
|
||
+++ b/arch/arm/mach-kirkwood/common.c
|
||
@@ -87,7 +87,7 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
|
||
|
||
orion_ge00_init(eth_data,
|
||
GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM,
|
||
- IRQ_KIRKWOOD_GE00_ERR, kirkwood_tclk);
|
||
+ IRQ_KIRKWOOD_GE00_ERR, kirkwood_tclk, 1600);
|
||
}
|
||
|
||
|
||
@@ -101,7 +101,7 @@ void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data)
|
||
|
||
orion_ge01_init(eth_data,
|
||
GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM,
|
||
- IRQ_KIRKWOOD_GE01_ERR, kirkwood_tclk);
|
||
+ IRQ_KIRKWOOD_GE01_ERR, kirkwood_tclk, 1600);
|
||
}
|
||
|
||
|
||
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
|
||
index a5dcf766..80ca49e 100644
|
||
--- a/arch/arm/mach-mv78xx0/common.c
|
||
+++ b/arch/arm/mach-mv78xx0/common.c
|
||
@@ -199,7 +199,8 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data)
|
||
{
|
||
orion_ge00_init(eth_data,
|
||
GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM,
|
||
- IRQ_MV78XX0_GE_ERR, get_tclk());
|
||
+ IRQ_MV78XX0_GE_ERR, get_tclk(),
|
||
+ MV643XX_TX_CSUM_DEFAULT_LIMIT);
|
||
}
|
||
|
||
|
||
@@ -210,7 +211,8 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
|
||
{
|
||
orion_ge01_init(eth_data,
|
||
GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM,
|
||
- NO_IRQ, get_tclk());
|
||
+ NO_IRQ, get_tclk(),
|
||
+ MV643XX_TX_CSUM_DEFAULT_LIMIT);
|
||
}
|
||
|
||
|
||
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
|
||
index 65f0d257..ccc9bcb 100644
|
||
--- a/arch/arm/mach-omap2/irq.c
|
||
+++ b/arch/arm/mach-omap2/irq.c
|
||
@@ -220,6 +220,7 @@ void __init ti81xx_init_irq(void)
|
||
static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs *regs)
|
||
{
|
||
u32 irqnr;
|
||
+ int handled_irq = 0;
|
||
|
||
do {
|
||
irqnr = readl_relaxed(base_addr + 0x98);
|
||
@@ -247,8 +248,15 @@ static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs
|
||
if (irqnr) {
|
||
irqnr = irq_find_mapping(domain, irqnr);
|
||
handle_IRQ(irqnr, regs);
|
||
+ handled_irq = 1;
|
||
}
|
||
} while (irqnr);
|
||
+
|
||
+ /* If an irq is masked or deasserted while active, we will
|
||
+ * keep ending up here with no irq handled. So remove it from
|
||
+ * the INTC with an ack.*/
|
||
+ if (!handled_irq)
|
||
+ omap_ack_irq(NULL);
|
||
}
|
||
|
||
asmlinkage void __exception_irq_entry omap2_intc_handle_irq(struct pt_regs *regs)
|
||
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
|
||
index 65c3391..90b33c5 100644
|
||
--- a/arch/arm/mach-omap2/mux.c
|
||
+++ b/arch/arm/mach-omap2/mux.c
|
||
@@ -184,8 +184,10 @@ static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition,
|
||
m0_entry = mux->muxnames[0];
|
||
|
||
/* First check for full name in mode0.muxmode format */
|
||
- if (mode0_len && strncmp(muxname, m0_entry, mode0_len))
|
||
- continue;
|
||
+ if (mode0_len)
|
||
+ if (strncmp(muxname, m0_entry, mode0_len) ||
|
||
+ (strlen(m0_entry) != mode0_len))
|
||
+ continue;
|
||
|
||
/* Then check for muxmode only */
|
||
for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
|
||
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
|
||
index 7144ae6..bb7ed98 100644
|
||
--- a/arch/arm/mach-omap2/omap_hwmod.c
|
||
+++ b/arch/arm/mach-omap2/omap_hwmod.c
|
||
@@ -317,7 +317,7 @@ static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v)
|
||
}
|
||
|
||
/**
|
||
- * _set_softreset: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v
|
||
+ * _set_softreset: set OCP_SYSCONFIG.SOFTRESET bit in @v
|
||
* @oh: struct omap_hwmod *
|
||
* @v: pointer to register contents to modify
|
||
*
|
||
@@ -1378,6 +1378,36 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
|
||
}
|
||
|
||
/**
|
||
+ * _clear_softreset: clear OCP_SYSCONFIG.SOFTRESET bit in @v
|
||
+ * @oh: struct omap_hwmod *
|
||
+ * @v: pointer to register contents to modify
|
||
+ *
|
||
+ * Clear the SOFTRESET bit in @v for hwmod @oh. Returns -EINVAL upon
|
||
+ * error or 0 upon success.
|
||
+ */
|
||
+static int _clear_softreset(struct omap_hwmod *oh, u32 *v)
|
||
+{
|
||
+ u32 softrst_mask;
|
||
+
|
||
+ if (!oh->class->sysc ||
|
||
+ !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
|
||
+ return -EINVAL;
|
||
+
|
||
+ if (!oh->class->sysc->sysc_fields) {
|
||
+ WARN(1,
|
||
+ "omap_hwmod: %s: sysc_fields absent for sysconfig class\n",
|
||
+ oh->name);
|
||
+ return -EINVAL;
|
||
+ }
|
||
+
|
||
+ softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
|
||
+
|
||
+ *v &= ~softrst_mask;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/**
|
||
* _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
|
||
* @oh: struct omap_hwmod *
|
||
*
|
||
@@ -1420,6 +1450,12 @@ static int _ocp_softreset(struct omap_hwmod *oh)
|
||
ret = _set_softreset(oh, &v);
|
||
if (ret)
|
||
goto dis_opt_clks;
|
||
+
|
||
+ _write_sysconfig(v, oh);
|
||
+ ret = _clear_softreset(oh, &v);
|
||
+ if (ret)
|
||
+ goto dis_opt_clks;
|
||
+
|
||
_write_sysconfig(v, oh);
|
||
|
||
if (oh->class->sysc->srst_udelay)
|
||
@@ -1918,6 +1954,11 @@ int omap_hwmod_softreset(struct omap_hwmod *oh)
|
||
goto error;
|
||
_write_sysconfig(v, oh);
|
||
|
||
+ ret = _clear_softreset(oh, &v);
|
||
+ if (ret)
|
||
+ goto error;
|
||
+ _write_sysconfig(v, oh);
|
||
+
|
||
error:
|
||
return ret;
|
||
}
|
||
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
|
||
index db86ce9..f71d09a 100644
|
||
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
|
||
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
|
||
@@ -3347,7 +3347,8 @@ static struct omap_hwmod_class_sysconfig omap3xxx_usb_host_hs_sysc = {
|
||
.syss_offs = 0x0014,
|
||
.sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
|
||
SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
|
||
- SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
|
||
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
|
||
+ SYSS_HAS_RESET_STATUS),
|
||
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
|
||
MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
|
||
.sysc_fields = &omap_hwmod_sysc_type1,
|
||
@@ -3407,7 +3408,7 @@ static struct omap_hwmod_irq_info omap3xxx_usb_host_hs_irqs[] = {
|
||
static struct omap_hwmod omap3xxx_usb_host_hs_hwmod = {
|
||
.name = "usb_host_hs",
|
||
.class = &omap3xxx_usb_host_hs_hwmod_class,
|
||
- .clkdm_name = "l3_init_clkdm",
|
||
+ .clkdm_name = "usbhost_clkdm",
|
||
.mpu_irqs = omap3xxx_usb_host_hs_irqs,
|
||
.main_clk = "usbhost_48m_fck",
|
||
.prcm = {
|
||
@@ -3465,15 +3466,7 @@ static struct omap_hwmod omap3xxx_usb_host_hs_hwmod = {
|
||
* hence HWMOD_SWSUP_MSTANDBY
|
||
*/
|
||
|
||
- /*
|
||
- * During system boot; If the hwmod framework resets the module
|
||
- * the module will have smart idle settings; which can lead to deadlock
|
||
- * (above Errata Id:i660); so, dont reset the module during boot;
|
||
- * Use HWMOD_INIT_NO_RESET.
|
||
- */
|
||
-
|
||
- .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
|
||
- HWMOD_INIT_NO_RESET,
|
||
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
|
||
};
|
||
|
||
/*
|
||
@@ -3526,7 +3519,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_usb_tll_hs_slaves[] = {
|
||
static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod = {
|
||
.name = "usb_tll_hs",
|
||
.class = &omap3xxx_usb_tll_hs_hwmod_class,
|
||
- .clkdm_name = "l3_init_clkdm",
|
||
+ .clkdm_name = "core_l4_clkdm",
|
||
.mpu_irqs = omap3xxx_usb_tll_hs_irqs,
|
||
.main_clk = "usbtll_fck",
|
||
.prcm = {
|
||
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
|
||
index 2448166..6702516 100644
|
||
--- a/arch/arm/mach-orion5x/common.c
|
||
+++ b/arch/arm/mach-orion5x/common.c
|
||
@@ -95,7 +95,8 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data)
|
||
{
|
||
orion_ge00_init(eth_data,
|
||
ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM,
|
||
- IRQ_ORION5X_ETH_ERR, orion5x_tclk);
|
||
+ IRQ_ORION5X_ETH_ERR, orion5x_tclk,
|
||
+ MV643XX_TX_CSUM_DEFAULT_LIMIT);
|
||
}
|
||
|
||
|
||
diff --git a/arch/arm/mach-pxa/reset.c b/arch/arm/mach-pxa/reset.c
|
||
index b452889..7f8cda4 100644
|
||
--- a/arch/arm/mach-pxa/reset.c
|
||
+++ b/arch/arm/mach-pxa/reset.c
|
||
@@ -13,6 +13,7 @@
|
||
|
||
#include <mach/regs-ost.h>
|
||
#include <mach/reset.h>
|
||
+#include <mach/smemc.h>
|
||
|
||
unsigned int reset_status;
|
||
EXPORT_SYMBOL(reset_status);
|
||
@@ -80,6 +81,12 @@ static void do_hw_reset(void)
|
||
OWER = OWER_WME;
|
||
OSSR = OSSR_M3;
|
||
OSMR3 = OSCR + 368640; /* ... in 100 ms */
|
||
+ /*
|
||
+ * SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71)
|
||
+ * we put SDRAM into self-refresh to prevent that
|
||
+ */
|
||
+ while (1)
|
||
+ writel_relaxed(MDREFR_SLFRSH, MDREFR);
|
||
}
|
||
|
||
void pxa_restart(char mode, const char *cmd)
|
||
@@ -103,4 +110,3 @@ void pxa_restart(char mode, const char *cmd)
|
||
break;
|
||
}
|
||
}
|
||
-
|
||
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
|
||
index 4d4eb60..aeb7c10 100644
|
||
--- a/arch/arm/mach-pxa/tosa.c
|
||
+++ b/arch/arm/mach-pxa/tosa.c
|
||
@@ -424,57 +424,57 @@ static struct platform_device tosa_power_device = {
|
||
* Tosa Keyboard
|
||
*/
|
||
static const uint32_t tosakbd_keymap[] = {
|
||
- KEY(0, 2, KEY_W),
|
||
- KEY(0, 6, KEY_K),
|
||
- KEY(0, 7, KEY_BACKSPACE),
|
||
- KEY(0, 8, KEY_P),
|
||
- KEY(1, 1, KEY_Q),
|
||
- KEY(1, 2, KEY_E),
|
||
- KEY(1, 3, KEY_T),
|
||
- KEY(1, 4, KEY_Y),
|
||
- KEY(1, 6, KEY_O),
|
||
- KEY(1, 7, KEY_I),
|
||
- KEY(1, 8, KEY_COMMA),
|
||
- KEY(2, 1, KEY_A),
|
||
- KEY(2, 2, KEY_D),
|
||
- KEY(2, 3, KEY_G),
|
||
- KEY(2, 4, KEY_U),
|
||
- KEY(2, 6, KEY_L),
|
||
- KEY(2, 7, KEY_ENTER),
|
||
- KEY(2, 8, KEY_DOT),
|
||
- KEY(3, 1, KEY_Z),
|
||
- KEY(3, 2, KEY_C),
|
||
- KEY(3, 3, KEY_V),
|
||
- KEY(3, 4, KEY_J),
|
||
- KEY(3, 5, TOSA_KEY_ADDRESSBOOK),
|
||
- KEY(3, 6, TOSA_KEY_CANCEL),
|
||
- KEY(3, 7, TOSA_KEY_CENTER),
|
||
- KEY(3, 8, TOSA_KEY_OK),
|
||
- KEY(3, 9, KEY_LEFTSHIFT),
|
||
- KEY(4, 1, KEY_S),
|
||
- KEY(4, 2, KEY_R),
|
||
- KEY(4, 3, KEY_B),
|
||
- KEY(4, 4, KEY_N),
|
||
- KEY(4, 5, TOSA_KEY_CALENDAR),
|
||
- KEY(4, 6, TOSA_KEY_HOMEPAGE),
|
||
- KEY(4, 7, KEY_LEFTCTRL),
|
||
- KEY(4, 8, TOSA_KEY_LIGHT),
|
||
- KEY(4, 10, KEY_RIGHTSHIFT),
|
||
- KEY(5, 1, KEY_TAB),
|
||
- KEY(5, 2, KEY_SLASH),
|
||
- KEY(5, 3, KEY_H),
|
||
- KEY(5, 4, KEY_M),
|
||
- KEY(5, 5, TOSA_KEY_MENU),
|
||
- KEY(5, 7, KEY_UP),
|
||
- KEY(5, 11, TOSA_KEY_FN),
|
||
- KEY(6, 1, KEY_X),
|
||
- KEY(6, 2, KEY_F),
|
||
- KEY(6, 3, KEY_SPACE),
|
||
- KEY(6, 4, KEY_APOSTROPHE),
|
||
- KEY(6, 5, TOSA_KEY_MAIL),
|
||
- KEY(6, 6, KEY_LEFT),
|
||
- KEY(6, 7, KEY_DOWN),
|
||
- KEY(6, 8, KEY_RIGHT),
|
||
+ KEY(0, 1, KEY_W),
|
||
+ KEY(0, 5, KEY_K),
|
||
+ KEY(0, 6, KEY_BACKSPACE),
|
||
+ KEY(0, 7, KEY_P),
|
||
+ KEY(1, 0, KEY_Q),
|
||
+ KEY(1, 1, KEY_E),
|
||
+ KEY(1, 2, KEY_T),
|
||
+ KEY(1, 3, KEY_Y),
|
||
+ KEY(1, 5, KEY_O),
|
||
+ KEY(1, 6, KEY_I),
|
||
+ KEY(1, 7, KEY_COMMA),
|
||
+ KEY(2, 0, KEY_A),
|
||
+ KEY(2, 1, KEY_D),
|
||
+ KEY(2, 2, KEY_G),
|
||
+ KEY(2, 3, KEY_U),
|
||
+ KEY(2, 5, KEY_L),
|
||
+ KEY(2, 6, KEY_ENTER),
|
||
+ KEY(2, 7, KEY_DOT),
|
||
+ KEY(3, 0, KEY_Z),
|
||
+ KEY(3, 1, KEY_C),
|
||
+ KEY(3, 2, KEY_V),
|
||
+ KEY(3, 3, KEY_J),
|
||
+ KEY(3, 4, TOSA_KEY_ADDRESSBOOK),
|
||
+ KEY(3, 5, TOSA_KEY_CANCEL),
|
||
+ KEY(3, 6, TOSA_KEY_CENTER),
|
||
+ KEY(3, 7, TOSA_KEY_OK),
|
||
+ KEY(3, 8, KEY_LEFTSHIFT),
|
||
+ KEY(4, 0, KEY_S),
|
||
+ KEY(4, 1, KEY_R),
|
||
+ KEY(4, 2, KEY_B),
|
||
+ KEY(4, 3, KEY_N),
|
||
+ KEY(4, 4, TOSA_KEY_CALENDAR),
|
||
+ KEY(4, 5, TOSA_KEY_HOMEPAGE),
|
||
+ KEY(4, 6, KEY_LEFTCTRL),
|
||
+ KEY(4, 7, TOSA_KEY_LIGHT),
|
||
+ KEY(4, 9, KEY_RIGHTSHIFT),
|
||
+ KEY(5, 0, KEY_TAB),
|
||
+ KEY(5, 1, KEY_SLASH),
|
||
+ KEY(5, 2, KEY_H),
|
||
+ KEY(5, 3, KEY_M),
|
||
+ KEY(5, 4, TOSA_KEY_MENU),
|
||
+ KEY(5, 6, KEY_UP),
|
||
+ KEY(5, 10, TOSA_KEY_FN),
|
||
+ KEY(6, 0, KEY_X),
|
||
+ KEY(6, 1, KEY_F),
|
||
+ KEY(6, 2, KEY_SPACE),
|
||
+ KEY(6, 3, KEY_APOSTROPHE),
|
||
+ KEY(6, 4, TOSA_KEY_MAIL),
|
||
+ KEY(6, 5, KEY_LEFT),
|
||
+ KEY(6, 6, KEY_DOWN),
|
||
+ KEY(6, 7, KEY_RIGHT),
|
||
};
|
||
|
||
static struct matrix_keymap_data tosakbd_keymap_data = {
|
||
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
|
||
index 375d3f7..8263670 100644
|
||
--- a/arch/arm/mach-sa1100/assabet.c
|
||
+++ b/arch/arm/mach-sa1100/assabet.c
|
||
@@ -509,6 +509,9 @@ static void __init assabet_map_io(void)
|
||
* Its called GPCLKR0 in my SA1110 manual.
|
||
*/
|
||
Ser1SDCR0 |= SDCR0_SUS;
|
||
+ MSC1 = (MSC1 & ~0xffff) |
|
||
+ MSC_NonBrst | MSC_32BitStMem |
|
||
+ MSC_RdAcc(2) | MSC_WrAcc(2) | MSC_Rec(0);
|
||
|
||
if (!machine_has_neponset())
|
||
sa1100_register_uart_fns(&assabet_port_fns);
|
||
diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h
|
||
index f33679d..50e1d85 100644
|
||
--- a/arch/arm/mach-sa1100/include/mach/collie.h
|
||
+++ b/arch/arm/mach-sa1100/include/mach/collie.h
|
||
@@ -13,6 +13,8 @@
|
||
#ifndef __ASM_ARCH_COLLIE_H
|
||
#define __ASM_ARCH_COLLIE_H
|
||
|
||
+#include "hardware.h" /* Gives GPIO_MAX */
|
||
+
|
||
extern void locomolcd_power(int on);
|
||
|
||
#define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1)
|
||
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
|
||
index 8c6202b..9c19b45 100644
|
||
--- a/arch/arm/mach-shmobile/board-mackerel.c
|
||
+++ b/arch/arm/mach-shmobile/board-mackerel.c
|
||
@@ -422,7 +422,7 @@ static struct platform_device lcdc_device = {
|
||
.resource = lcdc_resources,
|
||
.dev = {
|
||
.platform_data = &lcdc_info,
|
||
- .coherent_dma_mask = ~0,
|
||
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
||
},
|
||
};
|
||
|
||
@@ -498,7 +498,7 @@ static struct platform_device hdmi_lcdc_device = {
|
||
.id = 1,
|
||
.dev = {
|
||
.platform_data = &hdmi_lcdc_info,
|
||
- .coherent_dma_mask = ~0,
|
||
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
||
},
|
||
};
|
||
|
||
diff --git a/arch/arm/mach-u300/include/mach/u300-regs.h b/arch/arm/mach-u300/include/mach/u300-regs.h
|
||
index 65f87c5..cacb2af 100644
|
||
--- a/arch/arm/mach-u300/include/mach/u300-regs.h
|
||
+++ b/arch/arm/mach-u300/include/mach/u300-regs.h
|
||
@@ -101,7 +101,7 @@
|
||
|
||
#ifdef CONFIG_MACH_U300_BS335
|
||
/* Fast UART1 on U335 only */
|
||
-#define U300_UART1_BASE (U300_SLOW_PER_PHYS_BASE+0x7000)
|
||
+#define U300_UART1_BASE (U300_FAST_PER_PHYS_BASE+0x7000)
|
||
#endif
|
||
|
||
/*
|
||
diff --git a/arch/arm/mach-w90x900/include/mach/entry-macro.S b/arch/arm/mach-w90x900/include/mach/entry-macro.S
|
||
index e286dac..0ff612a 100644
|
||
--- a/arch/arm/mach-w90x900/include/mach/entry-macro.S
|
||
+++ b/arch/arm/mach-w90x900/include/mach/entry-macro.S
|
||
@@ -19,8 +19,8 @@
|
||
|
||
mov \base, #AIC_BA
|
||
|
||
- ldr \irqnr, [ \base, #AIC_IPER]
|
||
- ldr \irqnr, [ \base, #AIC_ISNR]
|
||
+ ldr \irqnr, [\base, #AIC_IPER]
|
||
+ ldr \irqnr, [\base, #AIC_ISNR]
|
||
cmp \irqnr, #0
|
||
|
||
.endm
|
||
diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S
|
||
index 8074199..5d777a5 100644
|
||
--- a/arch/arm/mm/abort-ev6.S
|
||
+++ b/arch/arm/mm/abort-ev6.S
|
||
@@ -17,12 +17,6 @@
|
||
*/
|
||
.align 5
|
||
ENTRY(v6_early_abort)
|
||
-#ifdef CONFIG_CPU_V6
|
||
- sub r1, sp, #4 @ Get unused stack location
|
||
- strex r0, r1, [r1] @ Clear the exclusive monitor
|
||
-#elif defined(CONFIG_CPU_32v6K)
|
||
- clrex
|
||
-#endif
|
||
mrc p15, 0, r1, c5, c0, 0 @ get FSR
|
||
mrc p15, 0, r0, c6, c0, 0 @ get FAR
|
||
/*
|
||
diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S
|
||
index 7033752..4812ad0 100644
|
||
--- a/arch/arm/mm/abort-ev7.S
|
||
+++ b/arch/arm/mm/abort-ev7.S
|
||
@@ -13,12 +13,6 @@
|
||
*/
|
||
.align 5
|
||
ENTRY(v7_early_abort)
|
||
- /*
|
||
- * The effect of data aborts on on the exclusive access monitor are
|
||
- * UNPREDICTABLE. Do a CLREX to clear the state
|
||
- */
|
||
- clrex
|
||
-
|
||
mrc p15, 0, r1, c5, c0, 0 @ get FSR
|
||
mrc p15, 0, r0, c6, c0, 0 @ get FAR
|
||
|
||
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
|
||
index ddc6376..23cc46e 100644
|
||
--- a/arch/arm/mm/idmap.c
|
||
+++ b/arch/arm/mm/idmap.c
|
||
@@ -22,6 +22,13 @@ static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
|
||
pr_warning("Failed to allocate identity pmd.\n");
|
||
return;
|
||
}
|
||
+ /*
|
||
+ * Copy the original PMD to ensure that the PMD entries for
|
||
+ * the kernel image are preserved.
|
||
+ */
|
||
+ if (!pud_none(*pud))
|
||
+ memcpy(pmd, pmd_offset(pud, 0),
|
||
+ PTRS_PER_PMD * sizeof(pmd_t));
|
||
pud_populate(&init_mm, pud, pmd);
|
||
pmd += pmd_index(addr);
|
||
} else
|
||
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
|
||
index 4dac6e0..8b68a2b 100644
|
||
--- a/arch/arm/plat-orion/common.c
|
||
+++ b/arch/arm/plat-orion/common.c
|
||
@@ -261,10 +261,12 @@ void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
|
||
unsigned long mapbase,
|
||
unsigned long irq,
|
||
unsigned long irq_err,
|
||
- int tclk)
|
||
+ int tclk,
|
||
+ unsigned int tx_csum_limit)
|
||
{
|
||
fill_resources(&orion_ge00_shared, orion_ge00_shared_resources,
|
||
mapbase + 0x2000, SZ_16K - 1, irq_err);
|
||
+ orion_ge00_shared_data.tx_csum_limit = tx_csum_limit;
|
||
ge_complete(&orion_ge00_shared_data, tclk,
|
||
orion_ge00_resources, irq, &orion_ge00_shared,
|
||
eth_data, &orion_ge00);
|
||
@@ -314,10 +316,12 @@ void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
|
||
unsigned long mapbase,
|
||
unsigned long irq,
|
||
unsigned long irq_err,
|
||
- int tclk)
|
||
+ int tclk,
|
||
+ unsigned int tx_csum_limit)
|
||
{
|
||
fill_resources(&orion_ge01_shared, orion_ge01_shared_resources,
|
||
mapbase + 0x2000, SZ_16K - 1, irq_err);
|
||
+ orion_ge01_shared_data.tx_csum_limit = tx_csum_limit;
|
||
ge_complete(&orion_ge01_shared_data, tclk,
|
||
orion_ge01_resources, irq, &orion_ge01_shared,
|
||
eth_data, &orion_ge01);
|
||
diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h
|
||
index a7fa005..5b690b5c 100644
|
||
--- a/arch/arm/plat-orion/include/plat/common.h
|
||
+++ b/arch/arm/plat-orion/include/plat/common.h
|
||
@@ -40,13 +40,15 @@ void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
|
||
unsigned long mapbase,
|
||
unsigned long irq,
|
||
unsigned long irq_err,
|
||
- int tclk);
|
||
+ int tclk,
|
||
+ unsigned int tx_csum_limit);
|
||
|
||
void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
|
||
unsigned long mapbase,
|
||
unsigned long irq,
|
||
unsigned long irq_err,
|
||
- int tclk);
|
||
+ int tclk,
|
||
+ unsigned int tx_csum_limit);
|
||
|
||
void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
|
||
unsigned long mapbase,
|
||
diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
|
||
index 22fb665..dba48a5d 100644
|
||
--- a/arch/avr32/Makefile
|
||
+++ b/arch/avr32/Makefile
|
||
@@ -11,7 +11,7 @@ all: uImage vmlinux.elf
|
||
|
||
KBUILD_DEFCONFIG := atstk1002_defconfig
|
||
|
||
-KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic
|
||
+KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic -D__linux__
|
||
KBUILD_AFLAGS += -mrelax -mno-pic
|
||
KBUILD_CFLAGS_MODULE += -mno-relax
|
||
LDFLAGS_vmlinux += --relax
|
||
diff --git a/arch/avr32/boards/mimc200/fram.c b/arch/avr32/boards/mimc200/fram.c
|
||
index 9764a1a..c1466a8 100644
|
||
--- a/arch/avr32/boards/mimc200/fram.c
|
||
+++ b/arch/avr32/boards/mimc200/fram.c
|
||
@@ -11,6 +11,7 @@
|
||
#define FRAM_VERSION "1.0"
|
||
|
||
#include <linux/miscdevice.h>
|
||
+#include <linux/module.h>
|
||
#include <linux/proc_fs.h>
|
||
#include <linux/mm.h>
|
||
#include <linux/io.h>
|
||
diff --git a/arch/avr32/boot/u-boot/head.S b/arch/avr32/boot/u-boot/head.S
|
||
index 4488fa2..2ffc298 100644
|
||
--- a/arch/avr32/boot/u-boot/head.S
|
||
+++ b/arch/avr32/boot/u-boot/head.S
|
||
@@ -8,6 +8,8 @@
|
||
* published by the Free Software Foundation.
|
||
*/
|
||
#include <asm/setup.h>
|
||
+#include <asm/thread_info.h>
|
||
+#include <asm/sysreg.h>
|
||
|
||
/*
|
||
* The kernel is loaded where we want it to be and all caches
|
||
@@ -20,11 +22,6 @@
|
||
.section .init.text,"ax"
|
||
.global _start
|
||
_start:
|
||
- /* Check if the boot loader actually provided a tag table */
|
||
- lddpc r0, magic_number
|
||
- cp.w r12, r0
|
||
- brne no_tag_table
|
||
-
|
||
/* Initialize .bss */
|
||
lddpc r2, bss_start_addr
|
||
lddpc r3, end_addr
|
||
@@ -34,6 +31,25 @@ _start:
|
||
cp r2, r3
|
||
brlo 1b
|
||
|
||
+ /* Initialize status register */
|
||
+ lddpc r0, init_sr
|
||
+ mtsr SYSREG_SR, r0
|
||
+
|
||
+ /* Set initial stack pointer */
|
||
+ lddpc sp, stack_addr
|
||
+ sub sp, -THREAD_SIZE
|
||
+
|
||
+#ifdef CONFIG_FRAME_POINTER
|
||
+ /* Mark last stack frame */
|
||
+ mov lr, 0
|
||
+ mov r7, 0
|
||
+#endif
|
||
+
|
||
+ /* Check if the boot loader actually provided a tag table */
|
||
+ lddpc r0, magic_number
|
||
+ cp.w r12, r0
|
||
+ brne no_tag_table
|
||
+
|
||
/*
|
||
* Save the tag table address for later use. This must be done
|
||
* _after_ .bss has been initialized...
|
||
@@ -53,8 +69,15 @@ bss_start_addr:
|
||
.long __bss_start
|
||
end_addr:
|
||
.long _end
|
||
+init_sr:
|
||
+ .long 0x007f0000 /* Supervisor mode, everything masked */
|
||
+stack_addr:
|
||
+ .long init_thread_union
|
||
+panic_addr:
|
||
+ .long panic
|
||
|
||
no_tag_table:
|
||
sub r12, pc, (. - 2f)
|
||
- bral panic
|
||
+ /* branch to panic() which can be far away with that construct */
|
||
+ lddpc pc, panic_addr
|
||
2: .asciz "Boot loader didn't provide correct magic number\n"
|
||
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
|
||
index 169268c..a91e898 100644
|
||
--- a/arch/avr32/kernel/entry-avr32b.S
|
||
+++ b/arch/avr32/kernel/entry-avr32b.S
|
||
@@ -399,9 +399,10 @@ handle_critical:
|
||
/* We should never get here... */
|
||
bad_return:
|
||
sub r12, pc, (. - 1f)
|
||
- bral panic
|
||
+ lddpc pc, 2f
|
||
.align 2
|
||
1: .asciz "Return from critical exception!"
|
||
+2: .long panic
|
||
|
||
.align 1
|
||
do_bus_error_write:
|
||
diff --git a/arch/avr32/kernel/head.S b/arch/avr32/kernel/head.S
|
||
index 6163bd0..59eae6d 100644
|
||
--- a/arch/avr32/kernel/head.S
|
||
+++ b/arch/avr32/kernel/head.S
|
||
@@ -10,33 +10,13 @@
|
||
#include <linux/linkage.h>
|
||
|
||
#include <asm/page.h>
|
||
-#include <asm/thread_info.h>
|
||
-#include <asm/sysreg.h>
|
||
|
||
.section .init.text,"ax"
|
||
.global kernel_entry
|
||
kernel_entry:
|
||
- /* Initialize status register */
|
||
- lddpc r0, init_sr
|
||
- mtsr SYSREG_SR, r0
|
||
-
|
||
- /* Set initial stack pointer */
|
||
- lddpc sp, stack_addr
|
||
- sub sp, -THREAD_SIZE
|
||
-
|
||
-#ifdef CONFIG_FRAME_POINTER
|
||
- /* Mark last stack frame */
|
||
- mov lr, 0
|
||
- mov r7, 0
|
||
-#endif
|
||
-
|
||
/* Start the show */
|
||
lddpc pc, kernel_start_addr
|
||
|
||
.align 2
|
||
-init_sr:
|
||
- .long 0x007f0000 /* Supervisor mode, everything masked */
|
||
-stack_addr:
|
||
- .long init_thread_union
|
||
kernel_start_addr:
|
||
.long start_kernel
|
||
diff --git a/arch/cris/include/asm/io.h b/arch/cris/include/asm/io.h
|
||
index ac12ae2..db9a16c 100644
|
||
--- a/arch/cris/include/asm/io.h
|
||
+++ b/arch/cris/include/asm/io.h
|
||
@@ -3,6 +3,7 @@
|
||
|
||
#include <asm/page.h> /* for __va, __pa */
|
||
#include <arch/io.h>
|
||
+#include <asm-generic/iomap.h>
|
||
#include <linux/kernel.h>
|
||
|
||
struct cris_io_operations
|
||
diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
|
||
index 483f6c6..2d0cb8e 100644
|
||
--- a/arch/ia64/include/asm/processor.h
|
||
+++ b/arch/ia64/include/asm/processor.h
|
||
@@ -322,7 +322,7 @@ struct thread_struct {
|
||
regs->loadrs = 0; \
|
||
regs->r8 = get_dumpable(current->mm); /* set "don't zap registers" flag */ \
|
||
regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \
|
||
- if (unlikely(!get_dumpable(current->mm))) { \
|
||
+ if (unlikely(get_dumpable(current->mm) != SUID_DUMP_USER)) { \
|
||
/* \
|
||
* Zap scratch regs to avoid leaking bits between processes with different \
|
||
* uid/privileges. \
|
||
diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c
|
||
index 5cad0fa..ca51d69 100644
|
||
--- a/arch/mips/boot/compressed/decompress.c
|
||
+++ b/arch/mips/boot/compressed/decompress.c
|
||
@@ -13,6 +13,7 @@
|
||
|
||
#include <linux/types.h>
|
||
#include <linux/kernel.h>
|
||
+#include <linux/string.h>
|
||
|
||
#include <asm/addrspace.h>
|
||
|
||
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
|
||
index d3a9f012..b6fb650 100644
|
||
--- a/arch/mips/cavium-octeon/setup.c
|
||
+++ b/arch/mips/cavium-octeon/setup.c
|
||
@@ -265,6 +265,18 @@ static irqreturn_t octeon_rlm_interrupt(int cpl, void *dev_id)
|
||
}
|
||
#endif
|
||
|
||
+static char __read_mostly octeon_system_type[80];
|
||
+
|
||
+static int __init init_octeon_system_type(void)
|
||
+{
|
||
+ snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)",
|
||
+ cvmx_board_type_to_string(octeon_bootinfo->board_type),
|
||
+ octeon_model_get_string(read_c0_prid()));
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+early_initcall(init_octeon_system_type);
|
||
+
|
||
/**
|
||
* Return a string representing the system type
|
||
*
|
||
@@ -272,11 +284,7 @@ static irqreturn_t octeon_rlm_interrupt(int cpl, void *dev_id)
|
||
*/
|
||
const char *octeon_board_type_string(void)
|
||
{
|
||
- static char name[80];
|
||
- sprintf(name, "%s (%s)",
|
||
- cvmx_board_type_to_string(octeon_bootinfo->board_type),
|
||
- octeon_model_get_string(read_c0_prid()));
|
||
- return name;
|
||
+ return octeon_system_type;
|
||
}
|
||
|
||
const char *get_system_type(void)
|
||
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h
|
||
index 4d6d77e..e194f95 100644
|
||
--- a/arch/mips/include/asm/jump_label.h
|
||
+++ b/arch/mips/include/asm/jump_label.h
|
||
@@ -22,7 +22,7 @@
|
||
|
||
static __always_inline bool arch_static_branch(struct static_key *key)
|
||
{
|
||
- asm goto("1:\tnop\n\t"
|
||
+ asm_volatile_goto("1:\tnop\n\t"
|
||
"nop\n\t"
|
||
".pushsection __jump_table, \"aw\"\n\t"
|
||
WORD_INSN " 1b, %l[l_yes], %0\n\t"
|
||
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
|
||
index 14ac52c..884de34 100644
|
||
--- a/arch/mips/kernel/irq-msc01.c
|
||
+++ b/arch/mips/kernel/irq-msc01.c
|
||
@@ -131,7 +131,7 @@ void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqma
|
||
|
||
board_bind_eic_interrupt = &msc_bind_eic_interrupt;
|
||
|
||
- for (; nirq >= 0; nirq--, imp++) {
|
||
+ for (; nirq > 0; nirq--, imp++) {
|
||
int n = imp->im_irq;
|
||
|
||
switch (imp->im_type) {
|
||
diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S
|
||
index 4c968e7..55eca41 100644
|
||
--- a/arch/mips/kernel/mcount.S
|
||
+++ b/arch/mips/kernel/mcount.S
|
||
@@ -119,7 +119,11 @@ NESTED(_mcount, PT_SIZE, ra)
|
||
nop
|
||
#endif
|
||
b ftrace_stub
|
||
+#ifdef CONFIG_32BIT
|
||
+ addiu sp, sp, 8
|
||
+#else
|
||
nop
|
||
+#endif
|
||
|
||
static_trace:
|
||
MCOUNT_SAVE_REGS
|
||
@@ -129,6 +133,9 @@ static_trace:
|
||
move a1, AT /* arg2: parent's return address */
|
||
|
||
MCOUNT_RESTORE_REGS
|
||
+#ifdef CONFIG_32BIT
|
||
+ addiu sp, sp, 8
|
||
+#endif
|
||
.globl ftrace_stub
|
||
ftrace_stub:
|
||
RETURN_BACK
|
||
@@ -177,6 +184,11 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra)
|
||
jal prepare_ftrace_return
|
||
nop
|
||
MCOUNT_RESTORE_REGS
|
||
+#ifndef CONFIG_DYNAMIC_FTRACE
|
||
+#ifdef CONFIG_32BIT
|
||
+ addiu sp, sp, 8
|
||
+#endif
|
||
+#endif
|
||
RETURN_BACK
|
||
END(ftrace_graph_caller)
|
||
|
||
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
|
||
index 811084f..52f60e5 100644
|
||
--- a/arch/mips/kernel/perf_event_mipsxx.c
|
||
+++ b/arch/mips/kernel/perf_event_mipsxx.c
|
||
@@ -162,11 +162,6 @@ static unsigned int counters_total_to_per_cpu(unsigned int counters)
|
||
return counters >> vpe_shift();
|
||
}
|
||
|
||
-static unsigned int counters_per_cpu_to_total(unsigned int counters)
|
||
-{
|
||
- return counters << vpe_shift();
|
||
-}
|
||
-
|
||
#else /* !CONFIG_MIPS_MT_SMP */
|
||
#define vpe_id() 0
|
||
|
||
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
|
||
index bda8eb2..fdd6042 100644
|
||
--- a/arch/mips/mm/c-r4k.c
|
||
+++ b/arch/mips/mm/c-r4k.c
|
||
@@ -12,6 +12,7 @@
|
||
#include <linux/highmem.h>
|
||
#include <linux/kernel.h>
|
||
#include <linux/linkage.h>
|
||
+#include <linux/preempt.h>
|
||
#include <linux/sched.h>
|
||
#include <linux/smp.h>
|
||
#include <linux/mm.h>
|
||
@@ -598,6 +599,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
|
||
/* Catch bad driver code */
|
||
BUG_ON(size == 0);
|
||
|
||
+ preempt_disable();
|
||
if (cpu_has_inclusive_pcaches) {
|
||
if (size >= scache_size)
|
||
r4k_blast_scache();
|
||
@@ -618,6 +620,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
|
||
R4600_HIT_CACHEOP_WAR_IMPL;
|
||
blast_dcache_range(addr, addr + size);
|
||
}
|
||
+ preempt_enable();
|
||
|
||
bc_wback_inv(addr, size);
|
||
__sync();
|
||
@@ -628,6 +631,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
|
||
/* Catch bad driver code */
|
||
BUG_ON(size == 0);
|
||
|
||
+ preempt_disable();
|
||
if (cpu_has_inclusive_pcaches) {
|
||
if (size >= scache_size)
|
||
r4k_blast_scache();
|
||
@@ -663,6 +667,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
|
||
cache_op(Hit_Writeback_Inv_D, (addr + size - 1) & almask);
|
||
blast_inv_dcache_range(addr, addr + size);
|
||
}
|
||
+ preempt_enable();
|
||
|
||
bc_inv(addr, size);
|
||
__sync();
|
||
diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
|
||
index 3fab204..0eea2d2 100644
|
||
--- a/arch/mips/mm/dma-default.c
|
||
+++ b/arch/mips/mm/dma-default.c
|
||
@@ -30,16 +30,20 @@ static inline struct page *dma_addr_to_page(struct device *dev,
|
||
}
|
||
|
||
/*
|
||
+ * The affected CPUs below in 'cpu_needs_post_dma_flush()' can
|
||
+ * speculatively fill random cachelines with stale data at any time,
|
||
+ * requiring an extra flush post-DMA.
|
||
+ *
|
||
* Warning on the terminology - Linux calls an uncached area coherent;
|
||
* MIPS terminology calls memory areas with hardware maintained coherency
|
||
* coherent.
|
||
*/
|
||
-
|
||
-static inline int cpu_is_noncoherent_r10000(struct device *dev)
|
||
+static inline int cpu_needs_post_dma_flush(struct device *dev)
|
||
{
|
||
return !plat_device_is_coherent(dev) &&
|
||
(current_cpu_type() == CPU_R10000 ||
|
||
- current_cpu_type() == CPU_R12000);
|
||
+ current_cpu_type() == CPU_R12000 ||
|
||
+ current_cpu_type() == CPU_BMIPS5000);
|
||
}
|
||
|
||
static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp)
|
||
@@ -209,7 +213,7 @@ static inline void __dma_sync(struct page *page,
|
||
static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
|
||
size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
|
||
{
|
||
- if (cpu_is_noncoherent_r10000(dev))
|
||
+ if (cpu_needs_post_dma_flush(dev))
|
||
__dma_sync(dma_addr_to_page(dev, dma_addr),
|
||
dma_addr & ~PAGE_MASK, size, direction);
|
||
|
||
@@ -260,7 +264,7 @@ static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
|
||
static void mips_dma_sync_single_for_cpu(struct device *dev,
|
||
dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
|
||
{
|
||
- if (cpu_is_noncoherent_r10000(dev))
|
||
+ if (cpu_needs_post_dma_flush(dev))
|
||
__dma_sync(dma_addr_to_page(dev, dma_handle),
|
||
dma_handle & ~PAGE_MASK, size, direction);
|
||
}
|
||
@@ -281,7 +285,7 @@ static void mips_dma_sync_sg_for_cpu(struct device *dev,
|
||
|
||
/* Make sure that gcc doesn't leave the empty loop body. */
|
||
for (i = 0; i < nelems; i++, sg++) {
|
||
- if (cpu_is_noncoherent_r10000(dev))
|
||
+ if (cpu_needs_post_dma_flush(dev))
|
||
__dma_sync(sg_page(sg), sg->offset, sg->length,
|
||
direction);
|
||
}
|
||
diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S
|
||
index f8a751c..5bf34ec8 100644
|
||
--- a/arch/mips/power/hibernate.S
|
||
+++ b/arch/mips/power/hibernate.S
|
||
@@ -44,6 +44,7 @@ LEAF(swsusp_arch_resume)
|
||
bne t1, t3, 1b
|
||
PTR_L t0, PBE_NEXT(t0)
|
||
bnez t0, 0b
|
||
+ jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */
|
||
PTR_LA t0, saved_regs
|
||
PTR_L ra, PT_R31(t0)
|
||
PTR_L sp, PT_R29(t0)
|
||
diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S
|
||
index 1088b5f..2745196 100644
|
||
--- a/arch/openrisc/kernel/head.S
|
||
+++ b/arch/openrisc/kernel/head.S
|
||
@@ -19,6 +19,7 @@
|
||
#include <linux/threads.h>
|
||
#include <linux/errno.h>
|
||
#include <linux/init.h>
|
||
+#include <linux/serial_reg.h>
|
||
#include <asm/processor.h>
|
||
#include <asm/page.h>
|
||
#include <asm/mmu.h>
|
||
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
|
||
index 19ab7b2..ac93ca2 100644
|
||
--- a/arch/parisc/Makefile
|
||
+++ b/arch/parisc/Makefile
|
||
@@ -51,7 +51,12 @@ cflags-y := -pipe
|
||
|
||
# These flags should be implied by an hppa-linux configuration, but they
|
||
# are not in gcc 3.2.
|
||
-cflags-y += -mno-space-regs -mfast-indirect-calls
|
||
+cflags-y += -mno-space-regs
|
||
+
|
||
+# -mfast-indirect-calls is only relevant for 32-bit kernels.
|
||
+ifndef CONFIG_64BIT
|
||
+cflags-y += -mfast-indirect-calls
|
||
+endif
|
||
|
||
# Currently we save and restore fpregs on all kernel entry/interruption paths.
|
||
# If that gets optimized, we might need to disable the use of fpregs in the
|
||
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
|
||
index 37aabd7..d2d5825 100644
|
||
--- a/arch/parisc/kernel/head.S
|
||
+++ b/arch/parisc/kernel/head.S
|
||
@@ -195,6 +195,8 @@ common_stext:
|
||
ldw MEM_PDC_HI(%r0),%r6
|
||
depd %r6, 31, 32, %r3 /* move to upper word */
|
||
|
||
+ mfctl %cr30,%r6 /* PCX-W2 firmware bug */
|
||
+
|
||
ldo PDC_PSW(%r0),%arg0 /* 21 */
|
||
ldo PDC_PSW_SET_DEFAULTS(%r0),%arg1 /* 2 */
|
||
ldo PDC_PSW_WIDE_BIT(%r0),%arg2 /* 2 */
|
||
@@ -203,6 +205,8 @@ common_stext:
|
||
copy %r0,%arg3
|
||
|
||
stext_pdc_ret:
|
||
+ mtctl %r6,%cr30 /* restore task thread info */
|
||
+
|
||
/* restore rfi target address*/
|
||
ldd TI_TASK-THREAD_SZ_ALGN(%sp), %r10
|
||
tophys_r1 %r10
|
||
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
|
||
index 3735abd..4014d90 100644
|
||
--- a/arch/parisc/kernel/syscall_table.S
|
||
+++ b/arch/parisc/kernel/syscall_table.S
|
||
@@ -395,7 +395,7 @@
|
||
ENTRY_COMP(vmsplice)
|
||
ENTRY_COMP(move_pages) /* 295 */
|
||
ENTRY_SAME(getcpu)
|
||
- ENTRY_SAME(epoll_pwait)
|
||
+ ENTRY_COMP(epoll_pwait)
|
||
ENTRY_COMP(statfs64)
|
||
ENTRY_COMP(fstatfs64)
|
||
ENTRY_COMP(kexec_load) /* 300 */
|
||
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
|
||
index 6524c6e..694aeed 100644
|
||
--- a/arch/powerpc/Makefile
|
||
+++ b/arch/powerpc/Makefile
|
||
@@ -67,9 +67,11 @@ LDFLAGS_vmlinux-y := -Bstatic
|
||
LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie
|
||
LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y)
|
||
|
||
+asinstr := $(call as-instr,lis 9$(comma)foo@high,-DHAVE_AS_ATHIGH=1)
|
||
+
|
||
CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=no -mcall-aixdesc
|
||
CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple
|
||
-KBUILD_CPPFLAGS += -Iarch/$(ARCH)
|
||
+KBUILD_CPPFLAGS += -Iarch/$(ARCH) $(asinstr)
|
||
KBUILD_AFLAGS += -Iarch/$(ARCH)
|
||
KBUILD_CFLAGS += -msoft-float -pipe -Iarch/$(ARCH) $(CFLAGS-y)
|
||
CPP = $(CC) -E $(KBUILD_CFLAGS)
|
||
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
|
||
index 6afb13a..241d2f3 100644
|
||
--- a/arch/powerpc/include/asm/exception-64s.h
|
||
+++ b/arch/powerpc/include/asm/exception-64s.h
|
||
@@ -163,7 +163,7 @@ do_kvm_##n: \
|
||
subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \
|
||
beq- 1f; \
|
||
ld r1,PACAKSAVE(r13); /* kernel stack to use */ \
|
||
-1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \
|
||
+1: cmpdi cr1,r1,-INT_FRAME_SIZE; /* check if r1 is in userspace */ \
|
||
blt+ cr1,3f; /* abort if it is */ \
|
||
li r1,(n); /* will be reloaded later */ \
|
||
sth r1,PACA_TRAP_SAVE(r13); \
|
||
diff --git a/arch/powerpc/include/asm/jump_label.h b/arch/powerpc/include/asm/jump_label.h
|
||
index ae098c4..f016bb6 100644
|
||
--- a/arch/powerpc/include/asm/jump_label.h
|
||
+++ b/arch/powerpc/include/asm/jump_label.h
|
||
@@ -19,7 +19,7 @@
|
||
|
||
static __always_inline bool arch_static_branch(struct static_key *key)
|
||
{
|
||
- asm goto("1:\n\t"
|
||
+ asm_volatile_goto("1:\n\t"
|
||
"nop\n\t"
|
||
".pushsection __jump_table, \"aw\"\n\t"
|
||
JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
|
||
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
|
||
index 50f73aa..6f5a837 100644
|
||
--- a/arch/powerpc/include/asm/ppc_asm.h
|
||
+++ b/arch/powerpc/include/asm/ppc_asm.h
|
||
@@ -294,11 +294,16 @@ GLUE(.,name):
|
||
* ld rY,ADDROFF(name)(rX)
|
||
*/
|
||
#ifdef __powerpc64__
|
||
+#ifdef HAVE_AS_ATHIGH
|
||
+#define __AS_ATHIGH high
|
||
+#else
|
||
+#define __AS_ATHIGH h
|
||
+#endif
|
||
#define LOAD_REG_IMMEDIATE(reg,expr) \
|
||
lis (reg),(expr)@highest; \
|
||
ori (reg),(reg),(expr)@higher; \
|
||
rldicr (reg),(reg),32,31; \
|
||
- oris (reg),(reg),(expr)@h; \
|
||
+ oris (reg),(reg),(expr)@__AS_ATHIGH; \
|
||
ori (reg),(reg),(expr)@l;
|
||
|
||
#define LOAD_REG_ADDR(reg,name) \
|
||
diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
|
||
index 92c6b00..b4437e8 100644
|
||
--- a/arch/powerpc/kernel/cacheinfo.c
|
||
+++ b/arch/powerpc/kernel/cacheinfo.c
|
||
@@ -788,6 +788,9 @@ static void remove_cache_dir(struct cache_dir *cache_dir)
|
||
{
|
||
remove_index_dirs(cache_dir);
|
||
|
||
+ /* Remove cache dir from sysfs */
|
||
+ kobject_del(cache_dir->kobj);
|
||
+
|
||
kobject_put(cache_dir->kobj);
|
||
|
||
kfree(cache_dir);
|
||
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
|
||
index b3ba516..9d6a4a4 100644
|
||
--- a/arch/powerpc/kernel/crash_dump.c
|
||
+++ b/arch/powerpc/kernel/crash_dump.c
|
||
@@ -108,17 +108,19 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
|
||
size_t csize, unsigned long offset, int userbuf)
|
||
{
|
||
void *vaddr;
|
||
+ phys_addr_t paddr;
|
||
|
||
if (!csize)
|
||
return 0;
|
||
|
||
csize = min_t(size_t, csize, PAGE_SIZE);
|
||
+ paddr = pfn << PAGE_SHIFT;
|
||
|
||
- if ((min_low_pfn < pfn) && (pfn < max_pfn)) {
|
||
- vaddr = __va(pfn << PAGE_SHIFT);
|
||
+ if (memblock_is_region_memory(paddr, csize)) {
|
||
+ vaddr = __va(paddr);
|
||
csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
|
||
} else {
|
||
- vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0);
|
||
+ vaddr = __ioremap(paddr, PAGE_SIZE, 0);
|
||
csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
|
||
iounmap(vaddr);
|
||
}
|
||
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
|
||
index 8f880bc..846a163 100644
|
||
--- a/arch/powerpc/kernel/exceptions-64s.S
|
||
+++ b/arch/powerpc/kernel/exceptions-64s.S
|
||
@@ -491,7 +491,7 @@ machine_check_common:
|
||
STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception)
|
||
STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception)
|
||
STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception)
|
||
- STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception)
|
||
+ STD_EXCEPTION_COMMON(0xe40, emulation_assist, .emulation_assist_interrupt)
|
||
STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception)
|
||
STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception)
|
||
STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception)
|
||
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
|
||
index 1a3607b..1a5b687 100644
|
||
--- a/arch/powerpc/kernel/head_64.S
|
||
+++ b/arch/powerpc/kernel/head_64.S
|
||
@@ -447,6 +447,7 @@ _STATIC(__after_prom_start)
|
||
mtctr r8
|
||
bctr
|
||
|
||
+.balign 8
|
||
p_end: .llong _end - _stext
|
||
|
||
4: /* Now copy the rest of the kernel up to _end */
|
||
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
|
||
index f5725bc..f62fda1 100644
|
||
--- a/arch/powerpc/kernel/lparcfg.c
|
||
+++ b/arch/powerpc/kernel/lparcfg.c
|
||
@@ -35,7 +35,13 @@
|
||
#include <asm/vdso_datapage.h>
|
||
#include <asm/vio.h>
|
||
#include <asm/mmu.h>
|
||
+#include <asm/machdep.h>
|
||
|
||
+
|
||
+/*
|
||
+ * This isn't a module but we expose that to userspace
|
||
+ * via /proc so leave the definitions here
|
||
+ */
|
||
#define MODULE_VERS "1.9"
|
||
#define MODULE_NAME "lparcfg"
|
||
|
||
@@ -301,6 +307,7 @@ static void parse_system_parameter_string(struct seq_file *m)
|
||
__pa(rtas_data_buf),
|
||
RTAS_DATA_BUF_SIZE);
|
||
memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH);
|
||
+ local_buffer[SPLPAR_MAXLENGTH - 1] = '\0';
|
||
spin_unlock(&rtas_data_buf_lock);
|
||
|
||
if (call_status != 0) {
|
||
@@ -419,7 +426,8 @@ static void parse_em_data(struct seq_file *m)
|
||
{
|
||
unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
|
||
|
||
- if (plpar_hcall(H_GET_EM_PARMS, retbuf) == H_SUCCESS)
|
||
+ if (firmware_has_feature(FW_FEATURE_LPAR) &&
|
||
+ plpar_hcall(H_GET_EM_PARMS, retbuf) == H_SUCCESS)
|
||
seq_printf(m, "power_mode_data=%016lx\n", retbuf[0]);
|
||
}
|
||
|
||
@@ -678,7 +686,6 @@ static int lparcfg_open(struct inode *inode, struct file *file)
|
||
}
|
||
|
||
static const struct file_operations lparcfg_fops = {
|
||
- .owner = THIS_MODULE,
|
||
.read = seq_read,
|
||
.write = lparcfg_write,
|
||
.open = lparcfg_open,
|
||
@@ -704,15 +711,4 @@ static int __init lparcfg_init(void)
|
||
proc_ppc64_lparcfg = ent;
|
||
return 0;
|
||
}
|
||
-
|
||
-static void __exit lparcfg_cleanup(void)
|
||
-{
|
||
- if (proc_ppc64_lparcfg)
|
||
- remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent);
|
||
-}
|
||
-
|
||
-module_init(lparcfg_init);
|
||
-module_exit(lparcfg_cleanup);
|
||
-MODULE_DESCRIPTION("Interface for LPAR configuration data");
|
||
-MODULE_AUTHOR("Dave Engebretsen");
|
||
-MODULE_LICENSE("GPL");
|
||
+machine_device_initcall(pseries, lparcfg_init);
|
||
diff --git a/arch/powerpc/kernel/reloc_64.S b/arch/powerpc/kernel/reloc_64.S
|
||
index b47a0e1..c712ece 100644
|
||
--- a/arch/powerpc/kernel/reloc_64.S
|
||
+++ b/arch/powerpc/kernel/reloc_64.S
|
||
@@ -81,6 +81,7 @@ _GLOBAL(relocate)
|
||
|
||
6: blr
|
||
|
||
+.balign 8
|
||
p_dyn: .llong __dynamic_start - 0b
|
||
p_rela: .llong __rela_dyn_start - 0b
|
||
p_st: .llong _stext - 0b
|
||
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
|
||
index 389bd4f..5c9eccc 100644
|
||
--- a/arch/powerpc/kernel/setup_64.c
|
||
+++ b/arch/powerpc/kernel/setup_64.c
|
||
@@ -76,7 +76,7 @@
|
||
#endif
|
||
|
||
int boot_cpuid = 0;
|
||
-int __initdata spinning_secondaries;
|
||
+int spinning_secondaries;
|
||
u64 ppc64_pft_size;
|
||
|
||
/* Pick defaults since we might want to patch instructions
|
||
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
|
||
index 45eb998..32e2c81 100644
|
||
--- a/arch/powerpc/kernel/signal_32.c
|
||
+++ b/arch/powerpc/kernel/signal_32.c
|
||
@@ -447,6 +447,12 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
|
||
#endif /* CONFIG_ALTIVEC */
|
||
if (copy_fpr_to_user(&frame->mc_fregs, current))
|
||
return 1;
|
||
+
|
||
+ /*
|
||
+ * Clear the MSR VSX bit to indicate there is no valid state attached
|
||
+ * to this context, except in the specific case below where we set it.
|
||
+ */
|
||
+ msr &= ~MSR_VSX;
|
||
#ifdef CONFIG_VSX
|
||
/*
|
||
* Copy VSR 0-31 upper half from thread_struct to local
|
||
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
|
||
index 2692efd..3ad1b50 100644
|
||
--- a/arch/powerpc/kernel/signal_64.c
|
||
+++ b/arch/powerpc/kernel/signal_64.c
|
||
@@ -117,6 +117,12 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
|
||
flush_fp_to_thread(current);
|
||
/* copy fpr regs and fpscr */
|
||
err |= copy_fpr_to_user(&sc->fp_regs, current);
|
||
+
|
||
+ /*
|
||
+ * Clear the MSR VSX bit to indicate there is no valid state attached
|
||
+ * to this context, except in the specific case below where we set it.
|
||
+ */
|
||
+ msr &= ~MSR_VSX;
|
||
#ifdef CONFIG_VSX
|
||
/*
|
||
* Copy VSX low doubleword to local buffer for formatting,
|
||
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
|
||
index 8302af6..a191a72 100644
|
||
--- a/arch/powerpc/kernel/sysfs.c
|
||
+++ b/arch/powerpc/kernel/sysfs.c
|
||
@@ -17,6 +17,7 @@
|
||
#include <asm/machdep.h>
|
||
#include <asm/smp.h>
|
||
#include <asm/pmc.h>
|
||
+#include <asm/firmware.h>
|
||
|
||
#include "cacheinfo.h"
|
||
|
||
@@ -179,15 +180,25 @@ SYSFS_PMCSETUP(spurr, SPRN_SPURR);
|
||
SYSFS_PMCSETUP(dscr, SPRN_DSCR);
|
||
SYSFS_PMCSETUP(pir, SPRN_PIR);
|
||
|
||
+/*
|
||
+ Lets only enable read for phyp resources and
|
||
+ enable write when needed with a separate function.
|
||
+ Lets be conservative and default to pseries.
|
||
+ */
|
||
static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
|
||
static DEVICE_ATTR(spurr, 0600, show_spurr, NULL);
|
||
static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);
|
||
-static DEVICE_ATTR(purr, 0600, show_purr, store_purr);
|
||
+static DEVICE_ATTR(purr, 0400, show_purr, store_purr);
|
||
static DEVICE_ATTR(pir, 0400, show_pir, NULL);
|
||
|
||
unsigned long dscr_default = 0;
|
||
EXPORT_SYMBOL(dscr_default);
|
||
|
||
+static void add_write_permission_dev_attr(struct device_attribute *attr)
|
||
+{
|
||
+ attr->attr.mode |= 0200;
|
||
+}
|
||
+
|
||
static ssize_t show_dscr_default(struct device *dev,
|
||
struct device_attribute *attr, char *buf)
|
||
{
|
||
@@ -394,8 +405,11 @@ static void __cpuinit register_cpu_online(unsigned int cpu)
|
||
if (cpu_has_feature(CPU_FTR_MMCRA))
|
||
device_create_file(s, &dev_attr_mmcra);
|
||
|
||
- if (cpu_has_feature(CPU_FTR_PURR))
|
||
+ if (cpu_has_feature(CPU_FTR_PURR)) {
|
||
+ if (!firmware_has_feature(FW_FEATURE_LPAR))
|
||
+ add_write_permission_dev_attr(&dev_attr_purr);
|
||
device_create_file(s, &dev_attr_purr);
|
||
+ }
|
||
|
||
if (cpu_has_feature(CPU_FTR_SPURR))
|
||
device_create_file(s, &dev_attr_spurr);
|
||
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
|
||
index e7dba0b..b32729b6 100644
|
||
--- a/arch/powerpc/kernel/time.c
|
||
+++ b/arch/powerpc/kernel/time.c
|
||
@@ -212,8 +212,6 @@ static u64 scan_dispatch_log(u64 stop_tb)
|
||
if (i == vpa->dtl_idx)
|
||
return 0;
|
||
while (i < vpa->dtl_idx) {
|
||
- if (dtl_consumer)
|
||
- dtl_consumer(dtl, i);
|
||
dtb = dtl->timebase;
|
||
tb_delta = dtl->enqueue_to_dispatch_time +
|
||
dtl->ready_to_enqueue_time;
|
||
@@ -226,6 +224,8 @@ static u64 scan_dispatch_log(u64 stop_tb)
|
||
}
|
||
if (dtb > stop_tb)
|
||
break;
|
||
+ if (dtl_consumer)
|
||
+ dtl_consumer(dtl, i);
|
||
stolen += tb_delta;
|
||
++i;
|
||
++dtl;
|
||
@@ -496,7 +496,7 @@ void timer_interrupt(struct pt_regs * regs)
|
||
|
||
__get_cpu_var(irq_stat).timer_irqs++;
|
||
|
||
-#if defined(CONFIG_PPC32) && defined(CONFIG_PMAC)
|
||
+#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_PMAC)
|
||
if (atomic_read(&ppc_n_lost_interrupts) != 0)
|
||
do_IRQ(regs);
|
||
#endif
|
||
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
|
||
index 3bb7197..5557044 100644
|
||
--- a/arch/powerpc/kernel/traps.c
|
||
+++ b/arch/powerpc/kernel/traps.c
|
||
@@ -1074,6 +1074,16 @@ void __kprobes program_check_exception(struct pt_regs *regs)
|
||
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
|
||
}
|
||
|
||
+/*
|
||
+ * This occurs when running in hypervisor mode on POWER6 or later
|
||
+ * and an illegal instruction is encountered.
|
||
+ */
|
||
+void __kprobes emulation_assist_interrupt(struct pt_regs *regs)
|
||
+{
|
||
+ regs->msr |= REASON_ILLEGAL;
|
||
+ program_check_exception(regs);
|
||
+}
|
||
+
|
||
void alignment_exception(struct pt_regs *regs)
|
||
{
|
||
int sig, code, fixed = 0;
|
||
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
|
||
index 469b861..a25dac7 100644
|
||
--- a/arch/powerpc/kernel/vio.c
|
||
+++ b/arch/powerpc/kernel/vio.c
|
||
@@ -1343,12 +1343,12 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||
|
||
dn = dev->of_node;
|
||
if (!dn) {
|
||
- strcat(buf, "\n");
|
||
+ strcpy(buf, "\n");
|
||
return strlen(buf);
|
||
}
|
||
cp = of_get_property(dn, "compatible", NULL);
|
||
if (!cp) {
|
||
- strcat(buf, "\n");
|
||
+ strcpy(buf, "\n");
|
||
return strlen(buf);
|
||
}
|
||
|
||
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
|
||
index c3beaee..87135be 100644
|
||
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
|
||
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
|
||
@@ -393,11 +393,14 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||
slb_v = vcpu->kvm->arch.vrma_slb_v;
|
||
}
|
||
|
||
+ preempt_disable();
|
||
/* Find the HPTE in the hash table */
|
||
index = kvmppc_hv_find_lock_hpte(kvm, eaddr, slb_v,
|
||
HPTE_V_VALID | HPTE_V_ABSENT);
|
||
- if (index < 0)
|
||
+ if (index < 0) {
|
||
+ preempt_enable();
|
||
return -ENOENT;
|
||
+ }
|
||
hptep = (unsigned long *)(kvm->arch.hpt_virt + (index << 4));
|
||
v = hptep[0] & ~HPTE_V_HVLOCK;
|
||
gr = kvm->arch.revmap[index].guest_rpte;
|
||
@@ -405,6 +408,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||
/* Unlock the HPTE */
|
||
asm volatile("lwsync" : : : "memory");
|
||
hptep[0] = v;
|
||
+ preempt_enable();
|
||
|
||
gpte->eaddr = eaddr;
|
||
gpte->vpage = ((v & HPTE_V_AVPN) << 4) | ((eaddr >> 12) & 0xfff);
|
||
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
|
||
index cec4dad..eacf164 100644
|
||
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
|
||
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
|
||
@@ -649,6 +649,10 @@ static int slb_base_page_shift[4] = {
|
||
20, /* 1M, unsupported */
|
||
};
|
||
|
||
+/* When called from virtmode, this func should be protected by
|
||
+ * preempt_disable(), otherwise, the holding of HPTE_V_HVLOCK
|
||
+ * can trigger deadlock issue.
|
||
+ */
|
||
long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
|
||
unsigned long valid)
|
||
{
|
||
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
|
||
index 968f401..59a1edd 100644
|
||
--- a/arch/powerpc/kvm/emulate.c
|
||
+++ b/arch/powerpc/kvm/emulate.c
|
||
@@ -36,6 +36,7 @@
|
||
#define OP_TRAP_64 2
|
||
|
||
#define OP_31_XOP_LWZX 23
|
||
+#define OP_31_XOP_DCBF 86
|
||
#define OP_31_XOP_LBZX 87
|
||
#define OP_31_XOP_STWX 151
|
||
#define OP_31_XOP_STBX 215
|
||
@@ -373,6 +374,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||
kvmppc_set_exit_type(vcpu, EMULATED_MTSPR_EXITS);
|
||
break;
|
||
|
||
+ case OP_31_XOP_DCBF:
|
||
case OP_31_XOP_DCBI:
|
||
/* Do nothing. The guest is performing dcbi because
|
||
* hardware DMA is not snooped by the dcache, but
|
||
diff --git a/arch/powerpc/lib/checksum_64.S b/arch/powerpc/lib/checksum_64.S
|
||
index afa2eba..3cdbc64 100644
|
||
--- a/arch/powerpc/lib/checksum_64.S
|
||
+++ b/arch/powerpc/lib/checksum_64.S
|
||
@@ -229,19 +229,35 @@ _GLOBAL(csum_partial)
|
||
blr
|
||
|
||
|
||
- .macro source
|
||
+ .macro srcnr
|
||
100:
|
||
.section __ex_table,"a"
|
||
.align 3
|
||
- .llong 100b,.Lsrc_error
|
||
+ .llong 100b,.Lsrc_error_nr
|
||
.previous
|
||
.endm
|
||
|
||
- .macro dest
|
||
+ .macro source
|
||
+150:
|
||
+ .section __ex_table,"a"
|
||
+ .align 3
|
||
+ .llong 150b,.Lsrc_error
|
||
+ .previous
|
||
+ .endm
|
||
+
|
||
+ .macro dstnr
|
||
200:
|
||
.section __ex_table,"a"
|
||
.align 3
|
||
- .llong 200b,.Ldest_error
|
||
+ .llong 200b,.Ldest_error_nr
|
||
+ .previous
|
||
+ .endm
|
||
+
|
||
+ .macro dest
|
||
+250:
|
||
+ .section __ex_table,"a"
|
||
+ .align 3
|
||
+ .llong 250b,.Ldest_error
|
||
.previous
|
||
.endm
|
||
|
||
@@ -277,11 +293,11 @@ _GLOBAL(csum_partial_copy_generic)
|
||
mtctr r6
|
||
|
||
1:
|
||
-source; lhz r6,0(r3) /* align to doubleword */
|
||
+srcnr; lhz r6,0(r3) /* align to doubleword */
|
||
subi r5,r5,2
|
||
addi r3,r3,2
|
||
adde r0,r0,r6
|
||
-dest; sth r6,0(r4)
|
||
+dstnr; sth r6,0(r4)
|
||
addi r4,r4,2
|
||
bdnz 1b
|
||
|
||
@@ -395,10 +411,10 @@ dest; std r16,56(r4)
|
||
|
||
mtctr r6
|
||
3:
|
||
-source; ld r6,0(r3)
|
||
+srcnr; ld r6,0(r3)
|
||
addi r3,r3,8
|
||
adde r0,r0,r6
|
||
-dest; std r6,0(r4)
|
||
+dstnr; std r6,0(r4)
|
||
addi r4,r4,8
|
||
bdnz 3b
|
||
|
||
@@ -408,10 +424,10 @@ dest; std r6,0(r4)
|
||
srdi. r6,r5,2
|
||
beq .Lcopy_tail_halfword
|
||
|
||
-source; lwz r6,0(r3)
|
||
+srcnr; lwz r6,0(r3)
|
||
addi r3,r3,4
|
||
adde r0,r0,r6
|
||
-dest; stw r6,0(r4)
|
||
+dstnr; stw r6,0(r4)
|
||
addi r4,r4,4
|
||
subi r5,r5,4
|
||
|
||
@@ -419,10 +435,10 @@ dest; stw r6,0(r4)
|
||
srdi. r6,r5,1
|
||
beq .Lcopy_tail_byte
|
||
|
||
-source; lhz r6,0(r3)
|
||
+srcnr; lhz r6,0(r3)
|
||
addi r3,r3,2
|
||
adde r0,r0,r6
|
||
-dest; sth r6,0(r4)
|
||
+dstnr; sth r6,0(r4)
|
||
addi r4,r4,2
|
||
subi r5,r5,2
|
||
|
||
@@ -430,10 +446,10 @@ dest; sth r6,0(r4)
|
||
andi. r6,r5,1
|
||
beq .Lcopy_finish
|
||
|
||
-source; lbz r6,0(r3)
|
||
+srcnr; lbz r6,0(r3)
|
||
sldi r9,r6,8 /* Pad the byte out to 16 bits */
|
||
adde r0,r0,r9
|
||
-dest; stb r6,0(r4)
|
||
+dstnr; stb r6,0(r4)
|
||
|
||
.Lcopy_finish:
|
||
addze r0,r0 /* add in final carry */
|
||
@@ -443,6 +459,11 @@ dest; stb r6,0(r4)
|
||
blr
|
||
|
||
.Lsrc_error:
|
||
+ ld r14,STK_REG(r14)(r1)
|
||
+ ld r15,STK_REG(r15)(r1)
|
||
+ ld r16,STK_REG(r16)(r1)
|
||
+ addi r1,r1,STACKFRAMESIZE
|
||
+.Lsrc_error_nr:
|
||
cmpdi 0,r7,0
|
||
beqlr
|
||
li r6,-EFAULT
|
||
@@ -450,6 +471,11 @@ dest; stb r6,0(r4)
|
||
blr
|
||
|
||
.Ldest_error:
|
||
+ ld r14,STK_REG(r14)(r1)
|
||
+ ld r15,STK_REG(r15)(r1)
|
||
+ ld r16,STK_REG(r16)(r1)
|
||
+ addi r1,r1,STACKFRAMESIZE
|
||
+.Ldest_error_nr:
|
||
cmpdi 0,r8,0
|
||
beqlr
|
||
li r6,-EFAULT
|
||
diff --git a/arch/powerpc/lib/crtsavres.S b/arch/powerpc/lib/crtsavres.S
|
||
index 1c893f0..21ecdf5 100644
|
||
--- a/arch/powerpc/lib/crtsavres.S
|
||
+++ b/arch/powerpc/lib/crtsavres.S
|
||
@@ -230,6 +230,87 @@ _GLOBAL(_rest32gpr_31_x)
|
||
mr 1,11
|
||
blr
|
||
|
||
+#ifdef CONFIG_ALTIVEC
|
||
+/* Called with r0 pointing just beyond the end of the vector save area. */
|
||
+
|
||
+_GLOBAL(_savevr_20)
|
||
+ li r11,-192
|
||
+ stvx vr20,r11,r0
|
||
+_GLOBAL(_savevr_21)
|
||
+ li r11,-176
|
||
+ stvx vr21,r11,r0
|
||
+_GLOBAL(_savevr_22)
|
||
+ li r11,-160
|
||
+ stvx vr22,r11,r0
|
||
+_GLOBAL(_savevr_23)
|
||
+ li r11,-144
|
||
+ stvx vr23,r11,r0
|
||
+_GLOBAL(_savevr_24)
|
||
+ li r11,-128
|
||
+ stvx vr24,r11,r0
|
||
+_GLOBAL(_savevr_25)
|
||
+ li r11,-112
|
||
+ stvx vr25,r11,r0
|
||
+_GLOBAL(_savevr_26)
|
||
+ li r11,-96
|
||
+ stvx vr26,r11,r0
|
||
+_GLOBAL(_savevr_27)
|
||
+ li r11,-80
|
||
+ stvx vr27,r11,r0
|
||
+_GLOBAL(_savevr_28)
|
||
+ li r11,-64
|
||
+ stvx vr28,r11,r0
|
||
+_GLOBAL(_savevr_29)
|
||
+ li r11,-48
|
||
+ stvx vr29,r11,r0
|
||
+_GLOBAL(_savevr_30)
|
||
+ li r11,-32
|
||
+ stvx vr30,r11,r0
|
||
+_GLOBAL(_savevr_31)
|
||
+ li r11,-16
|
||
+ stvx vr31,r11,r0
|
||
+ blr
|
||
+
|
||
+_GLOBAL(_restvr_20)
|
||
+ li r11,-192
|
||
+ lvx vr20,r11,r0
|
||
+_GLOBAL(_restvr_21)
|
||
+ li r11,-176
|
||
+ lvx vr21,r11,r0
|
||
+_GLOBAL(_restvr_22)
|
||
+ li r11,-160
|
||
+ lvx vr22,r11,r0
|
||
+_GLOBAL(_restvr_23)
|
||
+ li r11,-144
|
||
+ lvx vr23,r11,r0
|
||
+_GLOBAL(_restvr_24)
|
||
+ li r11,-128
|
||
+ lvx vr24,r11,r0
|
||
+_GLOBAL(_restvr_25)
|
||
+ li r11,-112
|
||
+ lvx vr25,r11,r0
|
||
+_GLOBAL(_restvr_26)
|
||
+ li r11,-96
|
||
+ lvx vr26,r11,r0
|
||
+_GLOBAL(_restvr_27)
|
||
+ li r11,-80
|
||
+ lvx vr27,r11,r0
|
||
+_GLOBAL(_restvr_28)
|
||
+ li r11,-64
|
||
+ lvx vr28,r11,r0
|
||
+_GLOBAL(_restvr_29)
|
||
+ li r11,-48
|
||
+ lvx vr29,r11,r0
|
||
+_GLOBAL(_restvr_30)
|
||
+ li r11,-32
|
||
+ lvx vr30,r11,r0
|
||
+_GLOBAL(_restvr_31)
|
||
+ li r11,-16
|
||
+ lvx vr31,r11,r0
|
||
+ blr
|
||
+
|
||
+#endif /* CONFIG_ALTIVEC */
|
||
+
|
||
#else /* CONFIG_PPC64 */
|
||
|
||
.globl _savegpr0_14
|
||
@@ -353,6 +434,111 @@ _restgpr0_31:
|
||
mtlr r0
|
||
blr
|
||
|
||
+#ifdef CONFIG_ALTIVEC
|
||
+/* Called with r0 pointing just beyond the end of the vector save area. */
|
||
+
|
||
+.globl _savevr_20
|
||
+_savevr_20:
|
||
+ li r12,-192
|
||
+ stvx vr20,r12,r0
|
||
+.globl _savevr_21
|
||
+_savevr_21:
|
||
+ li r12,-176
|
||
+ stvx vr21,r12,r0
|
||
+.globl _savevr_22
|
||
+_savevr_22:
|
||
+ li r12,-160
|
||
+ stvx vr22,r12,r0
|
||
+.globl _savevr_23
|
||
+_savevr_23:
|
||
+ li r12,-144
|
||
+ stvx vr23,r12,r0
|
||
+.globl _savevr_24
|
||
+_savevr_24:
|
||
+ li r12,-128
|
||
+ stvx vr24,r12,r0
|
||
+.globl _savevr_25
|
||
+_savevr_25:
|
||
+ li r12,-112
|
||
+ stvx vr25,r12,r0
|
||
+.globl _savevr_26
|
||
+_savevr_26:
|
||
+ li r12,-96
|
||
+ stvx vr26,r12,r0
|
||
+.globl _savevr_27
|
||
+_savevr_27:
|
||
+ li r12,-80
|
||
+ stvx vr27,r12,r0
|
||
+.globl _savevr_28
|
||
+_savevr_28:
|
||
+ li r12,-64
|
||
+ stvx vr28,r12,r0
|
||
+.globl _savevr_29
|
||
+_savevr_29:
|
||
+ li r12,-48
|
||
+ stvx vr29,r12,r0
|
||
+.globl _savevr_30
|
||
+_savevr_30:
|
||
+ li r12,-32
|
||
+ stvx vr30,r12,r0
|
||
+.globl _savevr_31
|
||
+_savevr_31:
|
||
+ li r12,-16
|
||
+ stvx vr31,r12,r0
|
||
+ blr
|
||
+
|
||
+.globl _restvr_20
|
||
+_restvr_20:
|
||
+ li r12,-192
|
||
+ lvx vr20,r12,r0
|
||
+.globl _restvr_21
|
||
+_restvr_21:
|
||
+ li r12,-176
|
||
+ lvx vr21,r12,r0
|
||
+.globl _restvr_22
|
||
+_restvr_22:
|
||
+ li r12,-160
|
||
+ lvx vr22,r12,r0
|
||
+.globl _restvr_23
|
||
+_restvr_23:
|
||
+ li r12,-144
|
||
+ lvx vr23,r12,r0
|
||
+.globl _restvr_24
|
||
+_restvr_24:
|
||
+ li r12,-128
|
||
+ lvx vr24,r12,r0
|
||
+.globl _restvr_25
|
||
+_restvr_25:
|
||
+ li r12,-112
|
||
+ lvx vr25,r12,r0
|
||
+.globl _restvr_26
|
||
+_restvr_26:
|
||
+ li r12,-96
|
||
+ lvx vr26,r12,r0
|
||
+.globl _restvr_27
|
||
+_restvr_27:
|
||
+ li r12,-80
|
||
+ lvx vr27,r12,r0
|
||
+.globl _restvr_28
|
||
+_restvr_28:
|
||
+ li r12,-64
|
||
+ lvx vr28,r12,r0
|
||
+.globl _restvr_29
|
||
+_restvr_29:
|
||
+ li r12,-48
|
||
+ lvx vr29,r12,r0
|
||
+.globl _restvr_30
|
||
+_restvr_30:
|
||
+ li r12,-32
|
||
+ lvx vr30,r12,r0
|
||
+.globl _restvr_31
|
||
+_restvr_31:
|
||
+ li r12,-16
|
||
+ lvx vr31,r12,r0
|
||
+ blr
|
||
+
|
||
+#endif /* CONFIG_ALTIVEC */
|
||
+
|
||
#endif /* CONFIG_PPC64 */
|
||
|
||
#endif
|
||
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
|
||
index 9a52349..e3b28e3 100644
|
||
--- a/arch/powerpc/lib/sstep.c
|
||
+++ b/arch/powerpc/lib/sstep.c
|
||
@@ -1395,7 +1395,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
|
||
regs->gpr[rd] = byterev_4(val);
|
||
goto ldst_done;
|
||
|
||
-#ifdef CONFIG_PPC_CPU
|
||
+#ifdef CONFIG_PPC_FPU
|
||
case 535: /* lfsx */
|
||
case 567: /* lfsux */
|
||
if (!(regs->msr & MSR_FP))
|
||
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
|
||
index 02aee03..1eef567 100644
|
||
--- a/arch/powerpc/perf/core-book3s.c
|
||
+++ b/arch/powerpc/perf/core-book3s.c
|
||
@@ -472,7 +472,22 @@ static void power_pmu_read(struct perf_event *event)
|
||
} while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
|
||
|
||
local64_add(delta, &event->count);
|
||
- local64_sub(delta, &event->hw.period_left);
|
||
+
|
||
+ /*
|
||
+ * A number of places program the PMC with (0x80000000 - period_left).
|
||
+ * We never want period_left to be less than 1 because we will program
|
||
+ * the PMC with a value >= 0x800000000 and an edge detected PMC will
|
||
+ * roll around to 0 before taking an exception. We have seen this
|
||
+ * on POWER8.
|
||
+ *
|
||
+ * To fix this, clamp the minimum value of period_left to 1.
|
||
+ */
|
||
+ do {
|
||
+ prev = local64_read(&event->hw.period_left);
|
||
+ val = prev - delta;
|
||
+ if (val < 1)
|
||
+ val = 1;
|
||
+ } while (local64_cmpxchg(&event->hw.period_left, prev, val) != prev);
|
||
}
|
||
|
||
/*
|
||
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
|
||
index fbdd74d..5da8e8d 100644
|
||
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
|
||
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
|
||
@@ -613,13 +613,23 @@ static int __devinit pnv_ioda_configure_pe(struct pnv_phb *phb,
|
||
rid_end = pe->rid + 1;
|
||
}
|
||
|
||
- /* Associate PE in PELT */
|
||
+ /*
|
||
+ * Associate PE in PELT. We need add the PE into the
|
||
+ * corresponding PELT-V as well. Otherwise, the error
|
||
+ * originated from the PE might contribute to other
|
||
+ * PEs.
|
||
+ */
|
||
rc = opal_pci_set_pe(phb->opal_id, pe->pe_number, pe->rid,
|
||
bcomp, dcomp, fcomp, OPAL_MAP_PE);
|
||
if (rc) {
|
||
pe_err(pe, "OPAL error %ld trying to setup PELT table\n", rc);
|
||
return -ENXIO;
|
||
}
|
||
+
|
||
+ rc = opal_pci_set_peltv(phb->opal_id, pe->pe_number,
|
||
+ pe->pe_number, OPAL_ADD_PE_TO_DOMAIN);
|
||
+ if (rc)
|
||
+ pe_warn(pe, "OPAL error %d adding self to PELTV\n", rc);
|
||
opal_pci_eeh_freeze_clear(phb->opal_id, pe->pe_number,
|
||
OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
|
||
|
||
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
|
||
index 8a811d9..9c9e245 100644
|
||
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
|
||
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
|
||
@@ -319,6 +319,7 @@ static int pseries_eeh_get_state(struct device_node *dn, int *state)
|
||
} else {
|
||
result = EEH_STATE_NOT_SUPPORT;
|
||
}
|
||
+ break;
|
||
default:
|
||
result = EEH_STATE_NOT_SUPPORT;
|
||
}
|
||
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
|
||
index a9ce135..3ec8b39 100644
|
||
--- a/arch/s390/crypto/aes_s390.c
|
||
+++ b/arch/s390/crypto/aes_s390.c
|
||
@@ -35,7 +35,6 @@ static u8 *ctrblk;
|
||
static char keylen_flag;
|
||
|
||
struct s390_aes_ctx {
|
||
- u8 iv[AES_BLOCK_SIZE];
|
||
u8 key[AES_MAX_KEY_SIZE];
|
||
long enc;
|
||
long dec;
|
||
@@ -56,8 +55,7 @@ struct pcc_param {
|
||
|
||
struct s390_xts_ctx {
|
||
u8 key[32];
|
||
- u8 xts_param[16];
|
||
- struct pcc_param pcc;
|
||
+ u8 pcc_key[32];
|
||
long enc;
|
||
long dec;
|
||
int key_len;
|
||
@@ -442,29 +440,35 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||
return aes_set_key(tfm, in_key, key_len);
|
||
}
|
||
|
||
-static int cbc_aes_crypt(struct blkcipher_desc *desc, long func, void *param,
|
||
+static int cbc_aes_crypt(struct blkcipher_desc *desc, long func,
|
||
struct blkcipher_walk *walk)
|
||
{
|
||
+ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
|
||
int ret = blkcipher_walk_virt(desc, walk);
|
||
unsigned int nbytes = walk->nbytes;
|
||
+ struct {
|
||
+ u8 iv[AES_BLOCK_SIZE];
|
||
+ u8 key[AES_MAX_KEY_SIZE];
|
||
+ } param;
|
||
|
||
if (!nbytes)
|
||
goto out;
|
||
|
||
- memcpy(param, walk->iv, AES_BLOCK_SIZE);
|
||
+ memcpy(param.iv, walk->iv, AES_BLOCK_SIZE);
|
||
+ memcpy(param.key, sctx->key, sctx->key_len);
|
||
do {
|
||
/* only use complete blocks */
|
||
unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||
u8 *out = walk->dst.virt.addr;
|
||
u8 *in = walk->src.virt.addr;
|
||
|
||
- ret = crypt_s390_kmc(func, param, out, in, n);
|
||
+ ret = crypt_s390_kmc(func, ¶m, out, in, n);
|
||
BUG_ON((ret < 0) || (ret != n));
|
||
|
||
nbytes &= AES_BLOCK_SIZE - 1;
|
||
ret = blkcipher_walk_done(desc, walk, nbytes);
|
||
} while ((nbytes = walk->nbytes));
|
||
- memcpy(walk->iv, param, AES_BLOCK_SIZE);
|
||
+ memcpy(walk->iv, param.iv, AES_BLOCK_SIZE);
|
||
|
||
out:
|
||
return ret;
|
||
@@ -481,7 +485,7 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
|
||
return fallback_blk_enc(desc, dst, src, nbytes);
|
||
|
||
blkcipher_walk_init(&walk, dst, src, nbytes);
|
||
- return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
|
||
+ return cbc_aes_crypt(desc, sctx->enc, &walk);
|
||
}
|
||
|
||
static int cbc_aes_decrypt(struct blkcipher_desc *desc,
|
||
@@ -495,7 +499,7 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
|
||
return fallback_blk_dec(desc, dst, src, nbytes);
|
||
|
||
blkcipher_walk_init(&walk, dst, src, nbytes);
|
||
- return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
|
||
+ return cbc_aes_crypt(desc, sctx->dec, &walk);
|
||
}
|
||
|
||
static struct crypto_alg cbc_aes_alg = {
|
||
@@ -587,7 +591,7 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||
xts_ctx->enc = KM_XTS_128_ENCRYPT;
|
||
xts_ctx->dec = KM_XTS_128_DECRYPT;
|
||
memcpy(xts_ctx->key + 16, in_key, 16);
|
||
- memcpy(xts_ctx->pcc.key + 16, in_key + 16, 16);
|
||
+ memcpy(xts_ctx->pcc_key + 16, in_key + 16, 16);
|
||
break;
|
||
case 48:
|
||
xts_ctx->enc = 0;
|
||
@@ -598,7 +602,7 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||
xts_ctx->enc = KM_XTS_256_ENCRYPT;
|
||
xts_ctx->dec = KM_XTS_256_DECRYPT;
|
||
memcpy(xts_ctx->key, in_key, 32);
|
||
- memcpy(xts_ctx->pcc.key, in_key + 32, 32);
|
||
+ memcpy(xts_ctx->pcc_key, in_key + 32, 32);
|
||
break;
|
||
default:
|
||
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
|
||
@@ -617,28 +621,32 @@ static int xts_aes_crypt(struct blkcipher_desc *desc, long func,
|
||
unsigned int nbytes = walk->nbytes;
|
||
unsigned int n;
|
||
u8 *in, *out;
|
||
- void *param;
|
||
+ struct pcc_param pcc_param;
|
||
+ struct {
|
||
+ u8 key[32];
|
||
+ u8 init[16];
|
||
+ } xts_param;
|
||
|
||
if (!nbytes)
|
||
goto out;
|
||
|
||
- memset(xts_ctx->pcc.block, 0, sizeof(xts_ctx->pcc.block));
|
||
- memset(xts_ctx->pcc.bit, 0, sizeof(xts_ctx->pcc.bit));
|
||
- memset(xts_ctx->pcc.xts, 0, sizeof(xts_ctx->pcc.xts));
|
||
- memcpy(xts_ctx->pcc.tweak, walk->iv, sizeof(xts_ctx->pcc.tweak));
|
||
- param = xts_ctx->pcc.key + offset;
|
||
- ret = crypt_s390_pcc(func, param);
|
||
+ memset(pcc_param.block, 0, sizeof(pcc_param.block));
|
||
+ memset(pcc_param.bit, 0, sizeof(pcc_param.bit));
|
||
+ memset(pcc_param.xts, 0, sizeof(pcc_param.xts));
|
||
+ memcpy(pcc_param.tweak, walk->iv, sizeof(pcc_param.tweak));
|
||
+ memcpy(pcc_param.key, xts_ctx->pcc_key, 32);
|
||
+ ret = crypt_s390_pcc(func, &pcc_param.key[offset]);
|
||
BUG_ON(ret < 0);
|
||
|
||
- memcpy(xts_ctx->xts_param, xts_ctx->pcc.xts, 16);
|
||
- param = xts_ctx->key + offset;
|
||
+ memcpy(xts_param.key, xts_ctx->key, 32);
|
||
+ memcpy(xts_param.init, pcc_param.xts, 16);
|
||
do {
|
||
/* only use complete blocks */
|
||
n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||
out = walk->dst.virt.addr;
|
||
in = walk->src.virt.addr;
|
||
|
||
- ret = crypt_s390_km(func, param, out, in, n);
|
||
+ ret = crypt_s390_km(func, &xts_param.key[offset], out, in, n);
|
||
BUG_ON(ret < 0 || ret != n);
|
||
|
||
nbytes &= AES_BLOCK_SIZE - 1;
|
||
diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h
|
||
index 6c32190..346b1c8 100644
|
||
--- a/arch/s390/include/asm/jump_label.h
|
||
+++ b/arch/s390/include/asm/jump_label.h
|
||
@@ -15,7 +15,7 @@
|
||
|
||
static __always_inline bool arch_static_branch(struct static_key *key)
|
||
{
|
||
- asm goto("0: brcl 0,0\n"
|
||
+ asm_volatile_goto("0: brcl 0,0\n"
|
||
".pushsection __jump_table, \"aw\"\n"
|
||
ASM_ALIGN "\n"
|
||
ASM_PTR " 0b, %l[label], %0\n"
|
||
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
|
||
index 47853de..025415e 100644
|
||
--- a/arch/s390/include/asm/lowcore.h
|
||
+++ b/arch/s390/include/asm/lowcore.h
|
||
@@ -142,9 +142,9 @@ struct _lowcore {
|
||
__u8 pad_0x02fc[0x0300-0x02fc]; /* 0x02fc */
|
||
|
||
/* Interrupt response block */
|
||
- __u8 irb[64]; /* 0x0300 */
|
||
+ __u8 irb[96]; /* 0x0300 */
|
||
|
||
- __u8 pad_0x0340[0x0e00-0x0340]; /* 0x0340 */
|
||
+ __u8 pad_0x0360[0x0e00-0x0360]; /* 0x0360 */
|
||
|
||
/*
|
||
* 0xe00 contains the address of the IPL Parameter Information
|
||
@@ -288,12 +288,13 @@ struct _lowcore {
|
||
__u8 pad_0x03a0[0x0400-0x03a0]; /* 0x03a0 */
|
||
|
||
/* Interrupt response block. */
|
||
- __u8 irb[64]; /* 0x0400 */
|
||
+ __u8 irb[96]; /* 0x0400 */
|
||
+ __u8 pad_0x0460[0x0480-0x0460]; /* 0x0460 */
|
||
|
||
/* Per cpu primary space access list */
|
||
- __u32 paste[16]; /* 0x0440 */
|
||
+ __u32 paste[16]; /* 0x0480 */
|
||
|
||
- __u8 pad_0x0480[0x0e00-0x0480]; /* 0x0480 */
|
||
+ __u8 pad_0x04c0[0x0e00-0x04c0]; /* 0x04c0 */
|
||
|
||
/*
|
||
* 0xe00 contains the address of the IPL Parameter Information
|
||
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
|
||
index 99348c0..78be245 100644
|
||
--- a/arch/s390/kernel/head64.S
|
||
+++ b/arch/s390/kernel/head64.S
|
||
@@ -61,7 +61,7 @@ ENTRY(startup_continue)
|
||
.quad 0 # cr12: tracing off
|
||
.quad 0 # cr13: home space segment table
|
||
.quad 0xc0000000 # cr14: machine check handling off
|
||
- .quad 0 # cr15: linkage stack operations
|
||
+ .quad .Llinkage_stack # cr15: linkage stack operations
|
||
.Lpcmsk:.quad 0x0000000180000000
|
||
.L4malign:.quad 0xffffffffffc00000
|
||
.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
|
||
@@ -69,12 +69,15 @@ ENTRY(startup_continue)
|
||
.Lparmaddr:
|
||
.quad PARMAREA
|
||
.align 64
|
||
-.Lduct: .long 0,0,0,0,.Lduald,0,0,0
|
||
+.Lduct: .long 0,.Laste,.Laste,0,.Lduald,0,0,0
|
||
.long 0,0,0,0,0,0,0,0
|
||
+.Laste: .quad 0,0xffffffffffffffff,0,0,0,0,0,0
|
||
.align 128
|
||
.Lduald:.rept 8
|
||
.long 0x80000000,0,0,0 # invalid access-list entries
|
||
.endr
|
||
+.Llinkage_stack:
|
||
+ .long 0,0,0x89000000,0,0,0,0x8a000000,0
|
||
|
||
ENTRY(_ehead)
|
||
|
||
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
|
||
index 4993e68..9e15f30 100644
|
||
--- a/arch/s390/kernel/ptrace.c
|
||
+++ b/arch/s390/kernel/ptrace.c
|
||
@@ -292,7 +292,9 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
||
* psw and gprs are stored on the stack
|
||
*/
|
||
if (addr == (addr_t) &dummy->regs.psw.mask &&
|
||
- ((data & ~PSW_MASK_USER) != psw_user_bits ||
|
||
+ (((data^psw_user_bits) & ~PSW_MASK_USER) ||
|
||
+ (((data^psw_user_bits) & PSW_MASK_ASC) &&
|
||
+ ((data|psw_user_bits) & PSW_MASK_ASC) == PSW_MASK_ASC) ||
|
||
((data & PSW_MASK_EA) && !(data & PSW_MASK_BA))))
|
||
/* Invalid psw mask. */
|
||
return -EINVAL;
|
||
@@ -595,7 +597,10 @@ static int __poke_user_compat(struct task_struct *child,
|
||
*/
|
||
if (addr == (addr_t) &dummy32->regs.psw.mask) {
|
||
/* Build a 64 bit psw mask from 31 bit mask. */
|
||
- if ((tmp & ~PSW32_MASK_USER) != psw32_user_bits)
|
||
+ if (((tmp^psw32_user_bits) & ~PSW32_MASK_USER) ||
|
||
+ (((tmp^psw32_user_bits) & PSW32_MASK_ASC) &&
|
||
+ ((tmp|psw32_user_bits) & PSW32_MASK_ASC)
|
||
+ == PSW32_MASK_ASC))
|
||
/* Invalid psw mask. */
|
||
return -EINVAL;
|
||
regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
|
||
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
|
||
index e00accf..0f250d1 100644
|
||
--- a/arch/s390/kvm/kvm-s390.c
|
||
+++ b/arch/s390/kvm/kvm-s390.c
|
||
@@ -525,13 +525,18 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
||
if (!kvm_is_ucontrol(vcpu->kvm))
|
||
kvm_s390_deliver_pending_interrupts(vcpu);
|
||
|
||
+ VCPU_EVENT(vcpu, 6, "entering sie flags %x",
|
||
+ atomic_read(&vcpu->arch.sie_block->cpuflags));
|
||
+
|
||
vcpu->arch.sie_block->icptcode = 0;
|
||
local_irq_disable();
|
||
kvm_guest_enter();
|
||
local_irq_enable();
|
||
- VCPU_EVENT(vcpu, 6, "entering sie flags %x",
|
||
- atomic_read(&vcpu->arch.sie_block->cpuflags));
|
||
rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
|
||
+ local_irq_disable();
|
||
+ kvm_guest_exit();
|
||
+ local_irq_enable();
|
||
+
|
||
if (rc) {
|
||
if (kvm_is_ucontrol(vcpu->kvm)) {
|
||
rc = SIE_INTERCEPT_UCONTROL;
|
||
@@ -543,9 +548,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
||
}
|
||
VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
|
||
vcpu->arch.sie_block->icptcode);
|
||
- local_irq_disable();
|
||
- kvm_guest_exit();
|
||
- local_irq_enable();
|
||
|
||
memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
|
||
return rc;
|
||
@@ -564,17 +566,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||
|
||
BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL);
|
||
|
||
- switch (kvm_run->exit_reason) {
|
||
- case KVM_EXIT_S390_SIEIC:
|
||
- case KVM_EXIT_UNKNOWN:
|
||
- case KVM_EXIT_INTR:
|
||
- case KVM_EXIT_S390_RESET:
|
||
- case KVM_EXIT_S390_UCONTROL:
|
||
- break;
|
||
- default:
|
||
- BUG();
|
||
- }
|
||
-
|
||
vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
|
||
vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
|
||
if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX) {
|
||
@@ -902,7 +893,7 @@ static int __init kvm_s390_init(void)
|
||
}
|
||
memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
|
||
facilities[0] &= 0xff00fff3f47c0000ULL;
|
||
- facilities[1] &= 0x201c000000000000ULL;
|
||
+ facilities[1] &= 0x001c000000000000ULL;
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c
|
||
index a90d45e..27c50f4 100644
|
||
--- a/arch/s390/mm/page-states.c
|
||
+++ b/arch/s390/mm/page-states.c
|
||
@@ -12,6 +12,8 @@
|
||
#include <linux/mm.h>
|
||
#include <linux/gfp.h>
|
||
#include <linux/init.h>
|
||
+#include <asm/setup.h>
|
||
+#include <asm/ipl.h>
|
||
|
||
#define ESSA_SET_STABLE 1
|
||
#define ESSA_SET_UNUSED 2
|
||
@@ -41,6 +43,14 @@ void __init cmma_init(void)
|
||
|
||
if (!cmma_flag)
|
||
return;
|
||
+ /*
|
||
+ * Disable CMM for dump, otherwise the tprot based memory
|
||
+ * detection can fail because of unstable pages.
|
||
+ */
|
||
+ if (OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP) {
|
||
+ cmma_flag = 0;
|
||
+ return;
|
||
+ }
|
||
asm volatile(
|
||
" .insn rrf,0xb9ab0000,%1,%1,0,0\n"
|
||
"0: la %0,0\n"
|
||
diff --git a/arch/sh/kernel/dumpstack.c b/arch/sh/kernel/dumpstack.c
|
||
index 694158b..3a6528c 100644
|
||
--- a/arch/sh/kernel/dumpstack.c
|
||
+++ b/arch/sh/kernel/dumpstack.c
|
||
@@ -80,7 +80,7 @@ static int print_trace_stack(void *data, char *name)
|
||
*/
|
||
static void print_trace_address(void *data, unsigned long addr, int reliable)
|
||
{
|
||
- printk(data);
|
||
+ printk("%s", (char *)data);
|
||
printk_address(addr, reliable);
|
||
}
|
||
|
||
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
|
||
index 7b95f29..3baff31 100644
|
||
--- a/arch/sh/lib/Makefile
|
||
+++ b/arch/sh/lib/Makefile
|
||
@@ -6,7 +6,7 @@ lib-y = delay.o memmove.o memchr.o \
|
||
checksum.o strlen.o div64.o div64-generic.o
|
||
|
||
# Extracted from libgcc
|
||
-lib-y += movmem.o ashldi3.o ashrdi3.o lshrdi3.o \
|
||
+obj-y += movmem.o ashldi3.o ashrdi3.o lshrdi3.o \
|
||
ashlsi3.o ashrsi3.o ashiftrt.o lshrsi3.o \
|
||
udiv_qrnnd.o
|
||
|
||
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
|
||
index 7aff1f8..4454b55 100644
|
||
--- a/arch/sparc/Kconfig
|
||
+++ b/arch/sparc/Kconfig
|
||
@@ -24,7 +24,7 @@ config SPARC
|
||
select HAVE_IRQ_WORK
|
||
select HAVE_DMA_ATTRS
|
||
select HAVE_DMA_API_DEBUG
|
||
- select HAVE_ARCH_JUMP_LABEL
|
||
+ select HAVE_ARCH_JUMP_LABEL if SPARC64
|
||
select HAVE_GENERIC_HARDIRQS
|
||
select GENERIC_IRQ_SHOW
|
||
select USE_GENERIC_SMP_HELPERS if SMP
|
||
diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h
|
||
index 5080d16..ec2e2e2 100644
|
||
--- a/arch/sparc/include/asm/jump_label.h
|
||
+++ b/arch/sparc/include/asm/jump_label.h
|
||
@@ -9,7 +9,7 @@
|
||
|
||
static __always_inline bool arch_static_branch(struct static_key *key)
|
||
{
|
||
- asm goto("1:\n\t"
|
||
+ asm_volatile_goto("1:\n\t"
|
||
"nop\n\t"
|
||
"nop\n\t"
|
||
".pushsection __jump_table, \"aw\"\n\t"
|
||
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
|
||
index 656de8b..cd24caf 100644
|
||
--- a/arch/sparc/include/asm/pgtable_64.h
|
||
+++ b/arch/sparc/include/asm/pgtable_64.h
|
||
@@ -24,7 +24,8 @@
|
||
|
||
/* The kernel image occupies 0x4000000 to 0x6000000 (4MB --> 96MB).
|
||
* The page copy blockops can use 0x6000000 to 0x8000000.
|
||
- * The TSB is mapped in the 0x8000000 to 0xa000000 range.
|
||
+ * The 8K TSB is mapped in the 0x8000000 to 0x8400000 range.
|
||
+ * The 4M TSB is mapped in the 0x8400000 to 0x8800000 range.
|
||
* The PROM resides in an area spanning 0xf0000000 to 0x100000000.
|
||
* The vmalloc area spans 0x100000000 to 0x200000000.
|
||
* Since modules need to be in the lowest 32-bits of the address space,
|
||
@@ -33,7 +34,8 @@
|
||
* 0x400000000.
|
||
*/
|
||
#define TLBTEMP_BASE _AC(0x0000000006000000,UL)
|
||
-#define TSBMAP_BASE _AC(0x0000000008000000,UL)
|
||
+#define TSBMAP_8K_BASE _AC(0x0000000008000000,UL)
|
||
+#define TSBMAP_4M_BASE _AC(0x0000000008400000,UL)
|
||
#define MODULES_VADDR _AC(0x0000000010000000,UL)
|
||
#define MODULES_LEN _AC(0x00000000e0000000,UL)
|
||
#define MODULES_END _AC(0x00000000f0000000,UL)
|
||
diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h
|
||
index f0d6a97..1a4bb97 100644
|
||
--- a/arch/sparc/include/asm/tlbflush_64.h
|
||
+++ b/arch/sparc/include/asm/tlbflush_64.h
|
||
@@ -35,6 +35,8 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
|
||
{
|
||
}
|
||
|
||
+void flush_tlb_kernel_range(unsigned long start, unsigned long end);
|
||
+
|
||
#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
|
||
|
||
extern void flush_tlb_pending(void);
|
||
@@ -49,11 +51,6 @@ extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end);
|
||
|
||
#ifndef CONFIG_SMP
|
||
|
||
-#define flush_tlb_kernel_range(start,end) \
|
||
-do { flush_tsb_kernel_range(start,end); \
|
||
- __flush_tlb_kernel_range(start,end); \
|
||
-} while (0)
|
||
-
|
||
static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
|
||
{
|
||
__flush_tlb_page(CTX_HWBITS(mm->context), vaddr);
|
||
@@ -64,11 +61,6 @@ static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vad
|
||
extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
|
||
extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr);
|
||
|
||
-#define flush_tlb_kernel_range(start, end) \
|
||
-do { flush_tsb_kernel_range(start,end); \
|
||
- smp_flush_tlb_kernel_range(start, end); \
|
||
-} while (0)
|
||
-
|
||
#define global_flush_tlb_page(mm, vaddr) \
|
||
smp_flush_tlb_page(mm, vaddr)
|
||
|
||
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h
|
||
index a1091afb..8bc9afd 100644
|
||
--- a/arch/sparc/include/asm/uaccess_64.h
|
||
+++ b/arch/sparc/include/asm/uaccess_64.h
|
||
@@ -266,8 +266,8 @@ extern long __strnlen_user(const char __user *, long len);
|
||
|
||
#define strlen_user __strlen_user
|
||
#define strnlen_user __strnlen_user
|
||
-#define __copy_to_user_inatomic ___copy_to_user
|
||
-#define __copy_from_user_inatomic ___copy_from_user
|
||
+#define __copy_to_user_inatomic __copy_to_user
|
||
+#define __copy_from_user_inatomic __copy_from_user
|
||
|
||
#endif /* __ASSEMBLY__ */
|
||
|
||
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
|
||
index 435e406..1beaf60 100644
|
||
--- a/arch/sparc/kernel/ldc.c
|
||
+++ b/arch/sparc/kernel/ldc.c
|
||
@@ -1339,7 +1339,7 @@ int ldc_connect(struct ldc_channel *lp)
|
||
if (!(lp->flags & LDC_FLAG_ALLOCED_QUEUES) ||
|
||
!(lp->flags & LDC_FLAG_REGISTERED_QUEUES) ||
|
||
lp->hs_state != LDC_HS_OPEN)
|
||
- err = -EINVAL;
|
||
+ err = ((lp->hs_state > LDC_HS_OPEN) ? 0 : -EINVAL);
|
||
else
|
||
err = start_handshake(lp);
|
||
|
||
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
|
||
index fdaf218..8c5c9a5 100644
|
||
--- a/arch/sparc/kernel/pci.c
|
||
+++ b/arch/sparc/kernel/pci.c
|
||
@@ -486,8 +486,8 @@ static void __devinit apb_fake_ranges(struct pci_dev *dev,
|
||
apb_calc_first_last(map, &first, &last);
|
||
res = bus->resource[1];
|
||
res->flags = IORESOURCE_MEM;
|
||
- region.start = (first << 21);
|
||
- region.end = (last << 21) + ((1 << 21) - 1);
|
||
+ region.start = (first << 29);
|
||
+ region.end = (last << 29) + ((1 << 29) - 1);
|
||
pcibios_bus_to_resource(dev, res, ®ion);
|
||
}
|
||
|
||
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
|
||
index b2d0568..3baecb9 100644
|
||
--- a/arch/sparc/kernel/smp_64.c
|
||
+++ b/arch/sparc/kernel/smp_64.c
|
||
@@ -151,7 +151,7 @@ void cpu_panic(void)
|
||
#define NUM_ROUNDS 64 /* magic value */
|
||
#define NUM_ITERS 5 /* likewise */
|
||
|
||
-static DEFINE_SPINLOCK(itc_sync_lock);
|
||
+static DEFINE_RAW_SPINLOCK(itc_sync_lock);
|
||
static unsigned long go[SLAVE + 1];
|
||
|
||
#define DEBUG_TICK_SYNC 0
|
||
@@ -259,7 +259,7 @@ static void smp_synchronize_one_tick(int cpu)
|
||
go[MASTER] = 0;
|
||
membar_safe("#StoreLoad");
|
||
|
||
- spin_lock_irqsave(&itc_sync_lock, flags);
|
||
+ raw_spin_lock_irqsave(&itc_sync_lock, flags);
|
||
{
|
||
for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) {
|
||
while (!go[MASTER])
|
||
@@ -270,7 +270,7 @@ static void smp_synchronize_one_tick(int cpu)
|
||
membar_safe("#StoreLoad");
|
||
}
|
||
}
|
||
- spin_unlock_irqrestore(&itc_sync_lock, flags);
|
||
+ raw_spin_unlock_irqrestore(&itc_sync_lock, flags);
|
||
}
|
||
|
||
#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
|
||
diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S
|
||
index d97f3eb..085c60f 100644
|
||
--- a/arch/sparc/kernel/sys32.S
|
||
+++ b/arch/sparc/kernel/sys32.S
|
||
@@ -87,7 +87,7 @@ SIGN1(sys32_io_submit, compat_sys_io_submit, %o1)
|
||
SIGN1(sys32_mq_open, compat_sys_mq_open, %o1)
|
||
SIGN1(sys32_select, compat_sys_select, %o0)
|
||
SIGN1(sys32_mkdir, sys_mkdir, %o1)
|
||
-SIGN3(sys32_futex, compat_sys_futex, %o1, %o2, %o5)
|
||
+SIGN1(sys32_futex, compat_sys_futex, %o1)
|
||
SIGN1(sys32_sysfs, compat_sys_sysfs, %o0)
|
||
SIGN2(sys32_sendfile, compat_sys_sendfile, %o0, %o1)
|
||
SIGN2(sys32_sendfile64, compat_sys_sendfile64, %o0, %o1)
|
||
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
|
||
index 817187d..557212c 100644
|
||
--- a/arch/sparc/kernel/syscalls.S
|
||
+++ b/arch/sparc/kernel/syscalls.S
|
||
@@ -184,7 +184,8 @@ linux_sparc_syscall32:
|
||
mov %i0, %l5 ! IEU1
|
||
5: call %l7 ! CTI Group brk forced
|
||
srl %i5, 0, %o5 ! IEU1
|
||
- ba,a,pt %xcc, 3f
|
||
+ ba,pt %xcc, 3f
|
||
+ sra %o0, 0, %o0
|
||
|
||
/* Linux native system calls enter here... */
|
||
.align 32
|
||
@@ -212,7 +213,6 @@ linux_sparc_syscall:
|
||
3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
|
||
ret_sys_call:
|
||
ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
|
||
- sra %o0, 0, %o0
|
||
mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
|
||
sllx %g2, 32, %g2
|
||
|
||
diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c
|
||
index dae85bc..a3c3a5b 100644
|
||
--- a/arch/sparc/kernel/unaligned_64.c
|
||
+++ b/arch/sparc/kernel/unaligned_64.c
|
||
@@ -156,17 +156,23 @@ static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
|
||
unsigned long compute_effective_address(struct pt_regs *regs,
|
||
unsigned int insn, unsigned int rd)
|
||
{
|
||
+ int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
|
||
unsigned int rs1 = (insn >> 14) & 0x1f;
|
||
unsigned int rs2 = insn & 0x1f;
|
||
- int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
|
||
+ unsigned long addr;
|
||
|
||
if (insn & 0x2000) {
|
||
maybe_flush_windows(rs1, 0, rd, from_kernel);
|
||
- return (fetch_reg(rs1, regs) + sign_extend_imm13(insn));
|
||
+ addr = (fetch_reg(rs1, regs) + sign_extend_imm13(insn));
|
||
} else {
|
||
maybe_flush_windows(rs1, rs2, rd, from_kernel);
|
||
- return (fetch_reg(rs1, regs) + fetch_reg(rs2, regs));
|
||
+ addr = (fetch_reg(rs1, regs) + fetch_reg(rs2, regs));
|
||
}
|
||
+
|
||
+ if (!from_kernel && test_thread_flag(TIF_32BIT))
|
||
+ addr &= 0xffffffff;
|
||
+
|
||
+ return addr;
|
||
}
|
||
|
||
/* This is just to make gcc think die_if_kernel does return... */
|
||
diff --git a/arch/sparc/lib/NG2memcpy.S b/arch/sparc/lib/NG2memcpy.S
|
||
index 0aed756..e993fc8 100644
|
||
--- a/arch/sparc/lib/NG2memcpy.S
|
||
+++ b/arch/sparc/lib/NG2memcpy.S
|
||
@@ -236,6 +236,7 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
|
||
*/
|
||
VISEntryHalf
|
||
|
||
+ membar #Sync
|
||
alignaddr %o1, %g0, %g0
|
||
|
||
add %o1, (64 - 1), %o4
|
||
diff --git a/arch/sparc/math-emu/math_32.c b/arch/sparc/math-emu/math_32.c
|
||
index aa4d55b..5ce8f2f 100644
|
||
--- a/arch/sparc/math-emu/math_32.c
|
||
+++ b/arch/sparc/math-emu/math_32.c
|
||
@@ -499,7 +499,7 @@ static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs)
|
||
case 0: fsr = *pfsr;
|
||
if (IR == -1) IR = 2;
|
||
/* fcc is always fcc0 */
|
||
- fsr &= ~0xc00; fsr |= (IR << 10); break;
|
||
+ fsr &= ~0xc00; fsr |= (IR << 10);
|
||
*pfsr = fsr;
|
||
break;
|
||
case 1: rd->s = IR; break;
|
||
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c
|
||
index 1fe0429..1387aca 100644
|
||
--- a/arch/sparc/mm/fault_64.c
|
||
+++ b/arch/sparc/mm/fault_64.c
|
||
@@ -95,38 +95,51 @@ static unsigned int get_user_insn(unsigned long tpc)
|
||
pte_t *ptep, pte;
|
||
unsigned long pa;
|
||
u32 insn = 0;
|
||
- unsigned long pstate;
|
||
|
||
- if (pgd_none(*pgdp))
|
||
- goto outret;
|
||
+ if (pgd_none(*pgdp) || unlikely(pgd_bad(*pgdp)))
|
||
+ goto out;
|
||
pudp = pud_offset(pgdp, tpc);
|
||
- if (pud_none(*pudp))
|
||
- goto outret;
|
||
- pmdp = pmd_offset(pudp, tpc);
|
||
- if (pmd_none(*pmdp))
|
||
- goto outret;
|
||
-
|
||
- /* This disables preemption for us as well. */
|
||
- __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
|
||
- __asm__ __volatile__("wrpr %0, %1, %%pstate"
|
||
- : : "r" (pstate), "i" (PSTATE_IE));
|
||
- ptep = pte_offset_map(pmdp, tpc);
|
||
- pte = *ptep;
|
||
- if (!pte_present(pte))
|
||
+ if (pud_none(*pudp) || unlikely(pud_bad(*pudp)))
|
||
goto out;
|
||
|
||
- pa = (pte_pfn(pte) << PAGE_SHIFT);
|
||
- pa += (tpc & ~PAGE_MASK);
|
||
-
|
||
- /* Use phys bypass so we don't pollute dtlb/dcache. */
|
||
- __asm__ __volatile__("lduwa [%1] %2, %0"
|
||
- : "=r" (insn)
|
||
- : "r" (pa), "i" (ASI_PHYS_USE_EC));
|
||
+ /* This disables preemption for us as well. */
|
||
+ local_irq_disable();
|
||
|
||
+ pmdp = pmd_offset(pudp, tpc);
|
||
+ if (pmd_none(*pmdp) || unlikely(pmd_bad(*pmdp)))
|
||
+ goto out_irq_enable;
|
||
+
|
||
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||
+ if (pmd_trans_huge(*pmdp)) {
|
||
+ if (pmd_trans_splitting(*pmdp))
|
||
+ goto out_irq_enable;
|
||
+
|
||
+ pa = pmd_pfn(*pmdp) << PAGE_SHIFT;
|
||
+ pa += tpc & ~HPAGE_MASK;
|
||
+
|
||
+ /* Use phys bypass so we don't pollute dtlb/dcache. */
|
||
+ __asm__ __volatile__("lduwa [%1] %2, %0"
|
||
+ : "=r" (insn)
|
||
+ : "r" (pa), "i" (ASI_PHYS_USE_EC));
|
||
+ } else
|
||
+#endif
|
||
+ {
|
||
+ ptep = pte_offset_map(pmdp, tpc);
|
||
+ pte = *ptep;
|
||
+ if (pte_present(pte)) {
|
||
+ pa = (pte_pfn(pte) << PAGE_SHIFT);
|
||
+ pa += (tpc & ~PAGE_MASK);
|
||
+
|
||
+ /* Use phys bypass so we don't pollute dtlb/dcache. */
|
||
+ __asm__ __volatile__("lduwa [%1] %2, %0"
|
||
+ : "=r" (insn)
|
||
+ : "r" (pa), "i" (ASI_PHYS_USE_EC));
|
||
+ }
|
||
+ pte_unmap(ptep);
|
||
+ }
|
||
+out_irq_enable:
|
||
+ local_irq_enable();
|
||
out:
|
||
- pte_unmap(ptep);
|
||
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
|
||
-outret:
|
||
return insn;
|
||
}
|
||
|
||
@@ -154,7 +167,8 @@ show_signal_msg(struct pt_regs *regs, int sig, int code,
|
||
extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int);
|
||
|
||
static void do_fault_siginfo(int code, int sig, struct pt_regs *regs,
|
||
- unsigned int insn, int fault_code)
|
||
+ unsigned long fault_addr, unsigned int insn,
|
||
+ int fault_code)
|
||
{
|
||
unsigned long addr;
|
||
siginfo_t info;
|
||
@@ -162,10 +176,18 @@ static void do_fault_siginfo(int code, int sig, struct pt_regs *regs,
|
||
info.si_code = code;
|
||
info.si_signo = sig;
|
||
info.si_errno = 0;
|
||
- if (fault_code & FAULT_CODE_ITLB)
|
||
+ if (fault_code & FAULT_CODE_ITLB) {
|
||
addr = regs->tpc;
|
||
- else
|
||
- addr = compute_effective_address(regs, insn, 0);
|
||
+ } else {
|
||
+ /* If we were able to probe the faulting instruction, use it
|
||
+ * to compute a precise fault address. Otherwise use the fault
|
||
+ * time provided address which may only have page granularity.
|
||
+ */
|
||
+ if (insn)
|
||
+ addr = compute_effective_address(regs, insn, 0);
|
||
+ else
|
||
+ addr = fault_addr;
|
||
+ }
|
||
info.si_addr = (void __user *) addr;
|
||
info.si_trapno = 0;
|
||
|
||
@@ -240,7 +262,7 @@ static void __kprobes do_kernel_fault(struct pt_regs *regs, int si_code,
|
||
/* The si_code was set to make clear whether
|
||
* this was a SEGV_MAPERR or SEGV_ACCERR fault.
|
||
*/
|
||
- do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code);
|
||
+ do_fault_siginfo(si_code, SIGSEGV, regs, address, insn, fault_code);
|
||
return;
|
||
}
|
||
|
||
@@ -260,18 +282,6 @@ static void noinline __kprobes bogus_32bit_fault_tpc(struct pt_regs *regs)
|
||
show_regs(regs);
|
||
}
|
||
|
||
-static void noinline __kprobes bogus_32bit_fault_address(struct pt_regs *regs,
|
||
- unsigned long addr)
|
||
-{
|
||
- static int times;
|
||
-
|
||
- if (times++ < 10)
|
||
- printk(KERN_ERR "FAULT[%s:%d]: 32-bit process "
|
||
- "reports 64-bit fault address [%lx]\n",
|
||
- current->comm, current->pid, addr);
|
||
- show_regs(regs);
|
||
-}
|
||
-
|
||
asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
|
||
{
|
||
struct mm_struct *mm = current->mm;
|
||
@@ -300,10 +310,8 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
|
||
goto intr_or_no_mm;
|
||
}
|
||
}
|
||
- if (unlikely((address >> 32) != 0)) {
|
||
- bogus_32bit_fault_address(regs, address);
|
||
+ if (unlikely((address >> 32) != 0))
|
||
goto intr_or_no_mm;
|
||
- }
|
||
}
|
||
|
||
if (regs->tstate & TSTATE_PRIV) {
|
||
@@ -515,7 +523,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
|
||
* Send a sigbus, regardless of whether we were in kernel
|
||
* or user mode.
|
||
*/
|
||
- do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code);
|
||
+ do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, address, insn, fault_code);
|
||
|
||
/* Kernel mode? Handle exceptions or die */
|
||
if (regs->tstate & TSTATE_PRIV)
|
||
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
|
||
index 7f8238f..7eb24bd 100644
|
||
--- a/arch/sparc/mm/init_64.c
|
||
+++ b/arch/sparc/mm/init_64.c
|
||
@@ -308,6 +308,10 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *
|
||
tsb_index = MM_TSB_BASE;
|
||
tsb_hash_shift = PAGE_SHIFT;
|
||
|
||
+ /* Don't insert a non-valid PTE into the TSB, we'll deadlock. */
|
||
+ if (!(pte_val(pte) & _PAGE_VALID))
|
||
+ return;
|
||
+
|
||
spin_lock_irqsave(&mm->context.lock, flags);
|
||
|
||
#ifdef CONFIG_HUGETLB_PAGE
|
||
@@ -2417,3 +2421,26 @@ void __flush_tlb_all(void)
|
||
__asm__ __volatile__("wrpr %0, 0, %%pstate"
|
||
: : "r" (pstate));
|
||
}
|
||
+
|
||
+#ifdef CONFIG_SMP
|
||
+#define do_flush_tlb_kernel_range smp_flush_tlb_kernel_range
|
||
+#else
|
||
+#define do_flush_tlb_kernel_range __flush_tlb_kernel_range
|
||
+#endif
|
||
+
|
||
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
||
+{
|
||
+ if (start < HI_OBP_ADDRESS && end > LOW_OBP_ADDRESS) {
|
||
+ if (start < LOW_OBP_ADDRESS) {
|
||
+ flush_tsb_kernel_range(start, LOW_OBP_ADDRESS);
|
||
+ do_flush_tlb_kernel_range(start, LOW_OBP_ADDRESS);
|
||
+ }
|
||
+ if (end > HI_OBP_ADDRESS) {
|
||
+ flush_tsb_kernel_range(end, HI_OBP_ADDRESS);
|
||
+ do_flush_tlb_kernel_range(end, HI_OBP_ADDRESS);
|
||
+ }
|
||
+ } else {
|
||
+ flush_tsb_kernel_range(start, end);
|
||
+ do_flush_tlb_kernel_range(start, end);
|
||
+ }
|
||
+}
|
||
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
|
||
index f4e84f3..4153019 100644
|
||
--- a/arch/sparc/mm/tsb.c
|
||
+++ b/arch/sparc/mm/tsb.c
|
||
@@ -150,7 +150,19 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign
|
||
mm->context.tsb_block[tsb_idx].tsb_nentries =
|
||
tsb_bytes / sizeof(struct tsb);
|
||
|
||
- base = TSBMAP_BASE;
|
||
+ switch (tsb_idx) {
|
||
+ case MM_TSB_BASE:
|
||
+ base = TSBMAP_8K_BASE;
|
||
+ break;
|
||
+#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
|
||
+ case MM_TSB_HUGE:
|
||
+ base = TSBMAP_4M_BASE;
|
||
+ break;
|
||
+#endif
|
||
+ default:
|
||
+ BUG();
|
||
+ }
|
||
+
|
||
tte = pgprot_val(PAGE_KERNEL_LOCKED);
|
||
tsb_paddr = __pa(mm->context.tsb_block[tsb_idx].tsb);
|
||
BUG_ON(tsb_paddr & (tsb_bytes - 1UL));
|
||
diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
|
||
index 829df49..41ebbfe 100644
|
||
--- a/arch/um/kernel/exitcode.c
|
||
+++ b/arch/um/kernel/exitcode.c
|
||
@@ -40,9 +40,11 @@ static ssize_t exitcode_proc_write(struct file *file,
|
||
const char __user *buffer, size_t count, loff_t *pos)
|
||
{
|
||
char *end, buf[sizeof("nnnnn\0")];
|
||
+ size_t size;
|
||
int tmp;
|
||
|
||
- if (copy_from_user(buf, buffer, count))
|
||
+ size = min(count, sizeof(buf));
|
||
+ if (copy_from_user(buf, buffer, size))
|
||
return -EFAULT;
|
||
|
||
tmp = simple_strtol(buf, &end, 0);
|
||
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
|
||
index eeb8054..1f3e9ea 100644
|
||
--- a/arch/unicore32/Kconfig
|
||
+++ b/arch/unicore32/Kconfig
|
||
@@ -6,6 +6,7 @@ config UNICORE32
|
||
select HAVE_DMA_ATTRS
|
||
select HAVE_KERNEL_GZIP
|
||
select HAVE_KERNEL_BZIP2
|
||
+ select GENERIC_ATOMIC64
|
||
select HAVE_KERNEL_LZO
|
||
select HAVE_KERNEL_LZMA
|
||
select GENERIC_FIND_FIRST_BIT
|
||
diff --git a/arch/unicore32/include/asm/bug.h b/arch/unicore32/include/asm/bug.h
|
||
index b1ff8ca..93a56f3 100644
|
||
--- a/arch/unicore32/include/asm/bug.h
|
||
+++ b/arch/unicore32/include/asm/bug.h
|
||
@@ -19,9 +19,4 @@ extern void die(const char *msg, struct pt_regs *regs, int err);
|
||
extern void uc32_notify_die(const char *str, struct pt_regs *regs,
|
||
struct siginfo *info, unsigned long err, unsigned long trap);
|
||
|
||
-extern asmlinkage void __backtrace(void);
|
||
-extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
|
||
-
|
||
-extern void __show_regs(struct pt_regs *);
|
||
-
|
||
#endif /* __UNICORE_BUG_H__ */
|
||
diff --git a/arch/unicore32/include/asm/cmpxchg.h b/arch/unicore32/include/asm/cmpxchg.h
|
||
index df4d5ac..8e797ad 100644
|
||
--- a/arch/unicore32/include/asm/cmpxchg.h
|
||
+++ b/arch/unicore32/include/asm/cmpxchg.h
|
||
@@ -35,7 +35,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
|
||
: "memory", "cc");
|
||
break;
|
||
default:
|
||
- ret = __xchg_bad_pointer();
|
||
+ __xchg_bad_pointer();
|
||
}
|
||
|
||
return ret;
|
||
diff --git a/arch/unicore32/kernel/setup.h b/arch/unicore32/kernel/setup.h
|
||
index f239550..30f749d 100644
|
||
--- a/arch/unicore32/kernel/setup.h
|
||
+++ b/arch/unicore32/kernel/setup.h
|
||
@@ -30,4 +30,10 @@ extern char __vectors_start[], __vectors_end[];
|
||
extern void kernel_thread_helper(void);
|
||
|
||
extern void __init early_signal_init(void);
|
||
+
|
||
+extern asmlinkage void __backtrace(void);
|
||
+extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
|
||
+
|
||
+extern void __show_regs(struct pt_regs *);
|
||
+
|
||
#endif
|
||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
||
index bf57545..38994ee 100644
|
||
--- a/arch/x86/Kconfig
|
||
+++ b/arch/x86/Kconfig
|
||
@@ -917,10 +917,27 @@ config VM86
|
||
default y
|
||
depends on X86_32
|
||
---help---
|
||
- This option is required by programs like DOSEMU to run 16-bit legacy
|
||
- code on X86 processors. It also may be needed by software like
|
||
- XFree86 to initialize some video cards via BIOS. Disabling this
|
||
- option saves about 6k.
|
||
+ This option is required by programs like DOSEMU to run
|
||
+ 16-bit real mode legacy code on x86 processors. It also may
|
||
+ be needed by software like XFree86 to initialize some video
|
||
+ cards via BIOS. Disabling this option saves about 6K.
|
||
+
|
||
+config X86_16BIT
|
||
+ bool "Enable support for 16-bit segments" if EXPERT
|
||
+ default y
|
||
+ ---help---
|
||
+ This option is required by programs like Wine to run 16-bit
|
||
+ protected mode legacy code on x86 processors. Disabling
|
||
+ this option saves about 300 bytes on i386, or around 6K text
|
||
+ plus 16K runtime memory on x86-64,
|
||
+
|
||
+config X86_ESPFIX32
|
||
+ def_bool y
|
||
+ depends on X86_16BIT && X86_32
|
||
+
|
||
+config X86_ESPFIX64
|
||
+ def_bool y
|
||
+ depends on X86_16BIT && X86_64
|
||
|
||
config TOSHIBA
|
||
tristate "Toshiba Laptop support"
|
||
@@ -2159,6 +2176,7 @@ source "fs/Kconfig.binfmt"
|
||
config IA32_EMULATION
|
||
bool "IA32 Emulation"
|
||
depends on X86_64
|
||
+ select BINFMT_ELF
|
||
select COMPAT_BINFMT_ELF
|
||
---help---
|
||
Include code to run legacy 32-bit programs under a
|
||
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
|
||
index 5a747dd..8dfb1ff 100644
|
||
--- a/arch/x86/boot/Makefile
|
||
+++ b/arch/x86/boot/Makefile
|
||
@@ -52,18 +52,18 @@ $(obj)/cpustr.h: $(obj)/mkcpustr FORCE
|
||
|
||
# How to compile the 16-bit code. Note we always compile for -march=i386,
|
||
# that way we can complain to the user if the CPU is insufficient.
|
||
-KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \
|
||
+KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \
|
||
-DDISABLE_BRANCH_PROFILING \
|
||
-Wall -Wstrict-prototypes \
|
||
-march=i386 -mregparm=3 \
|
||
-include $(srctree)/$(src)/code16gcc.h \
|
||
-fno-strict-aliasing -fomit-frame-pointer \
|
||
+ -mno-mmx -mno-sse \
|
||
$(call cc-option, -ffreestanding) \
|
||
$(call cc-option, -fno-toplevel-reorder,\
|
||
- $(call cc-option, -fno-unit-at-a-time)) \
|
||
+ $(call cc-option, -fno-unit-at-a-time)) \
|
||
$(call cc-option, -fno-stack-protector) \
|
||
$(call cc-option, -mpreferred-stack-boundary=2)
|
||
-KBUILD_CFLAGS += $(call cc-option, -m32)
|
||
KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
|
||
GCOV_PROFILE := n
|
||
|
||
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
|
||
index 5ef205c..7194d9f 100644
|
||
--- a/arch/x86/boot/compressed/Makefile
|
||
+++ b/arch/x86/boot/compressed/Makefile
|
||
@@ -12,6 +12,7 @@ KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
|
||
cflags-$(CONFIG_X86_32) := -march=i386
|
||
cflags-$(CONFIG_X86_64) := -mcmodel=small
|
||
KBUILD_CFLAGS += $(cflags-y)
|
||
+KBUILD_CFLAGS += -mno-mmx -mno-sse
|
||
KBUILD_CFLAGS += $(call cc-option,-ffreestanding)
|
||
KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector)
|
||
|
||
diff --git a/arch/x86/crypto/ghash-clmulni-intel_asm.S b/arch/x86/crypto/ghash-clmulni-intel_asm.S
|
||
index 1eb7f90..eb4d2a2 100644
|
||
--- a/arch/x86/crypto/ghash-clmulni-intel_asm.S
|
||
+++ b/arch/x86/crypto/ghash-clmulni-intel_asm.S
|
||
@@ -24,10 +24,6 @@
|
||
.align 16
|
||
.Lbswap_mask:
|
||
.octa 0x000102030405060708090a0b0c0d0e0f
|
||
-.Lpoly:
|
||
- .octa 0xc2000000000000000000000000000001
|
||
-.Ltwo_one:
|
||
- .octa 0x00000001000000000000000000000001
|
||
|
||
#define DATA %xmm0
|
||
#define SHASH %xmm1
|
||
@@ -131,27 +127,3 @@ ENTRY(clmul_ghash_update)
|
||
movups DATA, (%rdi)
|
||
.Lupdate_just_ret:
|
||
ret
|
||
-
|
||
-/*
|
||
- * void clmul_ghash_setkey(be128 *shash, const u8 *key);
|
||
- *
|
||
- * Calculate hash_key << 1 mod poly
|
||
- */
|
||
-ENTRY(clmul_ghash_setkey)
|
||
- movaps .Lbswap_mask, BSWAP
|
||
- movups (%rsi), %xmm0
|
||
- PSHUFB_XMM BSWAP %xmm0
|
||
- movaps %xmm0, %xmm1
|
||
- psllq $1, %xmm0
|
||
- psrlq $63, %xmm1
|
||
- movaps %xmm1, %xmm2
|
||
- pslldq $8, %xmm1
|
||
- psrldq $8, %xmm2
|
||
- por %xmm1, %xmm0
|
||
- # reduction
|
||
- pshufd $0b00100100, %xmm2, %xmm1
|
||
- pcmpeqd .Ltwo_one, %xmm1
|
||
- pand .Lpoly, %xmm1
|
||
- pxor %xmm1, %xmm0
|
||
- movups %xmm0, (%rdi)
|
||
- ret
|
||
diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c
|
||
index b4bf0a6..c07446d 100644
|
||
--- a/arch/x86/crypto/ghash-clmulni-intel_glue.c
|
||
+++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c
|
||
@@ -30,8 +30,6 @@ void clmul_ghash_mul(char *dst, const be128 *shash);
|
||
void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
|
||
const be128 *shash);
|
||
|
||
-void clmul_ghash_setkey(be128 *shash, const u8 *key);
|
||
-
|
||
struct ghash_async_ctx {
|
||
struct cryptd_ahash *cryptd_tfm;
|
||
};
|
||
@@ -58,13 +56,23 @@ static int ghash_setkey(struct crypto_shash *tfm,
|
||
const u8 *key, unsigned int keylen)
|
||
{
|
||
struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
|
||
+ be128 *x = (be128 *)key;
|
||
+ u64 a, b;
|
||
|
||
if (keylen != GHASH_BLOCK_SIZE) {
|
||
crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
|
||
return -EINVAL;
|
||
}
|
||
|
||
- clmul_ghash_setkey(&ctx->shash, key);
|
||
+ /* perform multiplication by 'x' in GF(2^128) */
|
||
+ a = be64_to_cpu(x->a);
|
||
+ b = be64_to_cpu(x->b);
|
||
+
|
||
+ ctx->shash.a = (__be64)((b << 1) | (a >> 63));
|
||
+ ctx->shash.b = (__be64)((a << 1) | (b >> 63));
|
||
+
|
||
+ if (a >> 63)
|
||
+ ctx->shash.b ^= cpu_to_be64(0xc2);
|
||
|
||
return 0;
|
||
}
|
||
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
|
||
index f91e80f..5bd3f9f 100644
|
||
--- a/arch/x86/include/asm/cpufeature.h
|
||
+++ b/arch/x86/include/asm/cpufeature.h
|
||
@@ -342,7 +342,7 @@ extern const char * const x86_power_flags[32];
|
||
static __always_inline __pure bool __static_cpu_has(u16 bit)
|
||
{
|
||
#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
|
||
- asm goto("1: jmp %l[t_no]\n"
|
||
+ asm_volatile_goto("1: jmp %l[t_no]\n"
|
||
"2:\n"
|
||
".section .altinstructions,\"a\"\n"
|
||
" .long 1b - .\n"
|
||
diff --git a/arch/x86/include/asm/espfix.h b/arch/x86/include/asm/espfix.h
|
||
new file mode 100644
|
||
index 0000000..99efebb
|
||
--- /dev/null
|
||
+++ b/arch/x86/include/asm/espfix.h
|
||
@@ -0,0 +1,16 @@
|
||
+#ifndef _ASM_X86_ESPFIX_H
|
||
+#define _ASM_X86_ESPFIX_H
|
||
+
|
||
+#ifdef CONFIG_X86_64
|
||
+
|
||
+#include <asm/percpu.h>
|
||
+
|
||
+DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack);
|
||
+DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr);
|
||
+
|
||
+extern void init_espfix_bsp(void);
|
||
+extern void init_espfix_ap(void);
|
||
+
|
||
+#endif /* CONFIG_X86_64 */
|
||
+
|
||
+#endif /* _ASM_X86_ESPFIX_H */
|
||
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
|
||
index 92e05b6..a65708f 100644
|
||
--- a/arch/x86/include/asm/fpu-internal.h
|
||
+++ b/arch/x86/include/asm/fpu-internal.h
|
||
@@ -266,12 +266,13 @@ static inline int restore_fpu_checking(struct task_struct *tsk)
|
||
/* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
|
||
is pending. Clear the x87 state here by setting it to fixed
|
||
values. "m" is a random variable that should be in L1 */
|
||
- alternative_input(
|
||
- ASM_NOP8 ASM_NOP2,
|
||
- "emms\n\t" /* clear stack tags */
|
||
- "fildl %P[addr]", /* set F?P to defined value */
|
||
- X86_FEATURE_FXSAVE_LEAK,
|
||
- [addr] "m" (tsk->thread.fpu.has_fpu));
|
||
+ if (unlikely(static_cpu_has(X86_FEATURE_FXSAVE_LEAK))) {
|
||
+ asm volatile(
|
||
+ "fnclex\n\t"
|
||
+ "emms\n\t"
|
||
+ "fildl %P[addr]" /* set F?P to defined value */
|
||
+ : : [addr] "m" (tsk->thread.fpu.has_fpu));
|
||
+ }
|
||
|
||
return fpu_restore_checking(&tsk->thread.fpu);
|
||
}
|
||
diff --git a/arch/x86/include/asm/hugetlb.h b/arch/x86/include/asm/hugetlb.h
|
||
index 439a9ac..48fa391 100644
|
||
--- a/arch/x86/include/asm/hugetlb.h
|
||
+++ b/arch/x86/include/asm/hugetlb.h
|
||
@@ -51,6 +51,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
|
||
static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
|
||
unsigned long addr, pte_t *ptep)
|
||
{
|
||
+ ptep_clear_flush(vma, addr, ptep);
|
||
}
|
||
|
||
static inline int huge_pte_none(pte_t pte)
|
||
diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h
|
||
index bba3cf8..0a8b519 100644
|
||
--- a/arch/x86/include/asm/irqflags.h
|
||
+++ b/arch/x86/include/asm/irqflags.h
|
||
@@ -129,7 +129,7 @@ static inline notrace unsigned long arch_local_irq_save(void)
|
||
|
||
#define PARAVIRT_ADJUST_EXCEPTION_FRAME /* */
|
||
|
||
-#define INTERRUPT_RETURN iretq
|
||
+#define INTERRUPT_RETURN jmp native_iret
|
||
#define USERGS_SYSRET64 \
|
||
swapgs; \
|
||
sysretq;
|
||
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
|
||
index 3a16c14..0297669 100644
|
||
--- a/arch/x86/include/asm/jump_label.h
|
||
+++ b/arch/x86/include/asm/jump_label.h
|
||
@@ -13,7 +13,7 @@
|
||
|
||
static __always_inline bool arch_static_branch(struct static_key *key)
|
||
{
|
||
- asm goto("1:"
|
||
+ asm_volatile_goto("1:"
|
||
STATIC_KEY_INITIAL_NOP
|
||
".pushsection __jump_table, \"aw\" \n\t"
|
||
_ASM_ALIGN "\n\t"
|
||
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
|
||
index d57eacb..944471f 100644
|
||
--- a/arch/x86/include/asm/kvm_host.h
|
||
+++ b/arch/x86/include/asm/kvm_host.h
|
||
@@ -102,7 +102,7 @@
|
||
#define KVM_REFILL_PAGES 25
|
||
#define KVM_MAX_CPUID_ENTRIES 80
|
||
#define KVM_NR_FIXED_MTRR_REGION 88
|
||
-#define KVM_NR_VAR_MTRR 8
|
||
+#define KVM_NR_VAR_MTRR 10
|
||
|
||
#define ASYNC_PF_PER_VCPU 64
|
||
|
||
@@ -436,7 +436,7 @@ struct kvm_vcpu_arch {
|
||
bool nmi_injected; /* Trying to inject an NMI this entry */
|
||
|
||
struct mtrr_state_type mtrr_state;
|
||
- u32 pat;
|
||
+ u64 pat;
|
||
|
||
int switch_db_regs;
|
||
unsigned long db[KVM_NR_DB_REGS];
|
||
diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h
|
||
index 766ea16..51817fa 100644
|
||
--- a/arch/x86/include/asm/pgtable_64_types.h
|
||
+++ b/arch/x86/include/asm/pgtable_64_types.h
|
||
@@ -59,5 +59,7 @@ typedef struct { pteval_t pte; } pte_t;
|
||
#define MODULES_VADDR _AC(0xffffffffa0000000, UL)
|
||
#define MODULES_END _AC(0xffffffffff000000, UL)
|
||
#define MODULES_LEN (MODULES_END - MODULES_VADDR)
|
||
+#define ESPFIX_PGD_ENTRY _AC(-2, UL)
|
||
+#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT)
|
||
|
||
#endif /* _ASM_X86_PGTABLE_64_DEFS_H */
|
||
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
|
||
index 19f16eb..0b60cd9 100644
|
||
--- a/arch/x86/include/asm/ptrace.h
|
||
+++ b/arch/x86/include/asm/ptrace.h
|
||
@@ -286,6 +286,22 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
|
||
|
||
#define ARCH_HAS_USER_SINGLE_STEP_INFO
|
||
|
||
+/*
|
||
+ * When hitting ptrace_stop(), we cannot return using SYSRET because
|
||
+ * that does not restore the full CPU state, only a minimal set. The
|
||
+ * ptracer can change arbitrary register values, which is usually okay
|
||
+ * because the usual ptrace stops run off the signal delivery path which
|
||
+ * forces IRET; however, ptrace_event() stops happen in arbitrary places
|
||
+ * in the kernel and don't force IRET path.
|
||
+ *
|
||
+ * So force IRET path after a ptrace stop.
|
||
+ */
|
||
+#define arch_ptrace_stop_needed(code, info) \
|
||
+({ \
|
||
+ set_thread_flag(TIF_NOTIFY_RESUME); \
|
||
+ false; \
|
||
+})
|
||
+
|
||
struct user_desc;
|
||
extern int do_get_thread_area(struct task_struct *p, int idx,
|
||
struct user_desc __user *info);
|
||
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
|
||
index d0f19f9..16c7971 100644
|
||
--- a/arch/x86/include/asm/setup.h
|
||
+++ b/arch/x86/include/asm/setup.h
|
||
@@ -61,6 +61,8 @@ static inline void x86_ce4100_early_setup(void) { }
|
||
|
||
#ifndef _SETUP
|
||
|
||
+#include <asm/espfix.h>
|
||
+
|
||
/*
|
||
* This is set up by the setup-routine at boot-time
|
||
*/
|
||
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
|
||
index b9676ae..ddaf130 100644
|
||
--- a/arch/x86/include/asm/topology.h
|
||
+++ b/arch/x86/include/asm/topology.h
|
||
@@ -157,9 +157,10 @@ static inline void setup_node_to_cpumask_map(void) { }
|
||
|
||
extern const struct cpumask *cpu_coregroup_mask(int cpu);
|
||
|
||
-#ifdef ENABLE_TOPO_DEFINES
|
||
#define topology_physical_package_id(cpu) (cpu_data(cpu).phys_proc_id)
|
||
#define topology_core_id(cpu) (cpu_data(cpu).cpu_core_id)
|
||
+
|
||
+#ifdef ENABLE_TOPO_DEFINES
|
||
#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu))
|
||
#define topology_thread_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
|
||
|
||
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
|
||
index 532d2e0..9f15a46 100644
|
||
--- a/arch/x86/kernel/Makefile
|
||
+++ b/arch/x86/kernel/Makefile
|
||
@@ -28,6 +28,7 @@ obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
|
||
obj-y += syscall_$(BITS).o
|
||
obj-$(CONFIG_X86_64) += vsyscall_64.o
|
||
obj-$(CONFIG_X86_64) += vsyscall_emu_64.o
|
||
+obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o
|
||
obj-y += bootflag.o e820.o
|
||
obj-y += pci-dma.o quirks.o topology.o kdebugfs.o
|
||
obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
|
||
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
|
||
index bb8e034..87477a1 100644
|
||
--- a/arch/x86/kernel/cpu/perf_event.c
|
||
+++ b/arch/x86/kernel/cpu/perf_event.c
|
||
@@ -1165,6 +1165,9 @@ static void x86_pmu_del(struct perf_event *event, int flags)
|
||
for (i = 0; i < cpuc->n_events; i++) {
|
||
if (event == cpuc->event_list[i]) {
|
||
|
||
+ if (i >= cpuc->n_events - cpuc->n_added)
|
||
+ --cpuc->n_added;
|
||
+
|
||
if (x86_pmu.put_event_constraints)
|
||
x86_pmu.put_event_constraints(cpuc, event);
|
||
|
||
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
|
||
index 3b8a2d3..ea34253 100644
|
||
--- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c
|
||
+++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
|
||
@@ -9,6 +9,7 @@
|
||
#include <linux/perf_event.h>
|
||
#include <linux/module.h>
|
||
#include <linux/pci.h>
|
||
+#include <linux/syscore_ops.h>
|
||
|
||
#include <asm/apic.h>
|
||
|
||
@@ -209,6 +210,18 @@ static int force_ibs_eilvt_setup(void)
|
||
return ret;
|
||
}
|
||
|
||
+static void ibs_eilvt_setup(void)
|
||
+{
|
||
+ /*
|
||
+ * Force LVT offset assignment for family 10h: The offsets are
|
||
+ * not assigned by the BIOS for this family, so the OS is
|
||
+ * responsible for doing it. If the OS assignment fails, fall
|
||
+ * back to BIOS settings and try to setup this.
|
||
+ */
|
||
+ if (boot_cpu_data.x86 == 0x10)
|
||
+ force_ibs_eilvt_setup();
|
||
+}
|
||
+
|
||
static inline int get_ibs_lvt_offset(void)
|
||
{
|
||
u64 val;
|
||
@@ -244,6 +257,36 @@ static void clear_APIC_ibs(void *dummy)
|
||
setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
|
||
}
|
||
|
||
+#ifdef CONFIG_PM
|
||
+
|
||
+static int perf_ibs_suspend(void)
|
||
+{
|
||
+ clear_APIC_ibs(NULL);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void perf_ibs_resume(void)
|
||
+{
|
||
+ ibs_eilvt_setup();
|
||
+ setup_APIC_ibs(NULL);
|
||
+}
|
||
+
|
||
+static struct syscore_ops perf_ibs_syscore_ops = {
|
||
+ .resume = perf_ibs_resume,
|
||
+ .suspend = perf_ibs_suspend,
|
||
+};
|
||
+
|
||
+static void perf_ibs_pm_init(void)
|
||
+{
|
||
+ register_syscore_ops(&perf_ibs_syscore_ops);
|
||
+}
|
||
+
|
||
+#else
|
||
+
|
||
+static inline void perf_ibs_pm_init(void) { }
|
||
+
|
||
+#endif
|
||
+
|
||
static int __cpuinit
|
||
perf_ibs_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
|
||
{
|
||
@@ -270,18 +313,12 @@ static __init int amd_ibs_init(void)
|
||
if (!caps)
|
||
return -ENODEV; /* ibs not supported by the cpu */
|
||
|
||
- /*
|
||
- * Force LVT offset assignment for family 10h: The offsets are
|
||
- * not assigned by the BIOS for this family, so the OS is
|
||
- * responsible for doing it. If the OS assignment fails, fall
|
||
- * back to BIOS settings and try to setup this.
|
||
- */
|
||
- if (boot_cpu_data.x86 == 0x10)
|
||
- force_ibs_eilvt_setup();
|
||
+ ibs_eilvt_setup();
|
||
|
||
if (!ibs_eilvt_valid())
|
||
goto out;
|
||
|
||
+ perf_ibs_pm_init();
|
||
get_online_cpus();
|
||
ibs_caps = caps;
|
||
/* make ibs_caps visible to other cpus: */
|
||
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
|
||
index 268b245..b1cbcff 100644
|
||
--- a/arch/x86/kernel/cpu/perf_event_intel.c
|
||
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
|
||
@@ -1070,6 +1070,15 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
|
||
intel_pmu_lbr_read();
|
||
|
||
/*
|
||
+ * CondChgd bit 63 doesn't mean any overflow status. Ignore
|
||
+ * and clear the bit.
|
||
+ */
|
||
+ if (__test_and_clear_bit(63, (unsigned long *)&status)) {
|
||
+ if (!status)
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ /*
|
||
* PEBS overflow sets bit 62 in the global status register
|
||
*/
|
||
if (__test_and_clear_bit(62, (unsigned long *)&status)) {
|
||
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
|
||
index 13ad899..69e231b 100644
|
||
--- a/arch/x86/kernel/crash.c
|
||
+++ b/arch/x86/kernel/crash.c
|
||
@@ -95,10 +95,10 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
|
||
cpu_emergency_vmxoff();
|
||
cpu_emergency_svm_disable();
|
||
|
||
- lapic_shutdown();
|
||
#if defined(CONFIG_X86_IO_APIC)
|
||
disable_IO_APIC();
|
||
#endif
|
||
+ lapic_shutdown();
|
||
#ifdef CONFIG_HPET_TIMER
|
||
hpet_disable();
|
||
#endif
|
||
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
|
||
index 2af4ccd..a075124 100644
|
||
--- a/arch/x86/kernel/entry_32.S
|
||
+++ b/arch/x86/kernel/entry_32.S
|
||
@@ -426,8 +426,9 @@ sysenter_past_esp:
|
||
jnz sysenter_audit
|
||
sysenter_do_call:
|
||
cmpl $(NR_syscalls), %eax
|
||
- jae syscall_badsys
|
||
+ jae sysenter_badsys
|
||
call *sys_call_table(,%eax,4)
|
||
+sysenter_after_call:
|
||
movl %eax,PT_EAX(%esp)
|
||
LOCKDEP_SYS_EXIT
|
||
DISABLE_INTERRUPTS(CLBR_ANY)
|
||
@@ -509,6 +510,7 @@ ENTRY(system_call)
|
||
jae syscall_badsys
|
||
syscall_call:
|
||
call *sys_call_table(,%eax,4)
|
||
+syscall_after_call:
|
||
movl %eax,PT_EAX(%esp) # store the return value
|
||
syscall_exit:
|
||
LOCKDEP_SYS_EXIT
|
||
@@ -523,6 +525,7 @@ syscall_exit:
|
||
restore_all:
|
||
TRACE_IRQS_IRET
|
||
restore_all_notrace:
|
||
+#ifdef CONFIG_X86_ESPFIX32
|
||
movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
|
||
# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
|
||
# are returning to the kernel.
|
||
@@ -533,6 +536,7 @@ restore_all_notrace:
|
||
cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
|
||
CFI_REMEMBER_STATE
|
||
je ldt_ss # returning to user-space with LDT SS
|
||
+#endif
|
||
restore_nocheck:
|
||
RESTORE_REGS 4 # skip orig_eax/error_code
|
||
irq_return:
|
||
@@ -548,13 +552,9 @@ ENTRY(iret_exc)
|
||
.long irq_return,iret_exc
|
||
.previous
|
||
|
||
+#ifdef CONFIG_X86_ESPFIX32
|
||
CFI_RESTORE_STATE
|
||
ldt_ss:
|
||
- larl PT_OLDSS(%esp), %eax
|
||
- jnz restore_nocheck
|
||
- testl $0x00400000, %eax # returning to 32bit stack?
|
||
- jnz restore_nocheck # allright, normal return
|
||
-
|
||
#ifdef CONFIG_PARAVIRT
|
||
/*
|
||
* The kernel can't run on a non-flat stack if paravirt mode
|
||
@@ -596,6 +596,7 @@ ldt_ss:
|
||
lss (%esp), %esp /* switch to espfix segment */
|
||
CFI_ADJUST_CFA_OFFSET -8
|
||
jmp restore_nocheck
|
||
+#endif
|
||
CFI_ENDPROC
|
||
ENDPROC(system_call)
|
||
|
||
@@ -682,8 +683,13 @@ syscall_fault:
|
||
END(syscall_fault)
|
||
|
||
syscall_badsys:
|
||
- movl $-ENOSYS,PT_EAX(%esp)
|
||
- jmp resume_userspace
|
||
+ movl $-ENOSYS,%eax
|
||
+ jmp syscall_after_call
|
||
+END(syscall_badsys)
|
||
+
|
||
+sysenter_badsys:
|
||
+ movl $-ENOSYS,%eax
|
||
+ jmp sysenter_after_call
|
||
END(syscall_badsys)
|
||
CFI_ENDPROC
|
||
/*
|
||
@@ -764,6 +770,7 @@ ENDPROC(ptregs_clone)
|
||
* the high word of the segment base from the GDT and swiches to the
|
||
* normal stack and adjusts ESP with the matching offset.
|
||
*/
|
||
+#ifdef CONFIG_X86_ESPFIX32
|
||
/* fixup the stack */
|
||
mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
|
||
mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
|
||
@@ -773,8 +780,10 @@ ENDPROC(ptregs_clone)
|
||
pushl_cfi %eax
|
||
lss (%esp), %esp /* switch to the normal stack segment */
|
||
CFI_ADJUST_CFA_OFFSET -8
|
||
+#endif
|
||
.endm
|
||
.macro UNWIND_ESPFIX_STACK
|
||
+#ifdef CONFIG_X86_ESPFIX32
|
||
movl %ss, %eax
|
||
/* see if on espfix stack */
|
||
cmpw $__ESPFIX_SS, %ax
|
||
@@ -785,6 +794,7 @@ ENDPROC(ptregs_clone)
|
||
/* switch to normal stack */
|
||
FIXUP_ESPFIX_STACK
|
||
27:
|
||
+#endif
|
||
.endm
|
||
|
||
/*
|
||
@@ -1316,11 +1326,13 @@ END(debug)
|
||
*/
|
||
ENTRY(nmi)
|
||
RING0_INT_FRAME
|
||
+#ifdef CONFIG_X86_ESPFIX32
|
||
pushl_cfi %eax
|
||
movl %ss, %eax
|
||
cmpw $__ESPFIX_SS, %ax
|
||
popl_cfi %eax
|
||
je nmi_espfix_stack
|
||
+#endif
|
||
cmpl $ia32_sysenter_target,(%esp)
|
||
je nmi_stack_fixup
|
||
pushl_cfi %eax
|
||
@@ -1360,6 +1372,7 @@ nmi_debug_stack_check:
|
||
FIX_STACK 24, nmi_stack_correct, 1
|
||
jmp nmi_stack_correct
|
||
|
||
+#ifdef CONFIG_X86_ESPFIX32
|
||
nmi_espfix_stack:
|
||
/* We have a RING0_INT_FRAME here.
|
||
*
|
||
@@ -1381,6 +1394,7 @@ nmi_espfix_stack:
|
||
lss 12+4(%esp), %esp # back to espfix stack
|
||
CFI_ADJUST_CFA_OFFSET -24
|
||
jmp irq_return
|
||
+#endif
|
||
CFI_ENDPROC
|
||
END(nmi)
|
||
|
||
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
|
||
index bd6f592..42b055e 100644
|
||
--- a/arch/x86/kernel/entry_64.S
|
||
+++ b/arch/x86/kernel/entry_64.S
|
||
@@ -55,6 +55,7 @@
|
||
#include <asm/paravirt.h>
|
||
#include <asm/ftrace.h>
|
||
#include <asm/percpu.h>
|
||
+#include <asm/pgtable_types.h>
|
||
#include <linux/err.h>
|
||
|
||
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
|
||
@@ -901,17 +902,47 @@ restore_args:
|
||
irq_return:
|
||
INTERRUPT_RETURN
|
||
|
||
- .section __ex_table, "a"
|
||
- .quad irq_return, bad_iret
|
||
- .previous
|
||
-
|
||
-#ifdef CONFIG_PARAVIRT
|
||
ENTRY(native_iret)
|
||
+ /*
|
||
+ * Are we returning to a stack segment from the LDT? Note: in
|
||
+ * 64-bit mode SS:RSP on the exception stack is always valid.
|
||
+ */
|
||
+#ifdef CONFIG_X86_ESPFIX64
|
||
+ testb $4,(SS-RIP)(%rsp)
|
||
+ jnz native_irq_return_ldt
|
||
+#endif
|
||
+
|
||
+native_irq_return_iret:
|
||
iretq
|
||
|
||
.section __ex_table,"a"
|
||
- .quad native_iret, bad_iret
|
||
+ .quad native_irq_return_iret, bad_iret
|
||
.previous
|
||
+
|
||
+#ifdef CONFIG_X86_ESPFIX64
|
||
+native_irq_return_ldt:
|
||
+ pushq_cfi %rax
|
||
+ pushq_cfi %rdi
|
||
+ SWAPGS
|
||
+ movq PER_CPU_VAR(espfix_waddr),%rdi
|
||
+ movq %rax,(0*8)(%rdi) /* RAX */
|
||
+ movq (2*8)(%rsp),%rax /* RIP */
|
||
+ movq %rax,(1*8)(%rdi)
|
||
+ movq (3*8)(%rsp),%rax /* CS */
|
||
+ movq %rax,(2*8)(%rdi)
|
||
+ movq (4*8)(%rsp),%rax /* RFLAGS */
|
||
+ movq %rax,(3*8)(%rdi)
|
||
+ movq (6*8)(%rsp),%rax /* SS */
|
||
+ movq %rax,(5*8)(%rdi)
|
||
+ movq (5*8)(%rsp),%rax /* RSP */
|
||
+ movq %rax,(4*8)(%rdi)
|
||
+ andl $0xffff0000,%eax
|
||
+ popq_cfi %rdi
|
||
+ orq PER_CPU_VAR(espfix_stack),%rax
|
||
+ SWAPGS
|
||
+ movq %rax,%rsp
|
||
+ popq_cfi %rax
|
||
+ jmp native_irq_return_iret
|
||
#endif
|
||
|
||
.section .fixup,"ax"
|
||
@@ -977,9 +1008,40 @@ ENTRY(retint_kernel)
|
||
call preempt_schedule_irq
|
||
jmp exit_intr
|
||
#endif
|
||
-
|
||
CFI_ENDPROC
|
||
END(common_interrupt)
|
||
+
|
||
+ /*
|
||
+ * If IRET takes a fault on the espfix stack, then we
|
||
+ * end up promoting it to a doublefault. In that case,
|
||
+ * modify the stack to make it look like we just entered
|
||
+ * the #GP handler from user space, similar to bad_iret.
|
||
+ */
|
||
+#ifdef CONFIG_X86_ESPFIX64
|
||
+ ALIGN
|
||
+__do_double_fault:
|
||
+ XCPT_FRAME 1 RDI+8
|
||
+ movq RSP(%rdi),%rax /* Trap on the espfix stack? */
|
||
+ sarq $PGDIR_SHIFT,%rax
|
||
+ cmpl $ESPFIX_PGD_ENTRY,%eax
|
||
+ jne do_double_fault /* No, just deliver the fault */
|
||
+ cmpl $__KERNEL_CS,CS(%rdi)
|
||
+ jne do_double_fault
|
||
+ movq RIP(%rdi),%rax
|
||
+ cmpq $native_irq_return_iret,%rax
|
||
+ jne do_double_fault /* This shouldn't happen... */
|
||
+ movq PER_CPU_VAR(kernel_stack),%rax
|
||
+ subq $(6*8-KERNEL_STACK_OFFSET),%rax /* Reset to original stack */
|
||
+ movq %rax,RSP(%rdi)
|
||
+ movq $0,(%rax) /* Missing (lost) #GP error code */
|
||
+ movq $general_protection,RIP(%rdi)
|
||
+ retq
|
||
+ CFI_ENDPROC
|
||
+END(__do_double_fault)
|
||
+#else
|
||
+# define __do_double_fault do_double_fault
|
||
+#endif
|
||
+
|
||
/*
|
||
* End of kprobes section
|
||
*/
|
||
@@ -1155,7 +1217,7 @@ zeroentry overflow do_overflow
|
||
zeroentry bounds do_bounds
|
||
zeroentry invalid_op do_invalid_op
|
||
zeroentry device_not_available do_device_not_available
|
||
-paranoiderrorentry double_fault do_double_fault
|
||
+paranoiderrorentry double_fault __do_double_fault
|
||
zeroentry coprocessor_segment_overrun do_coprocessor_segment_overrun
|
||
errorentry invalid_TSS do_invalid_TSS
|
||
errorentry segment_not_present do_segment_not_present
|
||
@@ -1486,7 +1548,7 @@ error_sti:
|
||
*/
|
||
error_kernelspace:
|
||
incl %ebx
|
||
- leaq irq_return(%rip),%rcx
|
||
+ leaq native_irq_return_iret(%rip),%rcx
|
||
cmpq %rcx,RIP+8(%rsp)
|
||
je error_swapgs
|
||
movl %ecx,%eax /* zero extend */
|
||
diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c
|
||
new file mode 100644
|
||
index 0000000..94d857f
|
||
--- /dev/null
|
||
+++ b/arch/x86/kernel/espfix_64.c
|
||
@@ -0,0 +1,208 @@
|
||
+/* ----------------------------------------------------------------------- *
|
||
+ *
|
||
+ * Copyright 2014 Intel Corporation; author: H. Peter Anvin
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify it
|
||
+ * under the terms and conditions of the GNU General Public License,
|
||
+ * version 2, as published by the Free Software Foundation.
|
||
+ *
|
||
+ * This program is distributed in the hope it will be useful, but WITHOUT
|
||
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||
+ * more details.
|
||
+ *
|
||
+ * ----------------------------------------------------------------------- */
|
||
+
|
||
+/*
|
||
+ * The IRET instruction, when returning to a 16-bit segment, only
|
||
+ * restores the bottom 16 bits of the user space stack pointer. This
|
||
+ * causes some 16-bit software to break, but it also leaks kernel state
|
||
+ * to user space.
|
||
+ *
|
||
+ * This works around this by creating percpu "ministacks", each of which
|
||
+ * is mapped 2^16 times 64K apart. When we detect that the return SS is
|
||
+ * on the LDT, we copy the IRET frame to the ministack and use the
|
||
+ * relevant alias to return to userspace. The ministacks are mapped
|
||
+ * readonly, so if the IRET fault we promote #GP to #DF which is an IST
|
||
+ * vector and thus has its own stack; we then do the fixup in the #DF
|
||
+ * handler.
|
||
+ *
|
||
+ * This file sets up the ministacks and the related page tables. The
|
||
+ * actual ministack invocation is in entry_64.S.
|
||
+ */
|
||
+
|
||
+#include <linux/init.h>
|
||
+#include <linux/init_task.h>
|
||
+#include <linux/kernel.h>
|
||
+#include <linux/percpu.h>
|
||
+#include <linux/gfp.h>
|
||
+#include <linux/random.h>
|
||
+#include <asm/pgtable.h>
|
||
+#include <asm/pgalloc.h>
|
||
+#include <asm/setup.h>
|
||
+#include <asm/espfix.h>
|
||
+
|
||
+/*
|
||
+ * Note: we only need 6*8 = 48 bytes for the espfix stack, but round
|
||
+ * it up to a cache line to avoid unnecessary sharing.
|
||
+ */
|
||
+#define ESPFIX_STACK_SIZE (8*8UL)
|
||
+#define ESPFIX_STACKS_PER_PAGE (PAGE_SIZE/ESPFIX_STACK_SIZE)
|
||
+
|
||
+/* There is address space for how many espfix pages? */
|
||
+#define ESPFIX_PAGE_SPACE (1UL << (PGDIR_SHIFT-PAGE_SHIFT-16))
|
||
+
|
||
+#define ESPFIX_MAX_CPUS (ESPFIX_STACKS_PER_PAGE * ESPFIX_PAGE_SPACE)
|
||
+#if CONFIG_NR_CPUS > ESPFIX_MAX_CPUS
|
||
+# error "Need more than one PGD for the ESPFIX hack"
|
||
+#endif
|
||
+
|
||
+#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
|
||
+
|
||
+/* This contains the *bottom* address of the espfix stack */
|
||
+DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack);
|
||
+DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr);
|
||
+
|
||
+/* Initialization mutex - should this be a spinlock? */
|
||
+static DEFINE_MUTEX(espfix_init_mutex);
|
||
+
|
||
+/* Page allocation bitmap - each page serves ESPFIX_STACKS_PER_PAGE CPUs */
|
||
+#define ESPFIX_MAX_PAGES DIV_ROUND_UP(CONFIG_NR_CPUS, ESPFIX_STACKS_PER_PAGE)
|
||
+static void *espfix_pages[ESPFIX_MAX_PAGES];
|
||
+
|
||
+static __page_aligned_bss pud_t espfix_pud_page[PTRS_PER_PUD]
|
||
+ __aligned(PAGE_SIZE);
|
||
+
|
||
+static unsigned int page_random, slot_random;
|
||
+
|
||
+/*
|
||
+ * This returns the bottom address of the espfix stack for a specific CPU.
|
||
+ * The math allows for a non-power-of-two ESPFIX_STACK_SIZE, in which case
|
||
+ * we have to account for some amount of padding at the end of each page.
|
||
+ */
|
||
+static inline unsigned long espfix_base_addr(unsigned int cpu)
|
||
+{
|
||
+ unsigned long page, slot;
|
||
+ unsigned long addr;
|
||
+
|
||
+ page = (cpu / ESPFIX_STACKS_PER_PAGE) ^ page_random;
|
||
+ slot = (cpu + slot_random) % ESPFIX_STACKS_PER_PAGE;
|
||
+ addr = (page << PAGE_SHIFT) + (slot * ESPFIX_STACK_SIZE);
|
||
+ addr = (addr & 0xffffUL) | ((addr & ~0xffffUL) << 16);
|
||
+ addr += ESPFIX_BASE_ADDR;
|
||
+ return addr;
|
||
+}
|
||
+
|
||
+#define PTE_STRIDE (65536/PAGE_SIZE)
|
||
+#define ESPFIX_PTE_CLONES (PTRS_PER_PTE/PTE_STRIDE)
|
||
+#define ESPFIX_PMD_CLONES PTRS_PER_PMD
|
||
+#define ESPFIX_PUD_CLONES (65536/(ESPFIX_PTE_CLONES*ESPFIX_PMD_CLONES))
|
||
+
|
||
+#define PGTABLE_PROT ((_KERNPG_TABLE & ~_PAGE_RW) | _PAGE_NX)
|
||
+
|
||
+static void init_espfix_random(void)
|
||
+{
|
||
+ unsigned long rand;
|
||
+
|
||
+ /*
|
||
+ * This is run before the entropy pools are initialized,
|
||
+ * but this is hopefully better than nothing.
|
||
+ */
|
||
+ if (!arch_get_random_long(&rand)) {
|
||
+ /* The constant is an arbitrary large prime */
|
||
+ rdtscll(rand);
|
||
+ rand *= 0xc345c6b72fd16123UL;
|
||
+ }
|
||
+
|
||
+ slot_random = rand % ESPFIX_STACKS_PER_PAGE;
|
||
+ page_random = (rand / ESPFIX_STACKS_PER_PAGE)
|
||
+ & (ESPFIX_PAGE_SPACE - 1);
|
||
+}
|
||
+
|
||
+void __init init_espfix_bsp(void)
|
||
+{
|
||
+ pgd_t *pgd_p;
|
||
+ pteval_t ptemask;
|
||
+
|
||
+ ptemask = __supported_pte_mask;
|
||
+
|
||
+ /* Install the espfix pud into the kernel page directory */
|
||
+ pgd_p = &init_level4_pgt[pgd_index(ESPFIX_BASE_ADDR)];
|
||
+ pgd_populate(&init_mm, pgd_p, (pud_t *)espfix_pud_page);
|
||
+
|
||
+ /* Randomize the locations */
|
||
+ init_espfix_random();
|
||
+
|
||
+ /* The rest is the same as for any other processor */
|
||
+ init_espfix_ap();
|
||
+}
|
||
+
|
||
+void init_espfix_ap(void)
|
||
+{
|
||
+ unsigned int cpu, page;
|
||
+ unsigned long addr;
|
||
+ pud_t pud, *pud_p;
|
||
+ pmd_t pmd, *pmd_p;
|
||
+ pte_t pte, *pte_p;
|
||
+ int n;
|
||
+ void *stack_page;
|
||
+ pteval_t ptemask;
|
||
+
|
||
+ /* We only have to do this once... */
|
||
+ if (likely(this_cpu_read(espfix_stack)))
|
||
+ return; /* Already initialized */
|
||
+
|
||
+ cpu = smp_processor_id();
|
||
+ addr = espfix_base_addr(cpu);
|
||
+ page = cpu/ESPFIX_STACKS_PER_PAGE;
|
||
+
|
||
+ /* Did another CPU already set this up? */
|
||
+ stack_page = ACCESS_ONCE(espfix_pages[page]);
|
||
+ if (likely(stack_page))
|
||
+ goto done;
|
||
+
|
||
+ mutex_lock(&espfix_init_mutex);
|
||
+
|
||
+ /* Did we race on the lock? */
|
||
+ stack_page = ACCESS_ONCE(espfix_pages[page]);
|
||
+ if (stack_page)
|
||
+ goto unlock_done;
|
||
+
|
||
+ ptemask = __supported_pte_mask;
|
||
+
|
||
+ pud_p = &espfix_pud_page[pud_index(addr)];
|
||
+ pud = *pud_p;
|
||
+ if (!pud_present(pud)) {
|
||
+ pmd_p = (pmd_t *)__get_free_page(PGALLOC_GFP);
|
||
+ pud = __pud(__pa(pmd_p) | (PGTABLE_PROT & ptemask));
|
||
+ paravirt_alloc_pmd(&init_mm, __pa(pmd_p) >> PAGE_SHIFT);
|
||
+ for (n = 0; n < ESPFIX_PUD_CLONES; n++)
|
||
+ set_pud(&pud_p[n], pud);
|
||
+ }
|
||
+
|
||
+ pmd_p = pmd_offset(&pud, addr);
|
||
+ pmd = *pmd_p;
|
||
+ if (!pmd_present(pmd)) {
|
||
+ pte_p = (pte_t *)__get_free_page(PGALLOC_GFP);
|
||
+ pmd = __pmd(__pa(pte_p) | (PGTABLE_PROT & ptemask));
|
||
+ paravirt_alloc_pte(&init_mm, __pa(pte_p) >> PAGE_SHIFT);
|
||
+ for (n = 0; n < ESPFIX_PMD_CLONES; n++)
|
||
+ set_pmd(&pmd_p[n], pmd);
|
||
+ }
|
||
+
|
||
+ pte_p = pte_offset_kernel(&pmd, addr);
|
||
+ stack_page = (void *)__get_free_page(GFP_KERNEL);
|
||
+ pte = __pte(__pa(stack_page) | (__PAGE_KERNEL_RO & ptemask));
|
||
+ for (n = 0; n < ESPFIX_PTE_CLONES; n++)
|
||
+ set_pte(&pte_p[n*PTE_STRIDE], pte);
|
||
+
|
||
+ /* Job is done for this CPU and any CPU which shares this page */
|
||
+ ACCESS_ONCE(espfix_pages[page]) = stack_page;
|
||
+
|
||
+unlock_done:
|
||
+ mutex_unlock(&espfix_init_mutex);
|
||
+done:
|
||
+ this_cpu_write(espfix_stack, addr);
|
||
+ this_cpu_write(espfix_waddr, (unsigned long)stack_page
|
||
+ + (addr & ~PAGE_MASK));
|
||
+}
|
||
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
|
||
index ebc9873..c37886d 100644
|
||
--- a/arch/x86/kernel/ldt.c
|
||
+++ b/arch/x86/kernel/ldt.c
|
||
@@ -229,6 +229,11 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
|
||
}
|
||
}
|
||
|
||
+ if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
|
||
+ error = -EINVAL;
|
||
+ goto out_unlock;
|
||
+ }
|
||
+
|
||
fill_ldt(&ldt, &ldt_info);
|
||
if (oldmode)
|
||
ldt.avl = 0;
|
||
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
|
||
index 5d8cf0d..b316ffe 100644
|
||
--- a/arch/x86/kernel/microcode_amd.c
|
||
+++ b/arch/x86/kernel/microcode_amd.c
|
||
@@ -338,7 +338,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
|
||
snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
|
||
|
||
if (request_firmware(&fw, (const char *)fw_name, device)) {
|
||
- pr_err("failed to load file %s\n", fw_name);
|
||
+ pr_debug("failed to load file %s\n", fw_name);
|
||
goto out;
|
||
}
|
||
|
||
diff --git a/arch/x86/kernel/paravirt_patch_64.c b/arch/x86/kernel/paravirt_patch_64.c
|
||
index 3f08f34..a1da673 100644
|
||
--- a/arch/x86/kernel/paravirt_patch_64.c
|
||
+++ b/arch/x86/kernel/paravirt_patch_64.c
|
||
@@ -6,7 +6,6 @@ DEF_NATIVE(pv_irq_ops, irq_disable, "cli");
|
||
DEF_NATIVE(pv_irq_ops, irq_enable, "sti");
|
||
DEF_NATIVE(pv_irq_ops, restore_fl, "pushq %rdi; popfq");
|
||
DEF_NATIVE(pv_irq_ops, save_fl, "pushfq; popq %rax");
|
||
-DEF_NATIVE(pv_cpu_ops, iret, "iretq");
|
||
DEF_NATIVE(pv_mmu_ops, read_cr2, "movq %cr2, %rax");
|
||
DEF_NATIVE(pv_mmu_ops, read_cr3, "movq %cr3, %rax");
|
||
DEF_NATIVE(pv_mmu_ops, write_cr3, "movq %rdi, %cr3");
|
||
@@ -50,7 +49,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
|
||
PATCH_SITE(pv_irq_ops, save_fl);
|
||
PATCH_SITE(pv_irq_ops, irq_enable);
|
||
PATCH_SITE(pv_irq_ops, irq_disable);
|
||
- PATCH_SITE(pv_cpu_ops, iret);
|
||
PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
|
||
PATCH_SITE(pv_cpu_ops, usergs_sysret32);
|
||
PATCH_SITE(pv_cpu_ops, usergs_sysret64);
|
||
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
|
||
index 03920a1..28a3e62 100644
|
||
--- a/arch/x86/kernel/quirks.c
|
||
+++ b/arch/x86/kernel/quirks.c
|
||
@@ -525,7 +525,7 @@ static void __init quirk_amd_nb_node(struct pci_dev *dev)
|
||
return;
|
||
|
||
pci_read_config_dword(nb_ht, 0x60, &val);
|
||
- node = val & 7;
|
||
+ node = pcibus_to_node(dev->bus) | (val & 7);
|
||
/*
|
||
* Some hardware may return an invalid node ID,
|
||
* so check it first:
|
||
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
|
||
index bd70df6..d398f31 100644
|
||
--- a/arch/x86/kernel/reboot.c
|
||
+++ b/arch/x86/kernel/reboot.c
|
||
@@ -668,6 +668,13 @@ void native_machine_shutdown(void)
|
||
|
||
/* The boot cpu is always logical cpu 0 */
|
||
int reboot_cpu_id = 0;
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_X86_IO_APIC
|
||
+ disable_IO_APIC();
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_SMP
|
||
|
||
#ifdef CONFIG_X86_32
|
||
/* See if there has been given a command line override */
|
||
@@ -691,10 +698,6 @@ void native_machine_shutdown(void)
|
||
|
||
lapic_shutdown();
|
||
|
||
-#ifdef CONFIG_X86_IO_APIC
|
||
- disable_IO_APIC();
|
||
-#endif
|
||
-
|
||
#ifdef CONFIG_HPET_TIMER
|
||
hpet_disable();
|
||
#endif
|
||
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
|
||
index dc29333..436aa6d 100644
|
||
--- a/arch/x86/kernel/setup.c
|
||
+++ b/arch/x86/kernel/setup.c
|
||
@@ -626,7 +626,7 @@ static bool __init snb_gfx_workaround_needed(void)
|
||
#ifdef CONFIG_PCI
|
||
int i;
|
||
u16 vendor, devid;
|
||
- static const u16 snb_ids[] = {
|
||
+ static const __initconst u16 snb_ids[] = {
|
||
0x0102,
|
||
0x0112,
|
||
0x0122,
|
||
@@ -659,7 +659,7 @@ static bool __init snb_gfx_workaround_needed(void)
|
||
*/
|
||
static void __init trim_snb_memory(void)
|
||
{
|
||
- static const unsigned long bad_pages[] = {
|
||
+ static const __initconst unsigned long bad_pages[] = {
|
||
0x20050000,
|
||
0x20110000,
|
||
0x20130000,
|
||
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
|
||
index 849cdcf..c7dbf02 100644
|
||
--- a/arch/x86/kernel/smpboot.c
|
||
+++ b/arch/x86/kernel/smpboot.c
|
||
@@ -271,6 +271,13 @@ notrace static void __cpuinit start_secondary(void *unused)
|
||
check_tsc_sync_target();
|
||
|
||
/*
|
||
+ * Enable the espfix hack for this CPU
|
||
+ */
|
||
+#ifdef CONFIG_X86_ESPFIX64
|
||
+ init_espfix_ap();
|
||
+#endif
|
||
+
|
||
+ /*
|
||
* We need to hold call_lock, so there is no inconsistency
|
||
* between the time smp_call_function() determines number of
|
||
* IPI recipients, and the time when the determination is made
|
||
@@ -1241,6 +1248,9 @@ static void remove_siblinginfo(int cpu)
|
||
|
||
for_each_cpu(sibling, cpu_sibling_mask(cpu))
|
||
cpumask_clear_cpu(cpu, cpu_sibling_mask(sibling));
|
||
+ for_each_cpu(sibling, cpu_llc_shared_mask(cpu))
|
||
+ cpumask_clear_cpu(cpu, cpu_llc_shared_mask(sibling));
|
||
+ cpumask_clear(cpu_llc_shared_mask(cpu));
|
||
cpumask_clear(cpu_sibling_mask(cpu));
|
||
cpumask_clear(cpu_core_mask(cpu));
|
||
c->phys_proc_id = 0;
|
||
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
|
||
index c346d11..f89cdc6 100644
|
||
--- a/arch/x86/kernel/step.c
|
||
+++ b/arch/x86/kernel/step.c
|
||
@@ -157,6 +157,33 @@ static int enable_single_step(struct task_struct *child)
|
||
return 1;
|
||
}
|
||
|
||
+static void set_task_blockstep(struct task_struct *task, bool on)
|
||
+{
|
||
+ unsigned long debugctl;
|
||
+
|
||
+ /*
|
||
+ * Ensure irq/preemption can't change debugctl in between.
|
||
+ * Note also that both TIF_BLOCKSTEP and debugctl should
|
||
+ * be changed atomically wrt preemption.
|
||
+ * FIXME: this means that set/clear TIF_BLOCKSTEP is simply
|
||
+ * wrong if task != current, SIGKILL can wakeup the stopped
|
||
+ * tracee and set/clear can play with the running task, this
|
||
+ * can confuse the next __switch_to_xtra().
|
||
+ */
|
||
+ local_irq_disable();
|
||
+ debugctl = get_debugctlmsr();
|
||
+ if (on) {
|
||
+ debugctl |= DEBUGCTLMSR_BTF;
|
||
+ set_tsk_thread_flag(task, TIF_BLOCKSTEP);
|
||
+ } else {
|
||
+ debugctl &= ~DEBUGCTLMSR_BTF;
|
||
+ clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
|
||
+ }
|
||
+ if (task == current)
|
||
+ update_debugctlmsr(debugctl);
|
||
+ local_irq_enable();
|
||
+}
|
||
+
|
||
/*
|
||
* Enable single or block step.
|
||
*/
|
||
@@ -169,19 +196,10 @@ static void enable_step(struct task_struct *child, bool block)
|
||
* So no one should try to use debugger block stepping in a program
|
||
* that uses user-mode single stepping itself.
|
||
*/
|
||
- if (enable_single_step(child) && block) {
|
||
- unsigned long debugctl = get_debugctlmsr();
|
||
-
|
||
- debugctl |= DEBUGCTLMSR_BTF;
|
||
- update_debugctlmsr(debugctl);
|
||
- set_tsk_thread_flag(child, TIF_BLOCKSTEP);
|
||
- } else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) {
|
||
- unsigned long debugctl = get_debugctlmsr();
|
||
-
|
||
- debugctl &= ~DEBUGCTLMSR_BTF;
|
||
- update_debugctlmsr(debugctl);
|
||
- clear_tsk_thread_flag(child, TIF_BLOCKSTEP);
|
||
- }
|
||
+ if (enable_single_step(child) && block)
|
||
+ set_task_blockstep(child, true);
|
||
+ else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP))
|
||
+ set_task_blockstep(child, false);
|
||
}
|
||
|
||
void user_enable_single_step(struct task_struct *child)
|
||
@@ -199,13 +217,8 @@ void user_disable_single_step(struct task_struct *child)
|
||
/*
|
||
* Make sure block stepping (BTF) is disabled.
|
||
*/
|
||
- if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) {
|
||
- unsigned long debugctl = get_debugctlmsr();
|
||
-
|
||
- debugctl &= ~DEBUGCTLMSR_BTF;
|
||
- update_debugctlmsr(debugctl);
|
||
- clear_tsk_thread_flag(child, TIF_BLOCKSTEP);
|
||
- }
|
||
+ if (test_tsk_thread_flag(child, TIF_BLOCKSTEP))
|
||
+ set_task_blockstep(child, false);
|
||
|
||
/* Always clear TIF_SINGLESTEP... */
|
||
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
|
||
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
|
||
index b4d3c39..51534ef 100644
|
||
--- a/arch/x86/kernel/sys_x86_64.c
|
||
+++ b/arch/x86/kernel/sys_x86_64.c
|
||
@@ -115,7 +115,7 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
|
||
*begin = new_begin;
|
||
}
|
||
} else {
|
||
- *begin = TASK_UNMAPPED_BASE;
|
||
+ *begin = current->mm->mmap_legacy_base;
|
||
*end = TASK_SIZE;
|
||
}
|
||
}
|
||
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
|
||
index 8584322..578613d 100644
|
||
--- a/arch/x86/kvm/lapic.c
|
||
+++ b/arch/x86/kvm/lapic.c
|
||
@@ -538,7 +538,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
|
||
ASSERT(apic != NULL);
|
||
|
||
/* if initial count is 0, current count should also be 0 */
|
||
- if (apic_get_reg(apic, APIC_TMICT) == 0)
|
||
+ if (apic_get_reg(apic, APIC_TMICT) == 0 ||
|
||
+ apic->lapic_timer.period == 0)
|
||
return 0;
|
||
|
||
remaining = hrtimer_get_remaining(&apic->lapic_timer.timer);
|
||
@@ -1278,14 +1279,12 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
|
||
void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu)
|
||
{
|
||
u32 data;
|
||
- void *vapic;
|
||
|
||
if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr)
|
||
return;
|
||
|
||
- vapic = kmap_atomic(vcpu->arch.apic->vapic_page);
|
||
- data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr));
|
||
- kunmap_atomic(vapic);
|
||
+ kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
|
||
+ sizeof(u32));
|
||
|
||
apic_set_tpr(vcpu->arch.apic, data & 0xff);
|
||
}
|
||
@@ -1295,7 +1294,6 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
|
||
u32 data, tpr;
|
||
int max_irr, max_isr;
|
||
struct kvm_lapic *apic;
|
||
- void *vapic;
|
||
|
||
if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr)
|
||
return;
|
||
@@ -1310,17 +1308,24 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
|
||
max_isr = 0;
|
||
data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24);
|
||
|
||
- vapic = kmap_atomic(vcpu->arch.apic->vapic_page);
|
||
- *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data;
|
||
- kunmap_atomic(vapic);
|
||
+ kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
|
||
+ sizeof(u32));
|
||
}
|
||
|
||
-void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
|
||
+int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
|
||
{
|
||
if (!irqchip_in_kernel(vcpu->kvm))
|
||
- return;
|
||
+ return -EINVAL;
|
||
+
|
||
+ if (vapic_addr) {
|
||
+ if (kvm_gfn_to_hva_cache_init(vcpu->kvm,
|
||
+ &vcpu->arch.apic->vapic_cache,
|
||
+ vapic_addr, sizeof(u32)))
|
||
+ return -EINVAL;
|
||
+ }
|
||
|
||
vcpu->arch.apic->vapic_addr = vapic_addr;
|
||
+ return 0;
|
||
}
|
||
|
||
int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
|
||
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
|
||
index 6f4ce25..6aec071 100644
|
||
--- a/arch/x86/kvm/lapic.h
|
||
+++ b/arch/x86/kvm/lapic.h
|
||
@@ -15,7 +15,7 @@ struct kvm_lapic {
|
||
bool irr_pending;
|
||
void *regs;
|
||
gpa_t vapic_addr;
|
||
- struct page *vapic_page;
|
||
+ struct gfn_to_hva_cache vapic_cache;
|
||
};
|
||
int kvm_create_lapic(struct kvm_vcpu *vcpu);
|
||
void kvm_free_lapic(struct kvm_vcpu *vcpu);
|
||
@@ -46,7 +46,7 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
|
||
u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
|
||
void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data);
|
||
|
||
-void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
|
||
+int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
|
||
void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
|
||
void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
|
||
|
||
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
|
||
index 4cb1642..fd6dec6 100644
|
||
--- a/arch/x86/kvm/mmu.c
|
||
+++ b/arch/x86/kvm/mmu.c
|
||
@@ -2451,6 +2451,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
|
||
int emulate = 0;
|
||
gfn_t pseudo_gfn;
|
||
|
||
+ if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
|
||
+ return 0;
|
||
+
|
||
for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) {
|
||
if (iterator.level == level) {
|
||
unsigned pte_access = ACC_ALL;
|
||
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
|
||
index e334389..b567285 100644
|
||
--- a/arch/x86/kvm/svm.c
|
||
+++ b/arch/x86/kvm/svm.c
|
||
@@ -3007,10 +3007,8 @@ static int cr8_write_interception(struct vcpu_svm *svm)
|
||
u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
|
||
/* instruction emulation calls kvm_set_cr8() */
|
||
r = cr_interception(svm);
|
||
- if (irqchip_in_kernel(svm->vcpu.kvm)) {
|
||
- clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
|
||
+ if (irqchip_in_kernel(svm->vcpu.kvm))
|
||
return r;
|
||
- }
|
||
if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
|
||
return r;
|
||
kvm_run->exit_reason = KVM_EXIT_SET_TPR;
|
||
@@ -3566,6 +3564,8 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
|
||
if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK))
|
||
return;
|
||
|
||
+ clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
|
||
+
|
||
if (irr == -1)
|
||
return;
|
||
|
||
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
|
||
index 90f5c0e..617b00b 100644
|
||
--- a/arch/x86/kvm/vmx.c
|
||
+++ b/arch/x86/kvm/vmx.c
|
||
@@ -6281,8 +6281,8 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
|
||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||
|
||
free_vpid(vmx);
|
||
- free_nested(vmx);
|
||
free_loaded_vmcs(vmx->loaded_vmcs);
|
||
+ free_nested(vmx);
|
||
kfree(vmx->guest_msrs);
|
||
kvm_vcpu_uninit(vcpu);
|
||
kmem_cache_free(kvm_vcpu_cache, vmx);
|
||
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
|
||
index 3663e0b..4b1be29 100644
|
||
--- a/arch/x86/kvm/x86.c
|
||
+++ b/arch/x86/kvm/x86.c
|
||
@@ -2728,8 +2728,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||
r = -EFAULT;
|
||
if (copy_from_user(&va, argp, sizeof va))
|
||
goto out;
|
||
- r = 0;
|
||
- kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
|
||
+ r = kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
|
||
break;
|
||
}
|
||
case KVM_X86_SETUP_MCE: {
|
||
@@ -5075,33 +5074,6 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
|
||
!kvm_event_needs_reinjection(vcpu);
|
||
}
|
||
|
||
-static void vapic_enter(struct kvm_vcpu *vcpu)
|
||
-{
|
||
- struct kvm_lapic *apic = vcpu->arch.apic;
|
||
- struct page *page;
|
||
-
|
||
- if (!apic || !apic->vapic_addr)
|
||
- return;
|
||
-
|
||
- page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
|
||
-
|
||
- vcpu->arch.apic->vapic_page = page;
|
||
-}
|
||
-
|
||
-static void vapic_exit(struct kvm_vcpu *vcpu)
|
||
-{
|
||
- struct kvm_lapic *apic = vcpu->arch.apic;
|
||
- int idx;
|
||
-
|
||
- if (!apic || !apic->vapic_addr)
|
||
- return;
|
||
-
|
||
- idx = srcu_read_lock(&vcpu->kvm->srcu);
|
||
- kvm_release_page_dirty(apic->vapic_page);
|
||
- mark_page_dirty(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
|
||
- srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
||
-}
|
||
-
|
||
static void update_cr8_intercept(struct kvm_vcpu *vcpu)
|
||
{
|
||
int max_irr, tpr;
|
||
@@ -5385,7 +5357,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
||
}
|
||
|
||
vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
|
||
- vapic_enter(vcpu);
|
||
|
||
r = 1;
|
||
while (r > 0) {
|
||
@@ -5442,8 +5413,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
||
|
||
srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
|
||
|
||
- vapic_exit(vcpu);
|
||
-
|
||
return r;
|
||
}
|
||
|
||
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
|
||
index 0002a3a..e04e677 100644
|
||
--- a/arch/x86/mm/dump_pagetables.c
|
||
+++ b/arch/x86/mm/dump_pagetables.c
|
||
@@ -30,11 +30,13 @@ struct pg_state {
|
||
unsigned long start_address;
|
||
unsigned long current_address;
|
||
const struct addr_marker *marker;
|
||
+ unsigned long lines;
|
||
};
|
||
|
||
struct addr_marker {
|
||
unsigned long start_address;
|
||
const char *name;
|
||
+ unsigned long max_lines;
|
||
};
|
||
|
||
/* indices for address_markers; keep sync'd w/ address_markers below */
|
||
@@ -45,6 +47,7 @@ enum address_markers_idx {
|
||
LOW_KERNEL_NR,
|
||
VMALLOC_START_NR,
|
||
VMEMMAP_START_NR,
|
||
+ ESPFIX_START_NR,
|
||
HIGH_KERNEL_NR,
|
||
MODULES_VADDR_NR,
|
||
MODULES_END_NR,
|
||
@@ -67,6 +70,7 @@ static struct addr_marker address_markers[] = {
|
||
{ PAGE_OFFSET, "Low Kernel Mapping" },
|
||
{ VMALLOC_START, "vmalloc() Area" },
|
||
{ VMEMMAP_START, "Vmemmap" },
|
||
+ { ESPFIX_BASE_ADDR, "ESPfix Area", 16 },
|
||
{ __START_KERNEL_map, "High Kernel Mapping" },
|
||
{ MODULES_VADDR, "Modules" },
|
||
{ MODULES_END, "End Modules" },
|
||
@@ -163,7 +167,7 @@ static void note_page(struct seq_file *m, struct pg_state *st,
|
||
pgprot_t new_prot, int level)
|
||
{
|
||
pgprotval_t prot, cur;
|
||
- static const char units[] = "KMGTPE";
|
||
+ static const char units[] = "BKMGTPE";
|
||
|
||
/*
|
||
* If we have a "break" in the series, we need to flush the state that
|
||
@@ -178,6 +182,7 @@ static void note_page(struct seq_file *m, struct pg_state *st,
|
||
st->current_prot = new_prot;
|
||
st->level = level;
|
||
st->marker = address_markers;
|
||
+ st->lines = 0;
|
||
seq_printf(m, "---[ %s ]---\n", st->marker->name);
|
||
} else if (prot != cur || level != st->level ||
|
||
st->current_address >= st->marker[1].start_address) {
|
||
@@ -188,17 +193,21 @@ static void note_page(struct seq_file *m, struct pg_state *st,
|
||
/*
|
||
* Now print the actual finished series
|
||
*/
|
||
- seq_printf(m, "0x%0*lx-0x%0*lx ",
|
||
- width, st->start_address,
|
||
- width, st->current_address);
|
||
-
|
||
- delta = (st->current_address - st->start_address) >> 10;
|
||
- while (!(delta & 1023) && unit[1]) {
|
||
- delta >>= 10;
|
||
- unit++;
|
||
+ if (!st->marker->max_lines ||
|
||
+ st->lines < st->marker->max_lines) {
|
||
+ seq_printf(m, "0x%0*lx-0x%0*lx ",
|
||
+ width, st->start_address,
|
||
+ width, st->current_address);
|
||
+
|
||
+ delta = (st->current_address - st->start_address);
|
||
+ while (!(delta & 1023) && unit[1]) {
|
||
+ delta >>= 10;
|
||
+ unit++;
|
||
+ }
|
||
+ seq_printf(m, "%9lu%c ", delta, *unit);
|
||
+ printk_prot(m, st->current_prot, st->level);
|
||
}
|
||
- seq_printf(m, "%9lu%c ", delta, *unit);
|
||
- printk_prot(m, st->current_prot, st->level);
|
||
+ st->lines++;
|
||
|
||
/*
|
||
* We print markers for special areas of address space,
|
||
@@ -206,7 +215,15 @@ static void note_page(struct seq_file *m, struct pg_state *st,
|
||
* This helps in the interpretation.
|
||
*/
|
||
if (st->current_address >= st->marker[1].start_address) {
|
||
+ if (st->marker->max_lines &&
|
||
+ st->lines > st->marker->max_lines) {
|
||
+ unsigned long nskip =
|
||
+ st->lines - st->marker->max_lines;
|
||
+ seq_printf(m, "... %lu entr%s skipped ... \n",
|
||
+ nskip, nskip == 1 ? "y" : "ies");
|
||
+ }
|
||
st->marker++;
|
||
+ st->lines = 0;
|
||
seq_printf(m, "---[ %s ]---\n", st->marker->name);
|
||
}
|
||
|
||
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
|
||
index be1ef57..dec49d3 100644
|
||
--- a/arch/x86/mm/ioremap.c
|
||
+++ b/arch/x86/mm/ioremap.c
|
||
@@ -50,6 +50,21 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size,
|
||
return err;
|
||
}
|
||
|
||
+static int __ioremap_check_ram(unsigned long start_pfn, unsigned long nr_pages,
|
||
+ void *arg)
|
||
+{
|
||
+ unsigned long i;
|
||
+
|
||
+ for (i = 0; i < nr_pages; ++i)
|
||
+ if (pfn_valid(start_pfn + i) &&
|
||
+ !PageReserved(pfn_to_page(start_pfn + i)))
|
||
+ return 1;
|
||
+
|
||
+ WARN_ONCE(1, "ioremap on RAM pfn 0x%lx\n", start_pfn);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
/*
|
||
* Remap an arbitrary physical address space into the kernel virtual
|
||
* address space. Needed when the kernel wants to access high addresses
|
||
@@ -93,14 +108,11 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
|
||
/*
|
||
* Don't allow anybody to remap normal RAM that we're using..
|
||
*/
|
||
+ pfn = phys_addr >> PAGE_SHIFT;
|
||
last_pfn = last_addr >> PAGE_SHIFT;
|
||
- for (pfn = phys_addr >> PAGE_SHIFT; pfn <= last_pfn; pfn++) {
|
||
- int is_ram = page_is_ram(pfn);
|
||
-
|
||
- if (is_ram && pfn_valid(pfn) && !PageReserved(pfn_to_page(pfn)))
|
||
- return NULL;
|
||
- WARN_ON_ONCE(is_ram);
|
||
- }
|
||
+ if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
|
||
+ __ioremap_check_ram) == 1)
|
||
+ return NULL;
|
||
|
||
/*
|
||
* Mappings have to be page-aligned
|
||
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
|
||
index 845df68..5c1ae28 100644
|
||
--- a/arch/x86/mm/mmap.c
|
||
+++ b/arch/x86/mm/mmap.c
|
||
@@ -112,12 +112,14 @@ static unsigned long mmap_legacy_base(void)
|
||
*/
|
||
void arch_pick_mmap_layout(struct mm_struct *mm)
|
||
{
|
||
+ mm->mmap_legacy_base = mmap_legacy_base();
|
||
+ mm->mmap_base = mmap_base();
|
||
+
|
||
if (mmap_is_legacy()) {
|
||
- mm->mmap_base = mmap_legacy_base();
|
||
+ mm->mmap_base = mm->mmap_legacy_base;
|
||
mm->get_unmapped_area = arch_get_unmapped_area;
|
||
mm->unmap_area = arch_unmap_area;
|
||
} else {
|
||
- mm->mmap_base = mmap_base();
|
||
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
|
||
mm->unmap_area = arch_unmap_area_topdown;
|
||
}
|
||
diff --git a/arch/x86/net/bpf_jit.S b/arch/x86/net/bpf_jit.S
|
||
index 877b9a1..0149575 100644
|
||
--- a/arch/x86/net/bpf_jit.S
|
||
+++ b/arch/x86/net/bpf_jit.S
|
||
@@ -140,7 +140,7 @@ bpf_slow_path_byte_msh:
|
||
push %r9; \
|
||
push SKBDATA; \
|
||
/* rsi already has offset */ \
|
||
- mov $SIZE,%ecx; /* size */ \
|
||
+ mov $SIZE,%edx; /* size */ \
|
||
call bpf_internal_load_pointer_neg_helper; \
|
||
test %rax,%rax; \
|
||
pop SKBDATA; \
|
||
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
|
||
index 454548c..46e5387 100644
|
||
--- a/arch/x86/platform/efi/efi.c
|
||
+++ b/arch/x86/platform/efi/efi.c
|
||
@@ -50,6 +50,13 @@
|
||
|
||
#define EFI_DEBUG 1
|
||
|
||
+#define EFI_MIN_RESERVE 5120
|
||
+
|
||
+#define EFI_DUMMY_GUID \
|
||
+ EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9)
|
||
+
|
||
+static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
|
||
+
|
||
struct efi __read_mostly efi = {
|
||
.mps = EFI_INVALID_TABLE_ADDR,
|
||
.acpi = EFI_INVALID_TABLE_ADDR,
|
||
@@ -102,6 +109,15 @@ static int __init setup_add_efi_memmap(char *arg)
|
||
}
|
||
early_param("add_efi_memmap", setup_add_efi_memmap);
|
||
|
||
+static bool efi_no_storage_paranoia;
|
||
+
|
||
+static int __init setup_storage_paranoia(char *arg)
|
||
+{
|
||
+ efi_no_storage_paranoia = true;
|
||
+ return 0;
|
||
+}
|
||
+early_param("efi_no_storage_paranoia", setup_storage_paranoia);
|
||
+
|
||
|
||
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
|
||
{
|
||
@@ -744,13 +760,6 @@ void __init efi_init(void)
|
||
|
||
set_bit(EFI_MEMMAP, &x86_efi_facility);
|
||
|
||
-#ifdef CONFIG_X86_32
|
||
- if (efi_is_native()) {
|
||
- x86_platform.get_wallclock = efi_get_time;
|
||
- x86_platform.set_wallclock = efi_set_rtc_mmss;
|
||
- }
|
||
-#endif
|
||
-
|
||
#if EFI_DEBUG
|
||
print_efi_memmap();
|
||
#endif
|
||
@@ -930,6 +939,13 @@ void __init efi_enter_virtual_mode(void)
|
||
runtime_code_page_mkexec();
|
||
|
||
kfree(new_memmap);
|
||
+
|
||
+ /* clean DUMMY object */
|
||
+ efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
|
||
+ EFI_VARIABLE_NON_VOLATILE |
|
||
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||
+ EFI_VARIABLE_RUNTIME_ACCESS,
|
||
+ 0, NULL);
|
||
}
|
||
|
||
/*
|
||
@@ -967,3 +983,85 @@ u64 efi_mem_attributes(unsigned long phys_addr)
|
||
}
|
||
return 0;
|
||
}
|
||
+
|
||
+/*
|
||
+ * Some firmware has serious problems when using more than 50% of the EFI
|
||
+ * variable store, i.e. it triggers bugs that can brick machines. Ensure that
|
||
+ * we never use more than this safe limit.
|
||
+ *
|
||
+ * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
|
||
+ * store.
|
||
+ */
|
||
+efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
|
||
+{
|
||
+ efi_status_t status;
|
||
+ u64 storage_size, remaining_size, max_size;
|
||
+
|
||
+ if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
|
||
+ return 0;
|
||
+
|
||
+ status = efi.query_variable_info(attributes, &storage_size,
|
||
+ &remaining_size, &max_size);
|
||
+ if (status != EFI_SUCCESS)
|
||
+ return status;
|
||
+
|
||
+ /*
|
||
+ * Some firmware implementations refuse to boot if there's insufficient
|
||
+ * space in the variable store. We account for that by refusing the
|
||
+ * write if permitting it would reduce the available space to under
|
||
+ * 5KB. This figure was provided by Samsung, so should be safe.
|
||
+ */
|
||
+ if ((remaining_size - size < EFI_MIN_RESERVE) &&
|
||
+ !efi_no_storage_paranoia) {
|
||
+
|
||
+ /*
|
||
+ * Triggering garbage collection may require that the firmware
|
||
+ * generate a real EFI_OUT_OF_RESOURCES error. We can force
|
||
+ * that by attempting to use more space than is available.
|
||
+ */
|
||
+ unsigned long dummy_size = remaining_size + 1024;
|
||
+ void *dummy = kzalloc(dummy_size, GFP_ATOMIC);
|
||
+
|
||
+ if (!dummy)
|
||
+ return EFI_OUT_OF_RESOURCES;
|
||
+
|
||
+ status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
|
||
+ EFI_VARIABLE_NON_VOLATILE |
|
||
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||
+ EFI_VARIABLE_RUNTIME_ACCESS,
|
||
+ dummy_size, dummy);
|
||
+
|
||
+ if (status == EFI_SUCCESS) {
|
||
+ /*
|
||
+ * This should have failed, so if it didn't make sure
|
||
+ * that we delete it...
|
||
+ */
|
||
+ efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
|
||
+ EFI_VARIABLE_NON_VOLATILE |
|
||
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||
+ EFI_VARIABLE_RUNTIME_ACCESS,
|
||
+ 0, dummy);
|
||
+ }
|
||
+
|
||
+ kfree(dummy);
|
||
+
|
||
+ /*
|
||
+ * The runtime code may now have triggered a garbage collection
|
||
+ * run, so check the variable info again
|
||
+ */
|
||
+ status = efi.query_variable_info(attributes, &storage_size,
|
||
+ &remaining_size, &max_size);
|
||
+
|
||
+ if (status != EFI_SUCCESS)
|
||
+ return status;
|
||
+
|
||
+ /*
|
||
+ * There still isn't enough room, so return an error
|
||
+ */
|
||
+ if (remaining_size - size < EFI_MIN_RESERVE)
|
||
+ return EFI_OUT_OF_RESOURCES;
|
||
+ }
|
||
+
|
||
+ return EFI_SUCCESS;
|
||
+}
|
||
+EXPORT_SYMBOL_GPL(efi_query_variable_store);
|
||
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
|
||
index 7b6b2fb..33335d1 100644
|
||
--- a/arch/x86/syscalls/syscall_64.tbl
|
||
+++ b/arch/x86/syscalls/syscall_64.tbl
|
||
@@ -212,10 +212,10 @@
|
||
203 common sched_setaffinity sys_sched_setaffinity
|
||
204 common sched_getaffinity sys_sched_getaffinity
|
||
205 64 set_thread_area
|
||
-206 common io_setup sys_io_setup
|
||
+206 64 io_setup sys_io_setup
|
||
207 common io_destroy sys_io_destroy
|
||
208 common io_getevents sys_io_getevents
|
||
-209 common io_submit sys_io_submit
|
||
+209 64 io_submit sys_io_submit
|
||
210 common io_cancel sys_io_cancel
|
||
211 64 get_thread_area
|
||
212 common lookup_dcookie sys_lookup_dcookie
|
||
@@ -355,3 +355,5 @@
|
||
540 x32 process_vm_writev compat_sys_process_vm_writev
|
||
541 x32 setsockopt compat_sys_setsockopt
|
||
542 x32 getsockopt compat_sys_getsockopt
|
||
+543 x32 io_setup compat_sys_io_setup
|
||
+544 x32 io_submit compat_sys_io_submit
|
||
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
|
||
index a7678fa..9598038 100644
|
||
--- a/arch/x86/xen/enlighten.c
|
||
+++ b/arch/x86/xen/enlighten.c
|
||
@@ -1448,6 +1448,10 @@ asmlinkage void __init xen_start_kernel(void)
|
||
|
||
/* Make sure ACS will be enabled */
|
||
pci_request_acs();
|
||
+
|
||
+ /* Avoid searching for BIOS MP tables */
|
||
+ x86_init.mpparse.find_smp_config = x86_init_noop;
|
||
+ x86_init.mpparse.get_smp_config = x86_init_uint_noop;
|
||
}
|
||
#ifdef CONFIG_PCI
|
||
/* PCI BIOS service won't work from a PV guest. */
|
||
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
|
||
index 0503c0c..a7f5806 100644
|
||
--- a/arch/x86/xen/smp.c
|
||
+++ b/arch/x86/xen/smp.c
|
||
@@ -576,6 +576,8 @@ static void xen_hvm_cpu_die(unsigned int cpu)
|
||
unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
|
||
unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
|
||
unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
|
||
+ xen_uninit_lock_cpu(cpu);
|
||
+ xen_teardown_timer(cpu);
|
||
native_cpu_die(cpu);
|
||
}
|
||
|
||
diff --git a/arch/xtensa/include/asm/ioctls.h b/arch/xtensa/include/asm/ioctls.h
|
||
index fd1d136..96341aa 100644
|
||
--- a/arch/xtensa/include/asm/ioctls.h
|
||
+++ b/arch/xtensa/include/asm/ioctls.h
|
||
@@ -28,17 +28,17 @@
|
||
#define TCSETSW 0x5403
|
||
#define TCSETSF 0x5404
|
||
|
||
-#define TCGETA _IOR('t', 23, struct termio)
|
||
-#define TCSETA _IOW('t', 24, struct termio)
|
||
-#define TCSETAW _IOW('t', 25, struct termio)
|
||
-#define TCSETAF _IOW('t', 28, struct termio)
|
||
+#define TCGETA 0x80127417 /* _IOR('t', 23, struct termio) */
|
||
+#define TCSETA 0x40127418 /* _IOW('t', 24, struct termio) */
|
||
+#define TCSETAW 0x40127419 /* _IOW('t', 25, struct termio) */
|
||
+#define TCSETAF 0x4012741C /* _IOW('t', 28, struct termio) */
|
||
|
||
#define TCSBRK _IO('t', 29)
|
||
#define TCXONC _IO('t', 30)
|
||
#define TCFLSH _IO('t', 31)
|
||
|
||
-#define TIOCSWINSZ _IOW('t', 103, struct winsize)
|
||
-#define TIOCGWINSZ _IOR('t', 104, struct winsize)
|
||
+#define TIOCSWINSZ 0x40087467 /* _IOW('t', 103, struct winsize) */
|
||
+#define TIOCGWINSZ 0x80087468 /* _IOR('t', 104, struct winsize) */
|
||
#define TIOCSTART _IO('t', 110) /* start output, like ^Q */
|
||
#define TIOCSTOP _IO('t', 111) /* stop output, like ^S */
|
||
#define TIOCOUTQ _IOR('t', 115, int) /* output queue size */
|
||
@@ -88,7 +88,6 @@
|
||
#define TIOCSETD _IOW('T', 35, int)
|
||
#define TIOCGETD _IOR('T', 36, int)
|
||
#define TCSBRKP _IOW('T', 37, int) /* Needed for POSIX tcsendbreak()*/
|
||
-#define TIOCTTYGSTRUCT _IOR('T', 38, struct tty_struct) /* For debugging only*/
|
||
#define TIOCSBRK _IO('T', 39) /* BSD compatibility */
|
||
#define TIOCCBRK _IO('T', 40) /* BSD compatibility */
|
||
#define TIOCGSID _IOR('T', 41, pid_t) /* Return the session ID of FD*/
|
||
@@ -111,8 +110,10 @@
|
||
#define TIOCSERGETLSR _IOR('T', 89, unsigned int) /* Get line status reg. */
|
||
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
|
||
# define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||
-#define TIOCSERGETMULTI _IOR('T', 90, struct serial_multiport_struct) /* Get multiport config */
|
||
-#define TIOCSERSETMULTI _IOW('T', 91, struct serial_multiport_struct) /* Set multiport config */
|
||
+#define TIOCSERGETMULTI 0x80a8545a /* Get multiport config */
|
||
+ /* _IOR('T', 90, struct serial_multiport_struct) */
|
||
+#define TIOCSERSETMULTI 0x40a8545b /* Set multiport config */
|
||
+ /* _IOW('T', 91, struct serial_multiport_struct) */
|
||
|
||
#define TIOCMIWAIT _IO('T', 92) /* wait for a change on serial input line(s) */
|
||
#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||
diff --git a/arch/xtensa/include/asm/pgtable.h b/arch/xtensa/include/asm/pgtable.h
|
||
index b03c043..7eeaf22 100644
|
||
--- a/arch/xtensa/include/asm/pgtable.h
|
||
+++ b/arch/xtensa/include/asm/pgtable.h
|
||
@@ -68,7 +68,12 @@
|
||
#define VMALLOC_START 0xC0000000
|
||
#define VMALLOC_END 0xC7FEFFFF
|
||
#define TLBTEMP_BASE_1 0xC7FF0000
|
||
-#define TLBTEMP_BASE_2 0xC7FF8000
|
||
+#define TLBTEMP_BASE_2 (TLBTEMP_BASE_1 + DCACHE_WAY_SIZE)
|
||
+#if 2 * DCACHE_WAY_SIZE > ICACHE_WAY_SIZE
|
||
+#define TLBTEMP_SIZE (2 * DCACHE_WAY_SIZE)
|
||
+#else
|
||
+#define TLBTEMP_SIZE ICACHE_WAY_SIZE
|
||
+#endif
|
||
|
||
/*
|
||
* Xtensa Linux config PTE layout (when present):
|
||
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
|
||
index 6223f33..e01cffc 100644
|
||
--- a/arch/xtensa/kernel/entry.S
|
||
+++ b/arch/xtensa/kernel/entry.S
|
||
@@ -1053,9 +1053,8 @@ ENTRY(fast_syscall_xtensa)
|
||
movi a7, 4 # sizeof(unsigned int)
|
||
access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp
|
||
|
||
- addi a6, a6, -1 # assuming SYS_XTENSA_ATOMIC_SET = 1
|
||
- _bgeui a6, SYS_XTENSA_COUNT - 1, .Lill
|
||
- _bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp
|
||
+ _bgeui a6, SYS_XTENSA_COUNT, .Lill
|
||
+ _bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP, .Lnswp
|
||
|
||
/* Fall through for ATOMIC_CMP_SWP. */
|
||
|
||
@@ -1067,27 +1066,26 @@ TRY s32i a5, a3, 0 # different, modify value
|
||
l32i a7, a2, PT_AREG7 # restore a7
|
||
l32i a0, a2, PT_AREG0 # restore a0
|
||
movi a2, 1 # and return 1
|
||
- addi a6, a6, 1 # restore a6 (really necessary?)
|
||
rfe
|
||
|
||
1: l32i a7, a2, PT_AREG7 # restore a7
|
||
l32i a0, a2, PT_AREG0 # restore a0
|
||
movi a2, 0 # return 0 (note that we cannot set
|
||
- addi a6, a6, 1 # restore a6 (really necessary?)
|
||
rfe
|
||
|
||
.Lnswp: /* Atomic set, add, and exg_add. */
|
||
|
||
TRY l32i a7, a3, 0 # orig
|
||
+ addi a6, a6, -SYS_XTENSA_ATOMIC_SET
|
||
add a0, a4, a7 # + arg
|
||
moveqz a0, a4, a6 # set
|
||
+ addi a6, a6, SYS_XTENSA_ATOMIC_SET
|
||
TRY s32i a0, a3, 0 # write new value
|
||
|
||
mov a0, a2
|
||
mov a2, a7
|
||
l32i a7, a0, PT_AREG7 # restore a7
|
||
l32i a0, a0, PT_AREG0 # restore a0
|
||
- addi a6, a6, 1 # restore a6 (really necessary?)
|
||
rfe
|
||
|
||
CATCH
|
||
@@ -1096,7 +1094,7 @@ CATCH
|
||
movi a2, -EFAULT
|
||
rfe
|
||
|
||
-.Lill: l32i a7, a2, PT_AREG0 # restore a7
|
||
+.Lill: l32i a7, a2, PT_AREG7 # restore a7
|
||
l32i a0, a2, PT_AREG0 # restore a0
|
||
movi a2, -EINVAL
|
||
rfe
|
||
@@ -1629,7 +1627,7 @@ ENTRY(fast_second_level_miss)
|
||
rsr a0, EXCVADDR
|
||
bltu a0, a3, 2f
|
||
|
||
- addi a1, a0, -(2 << (DCACHE_ALIAS_ORDER + PAGE_SHIFT))
|
||
+ addi a1, a0, -TLBTEMP_SIZE
|
||
bgeu a1, a3, 2f
|
||
|
||
/* Check if we have to restore an ITLB mapping. */
|
||
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
|
||
index 2783fda..c055c91 100644
|
||
--- a/arch/xtensa/kernel/pci-dma.c
|
||
+++ b/arch/xtensa/kernel/pci-dma.c
|
||
@@ -48,9 +48,8 @@ dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag)
|
||
|
||
/* We currently don't support coherent memory outside KSEG */
|
||
|
||
- if (ret < XCHAL_KSEG_CACHED_VADDR
|
||
- || ret >= XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE)
|
||
- BUG();
|
||
+ BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR ||
|
||
+ ret > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
|
||
|
||
|
||
if (ret != 0) {
|
||
@@ -66,10 +65,11 @@ dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag)
|
||
void dma_free_coherent(struct device *hwdev, size_t size,
|
||
void *vaddr, dma_addr_t dma_handle)
|
||
{
|
||
- long addr=(long)vaddr+XCHAL_KSEG_CACHED_VADDR-XCHAL_KSEG_BYPASS_VADDR;
|
||
+ unsigned long addr = (unsigned long)vaddr +
|
||
+ XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
|
||
|
||
- if (addr < 0 || addr >= XCHAL_KSEG_SIZE)
|
||
- BUG();
|
||
+ BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR ||
|
||
+ addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
|
||
|
||
free_pages(addr, get_order(size));
|
||
}
|
||
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
|
||
index d78869a..b08caaa 100644
|
||
--- a/arch/xtensa/kernel/signal.c
|
||
+++ b/arch/xtensa/kernel/signal.c
|
||
@@ -343,7 +343,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||
|
||
sp = regs->areg[1];
|
||
|
||
- if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) {
|
||
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && sas_ss_flags(sp) == 0) {
|
||
sp = current->sas_ss_sp + current->sas_ss_size;
|
||
}
|
||
|
||
diff --git a/block/blk-core.c b/block/blk-core.c
|
||
index e264d3f..8509a8b 100644
|
||
--- a/block/blk-core.c
|
||
+++ b/block/blk-core.c
|
||
@@ -515,7 +515,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
|
||
goto fail_id;
|
||
|
||
if (blk_throtl_init(q))
|
||
- goto fail_id;
|
||
+ goto fail_bdi;
|
||
|
||
setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
|
||
laptop_mode_timer_fn, (unsigned long) q);
|
||
@@ -540,6 +540,8 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
|
||
|
||
return q;
|
||
|
||
+fail_bdi:
|
||
+ bdi_destroy(&q->backing_dev_info);
|
||
fail_id:
|
||
ida_simple_remove(&blk_queue_ida, q->id);
|
||
fail_q:
|
||
@@ -2172,6 +2174,7 @@ void blk_start_request(struct request *req)
|
||
if (unlikely(blk_bidi_rq(req)))
|
||
req->next_rq->resid_len = blk_rq_bytes(req->next_rq);
|
||
|
||
+ BUG_ON(test_bit(REQ_ATOM_COMPLETE, &req->atomic_flags));
|
||
blk_add_timer(req);
|
||
}
|
||
EXPORT_SYMBOL(blk_start_request);
|
||
@@ -2232,7 +2235,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
|
||
if (!req->bio)
|
||
return false;
|
||
|
||
- trace_block_rq_complete(req->q, req);
|
||
+ trace_block_rq_complete(req->q, req, nr_bytes);
|
||
|
||
/*
|
||
* For fs requests, rq is just carrier of independent bio's
|
||
diff --git a/block/blk-exec.c b/block/blk-exec.c
|
||
index fb2cbd5..1b5cb66 100644
|
||
--- a/block/blk-exec.c
|
||
+++ b/block/blk-exec.c
|
||
@@ -49,8 +49,18 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
|
||
rq_end_io_fn *done)
|
||
{
|
||
int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
|
||
+ bool is_pm_resume;
|
||
|
||
WARN_ON(irqs_disabled());
|
||
+
|
||
+ rq->rq_disk = bd_disk;
|
||
+ rq->end_io = done;
|
||
+ /*
|
||
+ * need to check this before __blk_run_queue(), because rq can
|
||
+ * be freed before that returns.
|
||
+ */
|
||
+ is_pm_resume = rq->cmd_type == REQ_TYPE_PM_RESUME;
|
||
+
|
||
spin_lock_irq(q->queue_lock);
|
||
|
||
if (unlikely(blk_queue_dead(q))) {
|
||
@@ -66,7 +76,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
|
||
__elv_add_request(q, rq, where);
|
||
__blk_run_queue(q);
|
||
/* the queue is stopped so it won't be run */
|
||
- if (rq->cmd_type == REQ_TYPE_PM_RESUME)
|
||
+ if (is_pm_resume)
|
||
q->request_fn(q);
|
||
spin_unlock_irq(q->queue_lock);
|
||
}
|
||
diff --git a/block/blk-settings.c b/block/blk-settings.c
|
||
index 579328c..0be72a0 100644
|
||
--- a/block/blk-settings.c
|
||
+++ b/block/blk-settings.c
|
||
@@ -155,6 +155,7 @@ void blk_set_stacking_limits(struct queue_limits *lim)
|
||
lim->discard_zeroes_data = 1;
|
||
lim->max_segments = USHRT_MAX;
|
||
lim->max_hw_sectors = UINT_MAX;
|
||
+ lim->max_segment_size = UINT_MAX;
|
||
|
||
lim->max_sectors = BLK_DEF_MAX_SECTORS;
|
||
}
|
||
diff --git a/block/blk-tag.c b/block/blk-tag.c
|
||
index 4af6f5c..f606487 100644
|
||
--- a/block/blk-tag.c
|
||
+++ b/block/blk-tag.c
|
||
@@ -27,18 +27,15 @@ struct request *blk_queue_find_tag(struct request_queue *q, int tag)
|
||
EXPORT_SYMBOL(blk_queue_find_tag);
|
||
|
||
/**
|
||
- * __blk_free_tags - release a given set of tag maintenance info
|
||
+ * blk_free_tags - release a given set of tag maintenance info
|
||
* @bqt: the tag map to free
|
||
*
|
||
- * Tries to free the specified @bqt. Returns true if it was
|
||
- * actually freed and false if there are still references using it
|
||
+ * Drop the reference count on @bqt and frees it when the last reference
|
||
+ * is dropped.
|
||
*/
|
||
-static int __blk_free_tags(struct blk_queue_tag *bqt)
|
||
+void blk_free_tags(struct blk_queue_tag *bqt)
|
||
{
|
||
- int retval;
|
||
-
|
||
- retval = atomic_dec_and_test(&bqt->refcnt);
|
||
- if (retval) {
|
||
+ if (atomic_dec_and_test(&bqt->refcnt)) {
|
||
BUG_ON(find_first_bit(bqt->tag_map, bqt->max_depth) <
|
||
bqt->max_depth);
|
||
|
||
@@ -50,9 +47,8 @@ static int __blk_free_tags(struct blk_queue_tag *bqt)
|
||
|
||
kfree(bqt);
|
||
}
|
||
-
|
||
- return retval;
|
||
}
|
||
+EXPORT_SYMBOL(blk_free_tags);
|
||
|
||
/**
|
||
* __blk_queue_free_tags - release tag maintenance info
|
||
@@ -69,28 +65,13 @@ void __blk_queue_free_tags(struct request_queue *q)
|
||
if (!bqt)
|
||
return;
|
||
|
||
- __blk_free_tags(bqt);
|
||
+ blk_free_tags(bqt);
|
||
|
||
q->queue_tags = NULL;
|
||
queue_flag_clear_unlocked(QUEUE_FLAG_QUEUED, q);
|
||
}
|
||
|
||
/**
|
||
- * blk_free_tags - release a given set of tag maintenance info
|
||
- * @bqt: the tag map to free
|
||
- *
|
||
- * For externally managed @bqt frees the map. Callers of this
|
||
- * function must guarantee to have released all the queues that
|
||
- * might have been using this tag map.
|
||
- */
|
||
-void blk_free_tags(struct blk_queue_tag *bqt)
|
||
-{
|
||
- if (unlikely(!__blk_free_tags(bqt)))
|
||
- BUG();
|
||
-}
|
||
-EXPORT_SYMBOL(blk_free_tags);
|
||
-
|
||
-/**
|
||
* blk_queue_free_tags - release tag maintenance info
|
||
* @q: the request queue for the device
|
||
*
|
||
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
|
||
index 7803548..b1182ea 100644
|
||
--- a/block/blk-timeout.c
|
||
+++ b/block/blk-timeout.c
|
||
@@ -90,8 +90,8 @@ static void blk_rq_timed_out(struct request *req)
|
||
__blk_complete_request(req);
|
||
break;
|
||
case BLK_EH_RESET_TIMER:
|
||
- blk_clear_rq_complete(req);
|
||
blk_add_timer(req);
|
||
+ blk_clear_rq_complete(req);
|
||
break;
|
||
case BLK_EH_NOT_HANDLED:
|
||
/*
|
||
@@ -173,7 +173,6 @@ void blk_add_timer(struct request *req)
|
||
return;
|
||
|
||
BUG_ON(!list_empty(&req->timeout_list));
|
||
- BUG_ON(test_bit(REQ_ATOM_COMPLETE, &req->atomic_flags));
|
||
|
||
/*
|
||
* Some LLDs, like scsi, peek at the timeout to prevent a
|
||
diff --git a/block/elevator.c b/block/elevator.c
|
||
index 44193a8..6d351a0 100644
|
||
--- a/block/elevator.c
|
||
+++ b/block/elevator.c
|
||
@@ -1063,7 +1063,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
|
||
/*
|
||
* Switch this queue to the given IO scheduler.
|
||
*/
|
||
-int elevator_change(struct request_queue *q, const char *name)
|
||
+static int __elevator_change(struct request_queue *q, const char *name)
|
||
{
|
||
char elevator_name[ELV_NAME_MAX];
|
||
struct elevator_type *e;
|
||
@@ -1085,6 +1085,18 @@ int elevator_change(struct request_queue *q, const char *name)
|
||
|
||
return elevator_switch(q, e);
|
||
}
|
||
+
|
||
+int elevator_change(struct request_queue *q, const char *name)
|
||
+{
|
||
+ int ret;
|
||
+
|
||
+ /* Protect q->elevator from elevator_init() */
|
||
+ mutex_lock(&q->sysfs_lock);
|
||
+ ret = __elevator_change(q, name);
|
||
+ mutex_unlock(&q->sysfs_lock);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
EXPORT_SYMBOL(elevator_change);
|
||
|
||
ssize_t elv_iosched_store(struct request_queue *q, const char *name,
|
||
@@ -1095,7 +1107,7 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
|
||
if (!q->elevator)
|
||
return count;
|
||
|
||
- ret = elevator_change(q, name);
|
||
+ ret = __elevator_change(q, name);
|
||
if (!ret)
|
||
return count;
|
||
|
||
diff --git a/block/genhd.c b/block/genhd.c
|
||
index dd44885..da61520 100644
|
||
--- a/block/genhd.c
|
||
+++ b/block/genhd.c
|
||
@@ -27,10 +27,10 @@ struct kobject *block_depr;
|
||
/* for extended dynamic devt allocation, currently only one major is used */
|
||
#define NR_EXT_DEVT (1 << MINORBITS)
|
||
|
||
-/* For extended devt allocation. ext_devt_mutex prevents look up
|
||
+/* For extended devt allocation. ext_devt_lock prevents look up
|
||
* results from going away underneath its user.
|
||
*/
|
||
-static DEFINE_MUTEX(ext_devt_mutex);
|
||
+static DEFINE_SPINLOCK(ext_devt_lock);
|
||
static DEFINE_IDR(ext_devt_idr);
|
||
|
||
static struct device_type disk_type;
|
||
@@ -420,13 +420,13 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
|
||
do {
|
||
if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL))
|
||
return -ENOMEM;
|
||
- mutex_lock(&ext_devt_mutex);
|
||
+ spin_lock(&ext_devt_lock);
|
||
rc = idr_get_new(&ext_devt_idr, part, &idx);
|
||
if (!rc && idx >= NR_EXT_DEVT) {
|
||
idr_remove(&ext_devt_idr, idx);
|
||
rc = -EBUSY;
|
||
}
|
||
- mutex_unlock(&ext_devt_mutex);
|
||
+ spin_unlock(&ext_devt_lock);
|
||
} while (rc == -EAGAIN);
|
||
|
||
if (rc)
|
||
@@ -447,15 +447,13 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
|
||
*/
|
||
void blk_free_devt(dev_t devt)
|
||
{
|
||
- might_sleep();
|
||
-
|
||
if (devt == MKDEV(0, 0))
|
||
return;
|
||
|
||
if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
|
||
- mutex_lock(&ext_devt_mutex);
|
||
+ spin_lock(&ext_devt_lock);
|
||
idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
|
||
- mutex_unlock(&ext_devt_mutex);
|
||
+ spin_unlock(&ext_devt_lock);
|
||
}
|
||
}
|
||
|
||
@@ -662,7 +660,6 @@ void del_gendisk(struct gendisk *disk)
|
||
if (!sysfs_deprecated)
|
||
sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
|
||
device_del(disk_to_dev(disk));
|
||
- blk_free_devt(disk_to_dev(disk)->devt);
|
||
}
|
||
EXPORT_SYMBOL(del_gendisk);
|
||
|
||
@@ -687,13 +684,13 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
|
||
} else {
|
||
struct hd_struct *part;
|
||
|
||
- mutex_lock(&ext_devt_mutex);
|
||
+ spin_lock(&ext_devt_lock);
|
||
part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
|
||
if (part && get_disk(part_to_disk(part))) {
|
||
*partno = part->partno;
|
||
disk = part_to_disk(part);
|
||
}
|
||
- mutex_unlock(&ext_devt_mutex);
|
||
+ spin_unlock(&ext_devt_lock);
|
||
}
|
||
|
||
return disk;
|
||
@@ -1101,6 +1098,7 @@ static void disk_release(struct device *dev)
|
||
{
|
||
struct gendisk *disk = dev_to_disk(dev);
|
||
|
||
+ blk_free_devt(dev->devt);
|
||
disk_release_events(disk);
|
||
kfree(disk->random);
|
||
disk_replace_part_tbl(disk, NULL);
|
||
diff --git a/block/partition-generic.c b/block/partition-generic.c
|
||
index 264028c..63487c6 100644
|
||
--- a/block/partition-generic.c
|
||
+++ b/block/partition-generic.c
|
||
@@ -211,6 +211,7 @@ static const struct attribute_group *part_attr_groups[] = {
|
||
static void part_release(struct device *dev)
|
||
{
|
||
struct hd_struct *p = dev_to_part(dev);
|
||
+ blk_free_devt(dev->devt);
|
||
free_part_stats(p);
|
||
free_part_info(p);
|
||
kfree(p);
|
||
@@ -264,7 +265,6 @@ void delete_partition(struct gendisk *disk, int partno)
|
||
rcu_assign_pointer(ptbl->last_lookup, NULL);
|
||
kobject_put(part->holder_dir);
|
||
device_del(part_to_dev(part));
|
||
- blk_free_devt(part_devt(part));
|
||
|
||
hd_struct_put(part);
|
||
}
|
||
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
|
||
index ac33d5f..bf948e1 100644
|
||
--- a/crypto/af_alg.c
|
||
+++ b/crypto/af_alg.c
|
||
@@ -21,6 +21,7 @@
|
||
#include <linux/module.h>
|
||
#include <linux/net.h>
|
||
#include <linux/rwsem.h>
|
||
+#include <linux/security.h>
|
||
|
||
struct alg_type_list {
|
||
const struct af_alg_type *type;
|
||
@@ -243,6 +244,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock)
|
||
|
||
sock_init_data(newsock, sk2);
|
||
sock_graft(sk2, newsock);
|
||
+ security_sk_clone(sk, sk2);
|
||
|
||
err = type->accept(ask->private, sk2);
|
||
if (err) {
|
||
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
|
||
index 0262210..8502462 100644
|
||
--- a/crypto/algif_hash.c
|
||
+++ b/crypto/algif_hash.c
|
||
@@ -114,6 +114,9 @@ static ssize_t hash_sendpage(struct socket *sock, struct page *page,
|
||
struct hash_ctx *ctx = ask->private;
|
||
int err;
|
||
|
||
+ if (flags & MSG_SENDPAGE_NOTLAST)
|
||
+ flags |= MSG_MORE;
|
||
+
|
||
lock_sock(sk);
|
||
sg_init_table(ctx->sgl.sg, 1);
|
||
sg_set_page(ctx->sgl.sg, page, size, offset);
|
||
@@ -161,8 +164,6 @@ static int hash_recvmsg(struct kiocb *unused, struct socket *sock,
|
||
else if (len < ds)
|
||
msg->msg_flags |= MSG_TRUNC;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
lock_sock(sk);
|
||
if (ctx->more) {
|
||
ctx->more = 0;
|
||
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
|
||
index a1c4f0a..a19c027 100644
|
||
--- a/crypto/algif_skcipher.c
|
||
+++ b/crypto/algif_skcipher.c
|
||
@@ -378,6 +378,9 @@ static ssize_t skcipher_sendpage(struct socket *sock, struct page *page,
|
||
struct skcipher_sg_list *sgl;
|
||
int err = -EINVAL;
|
||
|
||
+ if (flags & MSG_SENDPAGE_NOTLAST)
|
||
+ flags |= MSG_MORE;
|
||
+
|
||
lock_sock(sk);
|
||
if (!ctx->more && ctx->used)
|
||
goto unlock;
|
||
@@ -432,7 +435,6 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
|
||
long copied = 0;
|
||
|
||
lock_sock(sk);
|
||
- msg->msg_namelen = 0;
|
||
for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
|
||
iovlen--, iov++) {
|
||
unsigned long seglen = iov->iov_len;
|
||
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
|
||
index 6ddd99e..c21f761 100644
|
||
--- a/crypto/ansi_cprng.c
|
||
+++ b/crypto/ansi_cprng.c
|
||
@@ -230,11 +230,11 @@ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx,
|
||
*/
|
||
if (byte_count < DEFAULT_BLK_SZ) {
|
||
empty_rbuf:
|
||
- for (; ctx->rand_data_valid < DEFAULT_BLK_SZ;
|
||
- ctx->rand_data_valid++) {
|
||
+ while (ctx->rand_data_valid < DEFAULT_BLK_SZ) {
|
||
*ptr = ctx->rand_data[ctx->rand_data_valid];
|
||
ptr++;
|
||
byte_count--;
|
||
+ ctx->rand_data_valid++;
|
||
if (byte_count == 0)
|
||
goto done;
|
||
}
|
||
diff --git a/crypto/authenc.c b/crypto/authenc.c
|
||
index 5ef7ba6..d21da2f 100644
|
||
--- a/crypto/authenc.c
|
||
+++ b/crypto/authenc.c
|
||
@@ -368,9 +368,10 @@ static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
|
||
if (!err) {
|
||
struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
|
||
struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
|
||
- struct ablkcipher_request *abreq = aead_request_ctx(areq);
|
||
- u8 *iv = (u8 *)(abreq + 1) +
|
||
- crypto_ablkcipher_reqsize(ctx->enc);
|
||
+ struct authenc_request_ctx *areq_ctx = aead_request_ctx(areq);
|
||
+ struct ablkcipher_request *abreq = (void *)(areq_ctx->tail
|
||
+ + ctx->reqoff);
|
||
+ u8 *iv = (u8 *)abreq - crypto_ablkcipher_ivsize(ctx->enc);
|
||
|
||
err = crypto_authenc_genicv(areq, iv, 0);
|
||
}
|
||
diff --git a/crypto/ccm.c b/crypto/ccm.c
|
||
index 32fe1bb..18d64ad 100644
|
||
--- a/crypto/ccm.c
|
||
+++ b/crypto/ccm.c
|
||
@@ -271,7 +271,8 @@ static int crypto_ccm_auth(struct aead_request *req, struct scatterlist *plain,
|
||
}
|
||
|
||
/* compute plaintext into mac */
|
||
- get_data_to_compute(cipher, pctx, plain, cryptlen);
|
||
+ if (cryptlen)
|
||
+ get_data_to_compute(cipher, pctx, plain, cryptlen);
|
||
|
||
out:
|
||
return err;
|
||
diff --git a/crypto/crypto_wq.c b/crypto/crypto_wq.c
|
||
index adad92a..2f1b8d1 100644
|
||
--- a/crypto/crypto_wq.c
|
||
+++ b/crypto/crypto_wq.c
|
||
@@ -33,7 +33,7 @@ static void __exit crypto_wq_exit(void)
|
||
destroy_workqueue(kcrypto_wq);
|
||
}
|
||
|
||
-module_init(crypto_wq_init);
|
||
+subsys_initcall(crypto_wq_init);
|
||
module_exit(crypto_wq_exit);
|
||
|
||
MODULE_LICENSE("GPL");
|
||
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
|
||
index 36e5a8e..1ae2e0e 100644
|
||
--- a/crypto/testmgr.h
|
||
+++ b/crypto/testmgr.h
|
||
@@ -14558,38 +14558,40 @@ static struct pcomp_testvec zlib_decomp_tv_template[] = {
|
||
static struct comp_testvec lzo_comp_tv_template[] = {
|
||
{
|
||
.inlen = 70,
|
||
- .outlen = 46,
|
||
+ .outlen = 57,
|
||
.input = "Join us now and share the software "
|
||
"Join us now and share the software ",
|
||
.output = "\x00\x0d\x4a\x6f\x69\x6e\x20\x75"
|
||
- "\x73\x20\x6e\x6f\x77\x20\x61\x6e"
|
||
- "\x64\x20\x73\x68\x61\x72\x65\x20"
|
||
- "\x74\x68\x65\x20\x73\x6f\x66\x74"
|
||
- "\x77\x70\x01\x01\x4a\x6f\x69\x6e"
|
||
- "\x3d\x88\x00\x11\x00\x00",
|
||
+ "\x73\x20\x6e\x6f\x77\x20\x61\x6e"
|
||
+ "\x64\x20\x73\x68\x61\x72\x65\x20"
|
||
+ "\x74\x68\x65\x20\x73\x6f\x66\x74"
|
||
+ "\x77\x70\x01\x32\x88\x00\x0c\x65"
|
||
+ "\x20\x74\x68\x65\x20\x73\x6f\x66"
|
||
+ "\x74\x77\x61\x72\x65\x20\x11\x00"
|
||
+ "\x00",
|
||
}, {
|
||
.inlen = 159,
|
||
- .outlen = 133,
|
||
+ .outlen = 131,
|
||
.input = "This document describes a compression method based on the LZO "
|
||
"compression algorithm. This document defines the application of "
|
||
"the LZO algorithm used in UBIFS.",
|
||
- .output = "\x00\x2b\x54\x68\x69\x73\x20\x64"
|
||
+ .output = "\x00\x2c\x54\x68\x69\x73\x20\x64"
|
||
"\x6f\x63\x75\x6d\x65\x6e\x74\x20"
|
||
"\x64\x65\x73\x63\x72\x69\x62\x65"
|
||
"\x73\x20\x61\x20\x63\x6f\x6d\x70"
|
||
"\x72\x65\x73\x73\x69\x6f\x6e\x20"
|
||
"\x6d\x65\x74\x68\x6f\x64\x20\x62"
|
||
"\x61\x73\x65\x64\x20\x6f\x6e\x20"
|
||
- "\x74\x68\x65\x20\x4c\x5a\x4f\x2b"
|
||
- "\x8c\x00\x0d\x61\x6c\x67\x6f\x72"
|
||
- "\x69\x74\x68\x6d\x2e\x20\x20\x54"
|
||
- "\x68\x69\x73\x2a\x54\x01\x02\x66"
|
||
- "\x69\x6e\x65\x73\x94\x06\x05\x61"
|
||
- "\x70\x70\x6c\x69\x63\x61\x74\x76"
|
||
- "\x0a\x6f\x66\x88\x02\x60\x09\x27"
|
||
- "\xf0\x00\x0c\x20\x75\x73\x65\x64"
|
||
- "\x20\x69\x6e\x20\x55\x42\x49\x46"
|
||
- "\x53\x2e\x11\x00\x00",
|
||
+ "\x74\x68\x65\x20\x4c\x5a\x4f\x20"
|
||
+ "\x2a\x8c\x00\x09\x61\x6c\x67\x6f"
|
||
+ "\x72\x69\x74\x68\x6d\x2e\x20\x20"
|
||
+ "\x2e\x54\x01\x03\x66\x69\x6e\x65"
|
||
+ "\x73\x20\x74\x06\x05\x61\x70\x70"
|
||
+ "\x6c\x69\x63\x61\x74\x76\x0a\x6f"
|
||
+ "\x66\x88\x02\x60\x09\x27\xf0\x00"
|
||
+ "\x0c\x20\x75\x73\x65\x64\x20\x69"
|
||
+ "\x6e\x20\x55\x42\x49\x46\x53\x2e"
|
||
+ "\x11\x00\x00",
|
||
},
|
||
};
|
||
|
||
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
|
||
index 9ba8c73..fe2f9d9 100644
|
||
--- a/drivers/acpi/acpica/exoparg1.c
|
||
+++ b/drivers/acpi/acpica/exoparg1.c
|
||
@@ -970,10 +970,17 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
|
||
*/
|
||
return_desc =
|
||
*(operand[0]->reference.where);
|
||
- if (return_desc) {
|
||
- acpi_ut_add_reference
|
||
- (return_desc);
|
||
+ if (!return_desc) {
|
||
+ /*
|
||
+ * Element is NULL, do not allow the dereference.
|
||
+ * This provides compatibility with other ACPI
|
||
+ * implementations.
|
||
+ */
|
||
+ return_ACPI_STATUS
|
||
+ (AE_AML_UNINITIALIZED_ELEMENT);
|
||
}
|
||
+
|
||
+ acpi_ut_add_reference(return_desc);
|
||
break;
|
||
|
||
default:
|
||
@@ -998,11 +1005,40 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
|
||
acpi_namespace_node
|
||
*)
|
||
return_desc);
|
||
- }
|
||
+ if (!return_desc) {
|
||
+ break;
|
||
+ }
|
||
|
||
- /* Add another reference to the object! */
|
||
+ /*
|
||
+ * June 2013:
|
||
+ * buffer_fields/field_units require additional resolution
|
||
+ */
|
||
+ switch (return_desc->common.type) {
|
||
+ case ACPI_TYPE_BUFFER_FIELD:
|
||
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
|
||
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
|
||
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
|
||
|
||
- acpi_ut_add_reference(return_desc);
|
||
+ status =
|
||
+ acpi_ex_read_data_from_field
|
||
+ (walk_state, return_desc,
|
||
+ &temp_desc);
|
||
+ if (ACPI_FAILURE(status)) {
|
||
+ goto cleanup;
|
||
+ }
|
||
+
|
||
+ return_desc = temp_desc;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+
|
||
+ /* Add another reference to the object */
|
||
+
|
||
+ acpi_ut_add_reference
|
||
+ (return_desc);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
break;
|
||
|
||
default:
|
||
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
|
||
index c6cf843..9806f4b 100644
|
||
--- a/drivers/acpi/acpica/exstore.c
|
||
+++ b/drivers/acpi/acpica/exstore.c
|
||
@@ -57,6 +57,11 @@ acpi_ex_store_object_to_index(union acpi_operand_object *val_desc,
|
||
union acpi_operand_object *dest_desc,
|
||
struct acpi_walk_state *walk_state);
|
||
|
||
+static acpi_status
|
||
+acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc,
|
||
+ struct acpi_namespace_node *node,
|
||
+ struct acpi_walk_state *walk_state);
|
||
+
|
||
/*******************************************************************************
|
||
*
|
||
* FUNCTION: acpi_ex_store
|
||
@@ -376,7 +381,11 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
|
||
* When storing into an object the data is converted to the
|
||
* target object type then stored in the object. This means
|
||
* that the target object type (for an initialized target) will
|
||
- * not be changed by a store operation.
|
||
+ * not be changed by a store operation. A copy_object can change
|
||
+ * the target type, however.
|
||
+ *
|
||
+ * The implicit_conversion flag is set to NO/FALSE only when
|
||
+ * storing to an arg_x -- as per the rules of the ACPI spec.
|
||
*
|
||
* Assumes parameters are already validated.
|
||
*
|
||
@@ -400,7 +409,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
|
||
target_type = acpi_ns_get_type(node);
|
||
target_desc = acpi_ns_get_attached_object(node);
|
||
|
||
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n",
|
||
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p (%s) to node %p (%s)\n",
|
||
source_desc,
|
||
acpi_ut_get_object_type_name(source_desc), node,
|
||
acpi_ut_get_type_name(target_type)));
|
||
@@ -414,46 +423,31 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
|
||
return_ACPI_STATUS(status);
|
||
}
|
||
|
||
- /* If no implicit conversion, drop into the default case below */
|
||
-
|
||
- if ((!implicit_conversion) ||
|
||
- ((walk_state->opcode == AML_COPY_OP) &&
|
||
- (target_type != ACPI_TYPE_LOCAL_REGION_FIELD) &&
|
||
- (target_type != ACPI_TYPE_LOCAL_BANK_FIELD) &&
|
||
- (target_type != ACPI_TYPE_LOCAL_INDEX_FIELD))) {
|
||
- /*
|
||
- * Force execution of default (no implicit conversion). Note:
|
||
- * copy_object does not perform an implicit conversion, as per the ACPI
|
||
- * spec -- except in case of region/bank/index fields -- because these
|
||
- * objects must retain their original type permanently.
|
||
- */
|
||
- target_type = ACPI_TYPE_ANY;
|
||
- }
|
||
-
|
||
/* Do the actual store operation */
|
||
|
||
switch (target_type) {
|
||
- case ACPI_TYPE_BUFFER_FIELD:
|
||
- case ACPI_TYPE_LOCAL_REGION_FIELD:
|
||
- case ACPI_TYPE_LOCAL_BANK_FIELD:
|
||
- case ACPI_TYPE_LOCAL_INDEX_FIELD:
|
||
-
|
||
- /* For fields, copy the source data to the target field. */
|
||
-
|
||
- status = acpi_ex_write_data_to_field(source_desc, target_desc,
|
||
- &walk_state->result_obj);
|
||
- break;
|
||
-
|
||
case ACPI_TYPE_INTEGER:
|
||
case ACPI_TYPE_STRING:
|
||
case ACPI_TYPE_BUFFER:
|
||
|
||
/*
|
||
- * These target types are all of type Integer/String/Buffer, and
|
||
- * therefore support implicit conversion before the store.
|
||
- *
|
||
- * Copy and/or convert the source object to a new target object
|
||
+ * The simple data types all support implicit source operand
|
||
+ * conversion before the store.
|
||
*/
|
||
+
|
||
+ if ((walk_state->opcode == AML_COPY_OP) || !implicit_conversion) {
|
||
+ /*
|
||
+ * However, copy_object and Stores to arg_x do not perform
|
||
+ * an implicit conversion, as per the ACPI specification.
|
||
+ * A direct store is performed instead.
|
||
+ */
|
||
+ status = acpi_ex_store_direct_to_node(source_desc, node,
|
||
+ walk_state);
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* Store with implicit source operand conversion support */
|
||
+
|
||
status =
|
||
acpi_ex_store_object_to_object(source_desc, target_desc,
|
||
&new_desc, walk_state);
|
||
@@ -467,13 +461,12 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
|
||
* the Name's type to that of the value being stored in it.
|
||
* source_desc reference count is incremented by attach_object.
|
||
*
|
||
- * Note: This may change the type of the node if an explicit store
|
||
- * has been performed such that the node/object type has been
|
||
- * changed.
|
||
+ * Note: This may change the type of the node if an explicit
|
||
+ * store has been performed such that the node/object type
|
||
+ * has been changed.
|
||
*/
|
||
- status =
|
||
- acpi_ns_attach_object(node, new_desc,
|
||
- new_desc->common.type);
|
||
+ status = acpi_ns_attach_object(node, new_desc,
|
||
+ new_desc->common.type);
|
||
|
||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||
"Store %s into %s via Convert/Attach\n",
|
||
@@ -484,19 +477,83 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
|
||
}
|
||
break;
|
||
|
||
+ case ACPI_TYPE_BUFFER_FIELD:
|
||
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
|
||
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
|
||
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
|
||
+ /*
|
||
+ * For all fields, always write the source data to the target
|
||
+ * field. Any required implicit source operand conversion is
|
||
+ * performed in the function below as necessary. Note, field
|
||
+ * objects must retain their original type permanently.
|
||
+ */
|
||
+ status = acpi_ex_write_data_to_field(source_desc, target_desc,
|
||
+ &walk_state->result_obj);
|
||
+ break;
|
||
+
|
||
default:
|
||
+ /*
|
||
+ * No conversions for all other types. Directly store a copy of
|
||
+ * the source object. This is the ACPI spec-defined behavior for
|
||
+ * the copy_object operator.
|
||
+ *
|
||
+ * NOTE: For the Store operator, this is a departure from the
|
||
+ * ACPI spec, which states "If conversion is impossible, abort
|
||
+ * the running control method". Instead, this code implements
|
||
+ * "If conversion is impossible, treat the Store operation as
|
||
+ * a CopyObject".
|
||
+ */
|
||
+ status = acpi_ex_store_direct_to_node(source_desc, node,
|
||
+ walk_state);
|
||
+ break;
|
||
+ }
|
||
|
||
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||
- "Storing %s (%p) directly into node (%p) with no implicit conversion\n",
|
||
- acpi_ut_get_object_type_name(source_desc),
|
||
- source_desc, node));
|
||
+ return_ACPI_STATUS(status);
|
||
+}
|
||
|
||
- /* No conversions for all other types. Just attach the source object */
|
||
+/*******************************************************************************
|
||
+ *
|
||
+ * FUNCTION: acpi_ex_store_direct_to_node
|
||
+ *
|
||
+ * PARAMETERS: source_desc - Value to be stored
|
||
+ * node - Named object to receive the value
|
||
+ * walk_state - Current walk state
|
||
+ *
|
||
+ * RETURN: Status
|
||
+ *
|
||
+ * DESCRIPTION: "Store" an object directly to a node. This involves a copy
|
||
+ * and an attach.
|
||
+ *
|
||
+ ******************************************************************************/
|
||
|
||
- status = acpi_ns_attach_object(node, source_desc,
|
||
- source_desc->common.type);
|
||
- break;
|
||
+static acpi_status
|
||
+acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc,
|
||
+ struct acpi_namespace_node *node,
|
||
+ struct acpi_walk_state *walk_state)
|
||
+{
|
||
+ acpi_status status;
|
||
+ union acpi_operand_object *new_desc;
|
||
+
|
||
+ ACPI_FUNCTION_TRACE(ex_store_direct_to_node);
|
||
+
|
||
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||
+ "Storing [%s] (%p) directly into node [%s] (%p)"
|
||
+ " with no implicit conversion\n",
|
||
+ acpi_ut_get_object_type_name(source_desc),
|
||
+ source_desc, acpi_ut_get_type_name(node->type),
|
||
+ node));
|
||
+
|
||
+ /* Copy the source object to a new object */
|
||
+
|
||
+ status =
|
||
+ acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc, walk_state);
|
||
+ if (ACPI_FAILURE(status)) {
|
||
+ return_ACPI_STATUS(status);
|
||
}
|
||
|
||
+ /* Attach the new object to the node */
|
||
+
|
||
+ status = acpi_ns_attach_object(node, new_desc, new_desc->common.type);
|
||
+ acpi_ut_remove_reference(new_desc);
|
||
return_ACPI_STATUS(status);
|
||
}
|
||
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
|
||
index 9bdfcf5..93f3034 100644
|
||
--- a/drivers/acpi/battery.c
|
||
+++ b/drivers/acpi/battery.c
|
||
@@ -34,6 +34,7 @@
|
||
#include <linux/dmi.h>
|
||
#include <linux/slab.h>
|
||
#include <linux/suspend.h>
|
||
+#include <linux/delay.h>
|
||
#include <asm/unaligned.h>
|
||
|
||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||
@@ -1055,6 +1056,28 @@ static int battery_notify(struct notifier_block *nb,
|
||
return 0;
|
||
}
|
||
|
||
+/*
|
||
+ * Some machines'(E,G Lenovo Z480) ECs are not stable
|
||
+ * during boot up and this causes battery driver fails to be
|
||
+ * probed due to failure of getting battery information
|
||
+ * from EC sometimes. After several retries, the operation
|
||
+ * may work. So add retry code here and 20ms sleep between
|
||
+ * every retries.
|
||
+ */
|
||
+static int acpi_battery_update_retry(struct acpi_battery *battery)
|
||
+{
|
||
+ int retry, ret;
|
||
+
|
||
+ for (retry = 5; retry; retry--) {
|
||
+ ret = acpi_battery_update(battery);
|
||
+ if (!ret)
|
||
+ break;
|
||
+
|
||
+ msleep(20);
|
||
+ }
|
||
+ return ret;
|
||
+}
|
||
+
|
||
static int acpi_battery_add(struct acpi_device *device)
|
||
{
|
||
int result = 0;
|
||
@@ -1074,9 +1097,11 @@ static int acpi_battery_add(struct acpi_device *device)
|
||
if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle,
|
||
"_BIX", &handle)))
|
||
set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
|
||
- result = acpi_battery_update(battery);
|
||
+
|
||
+ result = acpi_battery_update_retry(battery);
|
||
if (result)
|
||
goto fail;
|
||
+
|
||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||
result = acpi_battery_add_fs(device);
|
||
#endif
|
||
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
|
||
index cb96296..76da257 100644
|
||
--- a/drivers/acpi/blacklist.c
|
||
+++ b/drivers/acpi/blacklist.c
|
||
@@ -327,6 +327,19 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
|
||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T500"),
|
||
},
|
||
},
|
||
+ /*
|
||
+ * Without this this EEEpc exports a non working WMI interface, with
|
||
+ * this it exports a working "good old" eeepc_laptop interface, fixing
|
||
+ * both brightness control, and rfkill not working.
|
||
+ */
|
||
+ {
|
||
+ .callback = dmi_enable_osi_linux,
|
||
+ .ident = "Asus EEE PC 1015PX",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"),
|
||
+ },
|
||
+ },
|
||
{}
|
||
};
|
||
|
||
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
|
||
index cf02e97..06d2d22 100644
|
||
--- a/drivers/acpi/bus.c
|
||
+++ b/drivers/acpi/bus.c
|
||
@@ -33,6 +33,7 @@
|
||
#include <linux/proc_fs.h>
|
||
#include <linux/acpi.h>
|
||
#include <linux/slab.h>
|
||
+#include <linux/regulator/machine.h>
|
||
#ifdef CONFIG_X86
|
||
#include <asm/mpspec.h>
|
||
#endif
|
||
@@ -56,6 +57,12 @@ EXPORT_SYMBOL(acpi_root_dir);
|
||
|
||
|
||
#ifdef CONFIG_X86
|
||
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
||
+static inline int set_copy_dsdt(const struct dmi_system_id *id)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+#else
|
||
static int set_copy_dsdt(const struct dmi_system_id *id)
|
||
{
|
||
printk(KERN_NOTICE "%s detected - "
|
||
@@ -63,6 +70,7 @@ static int set_copy_dsdt(const struct dmi_system_id *id)
|
||
acpi_gbl_copy_dsdt_locally = 1;
|
||
return 0;
|
||
}
|
||
+#endif
|
||
|
||
static struct dmi_system_id dsdt_dmi_table[] __initdata = {
|
||
/*
|
||
@@ -921,6 +929,14 @@ void __init acpi_early_init(void)
|
||
goto error0;
|
||
}
|
||
|
||
+ /*
|
||
+ * If the system is using ACPI then we can be reasonably
|
||
+ * confident that any regulators are managed by the firmware
|
||
+ * so tell the regulator core it has everything it needs to
|
||
+ * know.
|
||
+ */
|
||
+ regulator_has_full_constraints();
|
||
+
|
||
return;
|
||
|
||
error0:
|
||
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
|
||
index 6cba428..e1180ce 100644
|
||
--- a/drivers/acpi/processor_idle.c
|
||
+++ b/drivers/acpi/processor_idle.c
|
||
@@ -1195,9 +1195,9 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
|
||
|
||
if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) {
|
||
|
||
- cpuidle_pause_and_lock();
|
||
/* Protect against cpu-hotplug */
|
||
get_online_cpus();
|
||
+ cpuidle_pause_and_lock();
|
||
|
||
/* Disable all cpuidle devices */
|
||
for_each_online_cpu(cpu) {
|
||
@@ -1222,8 +1222,8 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
|
||
cpuidle_enable_device(&_pr->power.dev);
|
||
}
|
||
}
|
||
- put_online_cpus();
|
||
cpuidle_resume_and_unlock();
|
||
+ put_online_cpus();
|
||
}
|
||
|
||
return 0;
|
||
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
|
||
index 1d02b7b..c653cc2 100644
|
||
--- a/drivers/acpi/processor_throttling.c
|
||
+++ b/drivers/acpi/processor_throttling.c
|
||
@@ -59,6 +59,12 @@ struct throttling_tstate {
|
||
int target_state; /* target T-state */
|
||
};
|
||
|
||
+struct acpi_processor_throttling_arg {
|
||
+ struct acpi_processor *pr;
|
||
+ int target_state;
|
||
+ bool force;
|
||
+};
|
||
+
|
||
#define THROTTLING_PRECHANGE (1)
|
||
#define THROTTLING_POSTCHANGE (2)
|
||
|
||
@@ -1062,16 +1068,24 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
|
||
return 0;
|
||
}
|
||
|
||
+static long acpi_processor_throttling_fn(void *data)
|
||
+{
|
||
+ struct acpi_processor_throttling_arg *arg = data;
|
||
+ struct acpi_processor *pr = arg->pr;
|
||
+
|
||
+ return pr->throttling.acpi_processor_set_throttling(pr,
|
||
+ arg->target_state, arg->force);
|
||
+}
|
||
+
|
||
int acpi_processor_set_throttling(struct acpi_processor *pr,
|
||
int state, bool force)
|
||
{
|
||
- cpumask_var_t saved_mask;
|
||
int ret = 0;
|
||
unsigned int i;
|
||
struct acpi_processor *match_pr;
|
||
struct acpi_processor_throttling *p_throttling;
|
||
+ struct acpi_processor_throttling_arg arg;
|
||
struct throttling_tstate t_state;
|
||
- cpumask_var_t online_throttling_cpus;
|
||
|
||
if (!pr)
|
||
return -EINVAL;
|
||
@@ -1082,14 +1096,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
|
||
if ((state < 0) || (state > (pr->throttling.state_count - 1)))
|
||
return -EINVAL;
|
||
|
||
- if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL))
|
||
- return -ENOMEM;
|
||
-
|
||
- if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) {
|
||
- free_cpumask_var(saved_mask);
|
||
- return -ENOMEM;
|
||
- }
|
||
-
|
||
if (cpu_is_offline(pr->id)) {
|
||
/*
|
||
* the cpu pointed by pr->id is offline. Unnecessary to change
|
||
@@ -1098,17 +1104,15 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
|
||
return -ENODEV;
|
||
}
|
||
|
||
- cpumask_copy(saved_mask, ¤t->cpus_allowed);
|
||
t_state.target_state = state;
|
||
p_throttling = &(pr->throttling);
|
||
- cpumask_and(online_throttling_cpus, cpu_online_mask,
|
||
- p_throttling->shared_cpu_map);
|
||
+
|
||
/*
|
||
* The throttling notifier will be called for every
|
||
* affected cpu in order to get one proper T-state.
|
||
* The notifier event is THROTTLING_PRECHANGE.
|
||
*/
|
||
- for_each_cpu(i, online_throttling_cpus) {
|
||
+ for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
|
||
t_state.cpu = i;
|
||
acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
|
||
&t_state);
|
||
@@ -1120,21 +1124,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
|
||
* it can be called only for the cpu pointed by pr.
|
||
*/
|
||
if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
|
||
- /* FIXME: use work_on_cpu() */
|
||
- if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
|
||
- /* Can't migrate to the pr->id CPU. Exit */
|
||
- ret = -ENODEV;
|
||
- goto exit;
|
||
- }
|
||
- ret = p_throttling->acpi_processor_set_throttling(pr,
|
||
- t_state.target_state, force);
|
||
+ arg.pr = pr;
|
||
+ arg.target_state = state;
|
||
+ arg.force = force;
|
||
+ ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg);
|
||
} else {
|
||
/*
|
||
* When the T-state coordination is SW_ALL or HW_ALL,
|
||
* it is necessary to set T-state for every affected
|
||
* cpus.
|
||
*/
|
||
- for_each_cpu(i, online_throttling_cpus) {
|
||
+ for_each_cpu_and(i, cpu_online_mask,
|
||
+ p_throttling->shared_cpu_map) {
|
||
match_pr = per_cpu(processors, i);
|
||
/*
|
||
* If the pointer is invalid, we will report the
|
||
@@ -1155,13 +1156,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
|
||
"on CPU %d\n", i));
|
||
continue;
|
||
}
|
||
- t_state.cpu = i;
|
||
- /* FIXME: use work_on_cpu() */
|
||
- if (set_cpus_allowed_ptr(current, cpumask_of(i)))
|
||
- continue;
|
||
- ret = match_pr->throttling.
|
||
- acpi_processor_set_throttling(
|
||
- match_pr, t_state.target_state, force);
|
||
+
|
||
+ arg.pr = match_pr;
|
||
+ arg.target_state = state;
|
||
+ arg.force = force;
|
||
+ ret = work_on_cpu(pr->id, acpi_processor_throttling_fn,
|
||
+ &arg);
|
||
}
|
||
}
|
||
/*
|
||
@@ -1170,17 +1170,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
|
||
* affected cpu to update the T-states.
|
||
* The notifier event is THROTTLING_POSTCHANGE
|
||
*/
|
||
- for_each_cpu(i, online_throttling_cpus) {
|
||
+ for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
|
||
t_state.cpu = i;
|
||
acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
|
||
&t_state);
|
||
}
|
||
- /* restore the previous state */
|
||
- /* FIXME: use work_on_cpu() */
|
||
- set_cpus_allowed_ptr(current, saved_mask);
|
||
-exit:
|
||
- free_cpumask_var(online_throttling_cpus);
|
||
- free_cpumask_var(saved_mask);
|
||
+
|
||
return ret;
|
||
}
|
||
|
||
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
|
||
index 6d2c49ba..8c5ad89 100644
|
||
--- a/drivers/acpi/video.c
|
||
+++ b/drivers/acpi/video.c
|
||
@@ -463,6 +463,22 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
|
||
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion m4 Notebook PC"),
|
||
},
|
||
},
|
||
+ {
|
||
+ .callback = video_ignore_initial_backlight,
|
||
+ .ident = "HP 1000 Notebook PC",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP 1000 Notebook PC"),
|
||
+ },
|
||
+ },
|
||
+ {
|
||
+ .callback = video_ignore_initial_backlight,
|
||
+ .ident = "HP Pavilion dm4",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dm4 Notebook PC"),
|
||
+ },
|
||
+ },
|
||
{}
|
||
};
|
||
|
||
@@ -632,6 +648,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
|
||
union acpi_object *o;
|
||
struct acpi_video_device_brightness *br = NULL;
|
||
int result = -EINVAL;
|
||
+ u32 value;
|
||
|
||
if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
|
||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
|
||
@@ -662,7 +679,12 @@ acpi_video_init_brightness(struct acpi_video_device *device)
|
||
printk(KERN_ERR PREFIX "Invalid data\n");
|
||
continue;
|
||
}
|
||
- br->levels[count] = (u32) o->integer.value;
|
||
+ value = (u32) o->integer.value;
|
||
+ /* Skip duplicate entries */
|
||
+ if (count > 2 && br->levels[count - 1] == value)
|
||
+ continue;
|
||
+
|
||
+ br->levels[count] = value;
|
||
|
||
if (br->levels[count] > max_level)
|
||
max_level = br->levels[count];
|
||
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
|
||
index 45d8097..1440887 100644
|
||
--- a/drivers/acpi/video_detect.c
|
||
+++ b/drivers/acpi/video_detect.c
|
||
@@ -132,6 +132,49 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||
return AE_OK;
|
||
}
|
||
|
||
+/* Force to use vendor driver when the ACPI device is known to be
|
||
+ * buggy */
|
||
+static int video_detect_force_vendor(const struct dmi_system_id *d)
|
||
+{
|
||
+ acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct dmi_system_id video_detect_dmi_table[] = {
|
||
+ /* On Samsung X360, the BIOS will set a flag (VDRV) if generic
|
||
+ * ACPI backlight device is used. This flag will definitively break
|
||
+ * the backlight interface (even the vendor interface) untill next
|
||
+ * reboot. It's why we should prevent video.ko from being used here
|
||
+ * and we can't rely on a later call to acpi_video_unregister().
|
||
+ */
|
||
+ {
|
||
+ .callback = video_detect_force_vendor,
|
||
+ .ident = "X360",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
|
||
+ DMI_MATCH(DMI_BOARD_NAME, "X360"),
|
||
+ },
|
||
+ },
|
||
+ {
|
||
+ .callback = video_detect_force_vendor,
|
||
+ .ident = "Asus UL30VT",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
|
||
+ },
|
||
+ },
|
||
+ {
|
||
+ .callback = video_detect_force_vendor,
|
||
+ .ident = "Asus UL30A",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
|
||
+ },
|
||
+ },
|
||
+ { },
|
||
+};
|
||
+
|
||
/*
|
||
* Returns the video capabilities of a specific ACPI graphics device
|
||
*
|
||
@@ -164,6 +207,8 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle)
|
||
* ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
|
||
*}
|
||
*/
|
||
+
|
||
+ dmi_check_system(video_detect_dmi_table);
|
||
} else {
|
||
status = acpi_bus_get_device(graphics_handle, &tmp_dev);
|
||
if (ACPI_FAILURE(status)) {
|
||
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
|
||
index aeb8220..d366a75 100644
|
||
--- a/drivers/ata/ahci.c
|
||
+++ b/drivers/ata/ahci.c
|
||
@@ -268,6 +268,51 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
||
{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
|
||
{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
|
||
{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c05), board_ahci }, /* Lynx Point-LP RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c06), board_ahci }, /* Lynx Point-LP RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c07), board_ahci }, /* Lynx Point-LP RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c0e), board_ahci }, /* Lynx Point-LP RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c0f), board_ahci }, /* Lynx Point-LP RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f25), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f26), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f32), board_ahci }, /* Avoton AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f33), board_ahci }, /* Avoton AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f34), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f35), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f36), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f37), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci }, /* Avoton RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x8d04), board_ahci }, /* Wellsburg RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8d06), board_ahci }, /* Wellsburg RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8d0e), board_ahci }, /* Wellsburg RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8d62), board_ahci }, /* Wellsburg AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c83), board_ahci }, /* Wildcat Point-LP AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c85), board_ahci }, /* Wildcat Point-LP RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
|
||
+ { PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
|
||
+ { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
|
||
|
||
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
|
||
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||
@@ -398,13 +443,20 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
||
.driver_data = board_ahci_yes_fbs }, /* 88se9125 */
|
||
{ PCI_DEVICE(0x1b4b, 0x917a),
|
||
.driver_data = board_ahci_yes_fbs }, /* 88se9172 */
|
||
+ { PCI_DEVICE(0x1b4b, 0x9182),
|
||
+ .driver_data = board_ahci_yes_fbs }, /* 88se9182 */
|
||
{ PCI_DEVICE(0x1b4b, 0x9192),
|
||
.driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */
|
||
{ PCI_DEVICE(0x1b4b, 0x91a3),
|
||
.driver_data = board_ahci_yes_fbs },
|
||
+ { PCI_DEVICE(0x1b4b, 0x9230),
|
||
+ .driver_data = board_ahci_yes_fbs },
|
||
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642),
|
||
+ .driver_data = board_ahci_yes_fbs },
|
||
|
||
/* Promise */
|
||
{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */
|
||
+ { PCI_VDEVICE(PROMISE, 0x3781), board_ahci }, /* FastTrak TX8660 ahci-mode */
|
||
|
||
/* Asmedia */
|
||
{ PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */
|
||
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
|
||
index 9dbd3ae..2f081a3 100644
|
||
--- a/drivers/ata/ata_piix.c
|
||
+++ b/drivers/ata/ata_piix.c
|
||
@@ -331,6 +331,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
|
||
{ 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
|
||
/* SATA Controller IDE (Lynx Point) */
|
||
{ 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
|
||
+ /* SATA Controller IDE (Lynx Point-LP) */
|
||
+ { 0x8086, 0x9c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
|
||
+ /* SATA Controller IDE (Lynx Point-LP) */
|
||
+ { 0x8086, 0x9c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
|
||
+ /* SATA Controller IDE (Lynx Point-LP) */
|
||
+ { 0x8086, 0x9c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
|
||
+ /* SATA Controller IDE (Lynx Point-LP) */
|
||
+ { 0x8086, 0x9c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
|
||
/* SATA Controller IDE (DH89xxCC) */
|
||
{ 0x8086, 0x2326, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
|
||
/* SATA Controller IDE (Avoton) */
|
||
@@ -354,6 +362,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
|
||
{ 0x8086, 0x0F21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
|
||
/* SATA Controller IDE (Coleto Creek) */
|
||
{ 0x8086, 0x23a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
|
||
+ /* SATA Controller IDE (9 Series) */
|
||
+ { 0x8086, 0x8c88, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
|
||
+ /* SATA Controller IDE (9 Series) */
|
||
+ { 0x8086, 0x8c89, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
|
||
+ /* SATA Controller IDE (9 Series) */
|
||
+ { 0x8086, 0x8c80, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
|
||
+ /* SATA Controller IDE (9 Series) */
|
||
+ { 0x8086, 0x8c81, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
|
||
|
||
{ } /* terminate list */
|
||
};
|
||
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
|
||
index 47a1fb8..60f41cd 100644
|
||
--- a/drivers/ata/libahci.c
|
||
+++ b/drivers/ata/libahci.c
|
||
@@ -1249,9 +1249,11 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
|
||
{
|
||
struct ata_port *ap = link->ap;
|
||
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||
+ struct ahci_port_priv *pp = ap->private_data;
|
||
const char *reason = NULL;
|
||
unsigned long now, msecs;
|
||
struct ata_taskfile tf;
|
||
+ bool fbs_disabled = false;
|
||
int rc;
|
||
|
||
DPRINTK("ENTER\n");
|
||
@@ -1261,6 +1263,16 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
|
||
if (rc && rc != -EOPNOTSUPP)
|
||
ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc);
|
||
|
||
+ /*
|
||
+ * According to AHCI-1.2 9.3.9: if FBS is enable, software shall
|
||
+ * clear PxFBS.EN to '0' prior to issuing software reset to devices
|
||
+ * that is attached to port multiplier.
|
||
+ */
|
||
+ if (!ata_is_host_link(link) && pp->fbs_enabled) {
|
||
+ ahci_disable_fbs(ap);
|
||
+ fbs_disabled = true;
|
||
+ }
|
||
+
|
||
ata_tf_init(link->device, &tf);
|
||
|
||
/* issue the first D2H Register FIS */
|
||
@@ -1301,6 +1313,10 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
|
||
} else
|
||
*class = ahci_dev_classify(ap);
|
||
|
||
+ /* re-enable FBS if disabled before */
|
||
+ if (fbs_disabled)
|
||
+ ahci_enable_fbs(ap);
|
||
+
|
||
DPRINTK("EXIT, class=%u\n", *class);
|
||
return 0;
|
||
|
||
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
|
||
index 9cf09ae..6b92236 100644
|
||
--- a/drivers/ata/libata-core.c
|
||
+++ b/drivers/ata/libata-core.c
|
||
@@ -4074,6 +4074,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
|
||
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
|
||
{ "QUANTUM DAT DAT72-000", NULL, ATA_HORKAGE_ATAPI_MOD16_DMA },
|
||
{ "Slimtype DVD A DS8A8SH", NULL, ATA_HORKAGE_MAX_SEC_LBA48 },
|
||
+ { "Slimtype DVD A DS8A9SH", NULL, ATA_HORKAGE_MAX_SEC_LBA48 },
|
||
|
||
/* Devices we expect to fail diagnostics */
|
||
|
||
@@ -4103,6 +4104,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
|
||
{ "ST3320[68]13AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
|
||
ATA_HORKAGE_FIRMWARE_WARN },
|
||
|
||
+ /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
|
||
+ { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
|
||
+ { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA },
|
||
+
|
||
/* Blacklist entries taken from Silicon Image 3124/3132
|
||
Windows driver .inf file - also several Linux problem reports */
|
||
{ "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, },
|
||
@@ -4688,6 +4693,10 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
|
||
* ata_qc_new - Request an available ATA command, for queueing
|
||
* @ap: target port
|
||
*
|
||
+ * Some ATA host controllers may implement a queue depth which is less
|
||
+ * than ATA_MAX_QUEUE. So we shouldn't allocate a tag which is beyond
|
||
+ * the hardware limitation.
|
||
+ *
|
||
* LOCKING:
|
||
* None.
|
||
*/
|
||
@@ -4695,21 +4704,27 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
|
||
static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
|
||
{
|
||
struct ata_queued_cmd *qc = NULL;
|
||
- unsigned int i;
|
||
+ unsigned int max_queue = ap->host->n_tags;
|
||
+ unsigned int i, tag;
|
||
|
||
/* no command while frozen */
|
||
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
|
||
return NULL;
|
||
|
||
- /* the last tag is reserved for internal command. */
|
||
- for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
|
||
- if (!test_and_set_bit(i, &ap->qc_allocated)) {
|
||
- qc = __ata_qc_from_tag(ap, i);
|
||
+ for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) {
|
||
+ tag = tag < max_queue ? tag : 0;
|
||
+
|
||
+ /* the last tag is reserved for internal command. */
|
||
+ if (tag == ATA_TAG_INTERNAL)
|
||
+ continue;
|
||
+
|
||
+ if (!test_and_set_bit(tag, &ap->qc_allocated)) {
|
||
+ qc = __ata_qc_from_tag(ap, tag);
|
||
+ qc->tag = tag;
|
||
+ ap->last_tag = tag;
|
||
break;
|
||
}
|
||
-
|
||
- if (qc)
|
||
- qc->tag = i;
|
||
+ }
|
||
|
||
return qc;
|
||
}
|
||
@@ -5949,6 +5964,7 @@ void ata_host_init(struct ata_host *host, struct device *dev,
|
||
{
|
||
spin_lock_init(&host->lock);
|
||
mutex_init(&host->eh_mutex);
|
||
+ host->n_tags = ATA_MAX_QUEUE - 1;
|
||
host->dev = dev;
|
||
host->flags = flags;
|
||
host->ops = ops;
|
||
@@ -6031,6 +6047,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
|
||
{
|
||
int i, rc;
|
||
|
||
+ host->n_tags = clamp(sht->can_queue, 1, ATA_MAX_QUEUE - 1);
|
||
+
|
||
/* host must have been started */
|
||
if (!(host->flags & ATA_HOST_STARTED)) {
|
||
dev_err(host->dev, "BUG: trying to register unstarted host\n");
|
||
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
|
||
index e47c224..37fb4d6 100644
|
||
--- a/drivers/ata/libata-eh.c
|
||
+++ b/drivers/ata/libata-eh.c
|
||
@@ -1287,14 +1287,14 @@ void ata_eh_qc_complete(struct ata_queued_cmd *qc)
|
||
* should be retried. To be used from EH.
|
||
*
|
||
* SCSI midlayer limits the number of retries to scmd->allowed.
|
||
- * scmd->retries is decremented for commands which get retried
|
||
+ * scmd->allowed is incremented for commands which get retried
|
||
* due to unrelated failures (qc->err_mask is zero).
|
||
*/
|
||
void ata_eh_qc_retry(struct ata_queued_cmd *qc)
|
||
{
|
||
struct scsi_cmnd *scmd = qc->scsicmd;
|
||
- if (!qc->err_mask && scmd->retries)
|
||
- scmd->retries--;
|
||
+ if (!qc->err_mask)
|
||
+ scmd->allowed++;
|
||
__ata_eh_qc_complete(qc);
|
||
}
|
||
|
||
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
|
||
index f5c35be..0ba32fe 100644
|
||
--- a/drivers/ata/libata-pmp.c
|
||
+++ b/drivers/ata/libata-pmp.c
|
||
@@ -447,8 +447,11 @@ static void sata_pmp_quirks(struct ata_port *ap)
|
||
* otherwise. Don't try hard to recover it.
|
||
*/
|
||
ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
|
||
- } else if (vendor == 0x197b && devid == 0x2352) {
|
||
- /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */
|
||
+ } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) {
|
||
+ /*
|
||
+ * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350?
|
||
+ * 0x0325: jmicron JMB394.
|
||
+ */
|
||
ata_for_each_link(link, ap, EDGE) {
|
||
/* SRST breaks detection and disks get misclassified
|
||
* LPM disabled to avoid potential problems
|
||
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
|
||
index c341904..9215677 100644
|
||
--- a/drivers/ata/libata-transport.c
|
||
+++ b/drivers/ata/libata-transport.c
|
||
@@ -319,25 +319,25 @@ int ata_tport_add(struct device *parent,
|
||
/*
|
||
* ATA link attributes
|
||
*/
|
||
+static int noop(int x) { return x; }
|
||
|
||
-
|
||
-#define ata_link_show_linkspeed(field) \
|
||
+#define ata_link_show_linkspeed(field, format) \
|
||
static ssize_t \
|
||
show_ata_link_##field(struct device *dev, \
|
||
struct device_attribute *attr, char *buf) \
|
||
{ \
|
||
struct ata_link *link = transport_class_to_link(dev); \
|
||
\
|
||
- return sprintf(buf,"%s\n", sata_spd_string(fls(link->field))); \
|
||
+ return sprintf(buf, "%s\n", sata_spd_string(format(link->field))); \
|
||
}
|
||
|
||
-#define ata_link_linkspeed_attr(field) \
|
||
- ata_link_show_linkspeed(field) \
|
||
+#define ata_link_linkspeed_attr(field, format) \
|
||
+ ata_link_show_linkspeed(field, format) \
|
||
static DEVICE_ATTR(field, S_IRUGO, show_ata_link_##field, NULL)
|
||
|
||
-ata_link_linkspeed_attr(hw_sata_spd_limit);
|
||
-ata_link_linkspeed_attr(sata_spd_limit);
|
||
-ata_link_linkspeed_attr(sata_spd);
|
||
+ata_link_linkspeed_attr(hw_sata_spd_limit, fls);
|
||
+ata_link_linkspeed_attr(sata_spd_limit, fls);
|
||
+ata_link_linkspeed_attr(sata_spd, noop);
|
||
|
||
|
||
static DECLARE_TRANSPORT_CLASS(ata_link_class,
|
||
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
|
||
index 53d3770..47d5d58 100644
|
||
--- a/drivers/ata/pata_at91.c
|
||
+++ b/drivers/ata/pata_at91.c
|
||
@@ -408,12 +408,13 @@ static int __devinit pata_at91_probe(struct platform_device *pdev)
|
||
|
||
host->private_data = info;
|
||
|
||
- return ata_host_activate(host, gpio_is_valid(irq) ? gpio_to_irq(irq) : 0,
|
||
- gpio_is_valid(irq) ? ata_sff_interrupt : NULL,
|
||
- irq_flags, &pata_at91_sht);
|
||
+ ret = ata_host_activate(host, gpio_is_valid(irq) ? gpio_to_irq(irq) : 0,
|
||
+ gpio_is_valid(irq) ? ata_sff_interrupt : NULL,
|
||
+ irq_flags, &pata_at91_sht);
|
||
+ if (ret)
|
||
+ goto err_put;
|
||
|
||
- if (!ret)
|
||
- return 0;
|
||
+ return 0;
|
||
|
||
err_put:
|
||
clk_put(info->mck);
|
||
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
|
||
index e265f83..19759d3 100644
|
||
--- a/drivers/ata/pata_scc.c
|
||
+++ b/drivers/ata/pata_scc.c
|
||
@@ -586,7 +586,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
|
||
* Note: Original code is ata_bus_softreset().
|
||
*/
|
||
|
||
-static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
|
||
+static int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
|
||
unsigned long deadline)
|
||
{
|
||
struct ata_ioports *ioaddr = &ap->ioaddr;
|
||
@@ -600,9 +600,7 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
|
||
udelay(20);
|
||
out_be32(ioaddr->ctl_addr, ap->ctl);
|
||
|
||
- scc_wait_after_reset(&ap->link, devmask, deadline);
|
||
-
|
||
- return 0;
|
||
+ return scc_wait_after_reset(&ap->link, devmask, deadline);
|
||
}
|
||
|
||
/**
|
||
@@ -619,7 +617,8 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes,
|
||
{
|
||
struct ata_port *ap = link->ap;
|
||
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
|
||
- unsigned int devmask = 0, err_mask;
|
||
+ unsigned int devmask = 0;
|
||
+ int rc;
|
||
u8 err;
|
||
|
||
DPRINTK("ENTER\n");
|
||
@@ -635,9 +634,9 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes,
|
||
|
||
/* issue bus reset */
|
||
DPRINTK("about to softreset, devmask=%x\n", devmask);
|
||
- err_mask = scc_bus_softreset(ap, devmask, deadline);
|
||
- if (err_mask) {
|
||
- ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", err_mask);
|
||
+ rc = scc_bus_softreset(ap, devmask, deadline);
|
||
+ if (rc) {
|
||
+ ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", rc);
|
||
return -EIO;
|
||
}
|
||
|
||
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
|
||
index 9dfb40b..0c4ed89 100644
|
||
--- a/drivers/ata/sata_sil.c
|
||
+++ b/drivers/ata/sata_sil.c
|
||
@@ -157,6 +157,7 @@ static const struct sil_drivelist {
|
||
{ "ST380011ASL", SIL_QUIRK_MOD15WRITE },
|
||
{ "ST3120022ASL", SIL_QUIRK_MOD15WRITE },
|
||
{ "ST3160021ASL", SIL_QUIRK_MOD15WRITE },
|
||
+ { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE },
|
||
{ "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX },
|
||
{ }
|
||
};
|
||
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
|
||
index f8f41e0..89b30f3 100644
|
||
--- a/drivers/atm/ambassador.c
|
||
+++ b/drivers/atm/ambassador.c
|
||
@@ -802,7 +802,7 @@ static void fill_rx_pool (amb_dev * dev, unsigned char pool,
|
||
}
|
||
// cast needed as there is no %? for pointer differences
|
||
PRINTD (DBG_SKB, "allocated skb at %p, head %p, area %li",
|
||
- skb, skb->head, (long) (skb_end_pointer(skb) - skb->head));
|
||
+ skb, skb->head, (long) skb_end_offset(skb));
|
||
rx.handle = virt_to_bus (skb);
|
||
rx.host_address = cpu_to_be32 (virt_to_bus (skb->data));
|
||
if (rx_give (dev, &rx, pool))
|
||
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
|
||
index 1c05212..81845fa 100644
|
||
--- a/drivers/atm/idt77252.c
|
||
+++ b/drivers/atm/idt77252.c
|
||
@@ -1258,7 +1258,7 @@ idt77252_rx_raw(struct idt77252_dev *card)
|
||
tail = readl(SAR_REG_RAWCT);
|
||
|
||
pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(queue),
|
||
- skb_end_pointer(queue) - queue->head - 16,
|
||
+ skb_end_offset(queue) - 16,
|
||
PCI_DMA_FROMDEVICE);
|
||
|
||
while (head != tail) {
|
||
@@ -3513,7 +3513,7 @@ init_card(struct atm_dev *dev)
|
||
tmp = dev_get_by_name(&init_net, tname); /* jhs: was "tmp = dev_get(tname);" */
|
||
if (tmp) {
|
||
memcpy(card->atmdev->esi, tmp->dev_addr, 6);
|
||
-
|
||
+ dev_put(tmp);
|
||
printk("%s: ESI %pM\n", card->name, card->atmdev->esi);
|
||
}
|
||
/*
|
||
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
|
||
index 4900e90..62a6942 100644
|
||
--- a/drivers/base/dd.c
|
||
+++ b/drivers/base/dd.c
|
||
@@ -52,6 +52,7 @@ static DEFINE_MUTEX(deferred_probe_mutex);
|
||
static LIST_HEAD(deferred_probe_pending_list);
|
||
static LIST_HEAD(deferred_probe_active_list);
|
||
static struct workqueue_struct *deferred_wq;
|
||
+static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
|
||
|
||
/**
|
||
* deferred_probe_work_func() - Retry probing devices in the active list.
|
||
@@ -123,6 +124,17 @@ static bool driver_deferred_probe_enable = false;
|
||
* This functions moves all devices from the pending list to the active
|
||
* list and schedules the deferred probe workqueue to process them. It
|
||
* should be called anytime a driver is successfully bound to a device.
|
||
+ *
|
||
+ * Note, there is a race condition in multi-threaded probe. In the case where
|
||
+ * more than one device is probing at the same time, it is possible for one
|
||
+ * probe to complete successfully while another is about to defer. If the second
|
||
+ * depends on the first, then it will get put on the pending list after the
|
||
+ * trigger event has already occured and will be stuck there.
|
||
+ *
|
||
+ * The atomic 'deferred_trigger_count' is used to determine if a successful
|
||
+ * trigger has occurred in the midst of probing a driver. If the trigger count
|
||
+ * changes in the midst of a probe, then deferred processing should be triggered
|
||
+ * again.
|
||
*/
|
||
static void driver_deferred_probe_trigger(void)
|
||
{
|
||
@@ -135,6 +147,7 @@ static void driver_deferred_probe_trigger(void)
|
||
* into the active list so they can be retried by the workqueue
|
||
*/
|
||
mutex_lock(&deferred_probe_mutex);
|
||
+ atomic_inc(&deferred_trigger_count);
|
||
list_splice_tail_init(&deferred_probe_pending_list,
|
||
&deferred_probe_active_list);
|
||
mutex_unlock(&deferred_probe_mutex);
|
||
@@ -253,6 +266,7 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
|
||
static int really_probe(struct device *dev, struct device_driver *drv)
|
||
{
|
||
int ret = 0;
|
||
+ int local_trigger_count = atomic_read(&deferred_trigger_count);
|
||
|
||
atomic_inc(&probe_count);
|
||
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
|
||
@@ -297,6 +311,9 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
||
/* Driver requested deferred probing */
|
||
dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
|
||
driver_deferred_probe_add(dev);
|
||
+ /* Did a trigger occur while probing? Need to re-trigger if yes */
|
||
+ if (local_trigger_count != atomic_read(&deferred_trigger_count))
|
||
+ driver_deferred_probe_trigger();
|
||
} else if (ret != -ENODEV && ret != -ENXIO) {
|
||
/* driver matched but the probe failed */
|
||
printk(KERN_WARNING
|
||
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
|
||
index ca72d1f..e554542 100644
|
||
--- a/drivers/base/regmap/regmap.c
|
||
+++ b/drivers/base/regmap/regmap.c
|
||
@@ -48,7 +48,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
|
||
|
||
bool regmap_volatile(struct regmap *map, unsigned int reg)
|
||
{
|
||
- if (!regmap_readable(map, reg))
|
||
+ if (!map->format.format_write && !regmap_readable(map, reg))
|
||
return false;
|
||
|
||
if (map->volatile_reg)
|
||
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
|
||
index 4e8213a..a7d70e2 100644
|
||
--- a/drivers/block/brd.c
|
||
+++ b/drivers/block/brd.c
|
||
@@ -546,7 +546,7 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data)
|
||
|
||
mutex_lock(&brd_devices_mutex);
|
||
brd = brd_init_one(MINOR(dev) >> part_shift);
|
||
- kobj = brd ? get_disk(brd->brd_disk) : ERR_PTR(-ENOMEM);
|
||
+ kobj = brd ? get_disk(brd->brd_disk) : NULL;
|
||
mutex_unlock(&brd_devices_mutex);
|
||
|
||
*part = 0;
|
||
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
|
||
index c82f06e..bc99e5c 100644
|
||
--- a/drivers/block/floppy.c
|
||
+++ b/drivers/block/floppy.c
|
||
@@ -3058,7 +3058,10 @@ static int raw_cmd_copyout(int cmd, void __user *param,
|
||
int ret;
|
||
|
||
while (ptr) {
|
||
- ret = copy_to_user(param, ptr, sizeof(*ptr));
|
||
+ struct floppy_raw_cmd cmd = *ptr;
|
||
+ cmd.next = NULL;
|
||
+ cmd.kernel_data = NULL;
|
||
+ ret = copy_to_user(param, &cmd, sizeof(cmd));
|
||
if (ret)
|
||
return -EFAULT;
|
||
param += sizeof(struct floppy_raw_cmd);
|
||
@@ -3112,10 +3115,11 @@ static int raw_cmd_copyin(int cmd, void __user *param,
|
||
return -ENOMEM;
|
||
*rcmd = ptr;
|
||
ret = copy_from_user(ptr, param, sizeof(*ptr));
|
||
- if (ret)
|
||
- return -EFAULT;
|
||
ptr->next = NULL;
|
||
ptr->buffer_length = 0;
|
||
+ ptr->kernel_data = NULL;
|
||
+ if (ret)
|
||
+ return -EFAULT;
|
||
param += sizeof(struct floppy_raw_cmd);
|
||
if (ptr->cmd_count > 33)
|
||
/* the command may now also take up the space
|
||
@@ -3131,7 +3135,6 @@ static int raw_cmd_copyin(int cmd, void __user *param,
|
||
for (i = 0; i < 16; i++)
|
||
ptr->reply[i] = 0;
|
||
ptr->resultcode = 0;
|
||
- ptr->kernel_data = NULL;
|
||
|
||
if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
|
||
if (ptr->length <= 0)
|
||
@@ -4303,7 +4306,7 @@ static int __init floppy_init(void)
|
||
|
||
err = platform_device_register(&floppy_device[drive]);
|
||
if (err)
|
||
- goto out_flush_work;
|
||
+ goto out_remove_drives;
|
||
|
||
err = device_create_file(&floppy_device[drive].dev,
|
||
&dev_attr_cmos);
|
||
@@ -4321,6 +4324,15 @@ static int __init floppy_init(void)
|
||
|
||
out_unreg_platform_dev:
|
||
platform_device_unregister(&floppy_device[drive]);
|
||
+out_remove_drives:
|
||
+ while (drive--) {
|
||
+ if ((allowed_drive_mask & (1 << drive)) &&
|
||
+ fdc_state[FDC(drive)].version != FDC_NONE) {
|
||
+ del_gendisk(disks[drive]);
|
||
+ device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
|
||
+ platform_device_unregister(&floppy_device[drive]);
|
||
+ }
|
||
+ }
|
||
out_flush_work:
|
||
flush_work_sync(&floppy_work);
|
||
if (atomic_read(&usage_count))
|
||
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
|
||
index 179b5b4..462fd18 100644
|
||
--- a/drivers/block/loop.c
|
||
+++ b/drivers/block/loop.c
|
||
@@ -1636,7 +1636,7 @@ static int loop_add(struct loop_device **l, int i)
|
||
|
||
lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
|
||
if (!lo->lo_queue)
|
||
- goto out_free_dev;
|
||
+ goto out_free_idr;
|
||
|
||
disk = lo->lo_disk = alloc_disk(1 << part_shift);
|
||
if (!disk)
|
||
@@ -1680,6 +1680,8 @@ static int loop_add(struct loop_device **l, int i)
|
||
|
||
out_free_queue:
|
||
blk_cleanup_queue(lo->lo_queue);
|
||
+out_free_idr:
|
||
+ idr_remove(&loop_index_idr, i);
|
||
out_free_dev:
|
||
kfree(lo);
|
||
out:
|
||
@@ -1743,7 +1745,7 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data)
|
||
if (err < 0)
|
||
err = loop_add(&lo, MINOR(dev) >> part_shift);
|
||
if (err < 0)
|
||
- kobj = ERR_PTR(err);
|
||
+ kobj = NULL;
|
||
else
|
||
kobj = get_disk(lo->lo_disk);
|
||
mutex_unlock(&loop_index_mutex);
|
||
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
|
||
index 386d40e..35fc569 100644
|
||
--- a/drivers/block/nbd.c
|
||
+++ b/drivers/block/nbd.c
|
||
@@ -584,14 +584,24 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
|
||
struct request sreq;
|
||
|
||
dev_info(disk_to_dev(nbd->disk), "NBD_DISCONNECT\n");
|
||
+ if (!nbd->sock)
|
||
+ return -EINVAL;
|
||
|
||
+ mutex_unlock(&nbd->tx_lock);
|
||
+ fsync_bdev(bdev);
|
||
+ mutex_lock(&nbd->tx_lock);
|
||
blk_rq_init(NULL, &sreq);
|
||
sreq.cmd_type = REQ_TYPE_SPECIAL;
|
||
nbd_cmd(&sreq) = NBD_CMD_DISC;
|
||
+
|
||
+ /* Check again after getting mutex back. */
|
||
if (!nbd->sock)
|
||
return -EINVAL;
|
||
+
|
||
+ nbd->disconnect = 1;
|
||
+
|
||
nbd_send_req(nbd, &sreq);
|
||
- return 0;
|
||
+ return 0;
|
||
}
|
||
|
||
case NBD_CLEAR_SOCK: {
|
||
@@ -603,6 +613,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
|
||
nbd_clear_que(nbd);
|
||
BUG_ON(!list_empty(&nbd->queue_head));
|
||
BUG_ON(!list_empty(&nbd->waiting_queue));
|
||
+ kill_bdev(bdev);
|
||
if (file)
|
||
fput(file);
|
||
return 0;
|
||
@@ -620,6 +631,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
|
||
nbd->sock = SOCKET_I(inode);
|
||
if (max_part > 0)
|
||
bdev->bd_invalidated = 1;
|
||
+ nbd->disconnect = 0; /* we're connected now */
|
||
return 0;
|
||
} else {
|
||
fput(file);
|
||
@@ -684,6 +696,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
|
||
nbd->file = NULL;
|
||
nbd_clear_que(nbd);
|
||
dev_warn(disk_to_dev(nbd->disk), "queue cleared\n");
|
||
+ kill_bdev(bdev);
|
||
if (file)
|
||
fput(file);
|
||
nbd->bytesize = 0;
|
||
@@ -691,6 +704,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
|
||
set_capacity(nbd->disk, 0);
|
||
if (max_part > 0)
|
||
ioctl_by_bdev(bdev, BLKRRPART, 0);
|
||
+ if (nbd->disconnect) /* user requested, ignore socket errors */
|
||
+ return 0;
|
||
return nbd->harderror;
|
||
}
|
||
|
||
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
|
||
index 0d39f2f..98bb43f 100644
|
||
--- a/drivers/block/virtio_blk.c
|
||
+++ b/drivers/block/virtio_blk.c
|
||
@@ -21,17 +21,12 @@ struct workqueue_struct *virtblk_wq;
|
||
|
||
struct virtio_blk
|
||
{
|
||
- spinlock_t lock;
|
||
-
|
||
struct virtio_device *vdev;
|
||
struct virtqueue *vq;
|
||
|
||
/* The disk structure for the kernel. */
|
||
struct gendisk *disk;
|
||
|
||
- /* Request tracking. */
|
||
- struct list_head reqs;
|
||
-
|
||
mempool_t *pool;
|
||
|
||
/* Process context for config space updates */
|
||
@@ -55,7 +50,6 @@ struct virtio_blk
|
||
|
||
struct virtblk_req
|
||
{
|
||
- struct list_head list;
|
||
struct request *req;
|
||
struct virtio_blk_outhdr out_hdr;
|
||
struct virtio_scsi_inhdr in_hdr;
|
||
@@ -69,7 +63,7 @@ static void blk_done(struct virtqueue *vq)
|
||
unsigned int len;
|
||
unsigned long flags;
|
||
|
||
- spin_lock_irqsave(&vblk->lock, flags);
|
||
+ spin_lock_irqsave(vblk->disk->queue->queue_lock, flags);
|
||
while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
|
||
int error;
|
||
|
||
@@ -99,12 +93,11 @@ static void blk_done(struct virtqueue *vq)
|
||
}
|
||
|
||
__blk_end_request_all(vbr->req, error);
|
||
- list_del(&vbr->list);
|
||
mempool_free(vbr, vblk->pool);
|
||
}
|
||
/* In case queue is stopped waiting for more buffers. */
|
||
blk_start_queue(vblk->disk->queue);
|
||
- spin_unlock_irqrestore(&vblk->lock, flags);
|
||
+ spin_unlock_irqrestore(vblk->disk->queue->queue_lock, flags);
|
||
}
|
||
|
||
static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
|
||
@@ -184,7 +177,6 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
|
||
return false;
|
||
}
|
||
|
||
- list_add_tail(&vbr->list, &vblk->reqs);
|
||
return true;
|
||
}
|
||
|
||
@@ -437,8 +429,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
|
||
goto out_free_index;
|
||
}
|
||
|
||
- INIT_LIST_HEAD(&vblk->reqs);
|
||
- spin_lock_init(&vblk->lock);
|
||
vblk->vdev = vdev;
|
||
vblk->sg_elems = sg_elems;
|
||
sg_init_table(vblk->sg, vblk->sg_elems);
|
||
@@ -463,7 +453,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
|
||
goto out_mempool;
|
||
}
|
||
|
||
- q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
|
||
+ q = vblk->disk->queue = blk_init_queue(do_virtblk_request, NULL);
|
||
if (!q) {
|
||
err = -ENOMEM;
|
||
goto out_put_disk;
|
||
@@ -583,27 +573,30 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
|
||
{
|
||
struct virtio_blk *vblk = vdev->priv;
|
||
int index = vblk->index;
|
||
+ int refc;
|
||
|
||
/* Prevent config work handler from accessing the device. */
|
||
mutex_lock(&vblk->config_lock);
|
||
vblk->config_enable = false;
|
||
mutex_unlock(&vblk->config_lock);
|
||
|
||
- /* Nothing should be pending. */
|
||
- BUG_ON(!list_empty(&vblk->reqs));
|
||
+ del_gendisk(vblk->disk);
|
||
+ blk_cleanup_queue(vblk->disk->queue);
|
||
|
||
/* Stop all the virtqueues. */
|
||
vdev->config->reset(vdev);
|
||
|
||
flush_work(&vblk->config_work);
|
||
|
||
- del_gendisk(vblk->disk);
|
||
- blk_cleanup_queue(vblk->disk->queue);
|
||
+ refc = atomic_read(&disk_to_dev(vblk->disk)->kobj.kref.refcount);
|
||
put_disk(vblk->disk);
|
||
mempool_destroy(vblk->pool);
|
||
vdev->config->del_vqs(vdev);
|
||
kfree(vblk);
|
||
- ida_simple_remove(&vd_index_ida, index);
|
||
+
|
||
+ /* Only free device id if we don't have any users */
|
||
+ if (refc == 1)
|
||
+ ida_simple_remove(&vd_index_ida, index);
|
||
}
|
||
|
||
#ifdef CONFIG_PM
|
||
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
|
||
index 4ed7bf9..ae1b0c4 100644
|
||
--- a/drivers/block/xen-blkback/blkback.c
|
||
+++ b/drivers/block/xen-blkback/blkback.c
|
||
@@ -274,6 +274,7 @@ int xen_blkif_schedule(void *arg)
|
||
{
|
||
struct xen_blkif *blkif = arg;
|
||
struct xen_vbd *vbd = &blkif->vbd;
|
||
+ int ret;
|
||
|
||
xen_blkif_get(blkif);
|
||
|
||
@@ -294,8 +295,12 @@ int xen_blkif_schedule(void *arg)
|
||
blkif->waiting_reqs = 0;
|
||
smp_mb(); /* clear flag *before* checking for work */
|
||
|
||
- if (do_block_io_op(blkif))
|
||
+ ret = do_block_io_op(blkif);
|
||
+ if (ret > 0)
|
||
blkif->waiting_reqs = 1;
|
||
+ if (ret == -EACCES)
|
||
+ wait_event_interruptible(blkif->shutdown_wq,
|
||
+ kthread_should_stop());
|
||
|
||
if (log_stats && time_after(jiffies, blkif->st_print))
|
||
print_stats(blkif);
|
||
@@ -401,6 +406,8 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
|
||
unsigned long secure;
|
||
struct phys_req preq;
|
||
|
||
+ xen_blkif_get(blkif);
|
||
+
|
||
preq.sector_number = req->u.discard.sector_number;
|
||
preq.nr_sects = req->u.discard.nr_sectors;
|
||
|
||
@@ -413,7 +420,6 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
|
||
}
|
||
blkif->st_ds_req++;
|
||
|
||
- xen_blkif_get(blkif);
|
||
secure = (blkif->vbd.discard_secure &&
|
||
(req->u.discard.flag & BLKIF_DISCARD_SECURE)) ?
|
||
BLKDEV_DISCARD_SECURE : 0;
|
||
@@ -530,6 +536,12 @@ __do_block_io_op(struct xen_blkif *blkif)
|
||
rp = blk_rings->common.sring->req_prod;
|
||
rmb(); /* Ensure we see queued requests up to 'rp'. */
|
||
|
||
+ if (RING_REQUEST_PROD_OVERFLOW(&blk_rings->common, rp)) {
|
||
+ rc = blk_rings->common.rsp_prod_pvt;
|
||
+ pr_warn(DRV_PFX "Frontend provided bogus ring requests (%d - %d = %d). Halting ring processing on dev=%04x\n",
|
||
+ rp, rc, rp - rc, blkif->vbd.pdevice);
|
||
+ return -EACCES;
|
||
+ }
|
||
while (rc != rp) {
|
||
|
||
if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
|
||
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
|
||
index fc2a486..933adc5 100644
|
||
--- a/drivers/block/xen-blkback/common.h
|
||
+++ b/drivers/block/xen-blkback/common.h
|
||
@@ -216,6 +216,8 @@ struct xen_blkif {
|
||
int st_wr_sect;
|
||
|
||
wait_queue_head_t waiting_to_free;
|
||
+ /* Thread shutdown wait queue. */
|
||
+ wait_queue_head_t shutdown_wq;
|
||
};
|
||
|
||
|
||
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
|
||
index a155254..5a0062f 100644
|
||
--- a/drivers/block/xen-blkback/xenbus.c
|
||
+++ b/drivers/block/xen-blkback/xenbus.c
|
||
@@ -118,6 +118,7 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
|
||
atomic_set(&blkif->drain, 0);
|
||
blkif->st_print = jiffies;
|
||
init_waitqueue_head(&blkif->waiting_to_free);
|
||
+ init_waitqueue_head(&blkif->shutdown_wq);
|
||
|
||
return blkif;
|
||
}
|
||
@@ -178,6 +179,7 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif)
|
||
{
|
||
if (blkif->xenblkd) {
|
||
kthread_stop(blkif->xenblkd);
|
||
+ wake_up(&blkif->shutdown_wq);
|
||
blkif->xenblkd = NULL;
|
||
}
|
||
|
||
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
|
||
index 4e86393..a81cdd7 100644
|
||
--- a/drivers/block/xen-blkfront.c
|
||
+++ b/drivers/block/xen-blkfront.c
|
||
@@ -1303,13 +1303,16 @@ static void blkback_changed(struct xenbus_device *dev,
|
||
case XenbusStateReconfiguring:
|
||
case XenbusStateReconfigured:
|
||
case XenbusStateUnknown:
|
||
- case XenbusStateClosed:
|
||
break;
|
||
|
||
case XenbusStateConnected:
|
||
blkfront_connect(info);
|
||
break;
|
||
|
||
+ case XenbusStateClosed:
|
||
+ if (dev->state == XenbusStateClosed)
|
||
+ break;
|
||
+ /* Missed the backend's Closing state -- fallthrough */
|
||
case XenbusStateClosing:
|
||
blkfront_closing(info);
|
||
break;
|
||
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
|
||
index 72c773d..2f70e80 100644
|
||
--- a/drivers/bluetooth/ath3k.c
|
||
+++ b/drivers/bluetooth/ath3k.c
|
||
@@ -83,6 +83,10 @@ static struct usb_device_id ath3k_table[] = {
|
||
/* Atheros AR5BBU12 with sflash firmware */
|
||
{ USB_DEVICE(0x0489, 0xE02C) },
|
||
|
||
+ /* Atheros AR5BBU22 with sflash firmware */
|
||
+ { USB_DEVICE(0x0489, 0xE03C) },
|
||
+ { USB_DEVICE(0x0489, 0xE036) },
|
||
+
|
||
{ } /* Terminating entry */
|
||
};
|
||
|
||
@@ -103,6 +107,10 @@ static struct usb_device_id ath3k_blist_tbl[] = {
|
||
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
|
||
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
|
||
|
||
+ /* Atheros AR5BBU22 with sflash firmware */
|
||
+ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
|
||
+ { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
|
||
+
|
||
{ } /* Terminating entry */
|
||
};
|
||
|
||
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
|
||
index a0a48ca..95060f4 100644
|
||
--- a/drivers/bluetooth/btusb.c
|
||
+++ b/drivers/bluetooth/btusb.c
|
||
@@ -63,6 +63,9 @@ static struct usb_device_id btusb_table[] = {
|
||
/* Apple-specific (Broadcom) devices */
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) },
|
||
|
||
+ /* MediaTek MT76x0E */
|
||
+ { USB_DEVICE(0x0e8d, 0x763f) },
|
||
+
|
||
/* Broadcom SoftSailing reporting vendor specific */
|
||
{ USB_DEVICE(0x05ac, 0x21e1) },
|
||
|
||
@@ -149,6 +152,10 @@ static struct usb_device_id blacklist_table[] = {
|
||
/* Atheros AR5BBU12 with sflash firmware */
|
||
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
|
||
|
||
+ /* Atheros AR5BBU12 with sflash firmware */
|
||
+ { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
|
||
+ { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
|
||
+
|
||
/* Broadcom BCM2035 */
|
||
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
|
||
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
|
||
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
|
||
index 25373df..5d069c7 100644
|
||
--- a/drivers/char/applicom.c
|
||
+++ b/drivers/char/applicom.c
|
||
@@ -345,7 +345,6 @@ static int __init applicom_init(void)
|
||
free_irq(apbs[i].irq, &dummy);
|
||
iounmap(apbs[i].RamIO);
|
||
}
|
||
- pci_disable_device(dev);
|
||
return ret;
|
||
}
|
||
|
||
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
|
||
index 40cc0cf2..e6939e1 100644
|
||
--- a/drivers/char/i8k.c
|
||
+++ b/drivers/char/i8k.c
|
||
@@ -664,6 +664,13 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {
|
||
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"),
|
||
},
|
||
},
|
||
+ {
|
||
+ .ident = "Dell XPS421",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
|
||
+ },
|
||
+ },
|
||
{ }
|
||
};
|
||
|
||
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
|
||
index a22a7a5..8156caf 100644
|
||
--- a/drivers/char/ipmi/ipmi_bt_sm.c
|
||
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
|
||
@@ -352,7 +352,7 @@ static inline void write_all_bytes(struct si_sm_data *bt)
|
||
|
||
static inline int read_all_bytes(struct si_sm_data *bt)
|
||
{
|
||
- unsigned char i;
|
||
+ unsigned int i;
|
||
|
||
/*
|
||
* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode.
|
||
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
|
||
index e53fc24..e1ddcf9 100644
|
||
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
|
||
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
|
||
@@ -251,8 +251,9 @@ static inline int check_obf(struct si_sm_data *kcs, unsigned char status,
|
||
if (!GET_STATUS_OBF(status)) {
|
||
kcs->obf_timeout -= time;
|
||
if (kcs->obf_timeout < 0) {
|
||
- start_error_recovery(kcs, "OBF not ready in time");
|
||
- return 1;
|
||
+ kcs->obf_timeout = OBF_RETRY_TIMEOUT;
|
||
+ start_error_recovery(kcs, "OBF not ready in time");
|
||
+ return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
|
||
index 1e638ff..bdecba5 100644
|
||
--- a/drivers/char/ipmi/ipmi_si_intf.c
|
||
+++ b/drivers/char/ipmi/ipmi_si_intf.c
|
||
@@ -244,6 +244,9 @@ struct smi_info {
|
||
/* The timer for this si. */
|
||
struct timer_list si_timer;
|
||
|
||
+ /* This flag is set, if the timer is running (timer_pending() isn't enough) */
|
||
+ bool timer_running;
|
||
+
|
||
/* The time (in jiffies) the last timeout occurred at. */
|
||
unsigned long last_timeout_jiffies;
|
||
|
||
@@ -427,6 +430,13 @@ static void start_clear_flags(struct smi_info *smi_info)
|
||
smi_info->si_state = SI_CLEARING_FLAGS;
|
||
}
|
||
|
||
+static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
|
||
+{
|
||
+ smi_info->last_timeout_jiffies = jiffies;
|
||
+ mod_timer(&smi_info->si_timer, new_val);
|
||
+ smi_info->timer_running = true;
|
||
+}
|
||
+
|
||
/*
|
||
* When we have a situtaion where we run out of memory and cannot
|
||
* allocate messages, we just leave them in the BMC and run the system
|
||
@@ -439,8 +449,7 @@ static inline void disable_si_irq(struct smi_info *smi_info)
|
||
start_disable_irq(smi_info);
|
||
smi_info->interrupt_disabled = 1;
|
||
if (!atomic_read(&smi_info->stop_operation))
|
||
- mod_timer(&smi_info->si_timer,
|
||
- jiffies + SI_TIMEOUT_JIFFIES);
|
||
+ smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
|
||
}
|
||
}
|
||
|
||
@@ -896,15 +905,7 @@ static void sender(void *send_info,
|
||
list_add_tail(&msg->link, &smi_info->xmit_msgs);
|
||
|
||
if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) {
|
||
- /*
|
||
- * last_timeout_jiffies is updated here to avoid
|
||
- * smi_timeout() handler passing very large time_diff
|
||
- * value to smi_event_handler() that causes
|
||
- * the send command to abort.
|
||
- */
|
||
- smi_info->last_timeout_jiffies = jiffies;
|
||
-
|
||
- mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
|
||
+ smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
|
||
|
||
if (smi_info->thread)
|
||
wake_up_process(smi_info->thread);
|
||
@@ -993,6 +994,17 @@ static int ipmi_thread(void *data)
|
||
|
||
spin_lock_irqsave(&(smi_info->si_lock), flags);
|
||
smi_result = smi_event_handler(smi_info, 0);
|
||
+
|
||
+ /*
|
||
+ * If the driver is doing something, there is a possible
|
||
+ * race with the timer. If the timer handler see idle,
|
||
+ * and the thread here sees something else, the timer
|
||
+ * handler won't restart the timer even though it is
|
||
+ * required. So start it here if necessary.
|
||
+ */
|
||
+ if (smi_result != SI_SM_IDLE && !smi_info->timer_running)
|
||
+ smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
|
||
+
|
||
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
|
||
busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
|
||
&busy_until);
|
||
@@ -1062,10 +1074,6 @@ static void smi_timeout(unsigned long data)
|
||
* SI_USEC_PER_JIFFY);
|
||
smi_result = smi_event_handler(smi_info, time_diff);
|
||
|
||
- spin_unlock_irqrestore(&(smi_info->si_lock), flags);
|
||
-
|
||
- smi_info->last_timeout_jiffies = jiffies_now;
|
||
-
|
||
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
|
||
/* Running with interrupts, only do long timeouts. */
|
||
timeout = jiffies + SI_TIMEOUT_JIFFIES;
|
||
@@ -1087,7 +1095,10 @@ static void smi_timeout(unsigned long data)
|
||
|
||
do_mod_timer:
|
||
if (smi_result != SI_SM_IDLE)
|
||
- mod_timer(&(smi_info->si_timer), timeout);
|
||
+ smi_mod_timer(smi_info, timeout);
|
||
+ else
|
||
+ smi_info->timer_running = false;
|
||
+ spin_unlock_irqrestore(&(smi_info->si_lock), flags);
|
||
}
|
||
|
||
static irqreturn_t si_irq_handler(int irq, void *data)
|
||
@@ -1135,8 +1146,7 @@ static int smi_start_processing(void *send_info,
|
||
|
||
/* Set up the timer that drives the interface. */
|
||
setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
|
||
- new_smi->last_timeout_jiffies = jiffies;
|
||
- mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
|
||
+ smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);
|
||
|
||
/*
|
||
* Check if the user forcefully enabled the daemon.
|
||
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
|
||
index 54a3a6d..5959669 100644
|
||
--- a/drivers/char/raw.c
|
||
+++ b/drivers/char/raw.c
|
||
@@ -190,7 +190,7 @@ static int bind_get(int number, dev_t *dev)
|
||
struct raw_device_data *rawdev;
|
||
struct block_device *bdev;
|
||
|
||
- if (number <= 0 || number >= MAX_RAW_MINORS)
|
||
+ if (number <= 0 || number >= max_raw_minors)
|
||
return -EINVAL;
|
||
|
||
rawdev = &raw_devices[number];
|
||
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
|
||
index 0cd2d50..a81f469 100644
|
||
--- a/drivers/char/virtio_console.c
|
||
+++ b/drivers/char/virtio_console.c
|
||
@@ -131,7 +131,8 @@ struct ports_device {
|
||
spinlock_t ports_lock;
|
||
|
||
/* To protect the vq operations for the control channel */
|
||
- spinlock_t cvq_lock;
|
||
+ spinlock_t c_ivq_lock;
|
||
+ spinlock_t c_ovq_lock;
|
||
|
||
/* The current config space is stored here */
|
||
struct virtio_console_config config;
|
||
@@ -460,11 +461,14 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
|
||
vq = portdev->c_ovq;
|
||
|
||
sg_init_one(sg, &cpkt, sizeof(cpkt));
|
||
+
|
||
+ spin_lock(&portdev->c_ovq_lock);
|
||
if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) >= 0) {
|
||
virtqueue_kick(vq);
|
||
while (!virtqueue_get_buf(vq, &len))
|
||
cpu_relax();
|
||
}
|
||
+ spin_unlock(&portdev->c_ovq_lock);
|
||
return 0;
|
||
}
|
||
|
||
@@ -1474,23 +1478,23 @@ static void control_work_handler(struct work_struct *work)
|
||
portdev = container_of(work, struct ports_device, control_work);
|
||
vq = portdev->c_ivq;
|
||
|
||
- spin_lock(&portdev->cvq_lock);
|
||
+ spin_lock(&portdev->c_ivq_lock);
|
||
while ((buf = virtqueue_get_buf(vq, &len))) {
|
||
- spin_unlock(&portdev->cvq_lock);
|
||
+ spin_unlock(&portdev->c_ivq_lock);
|
||
|
||
buf->len = len;
|
||
buf->offset = 0;
|
||
|
||
handle_control_message(portdev, buf);
|
||
|
||
- spin_lock(&portdev->cvq_lock);
|
||
+ spin_lock(&portdev->c_ivq_lock);
|
||
if (add_inbuf(portdev->c_ivq, buf) < 0) {
|
||
dev_warn(&portdev->vdev->dev,
|
||
"Error adding buffer to queue\n");
|
||
free_buf(buf);
|
||
}
|
||
}
|
||
- spin_unlock(&portdev->cvq_lock);
|
||
+ spin_unlock(&portdev->c_ivq_lock);
|
||
}
|
||
|
||
static void out_intr(struct virtqueue *vq)
|
||
@@ -1751,10 +1755,12 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
|
||
if (multiport) {
|
||
unsigned int nr_added_bufs;
|
||
|
||
- spin_lock_init(&portdev->cvq_lock);
|
||
+ spin_lock_init(&portdev->c_ivq_lock);
|
||
+ spin_lock_init(&portdev->c_ovq_lock);
|
||
INIT_WORK(&portdev->control_work, &control_work_handler);
|
||
|
||
- nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
|
||
+ nr_added_bufs = fill_queue(portdev->c_ivq,
|
||
+ &portdev->c_ivq_lock);
|
||
if (!nr_added_bufs) {
|
||
dev_err(&vdev->dev,
|
||
"Error allocating buffers for control queue\n");
|
||
@@ -1895,7 +1901,7 @@ static int virtcons_restore(struct virtio_device *vdev)
|
||
return ret;
|
||
|
||
if (use_multiport(portdev))
|
||
- fill_queue(portdev->c_ivq, &portdev->cvq_lock);
|
||
+ fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
|
||
|
||
list_for_each_entry(port, &portdev->ports, list) {
|
||
port->in_vq = portdev->in_vqs[port->id];
|
||
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
|
||
index 77e1e6c..094a710 100644
|
||
--- a/drivers/connector/cn_proc.c
|
||
+++ b/drivers/connector/cn_proc.c
|
||
@@ -31,11 +31,23 @@
|
||
#include <linux/ptrace.h>
|
||
#include <linux/atomic.h>
|
||
|
||
-#include <asm/unaligned.h>
|
||
-
|
||
#include <linux/cn_proc.h>
|
||
|
||
-#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event))
|
||
+/*
|
||
+ * Size of a cn_msg followed by a proc_event structure. Since the
|
||
+ * sizeof struct cn_msg is a multiple of 4 bytes, but not 8 bytes, we
|
||
+ * add one 4-byte word to the size here, and then start the actual
|
||
+ * cn_msg structure 4 bytes into the stack buffer. The result is that
|
||
+ * the immediately following proc_event structure is aligned to 8 bytes.
|
||
+ */
|
||
+#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event) + 4)
|
||
+
|
||
+/* See comment above; we test our assumption about sizeof struct cn_msg here. */
|
||
+static inline struct cn_msg *buffer_to_cn_msg(__u8 *buffer)
|
||
+{
|
||
+ BUILD_BUG_ON(sizeof(struct cn_msg) != 20);
|
||
+ return (struct cn_msg *)(buffer + 4);
|
||
+}
|
||
|
||
static atomic_t proc_event_num_listeners = ATOMIC_INIT(0);
|
||
static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC };
|
||
@@ -55,18 +67,19 @@ void proc_fork_connector(struct task_struct *task)
|
||
{
|
||
struct cn_msg *msg;
|
||
struct proc_event *ev;
|
||
- __u8 buffer[CN_PROC_MSG_SIZE];
|
||
+ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
|
||
struct timespec ts;
|
||
struct task_struct *parent;
|
||
|
||
if (atomic_read(&proc_event_num_listeners) < 1)
|
||
return;
|
||
|
||
- msg = (struct cn_msg*)buffer;
|
||
+ msg = buffer_to_cn_msg(buffer);
|
||
ev = (struct proc_event*)msg->data;
|
||
+ memset(&ev->event_data, 0, sizeof(ev->event_data));
|
||
get_seq(&msg->seq, &ev->cpu);
|
||
ktime_get_ts(&ts); /* get high res monotonic timestamp */
|
||
- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
|
||
+ ev->timestamp_ns = timespec_to_ns(&ts);
|
||
ev->what = PROC_EVENT_FORK;
|
||
rcu_read_lock();
|
||
parent = rcu_dereference(task->real_parent);
|
||
@@ -79,6 +92,7 @@ void proc_fork_connector(struct task_struct *task)
|
||
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
|
||
msg->ack = 0; /* not used */
|
||
msg->len = sizeof(*ev);
|
||
+ msg->flags = 0; /* not used */
|
||
/* If cn_netlink_send() failed, the data is not sent */
|
||
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
|
||
}
|
||
@@ -88,16 +102,17 @@ void proc_exec_connector(struct task_struct *task)
|
||
struct cn_msg *msg;
|
||
struct proc_event *ev;
|
||
struct timespec ts;
|
||
- __u8 buffer[CN_PROC_MSG_SIZE];
|
||
+ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
|
||
|
||
if (atomic_read(&proc_event_num_listeners) < 1)
|
||
return;
|
||
|
||
- msg = (struct cn_msg*)buffer;
|
||
+ msg = buffer_to_cn_msg(buffer);
|
||
ev = (struct proc_event*)msg->data;
|
||
+ memset(&ev->event_data, 0, sizeof(ev->event_data));
|
||
get_seq(&msg->seq, &ev->cpu);
|
||
ktime_get_ts(&ts); /* get high res monotonic timestamp */
|
||
- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
|
||
+ ev->timestamp_ns = timespec_to_ns(&ts);
|
||
ev->what = PROC_EVENT_EXEC;
|
||
ev->event_data.exec.process_pid = task->pid;
|
||
ev->event_data.exec.process_tgid = task->tgid;
|
||
@@ -105,6 +120,7 @@ void proc_exec_connector(struct task_struct *task)
|
||
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
|
||
msg->ack = 0; /* not used */
|
||
msg->len = sizeof(*ev);
|
||
+ msg->flags = 0; /* not used */
|
||
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
|
||
}
|
||
|
||
@@ -112,15 +128,16 @@ void proc_id_connector(struct task_struct *task, int which_id)
|
||
{
|
||
struct cn_msg *msg;
|
||
struct proc_event *ev;
|
||
- __u8 buffer[CN_PROC_MSG_SIZE];
|
||
+ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
|
||
struct timespec ts;
|
||
const struct cred *cred;
|
||
|
||
if (atomic_read(&proc_event_num_listeners) < 1)
|
||
return;
|
||
|
||
- msg = (struct cn_msg*)buffer;
|
||
+ msg = buffer_to_cn_msg(buffer);
|
||
ev = (struct proc_event*)msg->data;
|
||
+ memset(&ev->event_data, 0, sizeof(ev->event_data));
|
||
ev->what = which_id;
|
||
ev->event_data.id.process_pid = task->pid;
|
||
ev->event_data.id.process_tgid = task->tgid;
|
||
@@ -139,11 +156,12 @@ void proc_id_connector(struct task_struct *task, int which_id)
|
||
rcu_read_unlock();
|
||
get_seq(&msg->seq, &ev->cpu);
|
||
ktime_get_ts(&ts); /* get high res monotonic timestamp */
|
||
- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
|
||
+ ev->timestamp_ns = timespec_to_ns(&ts);
|
||
|
||
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
|
||
msg->ack = 0; /* not used */
|
||
msg->len = sizeof(*ev);
|
||
+ msg->flags = 0; /* not used */
|
||
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
|
||
}
|
||
|
||
@@ -152,16 +170,17 @@ void proc_sid_connector(struct task_struct *task)
|
||
struct cn_msg *msg;
|
||
struct proc_event *ev;
|
||
struct timespec ts;
|
||
- __u8 buffer[CN_PROC_MSG_SIZE];
|
||
+ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
|
||
|
||
if (atomic_read(&proc_event_num_listeners) < 1)
|
||
return;
|
||
|
||
- msg = (struct cn_msg *)buffer;
|
||
+ msg = buffer_to_cn_msg(buffer);
|
||
ev = (struct proc_event *)msg->data;
|
||
+ memset(&ev->event_data, 0, sizeof(ev->event_data));
|
||
get_seq(&msg->seq, &ev->cpu);
|
||
ktime_get_ts(&ts); /* get high res monotonic timestamp */
|
||
- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
|
||
+ ev->timestamp_ns = timespec_to_ns(&ts);
|
||
ev->what = PROC_EVENT_SID;
|
||
ev->event_data.sid.process_pid = task->pid;
|
||
ev->event_data.sid.process_tgid = task->tgid;
|
||
@@ -169,6 +188,7 @@ void proc_sid_connector(struct task_struct *task)
|
||
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
|
||
msg->ack = 0; /* not used */
|
||
msg->len = sizeof(*ev);
|
||
+ msg->flags = 0; /* not used */
|
||
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
|
||
}
|
||
|
||
@@ -177,16 +197,17 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
|
||
struct cn_msg *msg;
|
||
struct proc_event *ev;
|
||
struct timespec ts;
|
||
- __u8 buffer[CN_PROC_MSG_SIZE];
|
||
+ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
|
||
|
||
if (atomic_read(&proc_event_num_listeners) < 1)
|
||
return;
|
||
|
||
- msg = (struct cn_msg *)buffer;
|
||
+ msg = buffer_to_cn_msg(buffer);
|
||
ev = (struct proc_event *)msg->data;
|
||
+ memset(&ev->event_data, 0, sizeof(ev->event_data));
|
||
get_seq(&msg->seq, &ev->cpu);
|
||
ktime_get_ts(&ts); /* get high res monotonic timestamp */
|
||
- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
|
||
+ ev->timestamp_ns = timespec_to_ns(&ts);
|
||
ev->what = PROC_EVENT_PTRACE;
|
||
ev->event_data.ptrace.process_pid = task->pid;
|
||
ev->event_data.ptrace.process_tgid = task->tgid;
|
||
@@ -202,6 +223,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
|
||
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
|
||
msg->ack = 0; /* not used */
|
||
msg->len = sizeof(*ev);
|
||
+ msg->flags = 0; /* not used */
|
||
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
|
||
}
|
||
|
||
@@ -210,16 +232,17 @@ void proc_comm_connector(struct task_struct *task)
|
||
struct cn_msg *msg;
|
||
struct proc_event *ev;
|
||
struct timespec ts;
|
||
- __u8 buffer[CN_PROC_MSG_SIZE];
|
||
+ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
|
||
|
||
if (atomic_read(&proc_event_num_listeners) < 1)
|
||
return;
|
||
|
||
- msg = (struct cn_msg *)buffer;
|
||
+ msg = buffer_to_cn_msg(buffer);
|
||
ev = (struct proc_event *)msg->data;
|
||
+ memset(&ev->event_data, 0, sizeof(ev->event_data));
|
||
get_seq(&msg->seq, &ev->cpu);
|
||
ktime_get_ts(&ts); /* get high res monotonic timestamp */
|
||
- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
|
||
+ ev->timestamp_ns = timespec_to_ns(&ts);
|
||
ev->what = PROC_EVENT_COMM;
|
||
ev->event_data.comm.process_pid = task->pid;
|
||
ev->event_data.comm.process_tgid = task->tgid;
|
||
@@ -228,6 +251,7 @@ void proc_comm_connector(struct task_struct *task)
|
||
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
|
||
msg->ack = 0; /* not used */
|
||
msg->len = sizeof(*ev);
|
||
+ msg->flags = 0; /* not used */
|
||
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
|
||
}
|
||
|
||
@@ -235,17 +259,18 @@ void proc_exit_connector(struct task_struct *task)
|
||
{
|
||
struct cn_msg *msg;
|
||
struct proc_event *ev;
|
||
- __u8 buffer[CN_PROC_MSG_SIZE];
|
||
+ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
|
||
struct timespec ts;
|
||
|
||
if (atomic_read(&proc_event_num_listeners) < 1)
|
||
return;
|
||
|
||
- msg = (struct cn_msg*)buffer;
|
||
+ msg = buffer_to_cn_msg(buffer);
|
||
ev = (struct proc_event*)msg->data;
|
||
+ memset(&ev->event_data, 0, sizeof(ev->event_data));
|
||
get_seq(&msg->seq, &ev->cpu);
|
||
ktime_get_ts(&ts); /* get high res monotonic timestamp */
|
||
- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
|
||
+ ev->timestamp_ns = timespec_to_ns(&ts);
|
||
ev->what = PROC_EVENT_EXIT;
|
||
ev->event_data.exit.process_pid = task->pid;
|
||
ev->event_data.exit.process_tgid = task->tgid;
|
||
@@ -255,6 +280,7 @@ void proc_exit_connector(struct task_struct *task)
|
||
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
|
||
msg->ack = 0; /* not used */
|
||
msg->len = sizeof(*ev);
|
||
+ msg->flags = 0; /* not used */
|
||
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
|
||
}
|
||
|
||
@@ -270,23 +296,25 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
|
||
{
|
||
struct cn_msg *msg;
|
||
struct proc_event *ev;
|
||
- __u8 buffer[CN_PROC_MSG_SIZE];
|
||
+ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
|
||
struct timespec ts;
|
||
|
||
if (atomic_read(&proc_event_num_listeners) < 1)
|
||
return;
|
||
|
||
- msg = (struct cn_msg*)buffer;
|
||
+ msg = buffer_to_cn_msg(buffer);
|
||
ev = (struct proc_event*)msg->data;
|
||
+ memset(&ev->event_data, 0, sizeof(ev->event_data));
|
||
msg->seq = rcvd_seq;
|
||
ktime_get_ts(&ts); /* get high res monotonic timestamp */
|
||
- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
|
||
+ ev->timestamp_ns = timespec_to_ns(&ts);
|
||
ev->cpu = -1;
|
||
ev->what = PROC_EVENT_NONE;
|
||
ev->event_data.ack.err = err;
|
||
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
|
||
msg->ack = rcvd_ack + 1;
|
||
msg->len = sizeof(*ev);
|
||
+ msg->flags = 0; /* not used */
|
||
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
|
||
}
|
||
|
||
@@ -303,6 +331,12 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
|
||
if (msg->len != sizeof(*mc_op))
|
||
return;
|
||
|
||
+ /* Can only change if privileged. */
|
||
+ if (!capable(CAP_NET_ADMIN)) {
|
||
+ err = EPERM;
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
mc_op = (enum proc_cn_mcast_op*)msg->data;
|
||
switch (*mc_op) {
|
||
case PROC_CN_MCAST_LISTEN:
|
||
@@ -315,6 +349,8 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
|
||
err = EINVAL;
|
||
break;
|
||
}
|
||
+
|
||
+out:
|
||
cn_proc_ack(err, msg->seq, msg->ack);
|
||
}
|
||
|
||
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
|
||
index dde6a0f..ea6efe8 100644
|
||
--- a/drivers/connector/connector.c
|
||
+++ b/drivers/connector/connector.c
|
||
@@ -157,17 +157,18 @@ static int cn_call_callback(struct sk_buff *skb)
|
||
static void cn_rx_skb(struct sk_buff *__skb)
|
||
{
|
||
struct nlmsghdr *nlh;
|
||
- int err;
|
||
struct sk_buff *skb;
|
||
+ int len, err;
|
||
|
||
skb = skb_get(__skb);
|
||
|
||
if (skb->len >= NLMSG_SPACE(0)) {
|
||
nlh = nlmsg_hdr(skb);
|
||
+ len = nlmsg_len(nlh);
|
||
|
||
- if (nlh->nlmsg_len < sizeof(struct cn_msg) ||
|
||
+ if (len < (int)sizeof(struct cn_msg) ||
|
||
skb->len < nlh->nlmsg_len ||
|
||
- nlh->nlmsg_len > CONNECTOR_MAX_MSG_SIZE) {
|
||
+ len > CONNECTOR_MAX_MSG_SIZE) {
|
||
kfree_skb(skb);
|
||
return;
|
||
}
|
||
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
|
||
index ea0222a..b07ca0d 100644
|
||
--- a/drivers/cpufreq/powernow-k6.c
|
||
+++ b/drivers/cpufreq/powernow-k6.c
|
||
@@ -26,41 +26,108 @@
|
||
static unsigned int busfreq; /* FSB, in 10 kHz */
|
||
static unsigned int max_multiplier;
|
||
|
||
+static unsigned int param_busfreq = 0;
|
||
+static unsigned int param_max_multiplier = 0;
|
||
+
|
||
+module_param_named(max_multiplier, param_max_multiplier, uint, S_IRUGO);
|
||
+MODULE_PARM_DESC(max_multiplier, "Maximum multiplier (allowed values: 20 30 35 40 45 50 55 60)");
|
||
+
|
||
+module_param_named(bus_frequency, param_busfreq, uint, S_IRUGO);
|
||
+MODULE_PARM_DESC(bus_frequency, "Bus frequency in kHz");
|
||
|
||
/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
|
||
static struct cpufreq_frequency_table clock_ratio[] = {
|
||
- {45, /* 000 -> 4.5x */ 0},
|
||
+ {60, /* 110 -> 6.0x */ 0},
|
||
+ {55, /* 011 -> 5.5x */ 0},
|
||
{50, /* 001 -> 5.0x */ 0},
|
||
+ {45, /* 000 -> 4.5x */ 0},
|
||
{40, /* 010 -> 4.0x */ 0},
|
||
- {55, /* 011 -> 5.5x */ 0},
|
||
- {20, /* 100 -> 2.0x */ 0},
|
||
- {30, /* 101 -> 3.0x */ 0},
|
||
- {60, /* 110 -> 6.0x */ 0},
|
||
{35, /* 111 -> 3.5x */ 0},
|
||
+ {30, /* 101 -> 3.0x */ 0},
|
||
+ {20, /* 100 -> 2.0x */ 0},
|
||
{0, CPUFREQ_TABLE_END}
|
||
};
|
||
|
||
+static const u8 index_to_register[8] = { 6, 3, 1, 0, 2, 7, 5, 4 };
|
||
+static const u8 register_to_index[8] = { 3, 2, 4, 1, 7, 6, 0, 5 };
|
||
+
|
||
+static const struct {
|
||
+ unsigned freq;
|
||
+ unsigned mult;
|
||
+} usual_frequency_table[] = {
|
||
+ { 400000, 40 }, // 100 * 4
|
||
+ { 450000, 45 }, // 100 * 4.5
|
||
+ { 475000, 50 }, // 95 * 5
|
||
+ { 500000, 50 }, // 100 * 5
|
||
+ { 506250, 45 }, // 112.5 * 4.5
|
||
+ { 533500, 55 }, // 97 * 5.5
|
||
+ { 550000, 55 }, // 100 * 5.5
|
||
+ { 562500, 50 }, // 112.5 * 5
|
||
+ { 570000, 60 }, // 95 * 6
|
||
+ { 600000, 60 }, // 100 * 6
|
||
+ { 618750, 55 }, // 112.5 * 5.5
|
||
+ { 660000, 55 }, // 120 * 5.5
|
||
+ { 675000, 60 }, // 112.5 * 6
|
||
+ { 720000, 60 }, // 120 * 6
|
||
+};
|
||
+
|
||
+#define FREQ_RANGE 3000
|
||
|
||
/**
|
||
* powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
|
||
*
|
||
- * Returns the current setting of the frequency multiplier. Core clock
|
||
+ * Returns the current setting of the frequency multiplier. Core clock
|
||
* speed is frequency of the Front-Side Bus multiplied with this value.
|
||
*/
|
||
static int powernow_k6_get_cpu_multiplier(void)
|
||
{
|
||
- u64 invalue = 0;
|
||
+ unsigned long invalue = 0;
|
||
u32 msrval;
|
||
|
||
+ local_irq_disable();
|
||
+
|
||
msrval = POWERNOW_IOPORT + 0x1;
|
||
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
|
||
invalue = inl(POWERNOW_IOPORT + 0x8);
|
||
msrval = POWERNOW_IOPORT + 0x0;
|
||
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
|
||
|
||
- return clock_ratio[(invalue >> 5)&7].index;
|
||
+ local_irq_enable();
|
||
+
|
||
+ return clock_ratio[register_to_index[(invalue >> 5)&7]].index;
|
||
}
|
||
|
||
+static void powernow_k6_set_cpu_multiplier(unsigned int best_i)
|
||
+{
|
||
+ unsigned long outvalue, invalue;
|
||
+ unsigned long msrval;
|
||
+ unsigned long cr0;
|
||
+
|
||
+ /* we now need to transform best_i to the BVC format, see AMD#23446 */
|
||
+
|
||
+ /*
|
||
+ * The processor doesn't respond to inquiry cycles while changing the
|
||
+ * frequency, so we must disable cache.
|
||
+ */
|
||
+ local_irq_disable();
|
||
+ cr0 = read_cr0();
|
||
+ write_cr0(cr0 | X86_CR0_CD);
|
||
+ wbinvd();
|
||
+
|
||
+ outvalue = (1<<12) | (1<<10) | (1<<9) | (index_to_register[best_i]<<5);
|
||
+
|
||
+ msrval = POWERNOW_IOPORT + 0x1;
|
||
+ wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
|
||
+ invalue = inl(POWERNOW_IOPORT + 0x8);
|
||
+ invalue = invalue & 0x1f;
|
||
+ outvalue = outvalue | invalue;
|
||
+ outl(outvalue, (POWERNOW_IOPORT + 0x8));
|
||
+ msrval = POWERNOW_IOPORT + 0x0;
|
||
+ wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
|
||
+
|
||
+ write_cr0(cr0);
|
||
+ local_irq_enable();
|
||
+}
|
||
|
||
/**
|
||
* powernow_k6_set_state - set the PowerNow! multiplier
|
||
@@ -71,8 +138,6 @@ static int powernow_k6_get_cpu_multiplier(void)
|
||
static void powernow_k6_set_state(struct cpufreq_policy *policy,
|
||
unsigned int best_i)
|
||
{
|
||
- unsigned long outvalue = 0, invalue = 0;
|
||
- unsigned long msrval;
|
||
struct cpufreq_freqs freqs;
|
||
|
||
if (clock_ratio[best_i].index > max_multiplier) {
|
||
@@ -85,18 +150,7 @@ static void powernow_k6_set_state(struct cpufreq_policy *policy,
|
||
|
||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||
|
||
- /* we now need to transform best_i to the BVC format, see AMD#23446 */
|
||
-
|
||
- outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5);
|
||
-
|
||
- msrval = POWERNOW_IOPORT + 0x1;
|
||
- wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
|
||
- invalue = inl(POWERNOW_IOPORT + 0x8);
|
||
- invalue = invalue & 0xf;
|
||
- outvalue = outvalue | invalue;
|
||
- outl(outvalue , (POWERNOW_IOPORT + 0x8));
|
||
- msrval = POWERNOW_IOPORT + 0x0;
|
||
- wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
|
||
+ powernow_k6_set_cpu_multiplier(best_i);
|
||
|
||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||
|
||
@@ -141,18 +195,57 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
|
||
return 0;
|
||
}
|
||
|
||
-
|
||
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
||
{
|
||
unsigned int i, f;
|
||
int result;
|
||
+ unsigned khz;
|
||
|
||
if (policy->cpu != 0)
|
||
return -ENODEV;
|
||
|
||
- /* get frequencies */
|
||
- max_multiplier = powernow_k6_get_cpu_multiplier();
|
||
- busfreq = cpu_khz / max_multiplier;
|
||
+ max_multiplier = 0;
|
||
+ khz = cpu_khz;
|
||
+ for (i = 0; i < ARRAY_SIZE(usual_frequency_table); i++) {
|
||
+ if (khz >= usual_frequency_table[i].freq - FREQ_RANGE &&
|
||
+ khz <= usual_frequency_table[i].freq + FREQ_RANGE) {
|
||
+ khz = usual_frequency_table[i].freq;
|
||
+ max_multiplier = usual_frequency_table[i].mult;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if (param_max_multiplier) {
|
||
+ for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||
+ if (clock_ratio[i].index == param_max_multiplier) {
|
||
+ max_multiplier = param_max_multiplier;
|
||
+ goto have_max_multiplier;
|
||
+ }
|
||
+ }
|
||
+ printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
|
||
+ return -EINVAL;
|
||
+ }
|
||
+
|
||
+ if (!max_multiplier) {
|
||
+ printk(KERN_WARNING "powernow-k6: unknown frequency %u, cannot determine current multiplier\n", khz);
|
||
+ printk(KERN_WARNING "powernow-k6: use module parameters max_multiplier and bus_frequency\n");
|
||
+ return -EOPNOTSUPP;
|
||
+ }
|
||
+
|
||
+have_max_multiplier:
|
||
+ param_max_multiplier = max_multiplier;
|
||
+
|
||
+ if (param_busfreq) {
|
||
+ if (param_busfreq >= 50000 && param_busfreq <= 150000) {
|
||
+ busfreq = param_busfreq / 10;
|
||
+ goto have_busfreq;
|
||
+ }
|
||
+ printk(KERN_ERR "powernow-k6: invalid bus_frequency parameter, allowed range 50000 - 150000 kHz\n");
|
||
+ return -EINVAL;
|
||
+ }
|
||
+
|
||
+ busfreq = khz / max_multiplier;
|
||
+have_busfreq:
|
||
+ param_busfreq = busfreq * 10;
|
||
|
||
/* table init */
|
||
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||
@@ -164,7 +257,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
||
}
|
||
|
||
/* cpuinfo and default policy values */
|
||
- policy->cpuinfo.transition_latency = 200000;
|
||
+ policy->cpuinfo.transition_latency = 500000;
|
||
policy->cur = busfreq * max_multiplier;
|
||
|
||
result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio);
|
||
diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c
|
||
index 7e2d54b..9b8d231 100644
|
||
--- a/drivers/crypto/caam/error.c
|
||
+++ b/drivers/crypto/caam/error.c
|
||
@@ -16,9 +16,13 @@
|
||
char *tmp; \
|
||
\
|
||
tmp = kmalloc(sizeof(format) + max_alloc, GFP_ATOMIC); \
|
||
- sprintf(tmp, format, param); \
|
||
- strcat(str, tmp); \
|
||
- kfree(tmp); \
|
||
+ if (likely(tmp)) { \
|
||
+ sprintf(tmp, format, param); \
|
||
+ strcat(str, tmp); \
|
||
+ kfree(tmp); \
|
||
+ } else { \
|
||
+ strcat(str, "kmalloc failure in SPRINTFCAT"); \
|
||
+ } \
|
||
}
|
||
|
||
static void report_jump_idx(u32 status, char *outstr)
|
||
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
|
||
index ef378b5..7de7a65 100644
|
||
--- a/drivers/dma/Kconfig
|
||
+++ b/drivers/dma/Kconfig
|
||
@@ -269,6 +269,7 @@ config NET_DMA
|
||
bool "Network: TCP receive copy offload"
|
||
depends on DMA_ENGINE && NET
|
||
default (INTEL_IOATDMA || FSL_DMA)
|
||
+ depends on BROKEN
|
||
help
|
||
This enables the use of DMA engines in the network stack to
|
||
offload receive copy-to-user operations, freeing CPU cycles.
|
||
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
|
||
index 2ed1ac3..28a9614 100644
|
||
--- a/drivers/dma/ste_dma40.c
|
||
+++ b/drivers/dma/ste_dma40.c
|
||
@@ -1409,6 +1409,7 @@ static void dma_tasklet(unsigned long data)
|
||
struct d40_chan *d40c = (struct d40_chan *) data;
|
||
struct d40_desc *d40d;
|
||
unsigned long flags;
|
||
+ bool callback_active;
|
||
dma_async_tx_callback callback;
|
||
void *callback_param;
|
||
|
||
@@ -1432,6 +1433,7 @@ static void dma_tasklet(unsigned long data)
|
||
}
|
||
|
||
/* Callback to client */
|
||
+ callback_active = !!(d40d->txd.flags & DMA_PREP_INTERRUPT);
|
||
callback = d40d->txd.callback;
|
||
callback_param = d40d->txd.callback_param;
|
||
|
||
@@ -1456,7 +1458,7 @@ static void dma_tasklet(unsigned long data)
|
||
|
||
spin_unlock_irqrestore(&d40c->lock, flags);
|
||
|
||
- if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT))
|
||
+ if (callback_active && callback)
|
||
callback(callback_param);
|
||
|
||
return;
|
||
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
|
||
index 4122326..b73beba 100644
|
||
--- a/drivers/edac/e752x_edac.c
|
||
+++ b/drivers/edac/e752x_edac.c
|
||
@@ -1145,9 +1145,11 @@ static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
|
||
pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
|
||
pvt->dev_info->err_dev, pvt->bridge_ck);
|
||
|
||
- if (pvt->bridge_ck == NULL)
|
||
+ if (pvt->bridge_ck == NULL) {
|
||
pvt->bridge_ck = pci_scan_single_device(pdev->bus,
|
||
PCI_DEVFN(0, 1));
|
||
+ pci_dev_get(pvt->bridge_ck);
|
||
+ }
|
||
|
||
if (pvt->bridge_ck == NULL) {
|
||
e752x_printk(KERN_ERR, "error reporting device not found:"
|
||
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
|
||
index f4059e9..8ba22eb 100644
|
||
--- a/drivers/edac/i7300_edac.c
|
||
+++ b/drivers/edac/i7300_edac.c
|
||
@@ -962,33 +962,35 @@ static int __devinit i7300_get_devices(struct mem_ctl_info *mci)
|
||
|
||
/* Attempt to 'get' the MCH register we want */
|
||
pdev = NULL;
|
||
- while (!pvt->pci_dev_16_1_fsb_addr_map ||
|
||
- !pvt->pci_dev_16_2_fsb_err_regs) {
|
||
- pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
|
||
- PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev);
|
||
- if (!pdev) {
|
||
- /* End of list, leave */
|
||
- i7300_printk(KERN_ERR,
|
||
- "'system address,Process Bus' "
|
||
- "device not found:"
|
||
- "vendor 0x%x device 0x%x ERR funcs "
|
||
- "(broken BIOS?)\n",
|
||
- PCI_VENDOR_ID_INTEL,
|
||
- PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
|
||
- goto error;
|
||
- }
|
||
-
|
||
+ while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
|
||
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
|
||
+ pdev))) {
|
||
/* Store device 16 funcs 1 and 2 */
|
||
switch (PCI_FUNC(pdev->devfn)) {
|
||
case 1:
|
||
- pvt->pci_dev_16_1_fsb_addr_map = pdev;
|
||
+ if (!pvt->pci_dev_16_1_fsb_addr_map)
|
||
+ pvt->pci_dev_16_1_fsb_addr_map =
|
||
+ pci_dev_get(pdev);
|
||
break;
|
||
case 2:
|
||
- pvt->pci_dev_16_2_fsb_err_regs = pdev;
|
||
+ if (!pvt->pci_dev_16_2_fsb_err_regs)
|
||
+ pvt->pci_dev_16_2_fsb_err_regs =
|
||
+ pci_dev_get(pdev);
|
||
break;
|
||
}
|
||
}
|
||
|
||
+ if (!pvt->pci_dev_16_1_fsb_addr_map ||
|
||
+ !pvt->pci_dev_16_2_fsb_err_regs) {
|
||
+ /* At least one device was not found */
|
||
+ i7300_printk(KERN_ERR,
|
||
+ "'system address,Process Bus' device not found:"
|
||
+ "vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n",
|
||
+ PCI_VENDOR_ID_INTEL,
|
||
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
|
||
+ goto error;
|
||
+ }
|
||
+
|
||
debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n",
|
||
pci_name(pvt->pci_dev_16_0_fsb_ctlr),
|
||
pvt->pci_dev_16_0_fsb_ctlr->vendor,
|
||
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
|
||
index 0fe2277..ddb725d 100644
|
||
--- a/drivers/edac/i7core_edac.c
|
||
+++ b/drivers/edac/i7core_edac.c
|
||
@@ -1365,14 +1365,19 @@ static int i7core_get_onedevice(struct pci_dev **prev,
|
||
* is at addr 8086:2c40, instead of 8086:2c41. So, we need
|
||
* to probe for the alternate address in case of failure
|
||
*/
|
||
- if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
|
||
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) {
|
||
+ pci_dev_get(*prev); /* pci_get_device will put it */
|
||
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
|
||
PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
|
||
+ }
|
||
|
||
- if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
|
||
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE &&
|
||
+ !pdev) {
|
||
+ pci_dev_get(*prev); /* pci_get_device will put it */
|
||
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
|
||
PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
|
||
*prev);
|
||
+ }
|
||
|
||
if (!pdev) {
|
||
if (*prev) {
|
||
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
|
||
index 0cd8368..182d82a 100644
|
||
--- a/drivers/edac/i82975x_edac.c
|
||
+++ b/drivers/edac/i82975x_edac.c
|
||
@@ -363,10 +363,6 @@ static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
|
||
static void i82975x_init_csrows(struct mem_ctl_info *mci,
|
||
struct pci_dev *pdev, void __iomem *mch_window)
|
||
{
|
||
- static const char *labels[4] = {
|
||
- "DIMM A1", "DIMM A2",
|
||
- "DIMM B1", "DIMM B2"
|
||
- };
|
||
struct csrow_info *csrow;
|
||
unsigned long last_cumul_size;
|
||
u8 value;
|
||
@@ -407,9 +403,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
|
||
* [0-3] for dual-channel; i.e. csrow->nr_channels = 2
|
||
*/
|
||
for (chan = 0; chan < csrow->nr_channels; chan++)
|
||
- strncpy(csrow->channels[chan].label,
|
||
- labels[(index >> 1) + (chan * 2)],
|
||
- EDAC_MC_LABEL_LEN);
|
||
+
|
||
+ snprintf(csrow->channels[chan].label, EDAC_MC_LABEL_LEN, "DIMM %c%d",
|
||
+ (chan == 0) ? 'A' : 'B',
|
||
+ index);
|
||
|
||
if (cumul_size == last_cumul_size)
|
||
continue; /* not populated */
|
||
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
|
||
index 0f9552d..0924c30 100644
|
||
--- a/drivers/edac/sb_edac.c
|
||
+++ b/drivers/edac/sb_edac.c
|
||
@@ -555,7 +555,8 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
|
||
{
|
||
struct sbridge_pvt *pvt = mci->pvt_info;
|
||
struct csrow_info *csr;
|
||
- int i, j, banks, ranks, rows, cols, size, npages;
|
||
+ unsigned i, j, banks, ranks, rows, cols, npages;
|
||
+ u64 size;
|
||
int csrow = 0;
|
||
unsigned long last_page = 0;
|
||
u32 reg;
|
||
@@ -627,10 +628,10 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
|
||
cols = numcol(mtr);
|
||
|
||
/* DDR3 has 8 I/O banks */
|
||
- size = (rows * cols * banks * ranks) >> (20 - 3);
|
||
+ size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
|
||
npages = MiB_TO_PAGES(size);
|
||
|
||
- debugf0("mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
|
||
+ debugf0("mc#%d: channel %d, dimm %d, %Ld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
|
||
pvt->sbridge_dev->mc, i, j,
|
||
size, npages,
|
||
banks, ranks, rows, cols);
|
||
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
|
||
index 04ebeaf..1026609 100644
|
||
--- a/drivers/firewire/core-device.c
|
||
+++ b/drivers/firewire/core-device.c
|
||
@@ -878,7 +878,7 @@ static int lookup_existing_device(struct device *dev, void *data)
|
||
old->config_rom_retries = 0;
|
||
fw_notice(card, "rediscovered device %s\n", dev_name(dev));
|
||
|
||
- PREPARE_DELAYED_WORK(&old->work, fw_device_update);
|
||
+ old->workfn = fw_device_update;
|
||
fw_schedule_device_work(old, 0);
|
||
|
||
if (current_node == card->root_node)
|
||
@@ -1040,7 +1040,7 @@ static void fw_device_init(struct work_struct *work)
|
||
if (atomic_cmpxchg(&device->state,
|
||
FW_DEVICE_INITIALIZING,
|
||
FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
|
||
- PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
|
||
+ device->workfn = fw_device_shutdown;
|
||
fw_schedule_device_work(device, SHUTDOWN_DELAY);
|
||
} else {
|
||
fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
|
||
@@ -1172,13 +1172,20 @@ static void fw_device_refresh(struct work_struct *work)
|
||
dev_name(&device->device));
|
||
gone:
|
||
atomic_set(&device->state, FW_DEVICE_GONE);
|
||
- PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
|
||
+ device->workfn = fw_device_shutdown;
|
||
fw_schedule_device_work(device, SHUTDOWN_DELAY);
|
||
out:
|
||
if (node_id == card->root_node->node_id)
|
||
fw_schedule_bm_work(card, 0);
|
||
}
|
||
|
||
+static void fw_device_workfn(struct work_struct *work)
|
||
+{
|
||
+ struct fw_device *device = container_of(to_delayed_work(work),
|
||
+ struct fw_device, work);
|
||
+ device->workfn(work);
|
||
+}
|
||
+
|
||
void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
|
||
{
|
||
struct fw_device *device;
|
||
@@ -1228,7 +1235,8 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
|
||
* power-up after getting plugged in. We schedule the
|
||
* first config rom scan half a second after bus reset.
|
||
*/
|
||
- INIT_DELAYED_WORK(&device->work, fw_device_init);
|
||
+ device->workfn = fw_device_init;
|
||
+ INIT_DELAYED_WORK(&device->work, fw_device_workfn);
|
||
fw_schedule_device_work(device, INITIAL_DELAY);
|
||
break;
|
||
|
||
@@ -1244,7 +1252,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
|
||
if (atomic_cmpxchg(&device->state,
|
||
FW_DEVICE_RUNNING,
|
||
FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
|
||
- PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
|
||
+ device->workfn = fw_device_refresh;
|
||
fw_schedule_device_work(device,
|
||
device->is_local ? 0 : INITIAL_DELAY);
|
||
}
|
||
@@ -1259,7 +1267,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
|
||
smp_wmb(); /* update node_id before generation */
|
||
device->generation = card->generation;
|
||
if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
|
||
- PREPARE_DELAYED_WORK(&device->work, fw_device_update);
|
||
+ device->workfn = fw_device_update;
|
||
fw_schedule_device_work(device, 0);
|
||
}
|
||
break;
|
||
@@ -1284,7 +1292,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
|
||
device = node->data;
|
||
if (atomic_xchg(&device->state,
|
||
FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
|
||
- PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
|
||
+ device->workfn = fw_device_shutdown;
|
||
fw_schedule_device_work(device,
|
||
list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
|
||
}
|
||
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
|
||
index 638e1f7..7cff7f7 100644
|
||
--- a/drivers/firewire/net.c
|
||
+++ b/drivers/firewire/net.c
|
||
@@ -1014,8 +1014,6 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
|
||
if (rcode == RCODE_COMPLETE) {
|
||
fwnet_transmit_packet_done(ptask);
|
||
} else {
|
||
- fwnet_transmit_packet_failed(ptask);
|
||
-
|
||
if (printk_timed_ratelimit(&j, 1000) || rcode != last_rcode) {
|
||
dev_err(&ptask->dev->netdev->dev,
|
||
"fwnet_write_complete failed: %x (skipped %d)\n",
|
||
@@ -1023,8 +1021,10 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
|
||
|
||
errors_skipped = 0;
|
||
last_rcode = rcode;
|
||
- } else
|
||
+ } else {
|
||
errors_skipped++;
|
||
+ }
|
||
+ fwnet_transmit_packet_failed(ptask);
|
||
}
|
||
}
|
||
|
||
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
|
||
index b7e65d7..23a9283 100644
|
||
--- a/drivers/firewire/sbp2.c
|
||
+++ b/drivers/firewire/sbp2.c
|
||
@@ -146,6 +146,7 @@ struct sbp2_logical_unit {
|
||
*/
|
||
int generation;
|
||
int retries;
|
||
+ work_func_t workfn;
|
||
struct delayed_work work;
|
||
bool has_sdev;
|
||
bool blocked;
|
||
@@ -865,7 +866,7 @@ static void sbp2_login(struct work_struct *work)
|
||
/* set appropriate retry limit(s) in BUSY_TIMEOUT register */
|
||
sbp2_set_busy_timeout(lu);
|
||
|
||
- PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
|
||
+ lu->workfn = sbp2_reconnect;
|
||
sbp2_agent_reset(lu);
|
||
|
||
/* This was a re-login. */
|
||
@@ -919,7 +920,7 @@ static void sbp2_login(struct work_struct *work)
|
||
* If a bus reset happened, sbp2_update will have requeued
|
||
* lu->work already. Reset the work from reconnect to login.
|
||
*/
|
||
- PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
|
||
+ lu->workfn = sbp2_login;
|
||
}
|
||
|
||
static void sbp2_reconnect(struct work_struct *work)
|
||
@@ -953,7 +954,7 @@ static void sbp2_reconnect(struct work_struct *work)
|
||
lu->retries++ >= 5) {
|
||
dev_err(tgt_dev(tgt), "failed to reconnect\n");
|
||
lu->retries = 0;
|
||
- PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
|
||
+ lu->workfn = sbp2_login;
|
||
}
|
||
sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
|
||
|
||
@@ -973,6 +974,13 @@ static void sbp2_reconnect(struct work_struct *work)
|
||
sbp2_conditionally_unblock(lu);
|
||
}
|
||
|
||
+static void sbp2_lu_workfn(struct work_struct *work)
|
||
+{
|
||
+ struct sbp2_logical_unit *lu = container_of(to_delayed_work(work),
|
||
+ struct sbp2_logical_unit, work);
|
||
+ lu->workfn(work);
|
||
+}
|
||
+
|
||
static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
|
||
{
|
||
struct sbp2_logical_unit *lu;
|
||
@@ -999,7 +1007,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
|
||
lu->blocked = false;
|
||
++tgt->dont_block;
|
||
INIT_LIST_HEAD(&lu->orb_list);
|
||
- INIT_DELAYED_WORK(&lu->work, sbp2_login);
|
||
+ lu->workfn = sbp2_login;
|
||
+ INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn);
|
||
|
||
list_add_tail(&lu->link, &tgt->lu_list);
|
||
return 0;
|
||
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
|
||
index 9b00072..42c759a 100644
|
||
--- a/drivers/firmware/Kconfig
|
||
+++ b/drivers/firmware/Kconfig
|
||
@@ -53,6 +53,24 @@ config EFI_VARS
|
||
Subsequent efibootmgr releases may be found at:
|
||
<http://linux.dell.com/efibootmgr>
|
||
|
||
+config EFI_VARS_PSTORE
|
||
+ bool "Register efivars backend for pstore"
|
||
+ depends on EFI_VARS && PSTORE
|
||
+ default y
|
||
+ help
|
||
+ Say Y here to enable use efivars as a backend to pstore. This
|
||
+ will allow writing console messages, crash dumps, or anything
|
||
+ else supported by pstore to EFI variables.
|
||
+
|
||
+config EFI_VARS_PSTORE_DEFAULT_DISABLE
|
||
+ bool "Disable using efivars as a pstore backend by default"
|
||
+ depends on EFI_VARS_PSTORE
|
||
+ default n
|
||
+ help
|
||
+ Saying Y here will disable the use of efivars as a storage
|
||
+ backend for pstore by default. This setting can be overridden
|
||
+ using the efivars module's pstore_disable parameter.
|
||
+
|
||
config EFI_PCDP
|
||
bool "Console device selection via EFI PCDP or HCDP table"
|
||
depends on ACPI && EFI && IA64
|
||
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
|
||
index 2cbb675..80c6667 100644
|
||
--- a/drivers/firmware/efivars.c
|
||
+++ b/drivers/firmware/efivars.c
|
||
@@ -92,6 +92,11 @@ MODULE_VERSION(EFIVARS_VERSION);
|
||
|
||
#define DUMP_NAME_LEN 52
|
||
|
||
+static bool efivars_pstore_disable =
|
||
+ IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
|
||
+
|
||
+module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
|
||
+
|
||
/*
|
||
* The maximum size of VariableName + Data = 1024
|
||
* Therefore, it's reasonable to save that much
|
||
@@ -149,6 +154,13 @@ efivar_create_sysfs_entry(struct efivars *efivars,
|
||
efi_char16_t *variable_name,
|
||
efi_guid_t *vendor_guid);
|
||
|
||
+/*
|
||
+ * Prototype for workqueue functions updating sysfs entry
|
||
+ */
|
||
+
|
||
+static void efivar_update_sysfs_entries(struct work_struct *);
|
||
+static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
|
||
+
|
||
/* Return the number of unicode characters in data */
|
||
static unsigned long
|
||
utf16_strnlen(efi_char16_t *s, size_t maxlength)
|
||
@@ -396,10 +408,11 @@ static efi_status_t
|
||
get_var_data(struct efivars *efivars, struct efi_variable *var)
|
||
{
|
||
efi_status_t status;
|
||
+ unsigned long flags;
|
||
|
||
- spin_lock(&efivars->lock);
|
||
+ spin_lock_irqsave(&efivars->lock, flags);
|
||
status = get_var_data_locked(efivars, var);
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irqrestore(&efivars->lock, flags);
|
||
|
||
if (status != EFI_SUCCESS) {
|
||
printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n",
|
||
@@ -408,6 +421,18 @@ get_var_data(struct efivars *efivars, struct efi_variable *var)
|
||
return status;
|
||
}
|
||
|
||
+static efi_status_t
|
||
+check_var_size_locked(struct efivars *efivars, u32 attributes,
|
||
+ unsigned long size)
|
||
+{
|
||
+ const struct efivar_operations *fops = efivars->ops;
|
||
+
|
||
+ if (!efivars->ops->query_variable_store)
|
||
+ return EFI_UNSUPPORTED;
|
||
+
|
||
+ return fops->query_variable_store(attributes, size);
|
||
+}
|
||
+
|
||
static ssize_t
|
||
efivar_guid_read(struct efivar_entry *entry, char *buf)
|
||
{
|
||
@@ -528,14 +553,19 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
|
||
return -EINVAL;
|
||
}
|
||
|
||
- spin_lock(&efivars->lock);
|
||
- status = efivars->ops->set_variable(new_var->VariableName,
|
||
- &new_var->VendorGuid,
|
||
- new_var->Attributes,
|
||
- new_var->DataSize,
|
||
- new_var->Data);
|
||
+ spin_lock_irq(&efivars->lock);
|
||
+
|
||
+ status = check_var_size_locked(efivars, new_var->Attributes,
|
||
+ new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
|
||
|
||
- spin_unlock(&efivars->lock);
|
||
+ if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
|
||
+ status = efivars->ops->set_variable(new_var->VariableName,
|
||
+ &new_var->VendorGuid,
|
||
+ new_var->Attributes,
|
||
+ new_var->DataSize,
|
||
+ new_var->Data);
|
||
+
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
|
||
if (status != EFI_SUCCESS) {
|
||
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
|
||
@@ -632,21 +662,49 @@ static struct kobj_type efivar_ktype = {
|
||
.default_attrs = def_attrs,
|
||
};
|
||
|
||
-static struct pstore_info efi_pstore_info;
|
||
-
|
||
static inline void
|
||
efivar_unregister(struct efivar_entry *var)
|
||
{
|
||
kobject_put(&var->kobj);
|
||
}
|
||
|
||
-#ifdef CONFIG_PSTORE
|
||
+static int efi_status_to_err(efi_status_t status)
|
||
+{
|
||
+ int err;
|
||
+
|
||
+ switch (status) {
|
||
+ case EFI_INVALID_PARAMETER:
|
||
+ err = -EINVAL;
|
||
+ break;
|
||
+ case EFI_OUT_OF_RESOURCES:
|
||
+ err = -ENOSPC;
|
||
+ break;
|
||
+ case EFI_DEVICE_ERROR:
|
||
+ err = -EIO;
|
||
+ break;
|
||
+ case EFI_WRITE_PROTECTED:
|
||
+ err = -EROFS;
|
||
+ break;
|
||
+ case EFI_SECURITY_VIOLATION:
|
||
+ err = -EACCES;
|
||
+ break;
|
||
+ case EFI_NOT_FOUND:
|
||
+ err = -ENOENT;
|
||
+ break;
|
||
+ default:
|
||
+ err = -EINVAL;
|
||
+ }
|
||
+
|
||
+ return err;
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_EFI_VARS_PSTORE
|
||
|
||
static int efi_pstore_open(struct pstore_info *psi)
|
||
{
|
||
struct efivars *efivars = psi->data;
|
||
|
||
- spin_lock(&efivars->lock);
|
||
+ spin_lock_irq(&efivars->lock);
|
||
efivars->walk_entry = list_first_entry(&efivars->list,
|
||
struct efivar_entry, list);
|
||
return 0;
|
||
@@ -656,7 +714,7 @@ static int efi_pstore_close(struct pstore_info *psi)
|
||
{
|
||
struct efivars *efivars = psi->data;
|
||
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
return 0;
|
||
}
|
||
|
||
@@ -710,11 +768,30 @@ static int efi_pstore_write(enum pstore_type_id type,
|
||
struct efivars *efivars = psi->data;
|
||
struct efivar_entry *entry, *found = NULL;
|
||
int i, ret = 0;
|
||
+ efi_status_t status = EFI_NOT_FOUND;
|
||
+ unsigned long flags;
|
||
|
||
sprintf(stub_name, "dump-type%u-%u-", type, part);
|
||
sprintf(name, "%s%lu", stub_name, get_seconds());
|
||
|
||
- spin_lock(&efivars->lock);
|
||
+ spin_lock_irqsave(&efivars->lock, flags);
|
||
+
|
||
+ if (size) {
|
||
+ /*
|
||
+ * Check if there is a space enough to log.
|
||
+ * size: a size of logging data
|
||
+ * DUMP_NAME_LEN * 2: a maximum size of variable name
|
||
+ */
|
||
+
|
||
+ status = check_var_size_locked(efivars, PSTORE_EFI_ATTRIBUTES,
|
||
+ size + DUMP_NAME_LEN * 2);
|
||
+
|
||
+ if (status) {
|
||
+ spin_unlock_irqrestore(&efivars->lock, flags);
|
||
+ *id = part;
|
||
+ return -ENOSPC;
|
||
+ }
|
||
+ }
|
||
|
||
for (i = 0; i < DUMP_NAME_LEN; i++)
|
||
efi_name[i] = stub_name[i];
|
||
@@ -752,16 +829,13 @@ static int efi_pstore_write(enum pstore_type_id type,
|
||
efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES,
|
||
size, psi->buf);
|
||
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irqrestore(&efivars->lock, flags);
|
||
|
||
if (found)
|
||
efivar_unregister(found);
|
||
|
||
- if (size)
|
||
- ret = efivar_create_sysfs_entry(efivars,
|
||
- utf16_strsize(efi_name,
|
||
- DUMP_NAME_LEN * 2),
|
||
- efi_name, &vendor);
|
||
+ if (reason == KMSG_DUMP_OOPS)
|
||
+ schedule_work(&efivar_work);
|
||
|
||
*id = part;
|
||
return ret;
|
||
@@ -774,37 +848,6 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id,
|
||
|
||
return 0;
|
||
}
|
||
-#else
|
||
-static int efi_pstore_open(struct pstore_info *psi)
|
||
-{
|
||
- return 0;
|
||
-}
|
||
-
|
||
-static int efi_pstore_close(struct pstore_info *psi)
|
||
-{
|
||
- return 0;
|
||
-}
|
||
-
|
||
-static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
|
||
- struct timespec *timespec,
|
||
- char **buf, struct pstore_info *psi)
|
||
-{
|
||
- return -1;
|
||
-}
|
||
-
|
||
-static int efi_pstore_write(enum pstore_type_id type,
|
||
- enum kmsg_dump_reason reason, u64 *id,
|
||
- unsigned int part, size_t size, struct pstore_info *psi)
|
||
-{
|
||
- return 0;
|
||
-}
|
||
-
|
||
-static int efi_pstore_erase(enum pstore_type_id type, u64 id,
|
||
- struct pstore_info *psi)
|
||
-{
|
||
- return 0;
|
||
-}
|
||
-#endif
|
||
|
||
static struct pstore_info efi_pstore_info = {
|
||
.owner = THIS_MODULE,
|
||
@@ -816,6 +859,24 @@ static struct pstore_info efi_pstore_info = {
|
||
.erase = efi_pstore_erase,
|
||
};
|
||
|
||
+static void efivar_pstore_register(struct efivars *efivars)
|
||
+{
|
||
+ efivars->efi_pstore_info = efi_pstore_info;
|
||
+ efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
|
||
+ if (efivars->efi_pstore_info.buf) {
|
||
+ efivars->efi_pstore_info.bufsize = 1024;
|
||
+ efivars->efi_pstore_info.data = efivars;
|
||
+ spin_lock_init(&efivars->efi_pstore_info.buf_lock);
|
||
+ pstore_register(&efivars->efi_pstore_info);
|
||
+ }
|
||
+}
|
||
+#else
|
||
+static void efivar_pstore_register(struct efivars *efivars)
|
||
+{
|
||
+ return;
|
||
+}
|
||
+#endif
|
||
+
|
||
static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||
struct bin_attribute *bin_attr,
|
||
char *buf, loff_t pos, size_t count)
|
||
@@ -836,7 +897,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||
return -EINVAL;
|
||
}
|
||
|
||
- spin_lock(&efivars->lock);
|
||
+ spin_lock_irq(&efivars->lock);
|
||
|
||
/*
|
||
* Does this variable already exist?
|
||
@@ -854,10 +915,18 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||
}
|
||
}
|
||
if (found) {
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
return -EINVAL;
|
||
}
|
||
|
||
+ status = check_var_size_locked(efivars, new_var->Attributes,
|
||
+ new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
|
||
+
|
||
+ if (status && status != EFI_UNSUPPORTED) {
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
+ return efi_status_to_err(status);
|
||
+ }
|
||
+
|
||
/* now *really* create the variable via EFI */
|
||
status = efivars->ops->set_variable(new_var->VariableName,
|
||
&new_var->VendorGuid,
|
||
@@ -868,10 +937,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||
if (status != EFI_SUCCESS) {
|
||
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
|
||
status);
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
return -EIO;
|
||
}
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
|
||
/* Create the entry in sysfs. Locking is not required here */
|
||
status = efivar_create_sysfs_entry(efivars,
|
||
@@ -899,7 +968,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
|
||
if (!capable(CAP_SYS_ADMIN))
|
||
return -EACCES;
|
||
|
||
- spin_lock(&efivars->lock);
|
||
+ spin_lock_irq(&efivars->lock);
|
||
|
||
/*
|
||
* Does this variable already exist?
|
||
@@ -917,7 +986,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
|
||
}
|
||
}
|
||
if (!found) {
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
return -EINVAL;
|
||
}
|
||
/* force the Attributes/DataSize to 0 to ensure deletion */
|
||
@@ -933,12 +1002,12 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
|
||
if (status != EFI_SUCCESS) {
|
||
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
|
||
status);
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
return -EIO;
|
||
}
|
||
list_del(&search_efivar->list);
|
||
/* We need to release this lock before unregistering. */
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
efivar_unregister(search_efivar);
|
||
|
||
/* It's dead Jim.... */
|
||
@@ -967,6 +1036,53 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
|
||
return found;
|
||
}
|
||
|
||
+static void efivar_update_sysfs_entries(struct work_struct *work)
|
||
+{
|
||
+ struct efivars *efivars = &__efivars;
|
||
+ efi_guid_t vendor;
|
||
+ efi_char16_t *variable_name;
|
||
+ unsigned long variable_name_size = 1024;
|
||
+ efi_status_t status = EFI_NOT_FOUND;
|
||
+ bool found;
|
||
+
|
||
+ /* Add new sysfs entries */
|
||
+ while (1) {
|
||
+ variable_name = kzalloc(variable_name_size, GFP_KERNEL);
|
||
+ if (!variable_name) {
|
||
+ pr_err("efivars: Memory allocation failed.\n");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ spin_lock_irq(&efivars->lock);
|
||
+ found = false;
|
||
+ while (1) {
|
||
+ variable_name_size = 1024;
|
||
+ status = efivars->ops->get_next_variable(
|
||
+ &variable_name_size,
|
||
+ variable_name,
|
||
+ &vendor);
|
||
+ if (status != EFI_SUCCESS) {
|
||
+ break;
|
||
+ } else {
|
||
+ if (!variable_is_present(variable_name,
|
||
+ &vendor)) {
|
||
+ found = true;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
+
|
||
+ if (!found) {
|
||
+ kfree(variable_name);
|
||
+ break;
|
||
+ } else
|
||
+ efivar_create_sysfs_entry(efivars,
|
||
+ variable_name_size,
|
||
+ variable_name, &vendor);
|
||
+ }
|
||
+}
|
||
+
|
||
/*
|
||
* Returns the size of variable_name, in bytes, including the
|
||
* terminating NULL character, or variable_name_size if no NULL
|
||
@@ -1093,9 +1209,9 @@ efivar_create_sysfs_entry(struct efivars *efivars,
|
||
kfree(short_name);
|
||
short_name = NULL;
|
||
|
||
- spin_lock(&efivars->lock);
|
||
+ spin_lock_irq(&efivars->lock);
|
||
list_add(&new_efivar->list, &efivars->list);
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
|
||
return 0;
|
||
}
|
||
@@ -1164,9 +1280,9 @@ void unregister_efivars(struct efivars *efivars)
|
||
struct efivar_entry *entry, *n;
|
||
|
||
list_for_each_entry_safe(entry, n, &efivars->list, list) {
|
||
- spin_lock(&efivars->lock);
|
||
+ spin_lock_irq(&efivars->lock);
|
||
list_del(&entry->list);
|
||
- spin_unlock(&efivars->lock);
|
||
+ spin_unlock_irq(&efivars->lock);
|
||
efivar_unregister(entry);
|
||
}
|
||
if (efivars->new_var)
|
||
@@ -1278,15 +1394,8 @@ int register_efivars(struct efivars *efivars,
|
||
if (error)
|
||
unregister_efivars(efivars);
|
||
|
||
- efivars->efi_pstore_info = efi_pstore_info;
|
||
-
|
||
- efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
|
||
- if (efivars->efi_pstore_info.buf) {
|
||
- efivars->efi_pstore_info.bufsize = 1024;
|
||
- efivars->efi_pstore_info.data = efivars;
|
||
- spin_lock_init(&efivars->efi_pstore_info.buf_lock);
|
||
- pstore_register(&efivars->efi_pstore_info);
|
||
- }
|
||
+ if (!efivars_pstore_disable)
|
||
+ efivar_pstore_register(efivars);
|
||
|
||
out:
|
||
kfree(variable_name);
|
||
@@ -1324,6 +1433,7 @@ efivars_init(void)
|
||
ops.get_variable = efi.get_variable;
|
||
ops.set_variable = efi.set_variable;
|
||
ops.get_next_variable = efi.get_next_variable;
|
||
+ ops.query_variable_store = efi_query_variable_store;
|
||
error = register_efivars(&__efivars, &ops, efi_kobj);
|
||
if (error)
|
||
goto err_put;
|
||
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
|
||
index 5a1817e..c81b8da 100644
|
||
--- a/drivers/gpio/gpio-mpc8xxx.c
|
||
+++ b/drivers/gpio/gpio-mpc8xxx.c
|
||
@@ -69,10 +69,14 @@ static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||
u32 val;
|
||
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
|
||
struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
|
||
+ u32 out_mask, out_shadow;
|
||
|
||
- val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR);
|
||
+ out_mask = in_be32(mm->regs + GPIO_DIR);
|
||
|
||
- return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio);
|
||
+ val = in_be32(mm->regs + GPIO_DAT) & ~out_mask;
|
||
+ out_shadow = mpc8xxx_gc->data & out_mask;
|
||
+
|
||
+ return (val | out_shadow) & mpc8xxx_gpio2mask(gpio);
|
||
}
|
||
|
||
static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
|
||
index 385c58e..0f8114d 100644
|
||
--- a/drivers/gpio/gpio-mxs.c
|
||
+++ b/drivers/gpio/gpio-mxs.c
|
||
@@ -167,7 +167,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port)
|
||
ct->regs.ack = PINCTRL_IRQSTAT(port->id) + MXS_CLR;
|
||
ct->regs.mask = PINCTRL_IRQEN(port->id);
|
||
|
||
- irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0);
|
||
+ irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK,
|
||
+ IRQ_NOREQUEST, 0);
|
||
}
|
||
|
||
static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
|
||
index 8111889..b3abf70 100644
|
||
--- a/drivers/gpu/drm/drm_crtc_helper.c
|
||
+++ b/drivers/gpu/drm/drm_crtc_helper.c
|
||
@@ -328,8 +328,8 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
|
||
* drm_crtc_set_mode - set a mode
|
||
* @crtc: CRTC to program
|
||
* @mode: mode to use
|
||
- * @x: width of mode
|
||
- * @y: height of mode
|
||
+ * @x: horizontal offset into the surface
|
||
+ * @y: vertical offset into the surface
|
||
*
|
||
* LOCKING:
|
||
* Caller must hold mode config lock.
|
||
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
|
||
index 6116e3b..e9f1ef5 100644
|
||
--- a/drivers/gpu/drm/drm_drv.c
|
||
+++ b/drivers/gpu/drm/drm_drv.c
|
||
@@ -420,9 +420,16 @@ long drm_ioctl(struct file *filp,
|
||
asize = drv_size;
|
||
}
|
||
else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
|
||
+ u32 drv_size;
|
||
+
|
||
ioctl = &drm_ioctls[nr];
|
||
- cmd = ioctl->cmd;
|
||
+
|
||
+ drv_size = _IOC_SIZE(ioctl->cmd);
|
||
usize = asize = _IOC_SIZE(cmd);
|
||
+ if (drv_size > asize)
|
||
+ asize = drv_size;
|
||
+
|
||
+ cmd = ioctl->cmd;
|
||
} else
|
||
goto err_i1;
|
||
|
||
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
|
||
index efe172f..d75dccb 100644
|
||
--- a/drivers/gpu/drm/drm_edid.c
|
||
+++ b/drivers/gpu/drm/drm_edid.c
|
||
@@ -68,6 +68,8 @@
|
||
#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
|
||
/* Force reduced-blanking timings for detailed modes */
|
||
#define EDID_QUIRK_FORCE_REDUCED_BLANKING (1 << 7)
|
||
+/* Force 8bpc */
|
||
+#define EDID_QUIRK_FORCE_8BPC (1 << 8)
|
||
|
||
struct detailed_mode_closure {
|
||
struct drm_connector *connector;
|
||
@@ -128,6 +130,9 @@ static struct edid_quirk {
|
||
|
||
/* Medion MD 30217 PG */
|
||
{ "MED", 0x7b8, EDID_QUIRK_PREFER_LARGE_75 },
|
||
+
|
||
+ /* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */
|
||
+ { "SEC", 0xd033, EDID_QUIRK_FORCE_8BPC },
|
||
};
|
||
|
||
/*** DDC fetch and block validation ***/
|
||
@@ -1782,6 +1787,9 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
||
|
||
drm_add_display_info(edid, &connector->display_info);
|
||
|
||
+ if (quirks & EDID_QUIRK_FORCE_8BPC)
|
||
+ connector->display_info.bpc = 8;
|
||
+
|
||
return num_modes;
|
||
}
|
||
EXPORT_SYMBOL(drm_add_edid_modes);
|
||
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
|
||
index 34791fb..39f8111 100644
|
||
--- a/drivers/gpu/drm/i915/i915_debugfs.c
|
||
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
|
||
@@ -30,6 +30,7 @@
|
||
#include <linux/debugfs.h>
|
||
#include <linux/slab.h>
|
||
#include <linux/export.h>
|
||
+#include <generated/utsrelease.h>
|
||
#include "drmP.h"
|
||
#include "drm.h"
|
||
#include "intel_drv.h"
|
||
@@ -340,7 +341,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
|
||
seq_printf(m, "No flip due on pipe %c (plane %c)\n",
|
||
pipe, plane);
|
||
} else {
|
||
- if (!work->pending) {
|
||
+ if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
|
||
seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
|
||
pipe, plane);
|
||
} else {
|
||
@@ -351,7 +352,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
|
||
seq_printf(m, "Stall check enabled, ");
|
||
else
|
||
seq_printf(m, "Stall check waiting for page flip ioctl, ");
|
||
- seq_printf(m, "%d prepares\n", work->pending);
|
||
+ seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
|
||
|
||
if (work->old_fb_obj) {
|
||
struct drm_i915_gem_object *obj = work->old_fb_obj;
|
||
@@ -750,6 +751,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
|
||
|
||
seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
|
||
error->time.tv_usec);
|
||
+ seq_printf(m, "Kernel: " UTS_RELEASE "\n");
|
||
seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
|
||
seq_printf(m, "EIR: 0x%08x\n", error->eir);
|
||
seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
|
||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
|
||
index ba60f3c..38c0a47 100644
|
||
--- a/drivers/gpu/drm/i915/i915_dma.c
|
||
+++ b/drivers/gpu/drm/i915/i915_dma.c
|
||
@@ -1934,6 +1934,27 @@ ips_ping_for_i915_load(void)
|
||
}
|
||
}
|
||
|
||
+static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
|
||
+{
|
||
+ struct apertures_struct *ap;
|
||
+ struct pci_dev *pdev = dev_priv->dev->pdev;
|
||
+ bool primary;
|
||
+
|
||
+ ap = alloc_apertures(1);
|
||
+ if (!ap)
|
||
+ return;
|
||
+
|
||
+ ap->ranges[0].base = dev_priv->dev->agp->base;
|
||
+ ap->ranges[0].size =
|
||
+ dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
|
||
+ primary =
|
||
+ pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
|
||
+
|
||
+ remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
|
||
+
|
||
+ kfree(ap);
|
||
+}
|
||
+
|
||
/**
|
||
* i915_driver_load - setup chip and create an initial config
|
||
* @dev: DRM device
|
||
@@ -1971,6 +1992,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
||
goto free_priv;
|
||
}
|
||
|
||
+ dev_priv->mm.gtt = intel_gtt_get();
|
||
+ if (!dev_priv->mm.gtt) {
|
||
+ DRM_ERROR("Failed to initialize GTT\n");
|
||
+ ret = -ENODEV;
|
||
+ goto put_bridge;
|
||
+ }
|
||
+
|
||
+ i915_kick_out_firmware_fb(dev_priv);
|
||
+
|
||
pci_set_master(dev->pdev);
|
||
|
||
/* overlay on gen2 is broken and can't address above 1G */
|
||
@@ -1996,13 +2026,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
||
goto put_bridge;
|
||
}
|
||
|
||
- dev_priv->mm.gtt = intel_gtt_get();
|
||
- if (!dev_priv->mm.gtt) {
|
||
- DRM_ERROR("Failed to initialize GTT\n");
|
||
- ret = -ENODEV;
|
||
- goto out_rmmap;
|
||
- }
|
||
-
|
||
agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
|
||
|
||
dev_priv->mm.gtt_mapping =
|
||
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
|
||
index 232119a..a8f00d0 100644
|
||
--- a/drivers/gpu/drm/i915/i915_drv.h
|
||
+++ b/drivers/gpu/drm/i915/i915_drv.h
|
||
@@ -296,7 +296,8 @@ enum intel_pch {
|
||
|
||
#define QUIRK_PIPEA_FORCE (1<<0)
|
||
#define QUIRK_LVDS_SSC_DISABLE (1<<1)
|
||
-#define QUIRK_NO_PCH_PWM_ENABLE (1<<2)
|
||
+#define QUIRK_INVERT_BRIGHTNESS (1<<2)
|
||
+#define QUIRK_NO_PCH_PWM_ENABLE (1<<3)
|
||
|
||
struct intel_fbdev;
|
||
struct intel_fbc_work;
|
||
@@ -1397,6 +1398,7 @@ static inline void intel_unregister_dsm_handler(void) { return; }
|
||
#endif /* CONFIG_ACPI */
|
||
|
||
/* modesetting */
|
||
+extern void i915_redisable_vga(struct drm_device *dev);
|
||
extern void intel_modeset_init(struct drm_device *dev);
|
||
extern void intel_modeset_gem_init(struct drm_device *dev);
|
||
extern void intel_modeset_cleanup(struct drm_device *dev);
|
||
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
|
||
index eb33945..2ac4ded 100644
|
||
--- a/drivers/gpu/drm/i915/i915_gem.c
|
||
+++ b/drivers/gpu/drm/i915/i915_gem.c
|
||
@@ -2468,6 +2468,11 @@ i915_find_fence_reg(struct drm_device *dev,
|
||
return avail;
|
||
}
|
||
|
||
+static void i915_gem_write_fence__ipi(void *data)
|
||
+{
|
||
+ wbinvd();
|
||
+}
|
||
+
|
||
/**
|
||
* i915_gem_object_get_fence - set up a fence reg for an object
|
||
* @obj: object to map through a fence reg
|
||
@@ -2589,6 +2594,17 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
|
||
switch (INTEL_INFO(dev)->gen) {
|
||
case 7:
|
||
case 6:
|
||
+ /* In order to fully serialize access to the fenced region and
|
||
+ * the update to the fence register we need to take extreme
|
||
+ * measures on SNB+. In theory, the write to the fence register
|
||
+ * flushes all memory transactions before, and coupled with the
|
||
+ * mb() placed around the register write we serialise all memory
|
||
+ * operations with respect to the changes in the tiler. Yet, on
|
||
+ * SNB+ we need to take a step further and emit an explicit wbinvd()
|
||
+ * on each processor in order to manually flush all memory
|
||
+ * transactions before updating the fence register.
|
||
+ */
|
||
+ on_each_cpu(i915_gem_write_fence__ipi, NULL, 1);
|
||
ret = sandybridge_write_fence_reg(obj, pipelined);
|
||
break;
|
||
case 5:
|
||
@@ -3411,14 +3427,15 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
|
||
goto out;
|
||
}
|
||
|
||
- obj->user_pin_count++;
|
||
- obj->pin_filp = file;
|
||
- if (obj->user_pin_count == 1) {
|
||
+ if (obj->user_pin_count == 0) {
|
||
ret = i915_gem_object_pin(obj, args->alignment, true);
|
||
if (ret)
|
||
goto out;
|
||
}
|
||
|
||
+ obj->user_pin_count++;
|
||
+ obj->pin_filp = file;
|
||
+
|
||
/* XXX - flush the CPU caches for pinned objects
|
||
* as the X server doesn't manage domains yet
|
||
*/
|
||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
|
||
index 8bca2d2..fc6f32a 100644
|
||
--- a/drivers/gpu/drm/i915/i915_irq.c
|
||
+++ b/drivers/gpu/drm/i915/i915_irq.c
|
||
@@ -1251,7 +1251,9 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
|
||
spin_lock_irqsave(&dev->event_lock, flags);
|
||
work = intel_crtc->unpin_work;
|
||
|
||
- if (work == NULL || work->pending || !work->enable_stall_check) {
|
||
+ if (work == NULL ||
|
||
+ atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE ||
|
||
+ !work->enable_stall_check) {
|
||
/* Either the pending flip IRQ arrived, or we're too early. Don't check */
|
||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||
return;
|
||
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
|
||
index a2c9e56..d9e359a 100644
|
||
--- a/drivers/gpu/drm/i915/intel_bios.c
|
||
+++ b/drivers/gpu/drm/i915/intel_bios.c
|
||
@@ -651,7 +651,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
|
||
DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq);
|
||
}
|
||
|
||
-static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
|
||
+static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
|
||
{
|
||
DRM_DEBUG_KMS("Falling back to manually reading VBT from "
|
||
"VBIOS ROM for %s\n",
|
||
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
|
||
index 342ffb7..b4f71c2 100644
|
||
--- a/drivers/gpu/drm/i915/intel_crt.c
|
||
+++ b/drivers/gpu/drm/i915/intel_crt.c
|
||
@@ -564,7 +564,7 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
|
||
.destroy = intel_encoder_destroy,
|
||
};
|
||
|
||
-static int __init intel_no_crt_dmi_callback(const struct dmi_system_id *id)
|
||
+static int intel_no_crt_dmi_callback(const struct dmi_system_id *id)
|
||
{
|
||
DRM_DEBUG_KMS("Skipping CRT initialization for %s\n", id->ident);
|
||
return 1;
|
||
@@ -579,6 +579,14 @@ static const struct dmi_system_id intel_no_crt[] = {
|
||
DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
|
||
},
|
||
},
|
||
+ {
|
||
+ .callback = intel_no_crt_dmi_callback,
|
||
+ .ident = "DELL XPS 8700",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS 8700"),
|
||
+ },
|
||
+ },
|
||
{ }
|
||
};
|
||
|
||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
|
||
index 0e35922..c975c99 100644
|
||
--- a/drivers/gpu/drm/i915/intel_display.c
|
||
+++ b/drivers/gpu/drm/i915/intel_display.c
|
||
@@ -25,6 +25,7 @@
|
||
*/
|
||
|
||
#include <linux/cpufreq.h>
|
||
+#include <linux/dmi.h>
|
||
#include <linux/module.h>
|
||
#include <linux/input.h>
|
||
#include <linux/i2c.h>
|
||
@@ -6377,7 +6378,9 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
|
||
intel_crtc->cursor_visible = visible;
|
||
}
|
||
/* and commit changes on next vblank */
|
||
+ POSTING_READ(CURCNTR(pipe));
|
||
I915_WRITE(CURBASE(pipe), base);
|
||
+ POSTING_READ(CURBASE(pipe));
|
||
}
|
||
|
||
static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
|
||
@@ -6402,7 +6405,9 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
|
||
intel_crtc->cursor_visible = visible;
|
||
}
|
||
/* and commit changes on next vblank */
|
||
+ POSTING_READ(CURCNTR_IVB(pipe));
|
||
I915_WRITE(CURBASE_IVB(pipe), base);
|
||
+ POSTING_READ(CURBASE_IVB(pipe));
|
||
}
|
||
|
||
/* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
|
||
@@ -7241,11 +7246,18 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
|
||
|
||
spin_lock_irqsave(&dev->event_lock, flags);
|
||
work = intel_crtc->unpin_work;
|
||
- if (work == NULL || !work->pending) {
|
||
+
|
||
+ /* Ensure we don't miss a work->pending update ... */
|
||
+ smp_rmb();
|
||
+
|
||
+ if (work == NULL || atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
|
||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||
return;
|
||
}
|
||
|
||
+ /* and that the unpin work is consistent wrt ->pending. */
|
||
+ smp_rmb();
|
||
+
|
||
intel_crtc->unpin_work = NULL;
|
||
|
||
if (work->event) {
|
||
@@ -7317,16 +7329,25 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)
|
||
to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
|
||
unsigned long flags;
|
||
|
||
+ /* NB: An MMIO update of the plane base pointer will also
|
||
+ * generate a page-flip completion irq, i.e. every modeset
|
||
+ * is also accompanied by a spurious intel_prepare_page_flip().
|
||
+ */
|
||
spin_lock_irqsave(&dev->event_lock, flags);
|
||
- if (intel_crtc->unpin_work) {
|
||
- if ((++intel_crtc->unpin_work->pending) > 1)
|
||
- DRM_ERROR("Prepared flip multiple times\n");
|
||
- } else {
|
||
- DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n");
|
||
- }
|
||
+ if (intel_crtc->unpin_work)
|
||
+ atomic_inc_not_zero(&intel_crtc->unpin_work->pending);
|
||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||
}
|
||
|
||
+inline static void intel_mark_page_flip_active(struct intel_crtc *intel_crtc)
|
||
+{
|
||
+ /* Ensure that the work item is consistent when activating it ... */
|
||
+ smp_wmb();
|
||
+ atomic_set(&intel_crtc->unpin_work->pending, INTEL_FLIP_PENDING);
|
||
+ /* and that it is marked active as soon as the irq could fire. */
|
||
+ smp_wmb();
|
||
+}
|
||
+
|
||
static int intel_gen2_queue_flip(struct drm_device *dev,
|
||
struct drm_crtc *crtc,
|
||
struct drm_framebuffer *fb,
|
||
@@ -7363,6 +7384,8 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
|
||
OUT_RING(fb->pitches[0]);
|
||
OUT_RING(obj->gtt_offset + offset);
|
||
OUT_RING(0); /* aux display base address, unused */
|
||
+
|
||
+ intel_mark_page_flip_active(intel_crtc);
|
||
ADVANCE_LP_RING();
|
||
return 0;
|
||
|
||
@@ -7406,6 +7429,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
|
||
OUT_RING(obj->gtt_offset + offset);
|
||
OUT_RING(MI_NOOP);
|
||
|
||
+ intel_mark_page_flip_active(intel_crtc);
|
||
ADVANCE_LP_RING();
|
||
return 0;
|
||
|
||
@@ -7449,6 +7473,8 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
|
||
pf = 0;
|
||
pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
|
||
OUT_RING(pf | pipesrc);
|
||
+
|
||
+ intel_mark_page_flip_active(intel_crtc);
|
||
ADVANCE_LP_RING();
|
||
return 0;
|
||
|
||
@@ -7490,6 +7516,8 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
|
||
pf = 0;
|
||
pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
|
||
OUT_RING(pf | pipesrc);
|
||
+
|
||
+ intel_mark_page_flip_active(intel_crtc);
|
||
ADVANCE_LP_RING();
|
||
return 0;
|
||
|
||
@@ -7544,6 +7572,8 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
|
||
intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
|
||
intel_ring_emit(ring, (obj->gtt_offset));
|
||
intel_ring_emit(ring, (MI_NOOP));
|
||
+
|
||
+ intel_mark_page_flip_active(intel_crtc);
|
||
intel_ring_advance(ring);
|
||
return 0;
|
||
|
||
@@ -9171,6 +9201,16 @@ static void quirk_no_pcm_pwm_enable(struct drm_device *dev)
|
||
DRM_INFO("applying no-PCH_PWM_ENABLE quirk\n");
|
||
}
|
||
|
||
+/*
|
||
+ * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight
|
||
+ * brightness value
|
||
+ */
|
||
+static void quirk_invert_brightness(struct drm_device *dev)
|
||
+{
|
||
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
||
+ dev_priv->quirks |= QUIRK_INVERT_BRIGHTNESS;
|
||
+}
|
||
+
|
||
struct intel_quirk {
|
||
int device;
|
||
int subsystem_vendor;
|
||
@@ -9178,6 +9218,34 @@ struct intel_quirk {
|
||
void (*hook)(struct drm_device *dev);
|
||
};
|
||
|
||
+/* For systems that don't have a meaningful PCI subdevice/subvendor ID */
|
||
+struct intel_dmi_quirk {
|
||
+ void (*hook)(struct drm_device *dev);
|
||
+ const struct dmi_system_id (*dmi_id_list)[];
|
||
+};
|
||
+
|
||
+static int intel_dmi_reverse_brightness(const struct dmi_system_id *id)
|
||
+{
|
||
+ DRM_INFO("Backlight polarity reversed on %s\n", id->ident);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static const struct intel_dmi_quirk intel_dmi_quirks[] = {
|
||
+ {
|
||
+ .dmi_id_list = &(const struct dmi_system_id[]) {
|
||
+ {
|
||
+ .callback = intel_dmi_reverse_brightness,
|
||
+ .ident = "NCR Corporation",
|
||
+ .matches = {DMI_MATCH(DMI_SYS_VENDOR, "NCR Corporation"),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, ""),
|
||
+ },
|
||
+ },
|
||
+ { } /* terminating entry */
|
||
+ },
|
||
+ .hook = quirk_invert_brightness,
|
||
+ },
|
||
+};
|
||
+
|
||
struct intel_quirk intel_quirks[] = {
|
||
/* HP Mini needs pipe A force quirk (LP: #322104) */
|
||
{ 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
|
||
@@ -9204,6 +9272,18 @@ struct intel_quirk intel_quirks[] = {
|
||
/* Sony Vaio Y cannot use SSC on LVDS */
|
||
{ 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable },
|
||
|
||
+ /* Acer Aspire 5734Z must invert backlight brightness */
|
||
+ { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness },
|
||
+
|
||
+ /* Acer/eMachines G725 */
|
||
+ { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness },
|
||
+
|
||
+ /* Acer/eMachines e725 */
|
||
+ { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness },
|
||
+
|
||
+ /* Acer/Packard Bell NCL20 */
|
||
+ { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness },
|
||
+
|
||
/* Dell XPS13 HD Sandy Bridge */
|
||
{ 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable },
|
||
/* Dell XPS13 HD and XPS13 FHD Ivy Bridge */
|
||
@@ -9225,6 +9305,10 @@ static void intel_init_quirks(struct drm_device *dev)
|
||
q->subsystem_device == PCI_ANY_ID))
|
||
q->hook(dev);
|
||
}
|
||
+ for (i = 0; i < ARRAY_SIZE(intel_dmi_quirks); i++) {
|
||
+ if (dmi_check_system(*intel_dmi_quirks[i].dmi_id_list) != 0)
|
||
+ intel_dmi_quirks[i].hook(dev);
|
||
+ }
|
||
}
|
||
|
||
/* Disable the VGA plane that we never use */
|
||
@@ -9250,6 +9334,23 @@ static void i915_disable_vga(struct drm_device *dev)
|
||
POSTING_READ(vga_reg);
|
||
}
|
||
|
||
+void i915_redisable_vga(struct drm_device *dev)
|
||
+{
|
||
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
||
+ u32 vga_reg;
|
||
+
|
||
+ if (HAS_PCH_SPLIT(dev))
|
||
+ vga_reg = CPU_VGACNTRL;
|
||
+ else
|
||
+ vga_reg = VGACNTRL;
|
||
+
|
||
+ if (I915_READ(vga_reg) != VGA_DISP_DISABLE) {
|
||
+ DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
|
||
+ I915_WRITE(vga_reg, VGA_DISP_DISABLE);
|
||
+ POSTING_READ(vga_reg);
|
||
+ }
|
||
+}
|
||
+
|
||
void intel_modeset_init(struct drm_device *dev)
|
||
{
|
||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||
@@ -9370,6 +9471,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
|
||
del_timer_sync(&dev_priv->idle_timer);
|
||
cancel_work_sync(&dev_priv->idle_work);
|
||
|
||
+ /* destroy backlight, if any, before the connectors */
|
||
+ intel_panel_destroy_backlight(dev);
|
||
+
|
||
drm_mode_config_cleanup(dev);
|
||
}
|
||
|
||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
|
||
index eee6cd3..9a3ecd6 100644
|
||
--- a/drivers/gpu/drm/i915/intel_dp.c
|
||
+++ b/drivers/gpu/drm/i915/intel_dp.c
|
||
@@ -2289,11 +2289,6 @@ intel_dp_set_property(struct drm_connector *connector,
|
||
static void
|
||
intel_dp_destroy(struct drm_connector *connector)
|
||
{
|
||
- struct drm_device *dev = connector->dev;
|
||
-
|
||
- if (intel_dpd_is_edp(dev))
|
||
- intel_panel_destroy_backlight(dev);
|
||
-
|
||
drm_sysfs_connector_remove(connector);
|
||
drm_connector_cleanup(connector);
|
||
kfree(connector);
|
||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
|
||
index cd623e8..018dfbd 100644
|
||
--- a/drivers/gpu/drm/i915/intel_drv.h
|
||
+++ b/drivers/gpu/drm/i915/intel_drv.h
|
||
@@ -277,7 +277,10 @@ struct intel_unpin_work {
|
||
struct drm_i915_gem_object *old_fb_obj;
|
||
struct drm_i915_gem_object *pending_flip_obj;
|
||
struct drm_pending_vblank_event *event;
|
||
- int pending;
|
||
+ atomic_t pending;
|
||
+#define INTEL_FLIP_INACTIVE 0
|
||
+#define INTEL_FLIP_PENDING 1
|
||
+#define INTEL_FLIP_COMPLETE 2
|
||
bool enable_stall_check;
|
||
};
|
||
|
||
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
|
||
index dc7c5f6..77190cc 100644
|
||
--- a/drivers/gpu/drm/i915/intel_lvds.c
|
||
+++ b/drivers/gpu/drm/i915/intel_lvds.c
|
||
@@ -535,6 +535,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||
|
||
mutex_lock(&dev->mode_config.mutex);
|
||
drm_helper_resume_force_mode(dev);
|
||
+ i915_redisable_vga(dev);
|
||
mutex_unlock(&dev->mode_config.mutex);
|
||
|
||
return NOTIFY_OK;
|
||
@@ -552,8 +553,6 @@ static void intel_lvds_destroy(struct drm_connector *connector)
|
||
struct drm_device *dev = connector->dev;
|
||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||
|
||
- intel_panel_destroy_backlight(dev);
|
||
-
|
||
if (dev_priv->lid_notifier.notifier_call)
|
||
acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
|
||
drm_sysfs_connector_remove(connector);
|
||
@@ -620,7 +619,7 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
|
||
.destroy = intel_encoder_destroy,
|
||
};
|
||
|
||
-static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
|
||
+static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
|
||
{
|
||
DRM_DEBUG_KMS("Skipping LVDS initialization for %s\n", id->ident);
|
||
return 1;
|
||
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
|
||
index cffb007..356a252 100644
|
||
--- a/drivers/gpu/drm/i915/intel_opregion.c
|
||
+++ b/drivers/gpu/drm/i915/intel_opregion.c
|
||
@@ -161,7 +161,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
|
||
|
||
max = intel_panel_get_max_backlight(dev);
|
||
intel_panel_set_backlight(dev, bclp * max / 255);
|
||
- asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
|
||
+ asle->cblv = DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID;
|
||
|
||
return 0;
|
||
}
|
||
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
|
||
index 48177ec..0bae2bb 100644
|
||
--- a/drivers/gpu/drm/i915/intel_panel.c
|
||
+++ b/drivers/gpu/drm/i915/intel_panel.c
|
||
@@ -28,6 +28,7 @@
|
||
* Chris Wilson <chris@chris-wilson.co.uk>
|
||
*/
|
||
|
||
+#include <linux/moduleparam.h>
|
||
#include "intel_drv.h"
|
||
|
||
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
|
||
@@ -189,6 +190,27 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev)
|
||
return max;
|
||
}
|
||
|
||
+static int i915_panel_invert_brightness;
|
||
+MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
|
||
+ "(-1 force normal, 0 machine defaults, 1 force inversion), please "
|
||
+ "report PCI device ID, subsystem vendor and subsystem device ID "
|
||
+ "to dri-devel@lists.freedesktop.org, if your machine needs it. "
|
||
+ "It will then be included in an upcoming module version.");
|
||
+module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
|
||
+static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
|
||
+{
|
||
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
||
+
|
||
+ if (i915_panel_invert_brightness < 0)
|
||
+ return val;
|
||
+
|
||
+ if (i915_panel_invert_brightness > 0 ||
|
||
+ dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS)
|
||
+ return intel_panel_get_max_backlight(dev) - val;
|
||
+
|
||
+ return val;
|
||
+}
|
||
+
|
||
u32 intel_panel_get_backlight(struct drm_device *dev)
|
||
{
|
||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||
@@ -209,6 +231,7 @@ u32 intel_panel_get_backlight(struct drm_device *dev)
|
||
}
|
||
}
|
||
|
||
+ val = intel_panel_compute_brightness(dev, val);
|
||
DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
|
||
return val;
|
||
}
|
||
@@ -226,6 +249,7 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level
|
||
u32 tmp;
|
||
|
||
DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
|
||
+ level = intel_panel_compute_brightness(dev, level);
|
||
|
||
if (HAS_PCH_SPLIT(dev))
|
||
return intel_pch_panel_set_backlight(dev, level);
|
||
@@ -335,6 +359,9 @@ int intel_panel_setup_backlight(struct drm_device *dev)
|
||
|
||
intel_panel_init_backlight(dev);
|
||
|
||
+ if (WARN_ON(dev_priv->backlight))
|
||
+ return -ENODEV;
|
||
+
|
||
if (dev_priv->int_lvds_connector)
|
||
connector = dev_priv->int_lvds_connector;
|
||
else if (dev_priv->int_edp_connector)
|
||
@@ -362,8 +389,10 @@ int intel_panel_setup_backlight(struct drm_device *dev)
|
||
void intel_panel_destroy_backlight(struct drm_device *dev)
|
||
{
|
||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||
- if (dev_priv->backlight)
|
||
+ if (dev_priv->backlight) {
|
||
backlight_device_unregister(dev_priv->backlight);
|
||
+ dev_priv->backlight = NULL;
|
||
+ }
|
||
}
|
||
#else
|
||
int intel_panel_setup_backlight(struct drm_device *dev)
|
||
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
|
||
index c0ba260..8d55a33 100644
|
||
--- a/drivers/gpu/drm/i915/intel_sdvo.c
|
||
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
|
||
@@ -2265,6 +2265,18 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags)
|
||
return true;
|
||
}
|
||
|
||
+static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo)
|
||
+{
|
||
+ struct drm_device *dev = intel_sdvo->base.base.dev;
|
||
+ struct drm_connector *connector, *tmp;
|
||
+
|
||
+ list_for_each_entry_safe(connector, tmp,
|
||
+ &dev->mode_config.connector_list, head) {
|
||
+ if (intel_attached_encoder(connector) == &intel_sdvo->base)
|
||
+ intel_sdvo_destroy(connector);
|
||
+ }
|
||
+}
|
||
+
|
||
static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
|
||
struct intel_sdvo_connector *intel_sdvo_connector,
|
||
int type)
|
||
@@ -2583,7 +2595,8 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
|
||
intel_sdvo->caps.output_flags) != true) {
|
||
DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
|
||
IS_SDVOB(sdvo_reg) ? 'B' : 'C');
|
||
- goto err;
|
||
+ /* Output_setup can leave behind connectors! */
|
||
+ goto err_output;
|
||
}
|
||
|
||
/* Only enable the hotplug irq if we need it, to work around noisy
|
||
@@ -2596,12 +2609,12 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
|
||
|
||
/* Set the input timing to the screen. Assume always input 0. */
|
||
if (!intel_sdvo_set_target_input(intel_sdvo))
|
||
- goto err;
|
||
+ goto err_output;
|
||
|
||
if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
|
||
&intel_sdvo->pixel_clock_min,
|
||
&intel_sdvo->pixel_clock_max))
|
||
- goto err;
|
||
+ goto err_output;
|
||
|
||
DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
|
||
"clock range %dMHz - %dMHz, "
|
||
@@ -2621,6 +2634,9 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
|
||
(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
|
||
return true;
|
||
|
||
+err_output:
|
||
+ intel_sdvo_output_cleanup(intel_sdvo);
|
||
+
|
||
err:
|
||
drm_encoder_cleanup(&intel_encoder->base);
|
||
i2c_del_adapter(&intel_sdvo->ddc);
|
||
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
|
||
index 284bd25..4339694 100644
|
||
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
|
||
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
|
||
@@ -375,9 +375,6 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
|
||
acpi_status status;
|
||
acpi_handle dhandle, rom_handle;
|
||
|
||
- if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected)
|
||
- return false;
|
||
-
|
||
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
|
||
if (!dhandle)
|
||
return false;
|
||
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
|
||
index 12ce044..2c3d5c8 100644
|
||
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
|
||
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
|
||
@@ -946,7 +946,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
|
||
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
|
||
mem->bus.offset = mem->start << PAGE_SHIFT;
|
||
mem->bus.base = dev_priv->gart_info.aper_base;
|
||
- mem->bus.is_iomem = true;
|
||
+ mem->bus.is_iomem = !dev->agp->cant_use_aperture;
|
||
}
|
||
#endif
|
||
break;
|
||
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
|
||
index ed52a6f..2f46bbf 100644
|
||
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
|
||
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
|
||
@@ -281,7 +281,8 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
|
||
list_for_each_safe(entry, tmp, list) {
|
||
nvbo = list_entry(entry, struct nouveau_bo, entry);
|
||
|
||
- nouveau_bo_fence(nvbo, fence);
|
||
+ if (likely(fence))
|
||
+ nouveau_bo_fence(nvbo, fence);
|
||
|
||
if (unlikely(nvbo->validate_mapped)) {
|
||
ttm_bo_kunmap(&nvbo->kmap);
|
||
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
|
||
index ebbfbd2..d51c08d 100644
|
||
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
|
||
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
|
||
@@ -573,6 +573,11 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
|
||
/* use frac fb div on APUs */
|
||
if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))
|
||
pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV;
|
||
+ /* use frac fb div on RS780/RS880 */
|
||
+ if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
|
||
+ pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV;
|
||
+ if (ASIC_IS_DCE32(rdev) && mode->clock > 165000)
|
||
+ pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV;
|
||
} else {
|
||
pll->flags |= RADEON_PLL_LEGACY;
|
||
|
||
@@ -858,14 +863,16 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
|
||
args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
|
||
if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
|
||
args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
|
||
- switch (bpc) {
|
||
- case 8:
|
||
- default:
|
||
- args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
|
||
- break;
|
||
- case 10:
|
||
- args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
|
||
- break;
|
||
+ if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
|
||
+ switch (bpc) {
|
||
+ case 8:
|
||
+ default:
|
||
+ args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
|
||
+ break;
|
||
+ case 10:
|
||
+ args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
|
||
+ break;
|
||
+ }
|
||
}
|
||
args.v5.ucTransmitterID = encoder_id;
|
||
args.v5.ucEncoderMode = encoder_mode;
|
||
@@ -880,20 +887,22 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
|
||
args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
|
||
if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
|
||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
|
||
- switch (bpc) {
|
||
- case 8:
|
||
- default:
|
||
- args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
|
||
- break;
|
||
- case 10:
|
||
- args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
|
||
- break;
|
||
- case 12:
|
||
- args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
|
||
- break;
|
||
- case 16:
|
||
- args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
|
||
- break;
|
||
+ if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
|
||
+ switch (bpc) {
|
||
+ case 8:
|
||
+ default:
|
||
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
|
||
+ break;
|
||
+ case 10:
|
||
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
|
||
+ break;
|
||
+ case 12:
|
||
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
|
||
+ break;
|
||
+ case 16:
|
||
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
|
||
+ break;
|
||
+ }
|
||
}
|
||
args.v6.ucTransmitterID = encoder_id;
|
||
args.v6.ucEncoderMode = encoder_mode;
|
||
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
|
||
index 2f755e2..dd5c14e 100644
|
||
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
|
||
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
|
||
@@ -1048,7 +1048,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
|
||
}
|
||
if (is_dp)
|
||
args.v5.ucLaneNum = dp_lane_count;
|
||
- else if (radeon_encoder->pixel_clock > 165000)
|
||
+ else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
|
||
args.v5.ucLaneNum = 8;
|
||
else
|
||
args.v5.ucLaneNum = 4;
|
||
@@ -1430,7 +1430,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
|
||
* does the same thing and more.
|
||
*/
|
||
if ((rdev->family != CHIP_RV710) && (rdev->family != CHIP_RV730) &&
|
||
- (rdev->family != CHIP_RS880))
|
||
+ (rdev->family != CHIP_RS780) && (rdev->family != CHIP_RS880))
|
||
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);
|
||
}
|
||
if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
|
||
@@ -1666,8 +1666,11 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
|
||
args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT;
|
||
else
|
||
args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
|
||
- } else
|
||
+ } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
|
||
+ args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
|
||
+ } else {
|
||
args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
|
||
+ }
|
||
switch (radeon_encoder->encoder_id) {
|
||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
|
||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
|
||
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
|
||
index ad72295..df62c39 100644
|
||
--- a/drivers/gpu/drm/radeon/evergreen.c
|
||
+++ b/drivers/gpu/drm/radeon/evergreen.c
|
||
@@ -1292,7 +1292,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
|
||
WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
|
||
|
||
for (i = 0; i < rdev->num_crtc; i++) {
|
||
- if (save->crtc_enabled) {
|
||
+ if (save->crtc_enabled[i]) {
|
||
if (ASIC_IS_DCE6(rdev)) {
|
||
tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]);
|
||
tmp |= EVERGREEN_CRTC_BLANK_DATA_EN;
|
||
@@ -1874,7 +1874,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
|
||
case CHIP_SUMO:
|
||
rdev->config.evergreen.num_ses = 1;
|
||
rdev->config.evergreen.max_pipes = 4;
|
||
- rdev->config.evergreen.max_tile_pipes = 2;
|
||
+ rdev->config.evergreen.max_tile_pipes = 4;
|
||
if (rdev->pdev->device == 0x9648)
|
||
rdev->config.evergreen.max_simds = 3;
|
||
else if ((rdev->pdev->device == 0x9647) ||
|
||
@@ -1963,7 +1963,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
|
||
break;
|
||
case CHIP_CAICOS:
|
||
rdev->config.evergreen.num_ses = 1;
|
||
- rdev->config.evergreen.max_pipes = 4;
|
||
+ rdev->config.evergreen.max_pipes = 2;
|
||
rdev->config.evergreen.max_tile_pipes = 2;
|
||
rdev->config.evergreen.max_simds = 2;
|
||
rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses;
|
||
@@ -3219,6 +3219,8 @@ static int evergreen_startup(struct radeon_device *rdev)
|
||
/* enable pcie gen2 link */
|
||
evergreen_pcie_gen2_enable(rdev);
|
||
|
||
+ evergreen_mc_program(rdev);
|
||
+
|
||
if (ASIC_IS_DCE5(rdev)) {
|
||
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
|
||
r = ni_init_microcode(rdev);
|
||
@@ -3246,7 +3248,6 @@ static int evergreen_startup(struct radeon_device *rdev)
|
||
if (r)
|
||
return r;
|
||
|
||
- evergreen_mc_program(rdev);
|
||
if (rdev->flags & RADEON_IS_AGP) {
|
||
evergreen_agp_enable(rdev);
|
||
} else {
|
||
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
|
||
index 2cbd369..7b4cfc54 100644
|
||
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
|
||
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
|
||
@@ -942,7 +942,10 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p)
|
||
if (track->cb_dirty) {
|
||
tmp = track->cb_target_mask;
|
||
for (i = 0; i < 8; i++) {
|
||
- if ((tmp >> (i * 4)) & 0xF) {
|
||
+ u32 format = G_028C70_FORMAT(track->cb_color_info[i]);
|
||
+
|
||
+ if (format != V_028C70_COLOR_INVALID &&
|
||
+ (tmp >> (i * 4)) & 0xF) {
|
||
/* at least one component is enabled */
|
||
if (track->cb_color_bo[i] == NULL) {
|
||
dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
|
||
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
|
||
index f5387b3..461262e 100644
|
||
--- a/drivers/gpu/drm/radeon/ni.c
|
||
+++ b/drivers/gpu/drm/radeon/ni.c
|
||
@@ -672,6 +672,10 @@ static void cayman_gpu_init(struct radeon_device *rdev)
|
||
(rdev->pdev->device == 0x999C)) {
|
||
rdev->config.cayman.max_simds_per_se = 6;
|
||
rdev->config.cayman.max_backends_per_se = 2;
|
||
+ rdev->config.cayman.max_hw_contexts = 8;
|
||
+ rdev->config.cayman.sx_max_export_size = 256;
|
||
+ rdev->config.cayman.sx_max_export_pos_size = 64;
|
||
+ rdev->config.cayman.sx_max_export_smx_size = 192;
|
||
} else if ((rdev->pdev->device == 0x9903) ||
|
||
(rdev->pdev->device == 0x9904) ||
|
||
(rdev->pdev->device == 0x990A) ||
|
||
@@ -682,6 +686,10 @@ static void cayman_gpu_init(struct radeon_device *rdev)
|
||
(rdev->pdev->device == 0x999D)) {
|
||
rdev->config.cayman.max_simds_per_se = 4;
|
||
rdev->config.cayman.max_backends_per_se = 2;
|
||
+ rdev->config.cayman.max_hw_contexts = 8;
|
||
+ rdev->config.cayman.sx_max_export_size = 256;
|
||
+ rdev->config.cayman.sx_max_export_pos_size = 64;
|
||
+ rdev->config.cayman.sx_max_export_smx_size = 192;
|
||
} else if ((rdev->pdev->device == 0x9919) ||
|
||
(rdev->pdev->device == 0x9990) ||
|
||
(rdev->pdev->device == 0x9991) ||
|
||
@@ -692,9 +700,17 @@ static void cayman_gpu_init(struct radeon_device *rdev)
|
||
(rdev->pdev->device == 0x99A0)) {
|
||
rdev->config.cayman.max_simds_per_se = 3;
|
||
rdev->config.cayman.max_backends_per_se = 1;
|
||
+ rdev->config.cayman.max_hw_contexts = 4;
|
||
+ rdev->config.cayman.sx_max_export_size = 128;
|
||
+ rdev->config.cayman.sx_max_export_pos_size = 32;
|
||
+ rdev->config.cayman.sx_max_export_smx_size = 96;
|
||
} else {
|
||
rdev->config.cayman.max_simds_per_se = 2;
|
||
rdev->config.cayman.max_backends_per_se = 1;
|
||
+ rdev->config.cayman.max_hw_contexts = 4;
|
||
+ rdev->config.cayman.sx_max_export_size = 128;
|
||
+ rdev->config.cayman.sx_max_export_pos_size = 32;
|
||
+ rdev->config.cayman.sx_max_export_smx_size = 96;
|
||
}
|
||
rdev->config.cayman.max_texture_channel_caches = 2;
|
||
rdev->config.cayman.max_gprs = 256;
|
||
@@ -702,10 +718,6 @@ static void cayman_gpu_init(struct radeon_device *rdev)
|
||
rdev->config.cayman.max_gs_threads = 32;
|
||
rdev->config.cayman.max_stack_entries = 512;
|
||
rdev->config.cayman.sx_num_of_sets = 8;
|
||
- rdev->config.cayman.sx_max_export_size = 256;
|
||
- rdev->config.cayman.sx_max_export_pos_size = 64;
|
||
- rdev->config.cayman.sx_max_export_smx_size = 192;
|
||
- rdev->config.cayman.max_hw_contexts = 8;
|
||
rdev->config.cayman.sq_num_cf_insts = 2;
|
||
|
||
rdev->config.cayman.sc_prim_fifo_size = 0x40;
|
||
@@ -1540,6 +1552,8 @@ static int cayman_startup(struct radeon_device *rdev)
|
||
/* enable pcie gen2 link */
|
||
evergreen_pcie_gen2_enable(rdev);
|
||
|
||
+ evergreen_mc_program(rdev);
|
||
+
|
||
if (rdev->flags & RADEON_IS_IGP) {
|
||
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
|
||
r = ni_init_microcode(rdev);
|
||
@@ -1568,7 +1582,6 @@ static int cayman_startup(struct radeon_device *rdev)
|
||
if (r)
|
||
return r;
|
||
|
||
- evergreen_mc_program(rdev);
|
||
r = cayman_pcie_gart_enable(rdev);
|
||
if (r)
|
||
return r;
|
||
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
|
||
index 8c403d9..1555cd6 100644
|
||
--- a/drivers/gpu/drm/radeon/r600.c
|
||
+++ b/drivers/gpu/drm/radeon/r600.c
|
||
@@ -2313,14 +2313,17 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
|
||
struct radeon_fence *fence)
|
||
{
|
||
struct radeon_ring *ring = &rdev->ring[fence->ring];
|
||
+ u32 cp_coher_cntl = PACKET3_TC_ACTION_ENA | PACKET3_VC_ACTION_ENA |
|
||
+ PACKET3_SH_ACTION_ENA;
|
||
+
|
||
+ if (rdev->family >= CHIP_RV770)
|
||
+ cp_coher_cntl |= PACKET3_FULL_CACHE_ENA;
|
||
|
||
if (rdev->wb.use_event) {
|
||
u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
|
||
/* flush read cache over gart */
|
||
radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
|
||
- radeon_ring_write(ring, PACKET3_TC_ACTION_ENA |
|
||
- PACKET3_VC_ACTION_ENA |
|
||
- PACKET3_SH_ACTION_ENA);
|
||
+ radeon_ring_write(ring, cp_coher_cntl);
|
||
radeon_ring_write(ring, 0xFFFFFFFF);
|
||
radeon_ring_write(ring, 0);
|
||
radeon_ring_write(ring, 10); /* poll interval */
|
||
@@ -2334,9 +2337,7 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
|
||
} else {
|
||
/* flush read cache over gart */
|
||
radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
|
||
- radeon_ring_write(ring, PACKET3_TC_ACTION_ENA |
|
||
- PACKET3_VC_ACTION_ENA |
|
||
- PACKET3_SH_ACTION_ENA);
|
||
+ radeon_ring_write(ring, cp_coher_cntl);
|
||
radeon_ring_write(ring, 0xFFFFFFFF);
|
||
radeon_ring_write(ring, 0);
|
||
radeon_ring_write(ring, 10); /* poll interval */
|
||
@@ -2430,6 +2431,8 @@ int r600_startup(struct radeon_device *rdev)
|
||
/* enable pcie gen2 link */
|
||
r600_pcie_gen2_enable(rdev);
|
||
|
||
+ r600_mc_program(rdev);
|
||
+
|
||
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
|
||
r = r600_init_microcode(rdev);
|
||
if (r) {
|
||
@@ -2442,7 +2445,6 @@ int r600_startup(struct radeon_device *rdev)
|
||
if (r)
|
||
return r;
|
||
|
||
- r600_mc_program(rdev);
|
||
if (rdev->flags & RADEON_IS_AGP) {
|
||
r600_agp_enable(rdev);
|
||
} else {
|
||
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
|
||
index b8e12af3..3cd9b0e 100644
|
||
--- a/drivers/gpu/drm/radeon/r600_cs.c
|
||
+++ b/drivers/gpu/drm/radeon/r600_cs.c
|
||
@@ -747,7 +747,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
|
||
if (track->cb_dirty) {
|
||
tmp = track->cb_target_mask;
|
||
for (i = 0; i < 8; i++) {
|
||
- if ((tmp >> (i * 4)) & 0xF) {
|
||
+ u32 format = G_0280A0_FORMAT(track->cb_color_info[i]);
|
||
+
|
||
+ if (format != V_0280A0_COLOR_INVALID &&
|
||
+ (tmp >> (i * 4)) & 0xF) {
|
||
/* at least one component is enabled */
|
||
if (track->cb_color_bo[i] == NULL) {
|
||
dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
|
||
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
|
||
index 0b59206..61ffe3c 100644
|
||
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
|
||
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
|
||
@@ -530,7 +530,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
|
||
WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1);
|
||
} else if (ASIC_IS_DCE3(rdev)) {
|
||
/* TODO */
|
||
- } else if (rdev->family >= CHIP_R600) {
|
||
+ } else if (ASIC_IS_DCE2(rdev)) {
|
||
switch (radeon_encoder->encoder_id) {
|
||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
|
||
WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN,
|
||
@@ -602,7 +602,7 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
|
||
WREG32_P(radeon_encoder->hdmi_config_offset + 0xc, 0, ~0x1);
|
||
} else if (ASIC_IS_DCE32(rdev)) {
|
||
WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1);
|
||
- } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
|
||
+ } else if (ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE3(rdev)) {
|
||
switch (radeon_encoder->encoder_id) {
|
||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
|
||
WREG32_P(AVIVO_TMDSA_CNTL, 0,
|
||
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
|
||
index 12ceb82..02bb238 100644
|
||
--- a/drivers/gpu/drm/radeon/r600d.h
|
||
+++ b/drivers/gpu/drm/radeon/r600d.h
|
||
@@ -873,6 +873,7 @@
|
||
#define PACKET3_INDIRECT_BUFFER 0x32
|
||
#define PACKET3_SURFACE_SYNC 0x43
|
||
# define PACKET3_CB0_DEST_BASE_ENA (1 << 6)
|
||
+# define PACKET3_FULL_CACHE_ENA (1 << 20) /* r7xx+ only */
|
||
# define PACKET3_TC_ACTION_ENA (1 << 23)
|
||
# define PACKET3_VC_ACTION_ENA (1 << 24)
|
||
# define PACKET3_CB_ACTION_ENA (1 << 25)
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
|
||
index c54d295..1ce6743 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
|
||
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
|
||
@@ -463,6 +463,13 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
|
||
}
|
||
}
|
||
|
||
+ /* Fujitsu D3003-S2 board lists DVI-I as DVI-I and VGA */
|
||
+ if ((dev->pdev->device == 0x9805) &&
|
||
+ (dev->pdev->subsystem_vendor == 0x1734) &&
|
||
+ (dev->pdev->subsystem_device == 0x11bd)) {
|
||
+ if (*connector_type == DRM_MODE_CONNECTOR_VGA)
|
||
+ return false;
|
||
+ }
|
||
|
||
return true;
|
||
}
|
||
@@ -2785,6 +2792,10 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
|
||
/* tell the bios not to handle mode switching */
|
||
bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
|
||
|
||
+ /* clear the vbios dpms state */
|
||
+ if (ASIC_IS_DCE4(rdev))
|
||
+ bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE;
|
||
+
|
||
if (rdev->family >= CHIP_R600) {
|
||
WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
|
||
WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
|
||
index 2a2cf0b..428bce6 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c
|
||
+++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
|
||
@@ -202,6 +202,13 @@ static bool radeon_atpx_detect(void)
|
||
has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
|
||
}
|
||
|
||
+ /* some newer PX laptops mark the dGPU as a non-VGA display device */
|
||
+ while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
|
||
+ vga_count++;
|
||
+
|
||
+ has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
|
||
+ }
|
||
+
|
||
if (has_atpx && vga_count == 2) {
|
||
acpi_get_name(radeon_atpx_priv.atpx_handle, ACPI_FULL_PATHNAME, &buffer);
|
||
printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
|
||
index 07d0bcd..cf5dd63 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_combios.c
|
||
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
|
||
@@ -898,10 +898,14 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
|
||
}
|
||
|
||
/* quirks */
|
||
+ /* Radeon 7000 (RV100) */
|
||
+ if (((dev->pdev->device == 0x5159) &&
|
||
+ (dev->pdev->subsystem_vendor == 0x174B) &&
|
||
+ (dev->pdev->subsystem_device == 0x7c28)) ||
|
||
/* Radeon 9100 (R200) */
|
||
- if ((dev->pdev->device == 0x514D) &&
|
||
+ ((dev->pdev->device == 0x514D) &&
|
||
(dev->pdev->subsystem_vendor == 0x174B) &&
|
||
- (dev->pdev->subsystem_device == 0x7149)) {
|
||
+ (dev->pdev->subsystem_device == 0x7149))) {
|
||
/* vbios value is bad, use the default */
|
||
found = 0;
|
||
}
|
||
@@ -1484,6 +1488,9 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
|
||
of_machine_is_compatible("PowerBook6,7")) {
|
||
/* ibook */
|
||
rdev->mode_info.connector_table = CT_IBOOK;
|
||
+ } else if (of_machine_is_compatible("PowerMac3,5")) {
|
||
+ /* PowerMac G4 Silver radeon 7500 */
|
||
+ rdev->mode_info.connector_table = CT_MAC_G4_SILVER;
|
||
} else if (of_machine_is_compatible("PowerMac4,4")) {
|
||
/* emac */
|
||
rdev->mode_info.connector_table = CT_EMAC;
|
||
@@ -1509,6 +1516,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
|
||
(rdev->pdev->subsystem_device == 0x4150)) {
|
||
/* Mac G5 tower 9600 */
|
||
rdev->mode_info.connector_table = CT_MAC_G5_9600;
|
||
+ } else if ((rdev->pdev->device == 0x4c66) &&
|
||
+ (rdev->pdev->subsystem_vendor == 0x1002) &&
|
||
+ (rdev->pdev->subsystem_device == 0x4c66)) {
|
||
+ /* SAM440ep RV250 embedded board */
|
||
+ rdev->mode_info.connector_table = CT_SAM440EP;
|
||
} else
|
||
#endif /* CONFIG_PPC_PMAC */
|
||
#ifdef CONFIG_PPC64
|
||
@@ -2082,6 +2094,115 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
|
||
CONNECTOR_OBJECT_ID_SVIDEO,
|
||
&hpd);
|
||
break;
|
||
+ case CT_SAM440EP:
|
||
+ DRM_INFO("Connector Table: %d (SAM440ep embedded board)\n",
|
||
+ rdev->mode_info.connector_table);
|
||
+ /* LVDS */
|
||
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_NONE_DETECTED, 0, 0);
|
||
+ hpd.hpd = RADEON_HPD_NONE;
|
||
+ radeon_add_legacy_encoder(dev,
|
||
+ radeon_get_encoder_enum(dev,
|
||
+ ATOM_DEVICE_LCD1_SUPPORT,
|
||
+ 0),
|
||
+ ATOM_DEVICE_LCD1_SUPPORT);
|
||
+ radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
|
||
+ DRM_MODE_CONNECTOR_LVDS, &ddc_i2c,
|
||
+ CONNECTOR_OBJECT_ID_LVDS,
|
||
+ &hpd);
|
||
+ /* DVI-I - secondary dac, int tmds */
|
||
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
|
||
+ hpd.hpd = RADEON_HPD_1; /* ??? */
|
||
+ radeon_add_legacy_encoder(dev,
|
||
+ radeon_get_encoder_enum(dev,
|
||
+ ATOM_DEVICE_DFP1_SUPPORT,
|
||
+ 0),
|
||
+ ATOM_DEVICE_DFP1_SUPPORT);
|
||
+ radeon_add_legacy_encoder(dev,
|
||
+ radeon_get_encoder_enum(dev,
|
||
+ ATOM_DEVICE_CRT2_SUPPORT,
|
||
+ 2),
|
||
+ ATOM_DEVICE_CRT2_SUPPORT);
|
||
+ radeon_add_legacy_connector(dev, 1,
|
||
+ ATOM_DEVICE_DFP1_SUPPORT |
|
||
+ ATOM_DEVICE_CRT2_SUPPORT,
|
||
+ DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
|
||
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
|
||
+ &hpd);
|
||
+ /* VGA - primary dac */
|
||
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
|
||
+ hpd.hpd = RADEON_HPD_NONE;
|
||
+ radeon_add_legacy_encoder(dev,
|
||
+ radeon_get_encoder_enum(dev,
|
||
+ ATOM_DEVICE_CRT1_SUPPORT,
|
||
+ 1),
|
||
+ ATOM_DEVICE_CRT1_SUPPORT);
|
||
+ radeon_add_legacy_connector(dev, 2,
|
||
+ ATOM_DEVICE_CRT1_SUPPORT,
|
||
+ DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
|
||
+ CONNECTOR_OBJECT_ID_VGA,
|
||
+ &hpd);
|
||
+ /* TV - TV DAC */
|
||
+ ddc_i2c.valid = false;
|
||
+ hpd.hpd = RADEON_HPD_NONE;
|
||
+ radeon_add_legacy_encoder(dev,
|
||
+ radeon_get_encoder_enum(dev,
|
||
+ ATOM_DEVICE_TV1_SUPPORT,
|
||
+ 2),
|
||
+ ATOM_DEVICE_TV1_SUPPORT);
|
||
+ radeon_add_legacy_connector(dev, 3, ATOM_DEVICE_TV1_SUPPORT,
|
||
+ DRM_MODE_CONNECTOR_SVIDEO,
|
||
+ &ddc_i2c,
|
||
+ CONNECTOR_OBJECT_ID_SVIDEO,
|
||
+ &hpd);
|
||
+ break;
|
||
+ case CT_MAC_G4_SILVER:
|
||
+ DRM_INFO("Connector Table: %d (mac g4 silver)\n",
|
||
+ rdev->mode_info.connector_table);
|
||
+ /* DVI-I - tv dac, int tmds */
|
||
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
|
||
+ hpd.hpd = RADEON_HPD_1; /* ??? */
|
||
+ radeon_add_legacy_encoder(dev,
|
||
+ radeon_get_encoder_enum(dev,
|
||
+ ATOM_DEVICE_DFP1_SUPPORT,
|
||
+ 0),
|
||
+ ATOM_DEVICE_DFP1_SUPPORT);
|
||
+ radeon_add_legacy_encoder(dev,
|
||
+ radeon_get_encoder_enum(dev,
|
||
+ ATOM_DEVICE_CRT2_SUPPORT,
|
||
+ 2),
|
||
+ ATOM_DEVICE_CRT2_SUPPORT);
|
||
+ radeon_add_legacy_connector(dev, 0,
|
||
+ ATOM_DEVICE_DFP1_SUPPORT |
|
||
+ ATOM_DEVICE_CRT2_SUPPORT,
|
||
+ DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
|
||
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
|
||
+ &hpd);
|
||
+ /* VGA - primary dac */
|
||
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
|
||
+ hpd.hpd = RADEON_HPD_NONE;
|
||
+ radeon_add_legacy_encoder(dev,
|
||
+ radeon_get_encoder_enum(dev,
|
||
+ ATOM_DEVICE_CRT1_SUPPORT,
|
||
+ 1),
|
||
+ ATOM_DEVICE_CRT1_SUPPORT);
|
||
+ radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT1_SUPPORT,
|
||
+ DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
|
||
+ CONNECTOR_OBJECT_ID_VGA,
|
||
+ &hpd);
|
||
+ /* TV - TV DAC */
|
||
+ ddc_i2c.valid = false;
|
||
+ hpd.hpd = RADEON_HPD_NONE;
|
||
+ radeon_add_legacy_encoder(dev,
|
||
+ radeon_get_encoder_enum(dev,
|
||
+ ATOM_DEVICE_TV1_SUPPORT,
|
||
+ 2),
|
||
+ ATOM_DEVICE_TV1_SUPPORT);
|
||
+ radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
|
||
+ DRM_MODE_CONNECTOR_SVIDEO,
|
||
+ &ddc_i2c,
|
||
+ CONNECTOR_OBJECT_ID_SVIDEO,
|
||
+ &hpd);
|
||
+ break;
|
||
default:
|
||
DRM_INFO("Connector table: %d (invalid)\n",
|
||
rdev->mode_info.connector_table);
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
|
||
index ab63bcd..9184bbe 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
|
||
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
|
||
@@ -1279,7 +1279,7 @@ bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
|
||
struct radeon_device *rdev = dev->dev_private;
|
||
|
||
if (ASIC_IS_DCE5(rdev) &&
|
||
- (rdev->clock.dp_extclk >= 53900) &&
|
||
+ (rdev->clock.default_dispclk >= 53900) &&
|
||
radeon_connector_encoder_is_hbr2(connector)) {
|
||
return true;
|
||
}
|
||
@@ -1423,6 +1423,24 @@ struct drm_connector_funcs radeon_dp_connector_funcs = {
|
||
.force = radeon_dvi_force,
|
||
};
|
||
|
||
+static const struct drm_connector_funcs radeon_edp_connector_funcs = {
|
||
+ .dpms = drm_helper_connector_dpms,
|
||
+ .detect = radeon_dp_detect,
|
||
+ .fill_modes = drm_helper_probe_single_connector_modes,
|
||
+ .set_property = radeon_lvds_set_property,
|
||
+ .destroy = radeon_dp_connector_destroy,
|
||
+ .force = radeon_dvi_force,
|
||
+};
|
||
+
|
||
+static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {
|
||
+ .dpms = drm_helper_connector_dpms,
|
||
+ .detect = radeon_dp_detect,
|
||
+ .fill_modes = drm_helper_probe_single_connector_modes,
|
||
+ .set_property = radeon_lvds_set_property,
|
||
+ .destroy = radeon_dp_connector_destroy,
|
||
+ .force = radeon_dvi_force,
|
||
+};
|
||
+
|
||
void
|
||
radeon_add_atom_connector(struct drm_device *dev,
|
||
uint32_t connector_id,
|
||
@@ -1514,8 +1532,6 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||
goto failed;
|
||
radeon_dig_connector->igp_lane_info = igp_lane_info;
|
||
radeon_connector->con_priv = radeon_dig_connector;
|
||
- drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
|
||
- drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
|
||
if (i2c_bus->valid) {
|
||
/* add DP i2c bus */
|
||
if (connector_type == DRM_MODE_CONNECTOR_eDP)
|
||
@@ -1532,6 +1548,10 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||
case DRM_MODE_CONNECTOR_VGA:
|
||
case DRM_MODE_CONNECTOR_DVIA:
|
||
default:
|
||
+ drm_connector_init(dev, &radeon_connector->base,
|
||
+ &radeon_dp_connector_funcs, connector_type);
|
||
+ drm_connector_helper_add(&radeon_connector->base,
|
||
+ &radeon_dp_connector_helper_funcs);
|
||
connector->interlace_allowed = true;
|
||
connector->doublescan_allowed = true;
|
||
radeon_connector->dac_load_detect = true;
|
||
@@ -1544,6 +1564,10 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||
case DRM_MODE_CONNECTOR_HDMIA:
|
||
case DRM_MODE_CONNECTOR_HDMIB:
|
||
case DRM_MODE_CONNECTOR_DisplayPort:
|
||
+ drm_connector_init(dev, &radeon_connector->base,
|
||
+ &radeon_dp_connector_funcs, connector_type);
|
||
+ drm_connector_helper_add(&radeon_connector->base,
|
||
+ &radeon_dp_connector_helper_funcs);
|
||
drm_connector_attach_property(&radeon_connector->base,
|
||
rdev->mode_info.underscan_property,
|
||
UNDERSCAN_OFF);
|
||
@@ -1568,6 +1592,10 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||
break;
|
||
case DRM_MODE_CONNECTOR_LVDS:
|
||
case DRM_MODE_CONNECTOR_eDP:
|
||
+ drm_connector_init(dev, &radeon_connector->base,
|
||
+ &radeon_lvds_bridge_connector_funcs, connector_type);
|
||
+ drm_connector_helper_add(&radeon_connector->base,
|
||
+ &radeon_dp_connector_helper_funcs);
|
||
drm_connector_attach_property(&radeon_connector->base,
|
||
dev->mode_config.scaling_mode_property,
|
||
DRM_MODE_SCALE_FULLSCREEN);
|
||
@@ -1731,7 +1759,7 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||
goto failed;
|
||
radeon_dig_connector->igp_lane_info = igp_lane_info;
|
||
radeon_connector->con_priv = radeon_dig_connector;
|
||
- drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
|
||
+ drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type);
|
||
drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
|
||
if (i2c_bus->valid) {
|
||
/* add DP i2c bus */
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
|
||
index 00d9cac..adc9bfd 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_display.c
|
||
+++ b/drivers/gpu/drm/radeon/radeon_display.c
|
||
@@ -709,6 +709,10 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
|
||
struct radeon_device *rdev = dev->dev_private;
|
||
int ret = 0;
|
||
|
||
+ /* don't leak the edid if we already fetched it in detect() */
|
||
+ if (radeon_connector->edid)
|
||
+ goto got_edid;
|
||
+
|
||
/* on hw with routers, select right port */
|
||
if (radeon_connector->router.ddc_valid)
|
||
radeon_router_select_ddc_port(radeon_connector);
|
||
@@ -748,8 +752,10 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
|
||
radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
|
||
}
|
||
if (radeon_connector->edid) {
|
||
+got_edid:
|
||
drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
|
||
ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
|
||
+ drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);
|
||
return ret;
|
||
}
|
||
drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
|
||
index 6076e85..19d68c5 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
|
||
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
|
||
@@ -1020,6 +1020,9 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
|
||
/* Add the default buses */
|
||
void radeon_i2c_init(struct radeon_device *rdev)
|
||
{
|
||
+ if (radeon_hw_i2c)
|
||
+ DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n");
|
||
+
|
||
if (rdev->is_atom_bios)
|
||
radeon_atombios_i2c_init(rdev);
|
||
else
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
|
||
index 3c2628b..9b46238 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_kms.c
|
||
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
|
||
@@ -39,8 +39,12 @@ int radeon_driver_unload_kms(struct drm_device *dev)
|
||
|
||
if (rdev == NULL)
|
||
return 0;
|
||
+ if (rdev->rmmio == NULL)
|
||
+ goto done_free;
|
||
radeon_modeset_fini(rdev);
|
||
radeon_device_fini(rdev);
|
||
+
|
||
+done_free:
|
||
kfree(rdev);
|
||
dev->dev_private = NULL;
|
||
return 0;
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
|
||
index 9760e5a..b44bbf5 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
|
||
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
|
||
@@ -416,6 +416,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
|
||
/* Pin framebuffer & get tilling informations */
|
||
obj = radeon_fb->obj;
|
||
rbo = gem_to_radeon_bo(obj);
|
||
+retry:
|
||
r = radeon_bo_reserve(rbo, false);
|
||
if (unlikely(r != 0))
|
||
return r;
|
||
@@ -424,6 +425,33 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
|
||
&base);
|
||
if (unlikely(r != 0)) {
|
||
radeon_bo_unreserve(rbo);
|
||
+
|
||
+ /* On old GPU like RN50 with little vram pining can fails because
|
||
+ * current fb is taking all space needed. So instead of unpining
|
||
+ * the old buffer after pining the new one, first unpin old one
|
||
+ * and then retry pining new one.
|
||
+ *
|
||
+ * As only master can set mode only master can pin and it is
|
||
+ * unlikely the master client will race with itself especialy
|
||
+ * on those old gpu with single crtc.
|
||
+ *
|
||
+ * We don't shutdown the display controller because new buffer
|
||
+ * will end up in same spot.
|
||
+ */
|
||
+ if (!atomic && fb && fb != crtc->fb) {
|
||
+ struct radeon_bo *old_rbo;
|
||
+ unsigned long nsize, osize;
|
||
+
|
||
+ old_rbo = gem_to_radeon_bo(to_radeon_framebuffer(fb)->obj);
|
||
+ osize = radeon_bo_size(old_rbo);
|
||
+ nsize = radeon_bo_size(rbo);
|
||
+ if (nsize <= osize && !radeon_bo_reserve(old_rbo, false)) {
|
||
+ radeon_bo_unpin(old_rbo);
|
||
+ radeon_bo_unreserve(old_rbo);
|
||
+ fb = NULL;
|
||
+ goto retry;
|
||
+ }
|
||
+ }
|
||
return -EINVAL;
|
||
}
|
||
radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
|
||
index dabfefd..65da706 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_mode.h
|
||
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
|
||
@@ -210,6 +210,8 @@ enum radeon_connector_table {
|
||
CT_RN50_POWER,
|
||
CT_MAC_X800,
|
||
CT_MAC_G5_9600,
|
||
+ CT_SAM440EP,
|
||
+ CT_MAC_G4_SILVER
|
||
};
|
||
|
||
enum radeon_dvo_chip {
|
||
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
|
||
index bf6ca2d..4c5a793 100644
|
||
--- a/drivers/gpu/drm/radeon/radeon_pm.c
|
||
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
|
||
@@ -587,8 +587,10 @@ void radeon_pm_resume(struct radeon_device *rdev)
|
||
rdev->pm.current_clock_mode_index = 0;
|
||
rdev->pm.current_sclk = rdev->pm.default_sclk;
|
||
rdev->pm.current_mclk = rdev->pm.default_mclk;
|
||
- rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
|
||
- rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci;
|
||
+ if (rdev->pm.power_state) {
|
||
+ rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
|
||
+ rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci;
|
||
+ }
|
||
if (rdev->pm.pm_method == PM_METHOD_DYNPM
|
||
&& rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) {
|
||
rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
|
||
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
|
||
index 5248001..739eb0d 100644
|
||
--- a/drivers/gpu/drm/radeon/rs600.c
|
||
+++ b/drivers/gpu/drm/radeon/rs600.c
|
||
@@ -539,8 +539,10 @@ int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
|
||
return -EINVAL;
|
||
}
|
||
addr = addr & 0xFFFFFFFFFFFFF000ULL;
|
||
- addr |= R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED;
|
||
- addr |= R600_PTE_READABLE | R600_PTE_WRITEABLE;
|
||
+ if (addr != rdev->dummy_page.addr)
|
||
+ addr |= R600_PTE_VALID | R600_PTE_READABLE |
|
||
+ R600_PTE_WRITEABLE;
|
||
+ addr |= R600_PTE_SYSTEM | R600_PTE_SNOOPED;
|
||
writeq(addr, ptr + (i * 8));
|
||
return 0;
|
||
}
|
||
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
|
||
index 4a3937f..1ec1255 100644
|
||
--- a/drivers/gpu/drm/radeon/rv770.c
|
||
+++ b/drivers/gpu/drm/radeon/rv770.c
|
||
@@ -1058,6 +1058,8 @@ static int rv770_startup(struct radeon_device *rdev)
|
||
/* enable pcie gen2 link */
|
||
rv770_pcie_gen2_enable(rdev);
|
||
|
||
+ rv770_mc_program(rdev);
|
||
+
|
||
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
|
||
r = r600_init_microcode(rdev);
|
||
if (r) {
|
||
@@ -1070,7 +1072,6 @@ static int rv770_startup(struct radeon_device *rdev)
|
||
if (r)
|
||
return r;
|
||
|
||
- rv770_mc_program(rdev);
|
||
if (rdev->flags & RADEON_IS_AGP) {
|
||
rv770_agp_enable(rdev);
|
||
} else {
|
||
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
|
||
index bd1f18c..e710073 100644
|
||
--- a/drivers/gpu/drm/radeon/si.c
|
||
+++ b/drivers/gpu/drm/radeon/si.c
|
||
@@ -2479,8 +2479,15 @@ static int si_mc_init(struct radeon_device *rdev)
|
||
rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
|
||
rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
|
||
/* size in MB on si */
|
||
- rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
|
||
- rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
|
||
+ tmp = RREG32(CONFIG_MEMSIZE);
|
||
+ /* some boards may have garbage in the upper 16 bits */
|
||
+ if (tmp & 0xffff0000) {
|
||
+ DRM_INFO("Probable bad vram size: 0x%08x\n", tmp);
|
||
+ if (tmp & 0xffff)
|
||
+ tmp &= 0xffff;
|
||
+ }
|
||
+ rdev->mc.mc_vram_size = tmp * 1024ULL * 1024ULL;
|
||
+ rdev->mc.real_vram_size = rdev->mc.mc_vram_size;
|
||
rdev->mc.visible_vram_size = rdev->mc.aper_size;
|
||
si_vram_gtt_location(rdev, &rdev->mc);
|
||
radeon_update_bandwidth_info(rdev);
|
||
@@ -3827,6 +3834,8 @@ static int si_startup(struct radeon_device *rdev)
|
||
struct radeon_ring *ring;
|
||
int r;
|
||
|
||
+ si_mc_program(rdev);
|
||
+
|
||
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
|
||
!rdev->rlc_fw || !rdev->mc_fw) {
|
||
r = si_init_microcode(rdev);
|
||
@@ -3846,7 +3855,6 @@ static int si_startup(struct radeon_device *rdev)
|
||
if (r)
|
||
return r;
|
||
|
||
- si_mc_program(rdev);
|
||
r = si_pcie_gart_enable(rdev);
|
||
if (r)
|
||
return r;
|
||
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
|
||
index 1767ae7..a9fcbe4 100644
|
||
--- a/drivers/gpu/drm/radeon/sid.h
|
||
+++ b/drivers/gpu/drm/radeon/sid.h
|
||
@@ -165,7 +165,7 @@
|
||
#define NOOFGROUPS_SHIFT 12
|
||
#define NOOFGROUPS_MASK 0x00001000
|
||
|
||
-#define MC_SEQ_TRAIN_WAKEUP_CNTL 0x2808
|
||
+#define MC_SEQ_TRAIN_WAKEUP_CNTL 0x28e8
|
||
#define TRAIN_DONE_D0 (1 << 30)
|
||
#define TRAIN_DONE_D1 (1 << 31)
|
||
|
||
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
|
||
index 8b73ae8..a67e61b 100644
|
||
--- a/drivers/gpu/drm/ttm/ttm_bo.c
|
||
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
|
||
@@ -430,9 +430,11 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
|
||
|
||
moved:
|
||
if (bo->evicted) {
|
||
- ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
|
||
- if (ret)
|
||
- pr_err("Can not flush read caches\n");
|
||
+ if (bdev->driver->invalidate_caches) {
|
||
+ ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
|
||
+ if (ret)
|
||
+ pr_err("Can not flush read caches\n");
|
||
+ }
|
||
bo->evicted = false;
|
||
}
|
||
|
||
@@ -1089,24 +1091,32 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
|
||
return ret;
|
||
}
|
||
|
||
-static int ttm_bo_mem_compat(struct ttm_placement *placement,
|
||
- struct ttm_mem_reg *mem)
|
||
+static bool ttm_bo_mem_compat(struct ttm_placement *placement,
|
||
+ struct ttm_mem_reg *mem,
|
||
+ uint32_t *new_flags)
|
||
{
|
||
int i;
|
||
|
||
if (mem->mm_node && placement->lpfn != 0 &&
|
||
(mem->start < placement->fpfn ||
|
||
mem->start + mem->num_pages > placement->lpfn))
|
||
- return -1;
|
||
+ return false;
|
||
|
||
for (i = 0; i < placement->num_placement; i++) {
|
||
- if ((placement->placement[i] & mem->placement &
|
||
- TTM_PL_MASK_CACHING) &&
|
||
- (placement->placement[i] & mem->placement &
|
||
- TTM_PL_MASK_MEM))
|
||
- return i;
|
||
+ *new_flags = placement->placement[i];
|
||
+ if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) &&
|
||
+ (*new_flags & mem->placement & TTM_PL_MASK_MEM))
|
||
+ return true;
|
||
}
|
||
- return -1;
|
||
+
|
||
+ for (i = 0; i < placement->num_busy_placement; i++) {
|
||
+ *new_flags = placement->busy_placement[i];
|
||
+ if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) &&
|
||
+ (*new_flags & mem->placement & TTM_PL_MASK_MEM))
|
||
+ return true;
|
||
+ }
|
||
+
|
||
+ return false;
|
||
}
|
||
|
||
int ttm_bo_validate(struct ttm_buffer_object *bo,
|
||
@@ -1115,6 +1125,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
|
||
bool no_wait_gpu)
|
||
{
|
||
int ret;
|
||
+ uint32_t new_flags;
|
||
|
||
BUG_ON(!atomic_read(&bo->reserved));
|
||
/* Check that range is valid */
|
||
@@ -1125,8 +1136,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
|
||
/*
|
||
* Check whether we need to move buffer.
|
||
*/
|
||
- ret = ttm_bo_mem_compat(placement, &bo->mem);
|
||
- if (ret < 0) {
|
||
+ if (!ttm_bo_mem_compat(placement, &bo->mem, &new_flags)) {
|
||
ret = ttm_bo_move_buffer(bo, placement, interruptible, no_wait_reserve, no_wait_gpu);
|
||
if (ret)
|
||
return ret;
|
||
@@ -1135,7 +1145,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
|
||
* Use the access and other non-mapping-related flag bits from
|
||
* the compatible memory placement flags to the active flags
|
||
*/
|
||
- ttm_flag_masked(&bo->mem.placement, placement->placement[ret],
|
||
+ ttm_flag_masked(&bo->mem.placement, new_flags,
|
||
~TTM_PL_MASK_MEMTYPE);
|
||
}
|
||
/*
|
||
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
|
||
index f8187ea..2d69262 100644
|
||
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
|
||
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
|
||
@@ -342,7 +342,9 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
|
||
if (old_iomap == NULL && ttm == NULL)
|
||
goto out2;
|
||
|
||
- if (ttm->state == tt_unpopulated) {
|
||
+ /* TTM might be null for moves within the same region.
|
||
+ */
|
||
+ if (ttm && ttm->state == tt_unpopulated) {
|
||
ret = ttm->bdev->driver->ttm_tt_populate(ttm);
|
||
if (ret)
|
||
goto out1;
|
||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
|
||
index 3c447bf..7fc3dc7 100644
|
||
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
|
||
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
|
||
@@ -147,7 +147,7 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var,
|
||
}
|
||
|
||
if (!vmw_kms_validate_mode_vram(vmw_priv,
|
||
- info->fix.line_length,
|
||
+ var->xres * var->bits_per_pixel/8,
|
||
var->yoffset + var->yres)) {
|
||
DRM_ERROR("Requested geom can not fit in framebuffer\n");
|
||
return -EINVAL;
|
||
@@ -162,6 +162,8 @@ static int vmw_fb_set_par(struct fb_info *info)
|
||
struct vmw_private *vmw_priv = par->vmw_priv;
|
||
int ret;
|
||
|
||
+ info->fix.line_length = info->var.xres * info->var.bits_per_pixel/8;
|
||
+
|
||
ret = vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres,
|
||
info->fix.line_length,
|
||
par->bpp, par->depth);
|
||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
|
||
index a0c2f12..decca82 100644
|
||
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
|
||
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
|
||
@@ -163,8 +163,9 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
|
||
|
||
mutex_lock(&dev_priv->hw_mutex);
|
||
|
||
+ vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
|
||
while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0)
|
||
- vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
|
||
+ ;
|
||
|
||
dev_priv->last_read_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
|
||
|
||
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
|
||
index 899c712..ddb83d3 100644
|
||
--- a/drivers/hid/hid-apple.c
|
||
+++ b/drivers/hid/hid-apple.c
|
||
@@ -48,6 +48,12 @@ module_param(iso_layout, uint, 0644);
|
||
MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. "
|
||
"(0 = disabled, [1] = enabled)");
|
||
|
||
+static unsigned int swap_opt_cmd = 0;
|
||
+module_param(swap_opt_cmd, uint, 0644);
|
||
+MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\") keys. "
|
||
+ "(For people who want to keep Windows PC keyboard muscle memory. "
|
||
+ "[0] = as-is, Mac layout. 1 = swapped, Windows layout.)");
|
||
+
|
||
struct apple_sc {
|
||
unsigned long quirks;
|
||
unsigned int fn_on;
|
||
@@ -152,6 +158,14 @@ static const struct apple_key_translation apple_iso_keyboard[] = {
|
||
{ }
|
||
};
|
||
|
||
+static const struct apple_key_translation swapped_option_cmd_keys[] = {
|
||
+ { KEY_LEFTALT, KEY_LEFTMETA },
|
||
+ { KEY_LEFTMETA, KEY_LEFTALT },
|
||
+ { KEY_RIGHTALT, KEY_RIGHTMETA },
|
||
+ { KEY_RIGHTMETA,KEY_RIGHTALT },
|
||
+ { }
|
||
+};
|
||
+
|
||
static const struct apple_key_translation *apple_find_translation(
|
||
const struct apple_key_translation *table, u16 from)
|
||
{
|
||
@@ -244,6 +258,14 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||
}
|
||
}
|
||
|
||
+ if (swap_opt_cmd) {
|
||
+ trans = apple_find_translation(swapped_option_cmd_keys, usage->code);
|
||
+ if (trans) {
|
||
+ input_event(input, usage->type, trans->to, value);
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
@@ -458,6 +480,9 @@ static const struct hid_device_id apple_devices[] = {
|
||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
|
||
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
|
||
APPLE_ISO_KEYBOARD },
|
||
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
|
||
+ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
|
||
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
|
||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
|
||
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
|
||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
|
||
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
|
||
index 888ece6..f870bb3 100644
|
||
--- a/drivers/hid/hid-cherry.c
|
||
+++ b/drivers/hid/hid-cherry.c
|
||
@@ -29,7 +29,7 @@
|
||
static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||
unsigned int *rsize)
|
||
{
|
||
- if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
|
||
+ if (*rsize >= 18 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
|
||
hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n");
|
||
rdesc[11] = rdesc[16] = 0xff;
|
||
rdesc[12] = rdesc[17] = 0x03;
|
||
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
||
index 865ca21..39f3296 100644
|
||
--- a/drivers/hid/hid-core.c
|
||
+++ b/drivers/hid/hid-core.c
|
||
@@ -222,9 +222,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
|
||
{
|
||
struct hid_report *report;
|
||
struct hid_field *field;
|
||
- int usages;
|
||
+ unsigned usages;
|
||
unsigned offset;
|
||
- int i;
|
||
+ unsigned i;
|
||
|
||
report = hid_register_report(parser->device, report_type, parser->global.report_id);
|
||
if (!report) {
|
||
@@ -244,7 +244,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
|
||
if (!parser->local.usage_index) /* Ignore padding fields */
|
||
return 0;
|
||
|
||
- usages = max_t(int, parser->local.usage_index, parser->global.report_count);
|
||
+ usages = max_t(unsigned, parser->local.usage_index,
|
||
+ parser->global.report_count);
|
||
|
||
field = hid_register_field(report, usages, parser->global.report_count);
|
||
if (!field)
|
||
@@ -255,7 +256,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
|
||
field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
|
||
|
||
for (i = 0; i < usages; i++) {
|
||
- int j = i;
|
||
+ unsigned j = i;
|
||
/* Duplicate the last usage we parsed if we have excess values */
|
||
if (i >= parser->local.usage_index)
|
||
j = parser->local.usage_index - 1;
|
||
@@ -860,7 +861,17 @@ struct hid_report *hid_validate_values(struct hid_device *hid,
|
||
* ->numbered being checked, which may not always be the case when
|
||
* drivers go to access report values.
|
||
*/
|
||
- report = hid->report_enum[type].report_id_hash[id];
|
||
+ if (id == 0) {
|
||
+ /*
|
||
+ * Validating on id 0 means we should examine the first
|
||
+ * report in the list.
|
||
+ */
|
||
+ report = list_entry(
|
||
+ hid->report_enum[type].report_list.next,
|
||
+ struct hid_report, list);
|
||
+ } else {
|
||
+ report = hid->report_enum[type].report_id_hash[id];
|
||
+ }
|
||
if (!report) {
|
||
hid_err(hid, "missing %s %u\n", hid_report_names[type], id);
|
||
return NULL;
|
||
@@ -1099,7 +1110,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
|
||
return report;
|
||
}
|
||
|
||
-void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||
int interrupt)
|
||
{
|
||
struct hid_report_enum *report_enum = hid->report_enum + type;
|
||
@@ -1107,10 +1118,11 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||
unsigned int a;
|
||
int rsize, csize = size;
|
||
u8 *cdata = data;
|
||
+ int ret = 0;
|
||
|
||
report = hid_get_report(report_enum, data);
|
||
if (!report)
|
||
- return;
|
||
+ goto out;
|
||
|
||
if (report_enum->numbered) {
|
||
cdata++;
|
||
@@ -1130,14 +1142,19 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||
|
||
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
|
||
hid->hiddev_report_event(hid, report);
|
||
- if (hid->claimed & HID_CLAIMED_HIDRAW)
|
||
- hidraw_report_event(hid, data, size);
|
||
+ if (hid->claimed & HID_CLAIMED_HIDRAW) {
|
||
+ ret = hidraw_report_event(hid, data, size);
|
||
+ if (ret)
|
||
+ goto out;
|
||
+ }
|
||
|
||
for (a = 0; a < report->maxfield; a++)
|
||
hid_input_field(hid, report->field[a], cdata, interrupt);
|
||
|
||
if (hid->claimed & HID_CLAIMED_INPUT)
|
||
hidinput_report_event(hid, report);
|
||
+out:
|
||
+ return ret;
|
||
}
|
||
EXPORT_SYMBOL_GPL(hid_report_raw_event);
|
||
|
||
@@ -1214,7 +1231,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
|
||
}
|
||
}
|
||
|
||
- hid_report_raw_event(hid, type, data, size, interrupt);
|
||
+ ret = hid_report_raw_event(hid, type, data, size, interrupt);
|
||
|
||
unlock:
|
||
up(&hid->driver_lock);
|
||
@@ -1612,6 +1629,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
|
||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
|
||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
|
||
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) },
|
||
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
|
||
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
|
||
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
|
||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
||
index 69e3e3d..e7089e9 100644
|
||
--- a/drivers/hid/hid-ids.h
|
||
+++ b/drivers/hid/hid-ids.h
|
||
@@ -293,6 +293,12 @@
|
||
#define USB_VENDOR_ID_FRUCTEL 0x25B6
|
||
#define USB_DEVICE_ID_GAMETEL_MT_MODE 0x0002
|
||
|
||
+#define USB_VENDOR_ID_FORMOSA 0x147a
|
||
+#define USB_DEVICE_ID_FORMOSA_IR_RECEIVER 0xe03e
|
||
+
|
||
+#define USB_VENDOR_ID_FREESCALE 0x15A2
|
||
+#define USB_DEVICE_ID_FREESCALE_MX28 0x004F
|
||
+
|
||
#define USB_VENDOR_ID_GAMERON 0x0810
|
||
#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
|
||
#define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002
|
||
@@ -553,6 +559,9 @@
|
||
#define USB_VENDOR_ID_MONTEREY 0x0566
|
||
#define USB_DEVICE_ID_GENIUS_KB29E 0x3004
|
||
|
||
+#define USB_VENDOR_ID_MSI 0x1770
|
||
+#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00
|
||
+
|
||
#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
|
||
#define USB_DEVICE_ID_N_S_HARMONY 0xc359
|
||
|
||
@@ -680,6 +689,7 @@
|
||
|
||
#define USB_VENDOR_ID_SONY 0x054c
|
||
#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
|
||
+#define USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE 0x0374
|
||
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
|
||
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
|
||
|
||
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
|
||
index 6c3e190..e783e5e 100644
|
||
--- a/drivers/hid/hid-input.c
|
||
+++ b/drivers/hid/hid-input.c
|
||
@@ -459,6 +459,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||
if (field->flags & HID_MAIN_ITEM_CONSTANT)
|
||
goto ignore;
|
||
|
||
+ /* Ignore if report count is out of bounds. */
|
||
+ if (field->report_count < 1)
|
||
+ goto ignore;
|
||
+
|
||
/* only LED usages are supported in output fields */
|
||
if (field->report_type == HID_OUTPUT_REPORT &&
|
||
(usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
|
||
@@ -1199,7 +1203,12 @@ static void report_features(struct hid_device *hid)
|
||
|
||
rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
|
||
list_for_each_entry(rep, &rep_enum->report_list, list)
|
||
- for (i = 0; i < rep->maxfield; i++)
|
||
+ for (i = 0; i < rep->maxfield; i++) {
|
||
+
|
||
+ /* Ignore if report count is out of bounds. */
|
||
+ if (rep->field[i]->report_count < 1)
|
||
+ continue;
|
||
+
|
||
for (j = 0; j < rep->field[i]->maxusage; j++) {
|
||
/* Verify if Battery Strength feature is available */
|
||
hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
|
||
@@ -1208,6 +1217,7 @@ static void report_features(struct hid_device *hid)
|
||
drv->feature_mapping(hid, rep->field[i],
|
||
rep->field[i]->usage + j);
|
||
}
|
||
+ }
|
||
}
|
||
|
||
/*
|
||
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
|
||
index b4f0d82..d7118f8 100644
|
||
--- a/drivers/hid/hid-kye.c
|
||
+++ b/drivers/hid/hid-kye.c
|
||
@@ -282,7 +282,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||
* - change the button usage range to 4-7 for the extra
|
||
* buttons
|
||
*/
|
||
- if (*rsize >= 74 &&
|
||
+ if (*rsize >= 75 &&
|
||
rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
|
||
rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
|
||
rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
|
||
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
|
||
index e7a7bd1..cb01e67 100644
|
||
--- a/drivers/hid/hid-lg.c
|
||
+++ b/drivers/hid/hid-lg.c
|
||
@@ -111,7 +111,7 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||
{
|
||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||
|
||
- if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
|
||
+ if ((quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
|
||
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
|
||
hid_info(hdev,
|
||
"fixing up Logitech keyboard report descriptor\n");
|
||
@@ -120,7 +120,7 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||
}
|
||
if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
|
||
rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
|
||
- rdesc[49] == 0x81 && rdesc[50] == 0x06) {
|
||
+ rdesc[49] == 0x81 && rdesc[51] == 0x06) {
|
||
hid_info(hdev,
|
||
"fixing up rel/abs in Logitech report descriptor\n");
|
||
rdesc[33] = rdesc[50] = 0x02;
|
||
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
|
||
index 2652846..f009ab2 100644
|
||
--- a/drivers/hid/hid-logitech-dj.c
|
||
+++ b/drivers/hid/hid-logitech-dj.c
|
||
@@ -230,13 +230,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
||
return;
|
||
}
|
||
|
||
- if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
|
||
- (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
|
||
- dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n",
|
||
- __func__, dj_report->device_index);
|
||
- return;
|
||
- }
|
||
-
|
||
if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
|
||
/* The device is already known. No need to reallocate it. */
|
||
dbg_hid("%s: device is already known\n", __func__);
|
||
@@ -474,28 +467,38 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
|
||
|
||
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
||
{
|
||
- struct dj_report dj_report;
|
||
+ struct dj_report *dj_report;
|
||
+ int retval;
|
||
|
||
- memset(&dj_report, 0, sizeof(dj_report));
|
||
- dj_report.report_id = REPORT_ID_DJ_SHORT;
|
||
- dj_report.device_index = 0xFF;
|
||
- dj_report.report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES;
|
||
- return logi_dj_recv_send_report(djrcv_dev, &dj_report);
|
||
+ dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
|
||
+ if (!dj_report)
|
||
+ return -ENOMEM;
|
||
+ dj_report->report_id = REPORT_ID_DJ_SHORT;
|
||
+ dj_report->device_index = 0xFF;
|
||
+ dj_report->report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES;
|
||
+ retval = logi_dj_recv_send_report(djrcv_dev, dj_report);
|
||
+ kfree(dj_report);
|
||
+ return retval;
|
||
}
|
||
|
||
|
||
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
|
||
unsigned timeout)
|
||
{
|
||
- struct dj_report dj_report;
|
||
+ struct dj_report *dj_report;
|
||
+ int retval;
|
||
|
||
- memset(&dj_report, 0, sizeof(dj_report));
|
||
- dj_report.report_id = REPORT_ID_DJ_SHORT;
|
||
- dj_report.device_index = 0xFF;
|
||
- dj_report.report_type = REPORT_TYPE_CMD_SWITCH;
|
||
- dj_report.report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x3F;
|
||
- dj_report.report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = (u8)timeout;
|
||
- return logi_dj_recv_send_report(djrcv_dev, &dj_report);
|
||
+ dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
|
||
+ if (!dj_report)
|
||
+ return -ENOMEM;
|
||
+ dj_report->report_id = REPORT_ID_DJ_SHORT;
|
||
+ dj_report->device_index = 0xFF;
|
||
+ dj_report->report_type = REPORT_TYPE_CMD_SWITCH;
|
||
+ dj_report->report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x3F;
|
||
+ dj_report->report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = (u8)timeout;
|
||
+ retval = logi_dj_recv_send_report(djrcv_dev, dj_report);
|
||
+ kfree(dj_report);
|
||
+ return retval;
|
||
}
|
||
|
||
|
||
@@ -678,7 +681,6 @@ static int logi_dj_raw_event(struct hid_device *hdev,
|
||
struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
|
||
struct dj_report *dj_report = (struct dj_report *) data;
|
||
unsigned long flags;
|
||
- bool report_processed = false;
|
||
|
||
dbg_hid("%s, size:%d\n", __func__, size);
|
||
|
||
@@ -706,27 +708,41 @@ static int logi_dj_raw_event(struct hid_device *hdev,
|
||
* anything else with it.
|
||
*/
|
||
|
||
+ /* case 1) */
|
||
+ if (data[0] != REPORT_ID_DJ_SHORT)
|
||
+ return false;
|
||
+
|
||
+ if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
|
||
+ (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
|
||
+ /*
|
||
+ * Device index is wrong, bail out.
|
||
+ * This driver can ignore safely the receiver notifications,
|
||
+ * so ignore those reports too.
|
||
+ */
|
||
+ if (dj_report->device_index != DJ_RECEIVER_INDEX)
|
||
+ dev_err(&hdev->dev, "%s: invalid device index:%d\n",
|
||
+ __func__, dj_report->device_index);
|
||
+ return false;
|
||
+ }
|
||
+
|
||
spin_lock_irqsave(&djrcv_dev->lock, flags);
|
||
- if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
|
||
- switch (dj_report->report_type) {
|
||
- case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
|
||
- case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
|
||
- logi_dj_recv_queue_notification(djrcv_dev, dj_report);
|
||
- break;
|
||
- case REPORT_TYPE_NOTIF_CONNECTION_STATUS:
|
||
- if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
|
||
- STATUS_LINKLOSS) {
|
||
- logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
|
||
- }
|
||
- break;
|
||
- default:
|
||
- logi_dj_recv_forward_report(djrcv_dev, dj_report);
|
||
+ switch (dj_report->report_type) {
|
||
+ case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
|
||
+ case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
|
||
+ logi_dj_recv_queue_notification(djrcv_dev, dj_report);
|
||
+ break;
|
||
+ case REPORT_TYPE_NOTIF_CONNECTION_STATUS:
|
||
+ if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
|
||
+ STATUS_LINKLOSS) {
|
||
+ logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
|
||
}
|
||
- report_processed = true;
|
||
+ break;
|
||
+ default:
|
||
+ logi_dj_recv_forward_report(djrcv_dev, dj_report);
|
||
}
|
||
spin_unlock_irqrestore(&djrcv_dev->lock, flags);
|
||
|
||
- return report_processed;
|
||
+ return true;
|
||
}
|
||
|
||
static int logi_dj_probe(struct hid_device *hdev,
|
||
diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h
|
||
index 4a40003..daeb0aa 100644
|
||
--- a/drivers/hid/hid-logitech-dj.h
|
||
+++ b/drivers/hid/hid-logitech-dj.h
|
||
@@ -27,6 +27,7 @@
|
||
|
||
#define DJ_MAX_PAIRED_DEVICES 6
|
||
#define DJ_MAX_NUMBER_NOTIFICATIONS 8
|
||
+#define DJ_RECEIVER_INDEX 0
|
||
#define DJ_DEVICE_INDEX_MIN 1
|
||
#define DJ_DEVICE_INDEX_MAX 6
|
||
|
||
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
|
||
index 8427463..05643cf 100644
|
||
--- a/drivers/hid/hid-magicmouse.c
|
||
+++ b/drivers/hid/hid-magicmouse.c
|
||
@@ -308,6 +308,11 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
||
if (size < 4 || ((size - 4) % 9) != 0)
|
||
return 0;
|
||
npoints = (size - 4) / 9;
|
||
+ if (npoints > 15) {
|
||
+ hid_warn(hdev, "invalid size value (%d) for TRACKPAD_REPORT_ID\n",
|
||
+ size);
|
||
+ return 0;
|
||
+ }
|
||
msc->ntouches = 0;
|
||
for (ii = 0; ii < npoints; ii++)
|
||
magicmouse_emit_touch(msc, ii, data + ii * 9 + 4);
|
||
@@ -331,6 +336,11 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
||
if (size < 6 || ((size - 6) % 8) != 0)
|
||
return 0;
|
||
npoints = (size - 6) / 8;
|
||
+ if (npoints > 15) {
|
||
+ hid_warn(hdev, "invalid size value (%d) for MOUSE_REPORT_ID\n",
|
||
+ size);
|
||
+ return 0;
|
||
+ }
|
||
msc->ntouches = 0;
|
||
for (ii = 0; ii < npoints; ii++)
|
||
magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
|
||
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
|
||
index dedf757..eb0271e 100644
|
||
--- a/drivers/hid/hid-monterey.c
|
||
+++ b/drivers/hid/hid-monterey.c
|
||
@@ -25,7 +25,7 @@
|
||
static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||
unsigned int *rsize)
|
||
{
|
||
- if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
|
||
+ if (*rsize >= 31 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
|
||
hid_info(hdev, "fixing up button/consumer in HID report descriptor\n");
|
||
rdesc[30] = 0x0c;
|
||
}
|
||
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
|
||
index 7a180b9..0e98570 100644
|
||
--- a/drivers/hid/hid-multitouch.c
|
||
+++ b/drivers/hid/hid-multitouch.c
|
||
@@ -82,8 +82,8 @@ struct mt_device {
|
||
multitouch fields */
|
||
unsigned last_field_index; /* last field index of the report */
|
||
unsigned last_slot_field; /* the last field of a slot */
|
||
- __s8 inputmode; /* InputMode HID feature, -1 if non-existent */
|
||
- __s8 maxcontact_report_id; /* Maximum Contact Number HID feature,
|
||
+ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */
|
||
+ __s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
|
||
-1 if non-existent */
|
||
__u8 num_received; /* how many contacts we received */
|
||
__u8 num_expected; /* expected last contact index */
|
||
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
|
||
index f1ea3ff..99f317a 100644
|
||
--- a/drivers/hid/hid-petalynx.c
|
||
+++ b/drivers/hid/hid-petalynx.c
|
||
@@ -26,7 +26,7 @@
|
||
static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||
unsigned int *rsize)
|
||
{
|
||
- if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
|
||
+ if (*rsize >= 62 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
|
||
rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
|
||
rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
|
||
hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
|
||
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
|
||
index 45c3433..4e37b1f 100644
|
||
--- a/drivers/hid/hid-picolcd.c
|
||
+++ b/drivers/hid/hid-picolcd.c
|
||
@@ -1424,7 +1424,7 @@ static ssize_t picolcd_operation_mode_store(struct device *dev,
|
||
buf += 10;
|
||
cnt -= 10;
|
||
}
|
||
- if (!report)
|
||
+ if (!report || report->maxfield != 1)
|
||
return -EINVAL;
|
||
|
||
while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))
|
||
@@ -2370,6 +2370,12 @@ static int picolcd_raw_event(struct hid_device *hdev,
|
||
if (!data)
|
||
return 1;
|
||
|
||
+ if (size > 64) {
|
||
+ hid_warn(hdev, "invalid size value (%d) for picolcd raw event\n",
|
||
+ size);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
if (report->id == REPORT_KEY_STATE) {
|
||
if (data->input_keys)
|
||
ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
|
||
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
|
||
index 112d934..1973cff 100644
|
||
--- a/drivers/hid/hid-roccat-kovaplus.c
|
||
+++ b/drivers/hid/hid-roccat-kovaplus.c
|
||
@@ -623,9 +623,13 @@ static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus,
|
||
break;
|
||
case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI:
|
||
kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1);
|
||
+ break;
|
||
case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY:
|
||
kovaplus->actual_x_sensitivity = button_report->data1;
|
||
kovaplus->actual_y_sensitivity = button_report->data2;
|
||
+ break;
|
||
+ default:
|
||
+ break;
|
||
}
|
||
}
|
||
|
||
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
|
||
index 5cd25bd..4142c21 100644
|
||
--- a/drivers/hid/hid-sony.c
|
||
+++ b/drivers/hid/hid-sony.c
|
||
@@ -44,9 +44,19 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||
{
|
||
struct sony_sc *sc = hid_get_drvdata(hdev);
|
||
|
||
- if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
|
||
- *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
|
||
- hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n");
|
||
+ /*
|
||
+ * Some Sony RF receivers wrongly declare the mouse pointer as a
|
||
+ * a constant non-data variable.
|
||
+ */
|
||
+ if ((sc->quirks & VAIO_RDESC_CONSTANT) && *rsize >= 56 &&
|
||
+ /* usage page: generic desktop controls */
|
||
+ /* rdesc[0] == 0x05 && rdesc[1] == 0x01 && */
|
||
+ /* usage: mouse */
|
||
+ rdesc[2] == 0x09 && rdesc[3] == 0x02 &&
|
||
+ /* input (usage page for x,y axes): constant, variable, relative */
|
||
+ rdesc[54] == 0x81 && rdesc[55] == 0x07) {
|
||
+ hid_info(hdev, "Fixing up Sony RF Receiver report descriptor\n");
|
||
+ /* input: data, variable, relative */
|
||
rdesc[55] = 0x06;
|
||
}
|
||
|
||
@@ -218,6 +228,8 @@ static const struct hid_device_id sony_devices[] = {
|
||
.driver_data = SIXAXIS_CONTROLLER_BT },
|
||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
|
||
.driver_data = VAIO_RDESC_CONSTANT },
|
||
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE),
|
||
+ .driver_data = VAIO_RDESC_CONSTANT },
|
||
{ }
|
||
};
|
||
MODULE_DEVICE_TABLE(hid, sony_devices);
|
||
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
|
||
index d484a00..3d6ae7b 100644
|
||
--- a/drivers/hid/hid-sunplus.c
|
||
+++ b/drivers/hid/hid-sunplus.c
|
||
@@ -25,7 +25,7 @@
|
||
static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||
unsigned int *rsize)
|
||
{
|
||
- if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
|
||
+ if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
|
||
rdesc[106] == 0x03) {
|
||
hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
|
||
rdesc[105] = rdesc[110] = 0x03;
|
||
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
|
||
index cf7d6d5..9e50f61 100644
|
||
--- a/drivers/hid/hidraw.c
|
||
+++ b/drivers/hid/hidraw.c
|
||
@@ -87,13 +87,16 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
|
||
len = list->buffer[list->tail].len > count ?
|
||
count : list->buffer[list->tail].len;
|
||
|
||
- if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
|
||
- ret = -EFAULT;
|
||
- goto out;
|
||
+ if (list->buffer[list->tail].value) {
|
||
+ if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
|
||
+ ret = -EFAULT;
|
||
+ goto out;
|
||
+ }
|
||
+ ret = len;
|
||
}
|
||
- ret = len;
|
||
|
||
kfree(list->buffer[list->tail].value);
|
||
+ list->buffer[list->tail].value = NULL;
|
||
list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
|
||
}
|
||
out:
|
||
@@ -110,7 +113,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
|
||
__u8 *buf;
|
||
int ret = 0;
|
||
|
||
- if (!hidraw_table[minor]) {
|
||
+ if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
|
||
ret = -ENODEV;
|
||
goto out;
|
||
}
|
||
@@ -258,7 +261,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
|
||
}
|
||
|
||
mutex_lock(&minors_lock);
|
||
- if (!hidraw_table[minor]) {
|
||
+ if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
|
||
err = -ENODEV;
|
||
goto out_unlock;
|
||
}
|
||
@@ -292,35 +295,38 @@ static int hidraw_open(struct inode *inode, struct file *file)
|
||
|
||
}
|
||
|
||
+static void drop_ref(struct hidraw *hidraw, int exists_bit)
|
||
+{
|
||
+ if (exists_bit) {
|
||
+ hid_hw_close(hidraw->hid);
|
||
+ hidraw->exist = 0;
|
||
+ if (hidraw->open)
|
||
+ wake_up_interruptible(&hidraw->wait);
|
||
+ } else {
|
||
+ --hidraw->open;
|
||
+ }
|
||
+
|
||
+ if (!hidraw->open && !hidraw->exist) {
|
||
+ device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
|
||
+ hidraw_table[hidraw->minor] = NULL;
|
||
+ kfree(hidraw);
|
||
+ }
|
||
+}
|
||
+
|
||
static int hidraw_release(struct inode * inode, struct file * file)
|
||
{
|
||
unsigned int minor = iminor(inode);
|
||
- struct hidraw *dev;
|
||
struct hidraw_list *list = file->private_data;
|
||
- int ret;
|
||
|
||
mutex_lock(&minors_lock);
|
||
- if (!hidraw_table[minor]) {
|
||
- ret = -ENODEV;
|
||
- goto unlock;
|
||
- }
|
||
|
||
list_del(&list->node);
|
||
- dev = hidraw_table[minor];
|
||
- if (!--dev->open) {
|
||
- if (list->hidraw->exist) {
|
||
- hid_hw_power(dev->hid, PM_HINT_NORMAL);
|
||
- hid_hw_close(dev->hid);
|
||
- } else {
|
||
- kfree(list->hidraw);
|
||
- }
|
||
- }
|
||
kfree(list);
|
||
- ret = 0;
|
||
-unlock:
|
||
- mutex_unlock(&minors_lock);
|
||
|
||
- return ret;
|
||
+ drop_ref(hidraw_table[minor], 0);
|
||
+
|
||
+ mutex_unlock(&minors_lock);
|
||
+ return 0;
|
||
}
|
||
|
||
static long hidraw_ioctl(struct file *file, unsigned int cmd,
|
||
@@ -437,19 +443,29 @@ static const struct file_operations hidraw_ops = {
|
||
.llseek = noop_llseek,
|
||
};
|
||
|
||
-void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
|
||
+int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
|
||
{
|
||
struct hidraw *dev = hid->hidraw;
|
||
struct hidraw_list *list;
|
||
+ int ret = 0;
|
||
|
||
list_for_each_entry(list, &dev->list, node) {
|
||
- list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
|
||
+ int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
|
||
+
|
||
+ if (new_head == list->tail)
|
||
+ continue;
|
||
+
|
||
+ if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
|
||
+ ret = -ENOMEM;
|
||
+ break;
|
||
+ }
|
||
list->buffer[list->head].len = len;
|
||
- list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
|
||
+ list->head = new_head;
|
||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||
}
|
||
|
||
wake_up_interruptible(&dev->wait);
|
||
+ return ret;
|
||
}
|
||
EXPORT_SYMBOL_GPL(hidraw_report_event);
|
||
|
||
@@ -514,18 +530,9 @@ void hidraw_disconnect(struct hid_device *hid)
|
||
struct hidraw *hidraw = hid->hidraw;
|
||
|
||
mutex_lock(&minors_lock);
|
||
- hidraw->exist = 0;
|
||
|
||
- device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
|
||
+ drop_ref(hidraw, 1);
|
||
|
||
- hidraw_table[hidraw->minor] = NULL;
|
||
-
|
||
- if (hidraw->open) {
|
||
- hid_hw_close(hid);
|
||
- wake_up_interruptible(&hidraw->wait);
|
||
- } else {
|
||
- kfree(hidraw);
|
||
- }
|
||
mutex_unlock(&minors_lock);
|
||
}
|
||
EXPORT_SYMBOL_GPL(hidraw_disconnect);
|
||
@@ -542,21 +549,28 @@ int __init hidraw_init(void)
|
||
|
||
if (result < 0) {
|
||
pr_warn("can't get major number\n");
|
||
- result = 0;
|
||
goto out;
|
||
}
|
||
|
||
hidraw_class = class_create(THIS_MODULE, "hidraw");
|
||
if (IS_ERR(hidraw_class)) {
|
||
result = PTR_ERR(hidraw_class);
|
||
- unregister_chrdev(hidraw_major, "hidraw");
|
||
- goto out;
|
||
+ goto error_cdev;
|
||
}
|
||
|
||
cdev_init(&hidraw_cdev, &hidraw_ops);
|
||
- cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
|
||
+ result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
|
||
+ if (result < 0)
|
||
+ goto error_class;
|
||
+
|
||
out:
|
||
return result;
|
||
+
|
||
+error_class:
|
||
+ class_destroy(hidraw_class);
|
||
+error_cdev:
|
||
+ unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
|
||
+ goto out;
|
||
}
|
||
|
||
void hidraw_exit(void)
|
||
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
|
||
index d712294..bf60cc3 100644
|
||
--- a/drivers/hid/usbhid/hid-quirks.c
|
||
+++ b/drivers/hid/usbhid/hid-quirks.c
|
||
@@ -70,7 +70,10 @@ static const struct hid_blacklist {
|
||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
|
||
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
|
||
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
|
||
+ { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
|
||
+ { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
|
||
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
|
||
+ { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
|
||
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
|
||
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
|
||
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
|
||
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
|
||
index 8af25a0..d01edf3 100644
|
||
--- a/drivers/hv/ring_buffer.c
|
||
+++ b/drivers/hv/ring_buffer.c
|
||
@@ -383,7 +383,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
|
||
sizeof(u64));
|
||
|
||
/* Make sure we flush all writes before updating the writeIndex */
|
||
- smp_wmb();
|
||
+ wmb();
|
||
|
||
/* Now, update the write location */
|
||
hv_set_next_write_location(outring_info, next_write_location);
|
||
@@ -485,7 +485,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
|
||
/* Make sure all reads are done before we update the read index since */
|
||
/* the writer may start writing to the read area once the read index */
|
||
/*is updated */
|
||
- smp_mb();
|
||
+ mb();
|
||
|
||
/* Update the read index */
|
||
hv_set_next_read_location(inring_info, next_read_location);
|
||
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
|
||
index a220e57..10619b3 100644
|
||
--- a/drivers/hv/vmbus_drv.c
|
||
+++ b/drivers/hv/vmbus_drv.c
|
||
@@ -466,7 +466,7 @@ static void vmbus_on_msg_dpc(unsigned long data)
|
||
* will not deliver any more messages since there is
|
||
* no empty slot
|
||
*/
|
||
- smp_mb();
|
||
+ mb();
|
||
|
||
if (msg->header.message_flags.msg_pending) {
|
||
/*
|
||
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
|
||
index 80cc465..f078bae 100644
|
||
--- a/drivers/hwmon/adm1029.c
|
||
+++ b/drivers/hwmon/adm1029.c
|
||
@@ -231,6 +231,9 @@ static ssize_t set_fan_div(struct device *dev,
|
||
/* Update the value */
|
||
reg = (reg & 0x3F) | (val << 6);
|
||
|
||
+ /* Update the cache */
|
||
+ data->fan_div[attr->index] = reg;
|
||
+
|
||
/* Write value */
|
||
i2c_smbus_write_byte_data(client,
|
||
ADM1029_REG_FAN_DIV[attr->index], reg);
|
||
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
|
||
index f600fa1..1d2bace 100644
|
||
--- a/drivers/hwmon/amc6821.c
|
||
+++ b/drivers/hwmon/amc6821.c
|
||
@@ -715,7 +715,7 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
|
||
get_temp_alarm, NULL, IDX_TEMP1_MAX);
|
||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
|
||
get_temp_alarm, NULL, IDX_TEMP1_CRIT);
|
||
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO | S_IWUSR,
|
||
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
|
||
get_temp, NULL, IDX_TEMP2_INPUT);
|
||
static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, get_temp,
|
||
set_temp, IDX_TEMP2_MIN);
|
||
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
|
||
index 73bea49..5b7afc0 100644
|
||
--- a/drivers/hwmon/applesmc.c
|
||
+++ b/drivers/hwmon/applesmc.c
|
||
@@ -212,6 +212,7 @@ static int send_argument(const char *key)
|
||
|
||
static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
|
||
{
|
||
+ u8 status, data = 0;
|
||
int i;
|
||
|
||
if (send_command(cmd) || send_argument(key)) {
|
||
@@ -219,6 +220,7 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
|
||
return -EIO;
|
||
}
|
||
|
||
+ /* This has no effect on newer (2012) SMCs */
|
||
outb(len, APPLESMC_DATA_PORT);
|
||
|
||
for (i = 0; i < len; i++) {
|
||
@@ -229,6 +231,17 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
|
||
buffer[i] = inb(APPLESMC_DATA_PORT);
|
||
}
|
||
|
||
+ /* Read the data port until bit0 is cleared */
|
||
+ for (i = 0; i < 16; i++) {
|
||
+ udelay(APPLESMC_MIN_WAIT);
|
||
+ status = inb(APPLESMC_CMD_PORT);
|
||
+ if (!(status & 0x01))
|
||
+ break;
|
||
+ data = inb(APPLESMC_DATA_PORT);
|
||
+ }
|
||
+ if (i)
|
||
+ pr_warn("flushed %d bytes, last value is: %d\n", i, data);
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
|
||
index 0f52799..5edfb75 100644
|
||
--- a/drivers/hwmon/coretemp.c
|
||
+++ b/drivers/hwmon/coretemp.c
|
||
@@ -53,7 +53,7 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
|
||
|
||
#define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */
|
||
#define NUM_REAL_CORES 32 /* Number of Real cores per cpu */
|
||
-#define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */
|
||
+#define CORETEMP_NAME_LENGTH 19 /* String Length of attrs */
|
||
#define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */
|
||
#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1)
|
||
#define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
|
||
@@ -191,6 +191,27 @@ static ssize_t show_temp(struct device *dev,
|
||
return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN;
|
||
}
|
||
|
||
+struct tjmax {
|
||
+ char const *id;
|
||
+ int tjmax;
|
||
+};
|
||
+
|
||
+static struct tjmax __cpuinitconst tjmax_table[] = {
|
||
+ { "CPU D410", 100000 },
|
||
+ { "CPU D425", 100000 },
|
||
+ { "CPU D510", 100000 },
|
||
+ { "CPU D525", 100000 },
|
||
+ { "CPU N450", 100000 },
|
||
+ { "CPU N455", 100000 },
|
||
+ { "CPU N470", 100000 },
|
||
+ { "CPU N475", 100000 },
|
||
+ { "CPU 230", 100000 }, /* Model 0x1c, stepping 2 */
|
||
+ { "CPU 330", 125000 }, /* Model 0x1c, stepping 2 */
|
||
+ { "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 */
|
||
+ { "CPU CE4150", 110000 }, /* Model 0x1c, stepping 10 */
|
||
+ { "CPU CE4170", 110000 }, /* Model 0x1c, stepping 10 */
|
||
+};
|
||
+
|
||
static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
|
||
struct device *dev)
|
||
{
|
||
@@ -202,6 +223,13 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
|
||
int err;
|
||
u32 eax, edx;
|
||
struct pci_dev *host_bridge;
|
||
+ int i;
|
||
+
|
||
+ /* explicit tjmax table entries override heuristics */
|
||
+ for (i = 0; i < ARRAY_SIZE(tjmax_table); i++) {
|
||
+ if (strstr(c->x86_model_id, tjmax_table[i].id))
|
||
+ return tjmax_table[i].tjmax;
|
||
+ }
|
||
|
||
/* Early chips have no MSR for TjMax */
|
||
|
||
@@ -210,7 +238,8 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
|
||
|
||
/* Atom CPUs */
|
||
|
||
- if (c->x86_model == 0x1c) {
|
||
+ if (c->x86_model == 0x1c || c->x86_model == 0x26
|
||
+ || c->x86_model == 0x27) {
|
||
usemsr_ee = 0;
|
||
|
||
host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
|
||
@@ -223,6 +252,9 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
|
||
tjmax = 90000;
|
||
|
||
pci_dev_put(host_bridge);
|
||
+ } else if (c->x86_model == 0x36) {
|
||
+ usemsr_ee = 0;
|
||
+ tjmax = 100000;
|
||
}
|
||
|
||
if (c->x86_model > 0xe && usemsr_ee) {
|
||
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
|
||
index 149dcb0..d5c33d5 100644
|
||
--- a/drivers/hwmon/emc1403.c
|
||
+++ b/drivers/hwmon/emc1403.c
|
||
@@ -161,7 +161,7 @@ static ssize_t store_hyst(struct device *dev,
|
||
if (retval < 0)
|
||
goto fail;
|
||
|
||
- hyst = val - retval * 1000;
|
||
+ hyst = retval * 1000 - val;
|
||
hyst = DIV_ROUND_CLOSEST(hyst, 1000);
|
||
if (hyst < 0 || hyst > 255) {
|
||
retval = -ERANGE;
|
||
@@ -294,7 +294,7 @@ static int emc1403_detect(struct i2c_client *client,
|
||
}
|
||
|
||
id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG);
|
||
- if (id != 0x01)
|
||
+ if (id < 0x01 || id > 0x04)
|
||
return -ENODEV;
|
||
|
||
return 0;
|
||
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
|
||
index f6bc414..8d6a133 100644
|
||
--- a/drivers/hwmon/lm78.c
|
||
+++ b/drivers/hwmon/lm78.c
|
||
@@ -94,6 +94,8 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
||
{
|
||
if (rpm <= 0)
|
||
return 255;
|
||
+ if (rpm > 1350000)
|
||
+ return 1;
|
||
return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
|
||
}
|
||
|
||
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
|
||
index 22b14a68..1f4f941 100644
|
||
--- a/drivers/hwmon/lm90.c
|
||
+++ b/drivers/hwmon/lm90.c
|
||
@@ -278,7 +278,7 @@ static const struct lm90_params lm90_params[] = {
|
||
[max6696] = {
|
||
.flags = LM90_HAVE_EMERGENCY
|
||
| LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
|
||
- .alert_alarms = 0x187c,
|
||
+ .alert_alarms = 0x1c7c,
|
||
.max_convrate = 6,
|
||
.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
|
||
},
|
||
@@ -1504,19 +1504,22 @@ static void lm90_alert(struct i2c_client *client, unsigned int flag)
|
||
if ((alarms & 0x7f) == 0 && (alarms2 & 0xfe) == 0) {
|
||
dev_info(&client->dev, "Everything OK\n");
|
||
} else {
|
||
- if (alarms & 0x61)
|
||
+ if ((alarms & 0x61) || (alarms2 & 0x80))
|
||
dev_warn(&client->dev,
|
||
"temp%d out of range, please check!\n", 1);
|
||
- if (alarms & 0x1a)
|
||
+ if ((alarms & 0x1a) || (alarms2 & 0x20))
|
||
dev_warn(&client->dev,
|
||
"temp%d out of range, please check!\n", 2);
|
||
if (alarms & 0x04)
|
||
dev_warn(&client->dev,
|
||
"temp%d diode open, please check!\n", 2);
|
||
|
||
- if (alarms2 & 0x18)
|
||
+ if (alarms2 & 0x5a)
|
||
dev_warn(&client->dev,
|
||
"temp%d out of range, please check!\n", 3);
|
||
+ if (alarms2 & 0x04)
|
||
+ dev_warn(&client->dev,
|
||
+ "temp%d diode open, please check!\n", 3);
|
||
|
||
/*
|
||
* Disable ALERT# output, because these chips don't implement
|
||
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
|
||
index 335b183..f058886 100644
|
||
--- a/drivers/hwmon/max1668.c
|
||
+++ b/drivers/hwmon/max1668.c
|
||
@@ -243,7 +243,7 @@ static ssize_t set_temp_min(struct device *dev,
|
||
data->temp_min[index] = SENSORS_LIMIT(temp/1000, -128, 127);
|
||
if (i2c_smbus_write_byte_data(client,
|
||
MAX1668_REG_LIML_WR(index),
|
||
- data->temp_max[index]))
|
||
+ data->temp_min[index]))
|
||
count = -EIO;
|
||
mutex_unlock(&data->update_lock);
|
||
|
||
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
|
||
index 6c4d8eb..098489c 100644
|
||
--- a/drivers/hwmon/sis5595.c
|
||
+++ b/drivers/hwmon/sis5595.c
|
||
@@ -141,6 +141,8 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
||
{
|
||
if (rpm <= 0)
|
||
return 255;
|
||
+ if (rpm > 1350000)
|
||
+ return 1;
|
||
return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
|
||
}
|
||
|
||
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
|
||
index 386a845..0a287e0 100644
|
||
--- a/drivers/hwmon/vt8231.c
|
||
+++ b/drivers/hwmon/vt8231.c
|
||
@@ -145,7 +145,7 @@ static const u8 regtempmin[] = { 0x3a, 0x3e, 0x2c, 0x2e, 0x30, 0x32 };
|
||
*/
|
||
static inline u8 FAN_TO_REG(long rpm, int div)
|
||
{
|
||
- if (rpm == 0)
|
||
+ if (rpm <= 0 || rpm > 1310720)
|
||
return 0;
|
||
return SENSORS_LIMIT(1310720 / (rpm * div), 1, 255);
|
||
}
|
||
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
|
||
index 5850b77..284d469 100644
|
||
--- a/drivers/hwmon/w83l786ng.c
|
||
+++ b/drivers/hwmon/w83l786ng.c
|
||
@@ -481,9 +481,11 @@ store_pwm(struct device *dev, struct device_attribute *attr,
|
||
if (err)
|
||
return err;
|
||
val = SENSORS_LIMIT(val, 0, 255);
|
||
+ val = DIV_ROUND_CLOSEST(val, 0x11);
|
||
|
||
mutex_lock(&data->update_lock);
|
||
- data->pwm[nr] = val;
|
||
+ data->pwm[nr] = val * 0x11;
|
||
+ val |= w83l786ng_read_value(client, W83L786NG_REG_PWM[nr]) & 0xf0;
|
||
w83l786ng_write_value(client, W83L786NG_REG_PWM[nr], val);
|
||
mutex_unlock(&data->update_lock);
|
||
return count;
|
||
@@ -510,7 +512,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||
mutex_lock(&data->update_lock);
|
||
reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG);
|
||
data->pwm_enable[nr] = val;
|
||
- reg &= ~(0x02 << W83L786NG_PWM_ENABLE_SHIFT[nr]);
|
||
+ reg &= ~(0x03 << W83L786NG_PWM_ENABLE_SHIFT[nr]);
|
||
reg |= (val - 1) << W83L786NG_PWM_ENABLE_SHIFT[nr];
|
||
w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg);
|
||
mutex_unlock(&data->update_lock);
|
||
@@ -781,9 +783,10 @@ static struct w83l786ng_data *w83l786ng_update_device(struct device *dev)
|
||
((pwmcfg >> W83L786NG_PWM_MODE_SHIFT[i]) & 1)
|
||
? 0 : 1;
|
||
data->pwm_enable[i] =
|
||
- ((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 2) + 1;
|
||
- data->pwm[i] = w83l786ng_read_value(client,
|
||
- W83L786NG_REG_PWM[i]);
|
||
+ ((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 3) + 1;
|
||
+ data->pwm[i] =
|
||
+ (w83l786ng_read_value(client, W83L786NG_REG_PWM[i])
|
||
+ & 0x0f) * 0x11;
|
||
}
|
||
|
||
|
||
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
|
||
index ac2e1e1..df36e53 100644
|
||
--- a/drivers/i2c/busses/Kconfig
|
||
+++ b/drivers/i2c/busses/Kconfig
|
||
@@ -105,6 +105,7 @@ config I2C_I801
|
||
Panther Point (PCH)
|
||
Lynx Point (PCH)
|
||
Lynx Point-LP (PCH)
|
||
+ Avoton (SOC)
|
||
|
||
This driver can also be built as a module. If so, the module
|
||
will be called i2c-i801.
|
||
@@ -137,6 +138,7 @@ config I2C_PIIX4
|
||
ATI SB700
|
||
ATI SB800
|
||
AMD Hudson-2
|
||
+ AMD CZ
|
||
Serverworks OSB4
|
||
Serverworks CSB5
|
||
Serverworks CSB6
|
||
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
|
||
index 3c2812f..aadb398 100644
|
||
--- a/drivers/i2c/busses/i2c-designware-core.c
|
||
+++ b/drivers/i2c/busses/i2c-designware-core.c
|
||
@@ -346,6 +346,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
||
ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
|
||
dw_writel(dev, ic_con, DW_IC_CON);
|
||
|
||
+ /* enforce disabled interrupts (due to HW issues) */
|
||
+ i2c_dw_disable_int(dev);
|
||
+
|
||
/* Enable the adapter */
|
||
dw_writel(dev, 1, DW_IC_ENABLE);
|
||
|
||
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
|
||
index d88ec81..d63e130 100644
|
||
--- a/drivers/i2c/busses/i2c-i801.c
|
||
+++ b/drivers/i2c/busses/i2c-i801.c
|
||
@@ -53,6 +53,7 @@
|
||
Panther Point (PCH) 0x1e22 32 hard yes yes yes
|
||
Lynx Point (PCH) 0x8c22 32 hard yes yes yes
|
||
Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes
|
||
+ Avoton (SOC) 0x1f3c 32 hard yes yes yes
|
||
|
||
Features supported by this driver:
|
||
Software PEC no
|
||
@@ -145,6 +146,7 @@
|
||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71
|
||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
|
||
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
|
||
+#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c
|
||
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
|
||
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
|
||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
|
||
@@ -639,6 +641,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
|
||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
|
||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) },
|
||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) },
|
||
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) },
|
||
{ 0, }
|
||
};
|
||
|
||
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
|
||
index c14d48d..a356974 100644
|
||
--- a/drivers/i2c/busses/i2c-piix4.c
|
||
+++ b/drivers/i2c/busses/i2c-piix4.c
|
||
@@ -22,7 +22,7 @@
|
||
Intel PIIX4, 440MX
|
||
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
|
||
ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
|
||
- AMD Hudson-2
|
||
+ AMD Hudson-2, CZ
|
||
SMSC Victory66
|
||
|
||
Note: we assume there can only be one device, with one SMBus interface.
|
||
@@ -481,6 +481,7 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
|
||
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
|
||
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
|
||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
|
||
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x790b) },
|
||
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
|
||
PCI_DEVICE_ID_SERVERWORKS_OSB4) },
|
||
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
|
||
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
|
||
index df19f3d..d47ca36 100644
|
||
--- a/drivers/i2c/busses/i2c-tegra.c
|
||
+++ b/drivers/i2c/busses/i2c-tegra.c
|
||
@@ -341,7 +341,11 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
||
u32 val;
|
||
int err = 0;
|
||
|
||
- clk_enable(i2c_dev->clk);
|
||
+ err = clk_enable(i2c_dev->clk);
|
||
+ if (err < 0) {
|
||
+ dev_err(i2c_dev->dev, "Clock enable failed %d\n", err);
|
||
+ return err;
|
||
+ }
|
||
|
||
tegra_periph_reset_assert(i2c_dev->clk);
|
||
udelay(2);
|
||
@@ -543,7 +547,12 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||
if (i2c_dev->is_suspended)
|
||
return -EBUSY;
|
||
|
||
- clk_enable(i2c_dev->clk);
|
||
+ ret = clk_enable(i2c_dev->clk);
|
||
+ if (ret < 0) {
|
||
+ dev_err(i2c_dev->dev, "Clock enable failed %d\n", ret);
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
for (i = 0; i < num; i++) {
|
||
int stop = (i == (num - 1)) ? 1 : 0;
|
||
ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
|
||
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
|
||
index d0f59c3..9b09185 100644
|
||
--- a/drivers/idle/intel_idle.c
|
||
+++ b/drivers/idle/intel_idle.c
|
||
@@ -169,6 +169,38 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
|
||
.enter = &intel_idle },
|
||
};
|
||
|
||
+static struct cpuidle_state ivb_cstates[MWAIT_MAX_NUM_CSTATES] = {
|
||
+ { /* MWAIT C0 */ },
|
||
+ { /* MWAIT C1 */
|
||
+ .name = "C1-IVB",
|
||
+ .desc = "MWAIT 0x00",
|
||
+ .flags = CPUIDLE_FLAG_TIME_VALID,
|
||
+ .exit_latency = 1,
|
||
+ .target_residency = 1,
|
||
+ .enter = &intel_idle },
|
||
+ { /* MWAIT C2 */
|
||
+ .name = "C3-IVB",
|
||
+ .desc = "MWAIT 0x10",
|
||
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
|
||
+ .exit_latency = 59,
|
||
+ .target_residency = 156,
|
||
+ .enter = &intel_idle },
|
||
+ { /* MWAIT C3 */
|
||
+ .name = "C6-IVB",
|
||
+ .desc = "MWAIT 0x20",
|
||
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
|
||
+ .exit_latency = 80,
|
||
+ .target_residency = 300,
|
||
+ .enter = &intel_idle },
|
||
+ { /* MWAIT C4 */
|
||
+ .name = "C7-IVB",
|
||
+ .desc = "MWAIT 0x30",
|
||
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
|
||
+ .exit_latency = 87,
|
||
+ .target_residency = 300,
|
||
+ .enter = &intel_idle },
|
||
+};
|
||
+
|
||
static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
|
||
{ /* MWAIT C0 */ },
|
||
{ /* MWAIT C1 */
|
||
@@ -347,6 +379,10 @@ static const struct idle_cpu idle_cpu_snb = {
|
||
.state_table = snb_cstates,
|
||
};
|
||
|
||
+static const struct idle_cpu idle_cpu_ivb = {
|
||
+ .state_table = ivb_cstates,
|
||
+};
|
||
+
|
||
#define ICPU(model, cpu) \
|
||
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
|
||
|
||
@@ -362,6 +398,8 @@ static const struct x86_cpu_id intel_idle_ids[] = {
|
||
ICPU(0x2f, idle_cpu_nehalem),
|
||
ICPU(0x2a, idle_cpu_snb),
|
||
ICPU(0x2d, idle_cpu_snb),
|
||
+ ICPU(0x3a, idle_cpu_ivb),
|
||
+ ICPU(0x3e, idle_cpu_ivb),
|
||
{}
|
||
};
|
||
MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
|
||
@@ -405,10 +443,8 @@ static int intel_idle_probe(void)
|
||
|
||
if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
|
||
lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
|
||
- else {
|
||
+ else
|
||
on_each_cpu(__setup_broadcast_timer, (void *)true, 1);
|
||
- register_cpu_notifier(&setup_broadcast_notifier);
|
||
- }
|
||
|
||
pr_debug(PREFIX "v" INTEL_IDLE_VERSION
|
||
" model 0x%X\n", boot_cpu_data.x86_model);
|
||
@@ -556,8 +592,9 @@ static int __init intel_idle_init(void)
|
||
intel_idle_cpuidle_driver_init();
|
||
retval = cpuidle_register_driver(&intel_idle_driver);
|
||
if (retval) {
|
||
+ struct cpuidle_driver *drv = cpuidle_get_driver();
|
||
printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",
|
||
- cpuidle_get_driver()->name);
|
||
+ drv ? drv->name : "none");
|
||
return retval;
|
||
}
|
||
|
||
@@ -573,6 +610,9 @@ static int __init intel_idle_init(void)
|
||
}
|
||
}
|
||
|
||
+ if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
|
||
+ register_cpu_notifier(&setup_broadcast_notifier);
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
|
||
index f0d588f..1acb991 100644
|
||
--- a/drivers/infiniband/core/user_mad.c
|
||
+++ b/drivers/infiniband/core/user_mad.c
|
||
@@ -98,7 +98,7 @@ struct ib_umad_port {
|
||
|
||
struct ib_umad_device {
|
||
int start_port, end_port;
|
||
- struct kref ref;
|
||
+ struct kobject kobj;
|
||
struct ib_umad_port port[0];
|
||
};
|
||
|
||
@@ -134,14 +134,18 @@ static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS);
|
||
static void ib_umad_add_one(struct ib_device *device);
|
||
static void ib_umad_remove_one(struct ib_device *device);
|
||
|
||
-static void ib_umad_release_dev(struct kref *ref)
|
||
+static void ib_umad_release_dev(struct kobject *kobj)
|
||
{
|
||
struct ib_umad_device *dev =
|
||
- container_of(ref, struct ib_umad_device, ref);
|
||
+ container_of(kobj, struct ib_umad_device, kobj);
|
||
|
||
kfree(dev);
|
||
}
|
||
|
||
+static struct kobj_type ib_umad_dev_ktype = {
|
||
+ .release = ib_umad_release_dev,
|
||
+};
|
||
+
|
||
static int hdr_size(struct ib_umad_file *file)
|
||
{
|
||
return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) :
|
||
@@ -780,27 +784,19 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
|
||
{
|
||
struct ib_umad_port *port;
|
||
struct ib_umad_file *file;
|
||
- int ret;
|
||
+ int ret = -ENXIO;
|
||
|
||
port = container_of(inode->i_cdev, struct ib_umad_port, cdev);
|
||
- if (port)
|
||
- kref_get(&port->umad_dev->ref);
|
||
- else
|
||
- return -ENXIO;
|
||
|
||
mutex_lock(&port->file_mutex);
|
||
|
||
- if (!port->ib_dev) {
|
||
- ret = -ENXIO;
|
||
+ if (!port->ib_dev)
|
||
goto out;
|
||
- }
|
||
|
||
+ ret = -ENOMEM;
|
||
file = kzalloc(sizeof *file, GFP_KERNEL);
|
||
- if (!file) {
|
||
- kref_put(&port->umad_dev->ref, ib_umad_release_dev);
|
||
- ret = -ENOMEM;
|
||
+ if (!file)
|
||
goto out;
|
||
- }
|
||
|
||
mutex_init(&file->mutex);
|
||
spin_lock_init(&file->send_lock);
|
||
@@ -814,6 +810,13 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
|
||
list_add_tail(&file->port_list, &port->file_list);
|
||
|
||
ret = nonseekable_open(inode, filp);
|
||
+ if (ret) {
|
||
+ list_del(&file->port_list);
|
||
+ kfree(file);
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ kobject_get(&port->umad_dev->kobj);
|
||
|
||
out:
|
||
mutex_unlock(&port->file_mutex);
|
||
@@ -852,7 +855,7 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
|
||
mutex_unlock(&file->port->file_mutex);
|
||
|
||
kfree(file);
|
||
- kref_put(&dev->ref, ib_umad_release_dev);
|
||
+ kobject_put(&dev->kobj);
|
||
|
||
return 0;
|
||
}
|
||
@@ -880,10 +883,6 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
|
||
int ret;
|
||
|
||
port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev);
|
||
- if (port)
|
||
- kref_get(&port->umad_dev->ref);
|
||
- else
|
||
- return -ENXIO;
|
||
|
||
if (filp->f_flags & O_NONBLOCK) {
|
||
if (down_trylock(&port->sm_sem)) {
|
||
@@ -898,17 +897,27 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
|
||
}
|
||
|
||
ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
|
||
- if (ret) {
|
||
- up(&port->sm_sem);
|
||
- goto fail;
|
||
- }
|
||
+ if (ret)
|
||
+ goto err_up_sem;
|
||
|
||
filp->private_data = port;
|
||
|
||
- return nonseekable_open(inode, filp);
|
||
+ ret = nonseekable_open(inode, filp);
|
||
+ if (ret)
|
||
+ goto err_clr_sm_cap;
|
||
+
|
||
+ kobject_get(&port->umad_dev->kobj);
|
||
+
|
||
+ return 0;
|
||
+
|
||
+err_clr_sm_cap:
|
||
+ swap(props.set_port_cap_mask, props.clr_port_cap_mask);
|
||
+ ib_modify_port(port->ib_dev, port->port_num, 0, &props);
|
||
+
|
||
+err_up_sem:
|
||
+ up(&port->sm_sem);
|
||
|
||
fail:
|
||
- kref_put(&port->umad_dev->ref, ib_umad_release_dev);
|
||
return ret;
|
||
}
|
||
|
||
@@ -927,7 +936,7 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
|
||
|
||
up(&port->sm_sem);
|
||
|
||
- kref_put(&port->umad_dev->ref, ib_umad_release_dev);
|
||
+ kobject_put(&port->umad_dev->kobj);
|
||
|
||
return ret;
|
||
}
|
||
@@ -995,6 +1004,7 @@ static int find_overflow_devnum(void)
|
||
}
|
||
|
||
static int ib_umad_init_port(struct ib_device *device, int port_num,
|
||
+ struct ib_umad_device *umad_dev,
|
||
struct ib_umad_port *port)
|
||
{
|
||
int devnum;
|
||
@@ -1027,6 +1037,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
|
||
|
||
cdev_init(&port->cdev, &umad_fops);
|
||
port->cdev.owner = THIS_MODULE;
|
||
+ port->cdev.kobj.parent = &umad_dev->kobj;
|
||
kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num);
|
||
if (cdev_add(&port->cdev, base, 1))
|
||
goto err_cdev;
|
||
@@ -1045,6 +1056,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
|
||
base += IB_UMAD_MAX_PORTS;
|
||
cdev_init(&port->sm_cdev, &umad_sm_fops);
|
||
port->sm_cdev.owner = THIS_MODULE;
|
||
+ port->sm_cdev.kobj.parent = &umad_dev->kobj;
|
||
kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num);
|
||
if (cdev_add(&port->sm_cdev, base, 1))
|
||
goto err_sm_cdev;
|
||
@@ -1138,7 +1150,7 @@ static void ib_umad_add_one(struct ib_device *device)
|
||
if (!umad_dev)
|
||
return;
|
||
|
||
- kref_init(&umad_dev->ref);
|
||
+ kobject_init(&umad_dev->kobj, &ib_umad_dev_ktype);
|
||
|
||
umad_dev->start_port = s;
|
||
umad_dev->end_port = e;
|
||
@@ -1146,7 +1158,8 @@ static void ib_umad_add_one(struct ib_device *device)
|
||
for (i = s; i <= e; ++i) {
|
||
umad_dev->port[i - s].umad_dev = umad_dev;
|
||
|
||
- if (ib_umad_init_port(device, i, &umad_dev->port[i - s]))
|
||
+ if (ib_umad_init_port(device, i, umad_dev,
|
||
+ &umad_dev->port[i - s]))
|
||
goto err;
|
||
}
|
||
|
||
@@ -1158,7 +1171,7 @@ static void ib_umad_add_one(struct ib_device *device)
|
||
while (--i >= s)
|
||
ib_umad_kill_port(&umad_dev->port[i - s]);
|
||
|
||
- kref_put(&umad_dev->ref, ib_umad_release_dev);
|
||
+ kobject_put(&umad_dev->kobj);
|
||
}
|
||
|
||
static void ib_umad_remove_one(struct ib_device *device)
|
||
@@ -1172,7 +1185,7 @@ static void ib_umad_remove_one(struct ib_device *device)
|
||
for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i)
|
||
ib_umad_kill_port(&umad_dev->port[i]);
|
||
|
||
- kref_put(&umad_dev->ref, ib_umad_release_dev);
|
||
+ kobject_put(&umad_dev->kobj);
|
||
}
|
||
|
||
static char *umad_devnode(struct device *dev, umode_t *mode)
|
||
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
|
||
index d9b0ebc..6eeb84d 100644
|
||
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
|
||
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
|
||
@@ -296,6 +296,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
|
||
(my_cq->galpas.user.fw_handle & (PAGE_SIZE - 1));
|
||
if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
|
||
ehca_err(device, "Copy to udata failed.");
|
||
+ cq = ERR_PTR(-EFAULT);
|
||
goto create_cq_exit4;
|
||
}
|
||
}
|
||
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
|
||
index 714293b..45802e9 100644
|
||
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
|
||
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
|
||
@@ -326,7 +326,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
|
||
size_t count, loff_t *off)
|
||
{
|
||
u32 __iomem *piobuf;
|
||
- u32 plen, clen, pbufn;
|
||
+ u32 plen, pbufn, maxlen_reserve;
|
||
struct ipath_diag_pkt odp;
|
||
struct ipath_diag_xpkt dp;
|
||
u32 *tmpbuf = NULL;
|
||
@@ -335,42 +335,24 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
|
||
u64 val;
|
||
u32 l_state, lt_state; /* LinkState, LinkTrainingState */
|
||
|
||
- if (count < sizeof(odp)) {
|
||
- ret = -EINVAL;
|
||
- goto bail;
|
||
- }
|
||
|
||
if (count == sizeof(dp)) {
|
||
if (copy_from_user(&dp, data, sizeof(dp))) {
|
||
ret = -EFAULT;
|
||
goto bail;
|
||
}
|
||
- } else if (copy_from_user(&odp, data, sizeof(odp))) {
|
||
- ret = -EFAULT;
|
||
- goto bail;
|
||
- }
|
||
-
|
||
- /*
|
||
- * Due to padding/alignment issues (lessened with new struct)
|
||
- * the old and new structs are the same length. We need to
|
||
- * disambiguate them, which we can do because odp.len has never
|
||
- * been less than the total of LRH+BTH+DETH so far, while
|
||
- * dp.unit (same offset) unit is unlikely to get that high.
|
||
- * Similarly, dp.data, the pointer to user at the same offset
|
||
- * as odp.unit, is almost certainly at least one (512byte)page
|
||
- * "above" NULL. The if-block below can be omitted if compatibility
|
||
- * between a new driver and older diagnostic code is unimportant.
|
||
- * compatibility the other direction (new diags, old driver) is
|
||
- * handled in the diagnostic code, with a warning.
|
||
- */
|
||
- if (dp.unit >= 20 && dp.data < 512) {
|
||
- /* very probable version mismatch. Fix it up */
|
||
- memcpy(&odp, &dp, sizeof(odp));
|
||
- /* We got a legacy dp, copy elements to dp */
|
||
+ } else if (count == sizeof(odp)) {
|
||
+ if (copy_from_user(&odp, data, sizeof(odp))) {
|
||
+ ret = -EFAULT;
|
||
+ goto bail;
|
||
+ }
|
||
+ dp.len = odp.len;
|
||
dp.unit = odp.unit;
|
||
dp.data = odp.data;
|
||
- dp.len = odp.len;
|
||
- dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
|
||
+ dp.pbc_wd = 0;
|
||
+ } else {
|
||
+ ret = -EINVAL;
|
||
+ goto bail;
|
||
}
|
||
|
||
/* send count must be an exact number of dwords */
|
||
@@ -379,7 +361,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
|
||
goto bail;
|
||
}
|
||
|
||
- clen = dp.len >> 2;
|
||
+ plen = dp.len >> 2;
|
||
|
||
dd = ipath_lookup(dp.unit);
|
||
if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
|
||
@@ -422,16 +404,22 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
|
||
goto bail;
|
||
}
|
||
|
||
- /* need total length before first word written */
|
||
- /* +1 word is for the qword padding */
|
||
- plen = sizeof(u32) + dp.len;
|
||
-
|
||
- if ((plen + 4) > dd->ipath_ibmaxlen) {
|
||
+ /*
|
||
+ * need total length before first word written, plus 2 Dwords. One Dword
|
||
+ * is for padding so we get the full user data when not aligned on
|
||
+ * a word boundary. The other Dword is to make sure we have room for the
|
||
+ * ICRC which gets tacked on later.
|
||
+ */
|
||
+ maxlen_reserve = 2 * sizeof(u32);
|
||
+ if (dp.len > dd->ipath_ibmaxlen - maxlen_reserve) {
|
||
ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
|
||
- plen - 4, dd->ipath_ibmaxlen);
|
||
+ dp.len, dd->ipath_ibmaxlen);
|
||
ret = -EINVAL;
|
||
- goto bail; /* before writing pbc */
|
||
+ goto bail;
|
||
}
|
||
+
|
||
+ plen = sizeof(u32) + dp.len;
|
||
+
|
||
tmpbuf = vmalloc(plen);
|
||
if (!tmpbuf) {
|
||
dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
|
||
@@ -473,11 +461,11 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
|
||
*/
|
||
if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
|
||
ipath_flush_wc();
|
||
- __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
|
||
+ __iowrite32_copy(piobuf + 2, tmpbuf, plen - 1);
|
||
ipath_flush_wc();
|
||
- __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
|
||
+ __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1);
|
||
} else
|
||
- __iowrite32_copy(piobuf + 2, tmpbuf, clen);
|
||
+ __iowrite32_copy(piobuf + 2, tmpbuf, plen);
|
||
|
||
ipath_flush_wc();
|
||
|
||
diff --git a/drivers/infiniband/hw/ipath/ipath_user_sdma.c b/drivers/infiniband/hw/ipath/ipath_user_sdma.c
|
||
index f5cb13b..cc04b7b 100644
|
||
--- a/drivers/infiniband/hw/ipath/ipath_user_sdma.c
|
||
+++ b/drivers/infiniband/hw/ipath/ipath_user_sdma.c
|
||
@@ -280,9 +280,7 @@ static int ipath_user_sdma_pin_pages(const struct ipath_devdata *dd,
|
||
int j;
|
||
int ret;
|
||
|
||
- ret = get_user_pages(current, current->mm, addr,
|
||
- npages, 0, 1, pages, NULL);
|
||
-
|
||
+ ret = get_user_pages_fast(addr, npages, 0, pages);
|
||
if (ret != npages) {
|
||
int i;
|
||
|
||
@@ -811,10 +809,7 @@ int ipath_user_sdma_writev(struct ipath_devdata *dd,
|
||
while (dim) {
|
||
const int mxp = 8;
|
||
|
||
- down_write(¤t->mm->mmap_sem);
|
||
ret = ipath_user_sdma_queue_pkts(dd, pq, &list, iov, dim, mxp);
|
||
- up_write(¤t->mm->mmap_sem);
|
||
-
|
||
if (ret <= 0)
|
||
goto done_unlock;
|
||
else {
|
||
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
|
||
index 5b71d43..42dde06 100644
|
||
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
|
||
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
|
||
@@ -695,6 +695,7 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
|
||
|
||
if (context && ib_copy_to_udata(udata, &cq->cqn, sizeof (__u32))) {
|
||
mthca_free_cq(to_mdev(ibdev), cq);
|
||
+ err = -EFAULT;
|
||
goto err_free;
|
||
}
|
||
|
||
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
|
||
index da84ea3..daf70d3 100644
|
||
--- a/drivers/infiniband/hw/nes/nes_verbs.c
|
||
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
|
||
@@ -1183,7 +1183,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
|
||
nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
|
||
kfree(nesqp->allocated_buffer);
|
||
nes_debug(NES_DBG_QP, "ib_copy_from_udata() Failed \n");
|
||
- return NULL;
|
||
+ return ERR_PTR(-EFAULT);
|
||
}
|
||
if (req.user_wqe_buffers) {
|
||
virt_wqs = 1;
|
||
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
|
||
index 060b960..d252053 100644
|
||
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
|
||
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
|
||
@@ -2279,6 +2279,11 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd)
|
||
qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a);
|
||
qib_write_kreg(dd, kr_scratch, 0ULL);
|
||
|
||
+ /* ensure previous Tx parameters are not still forced */
|
||
+ qib_write_kreg_port(ppd, krp_tx_deemph_override,
|
||
+ SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
|
||
+ reset_tx_deemphasis_override));
|
||
+
|
||
if (qib_compat_ddr_negotiate) {
|
||
ppd->cpspec->ibdeltainprog = 1;
|
||
ppd->cpspec->ibsymsnap = read_7322_creg32_port(ppd,
|
||
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c
|
||
index c4ff788..14f3929 100644
|
||
--- a/drivers/infiniband/hw/qib/qib_mad.c
|
||
+++ b/drivers/infiniband/hw/qib/qib_mad.c
|
||
@@ -1005,7 +1005,7 @@ static int set_pkeys(struct qib_devdata *dd, u8 port, u16 *pkeys)
|
||
|
||
event.event = IB_EVENT_PKEY_CHANGE;
|
||
event.device = &dd->verbs_dev.ibdev;
|
||
- event.element.port_num = 1;
|
||
+ event.element.port_num = port;
|
||
ib_dispatch_event(&event);
|
||
}
|
||
return 0;
|
||
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
|
||
index 828609f..c0d93d4 100644
|
||
--- a/drivers/infiniband/hw/qib/qib_ud.c
|
||
+++ b/drivers/infiniband/hw/qib/qib_ud.c
|
||
@@ -57,13 +57,20 @@ static void qib_ud_loopback(struct qib_qp *sqp, struct qib_swqe *swqe)
|
||
struct qib_sge *sge;
|
||
struct ib_wc wc;
|
||
u32 length;
|
||
+ enum ib_qp_type sqptype, dqptype;
|
||
|
||
qp = qib_lookup_qpn(ibp, swqe->wr.wr.ud.remote_qpn);
|
||
if (!qp) {
|
||
ibp->n_pkt_drops++;
|
||
return;
|
||
}
|
||
- if (qp->ibqp.qp_type != sqp->ibqp.qp_type ||
|
||
+
|
||
+ sqptype = sqp->ibqp.qp_type == IB_QPT_GSI ?
|
||
+ IB_QPT_UD : sqp->ibqp.qp_type;
|
||
+ dqptype = qp->ibqp.qp_type == IB_QPT_GSI ?
|
||
+ IB_QPT_UD : qp->ibqp.qp_type;
|
||
+
|
||
+ if (dqptype != sqptype ||
|
||
!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) {
|
||
ibp->n_pkt_drops++;
|
||
goto drop;
|
||
diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c
|
||
index 8244208..573b460 100644
|
||
--- a/drivers/infiniband/hw/qib/qib_user_sdma.c
|
||
+++ b/drivers/infiniband/hw/qib/qib_user_sdma.c
|
||
@@ -284,8 +284,7 @@ static int qib_user_sdma_pin_pages(const struct qib_devdata *dd,
|
||
int j;
|
||
int ret;
|
||
|
||
- ret = get_user_pages(current, current->mm, addr,
|
||
- npages, 0, 1, pages, NULL);
|
||
+ ret = get_user_pages_fast(addr, npages, 0, pages);
|
||
|
||
if (ret != npages) {
|
||
int i;
|
||
@@ -830,10 +829,7 @@ int qib_user_sdma_writev(struct qib_ctxtdata *rcd,
|
||
while (dim) {
|
||
const int mxp = 8;
|
||
|
||
- down_write(¤t->mm->mmap_sem);
|
||
ret = qib_user_sdma_queue_pkts(dd, pq, &list, iov, dim, mxp);
|
||
- up_write(¤t->mm->mmap_sem);
|
||
-
|
||
if (ret <= 0)
|
||
goto done_unlock;
|
||
else {
|
||
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
|
||
index 922d845..7fa948d 100644
|
||
--- a/drivers/infiniband/ulp/srp/ib_srp.c
|
||
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
|
||
@@ -1371,6 +1371,12 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
|
||
err_iu:
|
||
srp_put_tx_iu(target, iu, SRP_IU_CMD);
|
||
|
||
+ /*
|
||
+ * Avoid that the loops that iterate over the request ring can
|
||
+ * encounter a dangling SCSI command pointer.
|
||
+ */
|
||
+ req->scmnd = NULL;
|
||
+
|
||
spin_lock_irqsave(&target->lock, flags);
|
||
list_add(&req->list, &target->free_reqs);
|
||
|
||
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
|
||
index c34d362..550c9ca 100644
|
||
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
|
||
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
|
||
@@ -1078,6 +1078,7 @@ static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||
static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||
struct srpt_send_ioctx *ioctx)
|
||
{
|
||
+ struct ib_device *dev = ch->sport->sdev->device;
|
||
struct se_cmd *cmd;
|
||
struct scatterlist *sg, *sg_orig;
|
||
int sg_cnt;
|
||
@@ -1125,7 +1126,7 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||
|
||
db = ioctx->rbufs;
|
||
tsize = cmd->data_length;
|
||
- dma_len = sg_dma_len(&sg[0]);
|
||
+ dma_len = ib_sg_dma_len(dev, &sg[0]);
|
||
riu = ioctx->rdma_ius;
|
||
|
||
/*
|
||
@@ -1156,7 +1157,8 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||
++j;
|
||
if (j < count) {
|
||
sg = sg_next(sg);
|
||
- dma_len = sg_dma_len(sg);
|
||
+ dma_len = ib_sg_dma_len(
|
||
+ dev, sg);
|
||
}
|
||
}
|
||
} else {
|
||
@@ -1193,8 +1195,8 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||
tsize = cmd->data_length;
|
||
riu = ioctx->rdma_ius;
|
||
sg = sg_orig;
|
||
- dma_len = sg_dma_len(&sg[0]);
|
||
- dma_addr = sg_dma_address(&sg[0]);
|
||
+ dma_len = ib_sg_dma_len(dev, &sg[0]);
|
||
+ dma_addr = ib_sg_dma_address(dev, &sg[0]);
|
||
|
||
/* this second loop is really mapped sg_addres to rdma_iu->ib_sge */
|
||
for (i = 0, j = 0;
|
||
@@ -1217,8 +1219,10 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||
++j;
|
||
if (j < count) {
|
||
sg = sg_next(sg);
|
||
- dma_len = sg_dma_len(sg);
|
||
- dma_addr = sg_dma_address(sg);
|
||
+ dma_len = ib_sg_dma_len(
|
||
+ dev, sg);
|
||
+ dma_addr = ib_sg_dma_address(
|
||
+ dev, sg);
|
||
}
|
||
}
|
||
} else {
|
||
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
|
||
index 69d3686..2c66a8c 100644
|
||
--- a/drivers/input/Kconfig
|
||
+++ b/drivers/input/Kconfig
|
||
@@ -71,7 +71,7 @@ config INPUT_SPARSEKMAP
|
||
comment "Userland interfaces"
|
||
|
||
config INPUT_MOUSEDEV
|
||
- tristate "Mouse interface" if EXPERT
|
||
+ tristate "Mouse interface"
|
||
default y
|
||
help
|
||
Say Y here if you want your mouse to be accessible as char devices
|
||
diff --git a/drivers/input/input.c b/drivers/input/input.c
|
||
index 79e1c40..d48d68b 100644
|
||
--- a/drivers/input/input.c
|
||
+++ b/drivers/input/input.c
|
||
@@ -1711,6 +1711,10 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
|
||
break;
|
||
|
||
case EV_ABS:
|
||
+ input_alloc_absinfo(dev);
|
||
+ if (!dev->absinfo)
|
||
+ return;
|
||
+
|
||
__set_bit(code, dev->absbit);
|
||
break;
|
||
|
||
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
|
||
index bfa48de..290d4d9 100644
|
||
--- a/drivers/input/keyboard/Kconfig
|
||
+++ b/drivers/input/keyboard/Kconfig
|
||
@@ -2,7 +2,7 @@
|
||
# Input core configuration
|
||
#
|
||
menuconfig INPUT_KEYBOARD
|
||
- bool "Keyboards" if EXPERT || !X86
|
||
+ bool "Keyboards"
|
||
default y
|
||
help
|
||
Say Y here, and a list of supported keyboards will be displayed.
|
||
@@ -67,7 +67,7 @@ config KEYBOARD_ATARI
|
||
module will be called atakbd.
|
||
|
||
config KEYBOARD_ATKBD
|
||
- tristate "AT keyboard" if EXPERT || !X86
|
||
+ tristate "AT keyboard"
|
||
default y
|
||
select SERIO
|
||
select SERIO_LIBPS2
|
||
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
|
||
index 4790110..f2c2ffe 100644
|
||
--- a/drivers/input/mouse/elantech.c
|
||
+++ b/drivers/input/mouse/elantech.c
|
||
@@ -472,8 +472,15 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
|
||
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
|
||
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
|
||
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
|
||
- input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||
- input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||
+
|
||
+ /* For clickpads map both buttons to BTN_LEFT */
|
||
+ if (etd->fw_version & 0x001000) {
|
||
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
|
||
+ } else {
|
||
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||
+ }
|
||
+
|
||
input_report_abs(dev, ABS_PRESSURE, pres);
|
||
input_report_abs(dev, ABS_TOOL_WIDTH, width);
|
||
|
||
@@ -483,9 +490,17 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
|
||
static void elantech_input_sync_v4(struct psmouse *psmouse)
|
||
{
|
||
struct input_dev *dev = psmouse->dev;
|
||
+ struct elantech_data *etd = psmouse->private;
|
||
unsigned char *packet = psmouse->packet;
|
||
|
||
- input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||
+ /* For clickpads map both buttons to BTN_LEFT */
|
||
+ if (etd->fw_version & 0x001000) {
|
||
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
|
||
+ } else {
|
||
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||
+ }
|
||
+
|
||
input_mt_report_pointer_emulation(dev, true);
|
||
input_sync(dev);
|
||
}
|
||
@@ -954,6 +969,44 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
|
||
}
|
||
|
||
/*
|
||
+ * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in
|
||
+ * fw_version for this is based on the following fw_version & caps table:
|
||
+ *
|
||
+ * Laptop-model: fw_version: caps: buttons:
|
||
+ * Acer S3 0x461f00 10, 13, 0e clickpad
|
||
+ * Acer S7-392 0x581f01 50, 17, 0d clickpad
|
||
+ * Acer V5-131 0x461f02 01, 16, 0c clickpad
|
||
+ * Acer V5-551 0x461f00 ? clickpad
|
||
+ * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons
|
||
+ * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons
|
||
+ * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons
|
||
+ * Asus UX31 0x361f00 20, 15, 0e clickpad
|
||
+ * Asus UX32VD 0x361f02 00, 15, 0e clickpad
|
||
+ * Avatar AVIU-145A2 0x361f00 ? clickpad
|
||
+ * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
|
||
+ * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
|
||
+ * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons
|
||
+ * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad
|
||
+ * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad
|
||
+ * Samsung NP900X3E-A02 0x575f03 ? clickpad
|
||
+ * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad
|
||
+ * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons
|
||
+ * Samsung RF710 0x450f00 ? 2 hw buttons
|
||
+ * System76 Pangolin 0x250f01 ? 2 hw buttons
|
||
+ * (*) + 3 trackpoint buttons
|
||
+ */
|
||
+static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
|
||
+{
|
||
+ struct input_dev *dev = psmouse->dev;
|
||
+ struct elantech_data *etd = psmouse->private;
|
||
+
|
||
+ if (etd->fw_version & 0x001000) {
|
||
+ __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
|
||
+ __clear_bit(BTN_RIGHT, dev->keybit);
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
* Set the appropriate event bits for the input subsystem
|
||
*/
|
||
static int elantech_set_input_params(struct psmouse *psmouse)
|
||
@@ -996,6 +1049,8 @@ static int elantech_set_input_params(struct psmouse *psmouse)
|
||
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
|
||
/* fall through */
|
||
case 3:
|
||
+ if (etd->hw_version == 3)
|
||
+ elantech_set_buttonpad_prop(psmouse);
|
||
input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
|
||
input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
|
||
if (etd->reports_pressure) {
|
||
@@ -1017,9 +1072,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
|
||
*/
|
||
psmouse_warn(psmouse, "couldn't query resolution data.\n");
|
||
}
|
||
- /* v4 is clickpad, with only one button. */
|
||
- __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
|
||
- __clear_bit(BTN_RIGHT, dev->keybit);
|
||
+ elantech_set_buttonpad_prop(psmouse);
|
||
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
|
||
/* For X to recognize me as touchpad. */
|
||
input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
|
||
@@ -1165,6 +1218,13 @@ static bool elantech_is_signature_valid(const unsigned char *param)
|
||
if (param[1] == 0)
|
||
return true;
|
||
|
||
+ /*
|
||
+ * Some models have a revision higher then 20. Meaning param[2] may
|
||
+ * be 10 or 20, skip the rates check for these.
|
||
+ */
|
||
+ if (param[0] == 0x46 && (param[1] & 0xef) == 0x0f && param[2] < 40)
|
||
+ return true;
|
||
+
|
||
for (i = 0; i < ARRAY_SIZE(rates); i++)
|
||
if (param[2] == rates[i])
|
||
return false;
|
||
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
|
||
index a4b14a4..32b1363 100644
|
||
--- a/drivers/input/mouse/synaptics.c
|
||
+++ b/drivers/input/mouse/synaptics.c
|
||
@@ -40,11 +40,33 @@
|
||
* Note that newer firmware allows querying device for maximum useable
|
||
* coordinates.
|
||
*/
|
||
+#define XMIN 0
|
||
+#define XMAX 6143
|
||
+#define YMIN 0
|
||
+#define YMAX 6143
|
||
#define XMIN_NOMINAL 1472
|
||
#define XMAX_NOMINAL 5472
|
||
#define YMIN_NOMINAL 1408
|
||
#define YMAX_NOMINAL 4448
|
||
|
||
+/* Size in bits of absolute position values reported by the hardware */
|
||
+#define ABS_POS_BITS 13
|
||
+
|
||
+/*
|
||
+ * These values should represent the absolute maximum value that will
|
||
+ * be reported for a positive position value. Some Synaptics firmware
|
||
+ * uses this value to indicate a finger near the edge of the touchpad
|
||
+ * whose precise position cannot be determined.
|
||
+ *
|
||
+ * At least one touchpad is known to report positions in excess of this
|
||
+ * value which are actually negative values truncated to the 13-bit
|
||
+ * reporting range. These values have never been observed to be lower
|
||
+ * than 8184 (i.e. -8), so we treat all values greater than 8176 as
|
||
+ * negative and any other value as positive.
|
||
+ */
|
||
+#define X_MAX_POSITIVE 8176
|
||
+#define Y_MAX_POSITIVE 8176
|
||
+
|
||
/*
|
||
* Synaptics touchpads report the y coordinate from bottom to top, which is
|
||
* opposite from what userspace expects.
|
||
@@ -215,11 +237,22 @@ static int synaptics_identify(struct psmouse *psmouse)
|
||
* Read touchpad resolution and maximum reported coordinates
|
||
* Resolution is left zero if touchpad does not support the query
|
||
*/
|
||
+
|
||
+static const int *quirk_min_max;
|
||
+
|
||
static int synaptics_resolution(struct psmouse *psmouse)
|
||
{
|
||
struct synaptics_data *priv = psmouse->private;
|
||
unsigned char resp[3];
|
||
|
||
+ if (quirk_min_max) {
|
||
+ priv->x_min = quirk_min_max[0];
|
||
+ priv->x_max = quirk_min_max[1];
|
||
+ priv->y_min = quirk_min_max[2];
|
||
+ priv->y_max = quirk_min_max[3];
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
if (SYN_ID_MAJOR(priv->identity) < 4)
|
||
return 0;
|
||
|
||
@@ -484,10 +517,61 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
||
((buf[0] & 0x04) >> 1) |
|
||
((buf[3] & 0x04) >> 2));
|
||
|
||
+ if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
|
||
+ SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
|
||
+ hw->w == 2) {
|
||
+ synaptics_parse_agm(buf, priv, hw);
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ hw->x = (((buf[3] & 0x10) << 8) |
|
||
+ ((buf[1] & 0x0f) << 8) |
|
||
+ buf[4]);
|
||
+ hw->y = (((buf[3] & 0x20) << 7) |
|
||
+ ((buf[1] & 0xf0) << 4) |
|
||
+ buf[5]);
|
||
+ hw->z = buf[2];
|
||
+
|
||
hw->left = (buf[0] & 0x01) ? 1 : 0;
|
||
hw->right = (buf[0] & 0x02) ? 1 : 0;
|
||
|
||
- if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
|
||
+ if (SYN_CAP_FORCEPAD(priv->ext_cap_0c)) {
|
||
+ /*
|
||
+ * ForcePads, like Clickpads, use middle button
|
||
+ * bits to report primary button clicks.
|
||
+ * Unfortunately they report primary button not
|
||
+ * only when user presses on the pad above certain
|
||
+ * threshold, but also when there are more than one
|
||
+ * finger on the touchpad, which interferes with
|
||
+ * out multi-finger gestures.
|
||
+ */
|
||
+ if (hw->z == 0) {
|
||
+ /* No contacts */
|
||
+ priv->press = priv->report_press = false;
|
||
+ } else if (hw->w >= 4 && ((buf[0] ^ buf[3]) & 0x01)) {
|
||
+ /*
|
||
+ * Single-finger touch with pressure above
|
||
+ * the threshold. If pressure stays long
|
||
+ * enough, we'll start reporting primary
|
||
+ * button. We rely on the device continuing
|
||
+ * sending data even if finger does not
|
||
+ * move.
|
||
+ */
|
||
+ if (!priv->press) {
|
||
+ priv->press_start = jiffies;
|
||
+ priv->press = true;
|
||
+ } else if (time_after(jiffies,
|
||
+ priv->press_start +
|
||
+ msecs_to_jiffies(50))) {
|
||
+ priv->report_press = true;
|
||
+ }
|
||
+ } else {
|
||
+ priv->press = false;
|
||
+ }
|
||
+
|
||
+ hw->left = priv->report_press;
|
||
+
|
||
+ } else if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
|
||
/*
|
||
* Clickpad's button is transmitted as middle button,
|
||
* however, since it is primary button, we will report
|
||
@@ -506,21 +590,6 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
||
hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
|
||
}
|
||
|
||
- if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
|
||
- SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
|
||
- hw->w == 2) {
|
||
- synaptics_parse_agm(buf, priv, hw);
|
||
- return 1;
|
||
- }
|
||
-
|
||
- hw->x = (((buf[3] & 0x10) << 8) |
|
||
- ((buf[1] & 0x0f) << 8) |
|
||
- buf[4]);
|
||
- hw->y = (((buf[3] & 0x20) << 7) |
|
||
- ((buf[1] & 0xf0) << 4) |
|
||
- buf[5]);
|
||
- hw->z = buf[2];
|
||
-
|
||
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
|
||
((buf[0] ^ buf[3]) & 0x02)) {
|
||
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
|
||
@@ -555,6 +624,22 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
||
hw->right = (buf[0] & 0x02) ? 1 : 0;
|
||
}
|
||
|
||
+ /*
|
||
+ * Convert wrap-around values to negative. (X|Y)_MAX_POSITIVE
|
||
+ * is used by some firmware to indicate a finger at the edge of
|
||
+ * the touchpad whose precise position cannot be determined, so
|
||
+ * convert these values to the maximum axis value.
|
||
+ */
|
||
+ if (hw->x > X_MAX_POSITIVE)
|
||
+ hw->x -= 1 << ABS_POS_BITS;
|
||
+ else if (hw->x == X_MAX_POSITIVE)
|
||
+ hw->x = XMAX;
|
||
+
|
||
+ if (hw->y > Y_MAX_POSITIVE)
|
||
+ hw->y -= 1 << ABS_POS_BITS;
|
||
+ else if (hw->y == Y_MAX_POSITIVE)
|
||
+ hw->y = YMAX;
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
@@ -1389,10 +1474,54 @@ static const struct dmi_system_id __initconst olpc_dmi_table[] = {
|
||
{ }
|
||
};
|
||
|
||
+static const struct dmi_system_id min_max_dmi_table[] __initconst = {
|
||
+#if defined(CONFIG_DMI)
|
||
+ {
|
||
+ /* Lenovo ThinkPad Helix */
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix"),
|
||
+ },
|
||
+ .driver_data = (int []){1024, 5052, 2258, 4832},
|
||
+ },
|
||
+ {
|
||
+ /* Lenovo ThinkPad X240 */
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X240"),
|
||
+ },
|
||
+ .driver_data = (int []){1232, 5710, 1156, 4696},
|
||
+ },
|
||
+ {
|
||
+ /* Lenovo ThinkPad T440s */
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T440"),
|
||
+ },
|
||
+ .driver_data = (int []){1024, 5112, 2024, 4832},
|
||
+ },
|
||
+ {
|
||
+ /* Lenovo ThinkPad T540p */
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T540"),
|
||
+ },
|
||
+ .driver_data = (int []){1024, 5056, 2058, 4832},
|
||
+ },
|
||
+#endif
|
||
+ { }
|
||
+};
|
||
+
|
||
void __init synaptics_module_init(void)
|
||
{
|
||
+ const struct dmi_system_id *min_max_dmi;
|
||
+
|
||
impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
|
||
broken_olpc_ec = dmi_check_system(olpc_dmi_table);
|
||
+
|
||
+ min_max_dmi = dmi_first_match(min_max_dmi_table);
|
||
+ if (min_max_dmi)
|
||
+ quirk_min_max = min_max_dmi->driver_data;
|
||
}
|
||
|
||
static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
|
||
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
|
||
index fd26ccc..ac1b773 100644
|
||
--- a/drivers/input/mouse/synaptics.h
|
||
+++ b/drivers/input/mouse/synaptics.h
|
||
@@ -77,6 +77,11 @@
|
||
* 2 0x08 image sensor image sensor tracks 5 fingers, but only
|
||
* reports 2.
|
||
* 2 0x20 report min query 0x0f gives min coord reported
|
||
+ * 2 0x80 forcepad forcepad is a variant of clickpad that
|
||
+ * does not have physical buttons but rather
|
||
+ * uses pressure above certain threshold to
|
||
+ * report primary clicks. Forcepads also have
|
||
+ * clickpad bit set.
|
||
*/
|
||
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
|
||
#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */
|
||
@@ -85,6 +90,7 @@
|
||
#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
|
||
#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400)
|
||
#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800)
|
||
+#define SYN_CAP_FORCEPAD(ex0c) ((ex0c) & 0x008000)
|
||
|
||
/* synaptics modes query bits */
|
||
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
|
||
@@ -174,6 +180,11 @@ struct synaptics_data {
|
||
*/
|
||
struct synaptics_hw_state agm;
|
||
bool agm_pending; /* new AGM packet received */
|
||
+
|
||
+ /* ForcePad handling */
|
||
+ unsigned long press_start;
|
||
+ bool press;
|
||
+ bool report_press;
|
||
};
|
||
|
||
void synaptics_module_init(void);
|
||
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
|
||
index 55f2c22..93d4182 100644
|
||
--- a/drivers/input/serio/Kconfig
|
||
+++ b/drivers/input/serio/Kconfig
|
||
@@ -2,7 +2,7 @@
|
||
# Input core configuration
|
||
#
|
||
config SERIO
|
||
- tristate "Serial I/O support" if EXPERT || !X86
|
||
+ tristate "Serial I/O support"
|
||
default y
|
||
help
|
||
Say Yes here if you have any input device that uses serial I/O to
|
||
@@ -19,7 +19,7 @@ config SERIO
|
||
if SERIO
|
||
|
||
config SERIO_I8042
|
||
- tristate "i8042 PC Keyboard controller" if EXPERT || !X86
|
||
+ tristate "i8042 PC Keyboard controller"
|
||
default y
|
||
depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \
|
||
(!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN
|
||
@@ -168,7 +168,7 @@ config SERIO_MACEPS2
|
||
module will be called maceps2.
|
||
|
||
config SERIO_LIBPS2
|
||
- tristate "PS/2 driver library" if EXPERT
|
||
+ tristate "PS/2 driver library"
|
||
depends on SERIO_I8042 || SERIO_I8042=n
|
||
help
|
||
Say Y here if you are using a driver for device connected
|
||
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
|
||
index 5f306f7..1291673 100644
|
||
--- a/drivers/input/serio/i8042-x86ia64io.h
|
||
+++ b/drivers/input/serio/i8042-x86ia64io.h
|
||
@@ -458,6 +458,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
|
||
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"),
|
||
},
|
||
},
|
||
+ {
|
||
+ /* Avatar AVIU-145A6 */
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"),
|
||
+ },
|
||
+ },
|
||
{ }
|
||
};
|
||
|
||
@@ -601,6 +608,14 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
|
||
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"),
|
||
},
|
||
},
|
||
+ {
|
||
+ /* Fujitsu U574 laptop */
|
||
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"),
|
||
+ },
|
||
+ },
|
||
{ }
|
||
};
|
||
|
||
@@ -765,6 +780,7 @@ static struct pnp_device_id pnp_kbd_devids[] = {
|
||
{ .id = "CPQA0D7", .driver_data = 0 },
|
||
{ .id = "", },
|
||
};
|
||
+MODULE_DEVICE_TABLE(pnp, pnp_kbd_devids);
|
||
|
||
static struct pnp_driver i8042_pnp_kbd_driver = {
|
||
.name = "i8042 kbd",
|
||
@@ -786,6 +802,7 @@ static struct pnp_device_id pnp_aux_devids[] = {
|
||
{ .id = "SYN0801", .driver_data = 0 },
|
||
{ .id = "", },
|
||
};
|
||
+MODULE_DEVICE_TABLE(pnp, pnp_aux_devids);
|
||
|
||
static struct pnp_driver i8042_pnp_aux_driver = {
|
||
.name = "i8042 aux",
|
||
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
|
||
index 8755f5f..e4ecf3b 100644
|
||
--- a/drivers/input/serio/serport.c
|
||
+++ b/drivers/input/serio/serport.c
|
||
@@ -21,6 +21,7 @@
|
||
#include <linux/init.h>
|
||
#include <linux/serio.h>
|
||
#include <linux/tty.h>
|
||
+#include <linux/compat.h>
|
||
|
||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||
MODULE_DESCRIPTION("Input device TTY line discipline");
|
||
@@ -196,28 +197,55 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
|
||
return 0;
|
||
}
|
||
|
||
+static void serport_set_type(struct tty_struct *tty, unsigned long type)
|
||
+{
|
||
+ struct serport *serport = tty->disc_data;
|
||
+
|
||
+ serport->id.proto = type & 0x000000ff;
|
||
+ serport->id.id = (type & 0x0000ff00) >> 8;
|
||
+ serport->id.extra = (type & 0x00ff0000) >> 16;
|
||
+}
|
||
+
|
||
/*
|
||
* serport_ldisc_ioctl() allows to set the port protocol, and device ID
|
||
*/
|
||
|
||
-static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
|
||
+static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file,
|
||
+ unsigned int cmd, unsigned long arg)
|
||
{
|
||
- struct serport *serport = (struct serport*) tty->disc_data;
|
||
- unsigned long type;
|
||
-
|
||
if (cmd == SPIOCSTYPE) {
|
||
+ unsigned long type;
|
||
+
|
||
if (get_user(type, (unsigned long __user *) arg))
|
||
return -EFAULT;
|
||
|
||
- serport->id.proto = type & 0x000000ff;
|
||
- serport->id.id = (type & 0x0000ff00) >> 8;
|
||
- serport->id.extra = (type & 0x00ff0000) >> 16;
|
||
+ serport_set_type(tty, type);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ return -EINVAL;
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_COMPAT
|
||
+#define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t)
|
||
+static long serport_ldisc_compat_ioctl(struct tty_struct *tty,
|
||
+ struct file *file,
|
||
+ unsigned int cmd, unsigned long arg)
|
||
+{
|
||
+ if (cmd == COMPAT_SPIOCSTYPE) {
|
||
+ void __user *uarg = compat_ptr(arg);
|
||
+ compat_ulong_t compat_type;
|
||
+
|
||
+ if (get_user(compat_type, (compat_ulong_t __user *)uarg))
|
||
+ return -EFAULT;
|
||
|
||
+ serport_set_type(tty, compat_type);
|
||
return 0;
|
||
}
|
||
|
||
return -EINVAL;
|
||
}
|
||
+#endif
|
||
|
||
static void serport_ldisc_write_wakeup(struct tty_struct * tty)
|
||
{
|
||
@@ -241,6 +269,9 @@ static struct tty_ldisc_ops serport_ldisc = {
|
||
.close = serport_ldisc_close,
|
||
.read = serport_ldisc_read,
|
||
.ioctl = serport_ldisc_ioctl,
|
||
+#ifdef CONFIG_COMPAT
|
||
+ .compat_ioctl = serport_ldisc_compat_ioctl,
|
||
+#endif
|
||
.receive_buf = serport_ldisc_receive,
|
||
.write_wakeup = serport_ldisc_write_wakeup
|
||
};
|
||
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
|
||
index 22cd96f..ce384a4 100644
|
||
--- a/drivers/input/touchscreen/usbtouchscreen.c
|
||
+++ b/drivers/input/touchscreen/usbtouchscreen.c
|
||
@@ -106,6 +106,7 @@ struct usbtouch_device_info {
|
||
struct usbtouch_usb {
|
||
unsigned char *data;
|
||
dma_addr_t data_dma;
|
||
+ int data_size;
|
||
unsigned char *buffer;
|
||
int buf_len;
|
||
struct urb *irq;
|
||
@@ -1474,7 +1475,7 @@ static int usbtouch_reset_resume(struct usb_interface *intf)
|
||
static void usbtouch_free_buffers(struct usb_device *udev,
|
||
struct usbtouch_usb *usbtouch)
|
||
{
|
||
- usb_free_coherent(udev, usbtouch->type->rept_size,
|
||
+ usb_free_coherent(udev, usbtouch->data_size,
|
||
usbtouch->data, usbtouch->data_dma);
|
||
kfree(usbtouch->buffer);
|
||
}
|
||
@@ -1519,7 +1520,20 @@ static int usbtouch_probe(struct usb_interface *intf,
|
||
if (!type->process_pkt)
|
||
type->process_pkt = usbtouch_process_pkt;
|
||
|
||
- usbtouch->data = usb_alloc_coherent(udev, type->rept_size,
|
||
+ usbtouch->data_size = type->rept_size;
|
||
+ if (type->get_pkt_len) {
|
||
+ /*
|
||
+ * When dealing with variable-length packets we should
|
||
+ * not request more than wMaxPacketSize bytes at once
|
||
+ * as we do not know if there is more data coming or
|
||
+ * we filled exactly wMaxPacketSize bytes and there is
|
||
+ * nothing else.
|
||
+ */
|
||
+ usbtouch->data_size = min(usbtouch->data_size,
|
||
+ usb_endpoint_maxp(endpoint));
|
||
+ }
|
||
+
|
||
+ usbtouch->data = usb_alloc_coherent(udev, usbtouch->data_size,
|
||
GFP_KERNEL, &usbtouch->data_dma);
|
||
if (!usbtouch->data)
|
||
goto out_free;
|
||
@@ -1578,12 +1592,12 @@ static int usbtouch_probe(struct usb_interface *intf,
|
||
if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
|
||
usb_fill_int_urb(usbtouch->irq, udev,
|
||
usb_rcvintpipe(udev, endpoint->bEndpointAddress),
|
||
- usbtouch->data, type->rept_size,
|
||
+ usbtouch->data, usbtouch->data_size,
|
||
usbtouch_irq, usbtouch, endpoint->bInterval);
|
||
else
|
||
usb_fill_bulk_urb(usbtouch->irq, udev,
|
||
usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
|
||
- usbtouch->data, type->rept_size,
|
||
+ usbtouch->data, usbtouch->data_size,
|
||
usbtouch_irq, usbtouch);
|
||
|
||
usbtouch->irq->dev = udev;
|
||
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
|
||
index 56ddfed..a20d64d 100644
|
||
--- a/drivers/iommu/amd_iommu.c
|
||
+++ b/drivers/iommu/amd_iommu.c
|
||
@@ -3028,14 +3028,16 @@ int __init amd_iommu_init_dma_ops(void)
|
||
|
||
static void cleanup_domain(struct protection_domain *domain)
|
||
{
|
||
- struct iommu_dev_data *dev_data, *next;
|
||
+ struct iommu_dev_data *entry;
|
||
unsigned long flags;
|
||
|
||
write_lock_irqsave(&amd_iommu_devtable_lock, flags);
|
||
|
||
- list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) {
|
||
- __detach_device(dev_data);
|
||
- atomic_set(&dev_data->bind, 0);
|
||
+ while (!list_empty(&domain->dev_list)) {
|
||
+ entry = list_first_entry(&domain->dev_list,
|
||
+ struct iommu_dev_data, list);
|
||
+ __detach_device(entry);
|
||
+ atomic_set(&entry->bind, 0);
|
||
}
|
||
|
||
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
|
||
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
|
||
index 97b2e21..cf065df 100644
|
||
--- a/drivers/iommu/dmar.c
|
||
+++ b/drivers/iommu/dmar.c
|
||
@@ -582,7 +582,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
|
||
{
|
||
struct intel_iommu *iommu;
|
||
int map_size;
|
||
- u32 ver;
|
||
+ u32 ver, sts;
|
||
static int iommu_allocated = 0;
|
||
int agaw = 0;
|
||
int msagaw = 0;
|
||
@@ -652,6 +652,15 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
|
||
(unsigned long long)iommu->cap,
|
||
(unsigned long long)iommu->ecap);
|
||
|
||
+ /* Reflect status in gcmd */
|
||
+ sts = readl(iommu->reg + DMAR_GSTS_REG);
|
||
+ if (sts & DMA_GSTS_IRES)
|
||
+ iommu->gcmd |= DMA_GCMD_IRE;
|
||
+ if (sts & DMA_GSTS_TES)
|
||
+ iommu->gcmd |= DMA_GCMD_TE;
|
||
+ if (sts & DMA_GSTS_QIES)
|
||
+ iommu->gcmd |= DMA_GCMD_QIE;
|
||
+
|
||
raw_spin_lock_init(&iommu->register_lock);
|
||
|
||
drhd->iommu = iommu;
|
||
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
|
||
index befab8c..a5f4359 100644
|
||
--- a/drivers/iommu/intel-iommu.c
|
||
+++ b/drivers/iommu/intel-iommu.c
|
||
@@ -778,7 +778,11 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
|
||
int offset;
|
||
|
||
BUG_ON(!domain->pgd);
|
||
- BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
|
||
+
|
||
+ if (addr_width < BITS_PER_LONG && pfn >> addr_width)
|
||
+ /* Address beyond IOMMU's addressing capabilities. */
|
||
+ return NULL;
|
||
+
|
||
parent = domain->pgd;
|
||
|
||
while (level > 0) {
|
||
@@ -909,7 +913,7 @@ static void dma_pte_free_level(struct dmar_domain *domain, int level,
|
||
|
||
/* If range covers entire pagetable, free it */
|
||
if (!(start_pfn > level_pfn ||
|
||
- last_pfn < level_pfn + level_size(level))) {
|
||
+ last_pfn < level_pfn + level_size(level) - 1)) {
|
||
dma_clear_pte(pte);
|
||
domain_flush_cache(domain, pte, sizeof(*pte));
|
||
free_pgtable_page(level_pte);
|
||
@@ -3655,6 +3659,7 @@ static struct notifier_block device_nb = {
|
||
int __init intel_iommu_init(void)
|
||
{
|
||
int ret = 0;
|
||
+ struct dmar_drhd_unit *drhd;
|
||
|
||
/* VT-d is required for a TXT/tboot launch, so enforce that */
|
||
force_on = tboot_force_iommu();
|
||
@@ -3665,6 +3670,20 @@ int __init intel_iommu_init(void)
|
||
return -ENODEV;
|
||
}
|
||
|
||
+ /*
|
||
+ * Disable translation if already enabled prior to OS handover.
|
||
+ */
|
||
+ for_each_drhd_unit(drhd) {
|
||
+ struct intel_iommu *iommu;
|
||
+
|
||
+ if (drhd->ignored)
|
||
+ continue;
|
||
+
|
||
+ iommu = drhd->iommu;
|
||
+ if (iommu->gcmd & DMA_GCMD_TE)
|
||
+ iommu_disable_translation(iommu);
|
||
+ }
|
||
+
|
||
if (dmar_dev_scope_init() < 0) {
|
||
if (force_on)
|
||
panic("tboot: Failed to initialize DMAR device scope\n");
|
||
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
|
||
index baf2686..5a4da94 100644
|
||
--- a/drivers/isdn/isdnloop/isdnloop.c
|
||
+++ b/drivers/isdn/isdnloop/isdnloop.c
|
||
@@ -518,9 +518,9 @@ static isdnloop_stat isdnloop_cmd_table[] =
|
||
static void
|
||
isdnloop_fake_err(isdnloop_card *card)
|
||
{
|
||
- char buf[60];
|
||
+ char buf[64];
|
||
|
||
- sprintf(buf, "E%s", card->omsg);
|
||
+ snprintf(buf, sizeof(buf), "E%s", card->omsg);
|
||
isdnloop_fake(card, buf, -1);
|
||
isdnloop_fake(card, "NAK", -1);
|
||
}
|
||
@@ -903,6 +903,8 @@ isdnloop_parse_cmd(isdnloop_card *card)
|
||
case 7:
|
||
/* 0x;EAZ */
|
||
p += 3;
|
||
+ if (strlen(p) >= sizeof(card->eazlist[0]))
|
||
+ break;
|
||
strcpy(card->eazlist[ch - 1], p);
|
||
break;
|
||
case 8:
|
||
@@ -1070,6 +1072,12 @@ isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp)
|
||
return -EBUSY;
|
||
if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef)))
|
||
return -EFAULT;
|
||
+
|
||
+ for (i = 0; i < 3; i++) {
|
||
+ if (!memchr(sdef.num[i], 0, sizeof(sdef.num[i])))
|
||
+ return -EINVAL;
|
||
+ }
|
||
+
|
||
spin_lock_irqsave(&card->isdnloop_lock, flags);
|
||
switch (sdef.ptype) {
|
||
case ISDN_PTYPE_EURO:
|
||
@@ -1083,8 +1091,10 @@ isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp)
|
||
spin_unlock_irqrestore(&card->isdnloop_lock, flags);
|
||
return -ENOMEM;
|
||
}
|
||
- for (i = 0; i < 3; i++)
|
||
- strcpy(card->s0num[i], sdef.num[i]);
|
||
+ for (i = 0; i < 3; i++) {
|
||
+ strlcpy(card->s0num[i], sdef.num[i],
|
||
+ sizeof(card->s0num[0]));
|
||
+ }
|
||
break;
|
||
case ISDN_PTYPE_1TR6:
|
||
if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
|
||
@@ -1097,7 +1107,7 @@ isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp)
|
||
spin_unlock_irqrestore(&card->isdnloop_lock, flags);
|
||
return -ENOMEM;
|
||
}
|
||
- strcpy(card->s0num[0], sdef.num[0]);
|
||
+ strlcpy(card->s0num[0], sdef.num[0], sizeof(card->s0num[0]));
|
||
card->s0num[1][0] = '\0';
|
||
card->s0num[2][0] = '\0';
|
||
break;
|
||
@@ -1125,7 +1135,7 @@ isdnloop_command(isdn_ctrl *c, isdnloop_card *card)
|
||
{
|
||
ulong a;
|
||
int i;
|
||
- char cbuf[60];
|
||
+ char cbuf[80];
|
||
isdn_ctrl cmd;
|
||
isdnloop_cdef cdef;
|
||
|
||
@@ -1190,7 +1200,6 @@ isdnloop_command(isdn_ctrl *c, isdnloop_card *card)
|
||
break;
|
||
if ((c->arg & 255) < ISDNLOOP_BCH) {
|
||
char *p;
|
||
- char dial[50];
|
||
char dcode[4];
|
||
|
||
a = c->arg;
|
||
@@ -1202,10 +1211,10 @@ isdnloop_command(isdn_ctrl *c, isdnloop_card *card)
|
||
} else
|
||
/* Normal Dial */
|
||
strcpy(dcode, "CAL");
|
||
- strcpy(dial, p);
|
||
- sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
|
||
- dcode, dial, c->parm.setup.si1,
|
||
- c->parm.setup.si2, c->parm.setup.eazmsn);
|
||
+ snprintf(cbuf, sizeof(cbuf),
|
||
+ "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
|
||
+ dcode, p, c->parm.setup.si1,
|
||
+ c->parm.setup.si2, c->parm.setup.eazmsn);
|
||
i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
|
||
}
|
||
break;
|
||
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
|
||
index abe2d69..ade1bcf 100644
|
||
--- a/drivers/isdn/mISDN/socket.c
|
||
+++ b/drivers/isdn/mISDN/socket.c
|
||
@@ -117,7 +117,6 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
{
|
||
struct sk_buff *skb;
|
||
struct sock *sk = sock->sk;
|
||
- struct sockaddr_mISDN *maddr;
|
||
|
||
int copied, err;
|
||
|
||
@@ -135,9 +134,9 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (!skb)
|
||
return err;
|
||
|
||
- if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) {
|
||
- msg->msg_namelen = sizeof(struct sockaddr_mISDN);
|
||
- maddr = (struct sockaddr_mISDN *)msg->msg_name;
|
||
+ if (msg->msg_name) {
|
||
+ struct sockaddr_mISDN *maddr = msg->msg_name;
|
||
+
|
||
maddr->family = AF_ISDN;
|
||
maddr->dev = _pms(sk)->dev->id;
|
||
if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
|
||
@@ -150,11 +149,7 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
maddr->sapi = _pms(sk)->ch.addr & 0xFF;
|
||
maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF;
|
||
}
|
||
- } else {
|
||
- if (msg->msg_namelen)
|
||
- printk(KERN_WARNING "%s: too small namelen %d\n",
|
||
- __func__, msg->msg_namelen);
|
||
- msg->msg_namelen = 0;
|
||
+ msg->msg_namelen = sizeof(*maddr);
|
||
}
|
||
|
||
copied = skb->len + MISDN_HEADER_LEN;
|
||
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
|
||
index 0c433eb..80a19fa 100644
|
||
--- a/drivers/md/Kconfig
|
||
+++ b/drivers/md/Kconfig
|
||
@@ -185,8 +185,12 @@ config MD_FAULTY
|
||
|
||
In unsure, say N.
|
||
|
||
+config BLK_DEV_DM_BUILTIN
|
||
+ boolean
|
||
+
|
||
config BLK_DEV_DM
|
||
tristate "Device mapper support"
|
||
+ select BLK_DEV_DM_BUILTIN
|
||
---help---
|
||
Device-mapper is a low level volume manager. It works by allowing
|
||
people to specify mappings for ranges of logical sectors. Various
|
||
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
|
||
index 1ac9624..94d4023 100644
|
||
--- a/drivers/md/Makefile
|
||
+++ b/drivers/md/Makefile
|
||
@@ -28,6 +28,7 @@ obj-$(CONFIG_MD_MULTIPATH) += multipath.o
|
||
obj-$(CONFIG_MD_FAULTY) += faulty.o
|
||
obj-$(CONFIG_BLK_DEV_MD) += md-mod.o
|
||
obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
|
||
+obj-$(CONFIG_BLK_DEV_DM_BUILTIN) += dm-builtin.o
|
||
obj-$(CONFIG_DM_BUFIO) += dm-bufio.o
|
||
obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
|
||
obj-$(CONFIG_DM_DELAY) += dm-delay.o
|
||
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
|
||
index cc06a1e..6f99500 100644
|
||
--- a/drivers/md/dm-bufio.c
|
||
+++ b/drivers/md/dm-bufio.c
|
||
@@ -321,6 +321,9 @@ static void __cache_size_refresh(void)
|
||
static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
|
||
enum data_mode *data_mode)
|
||
{
|
||
+ unsigned noio_flag;
|
||
+ void *ptr;
|
||
+
|
||
if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) {
|
||
*data_mode = DATA_MODE_SLAB;
|
||
return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask);
|
||
@@ -334,7 +337,28 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
|
||
}
|
||
|
||
*data_mode = DATA_MODE_VMALLOC;
|
||
- return __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
|
||
+
|
||
+ /*
|
||
+ * __vmalloc allocates the data pages and auxiliary structures with
|
||
+ * gfp_flags that were specified, but pagetables are always allocated
|
||
+ * with GFP_KERNEL, no matter what was specified as gfp_mask.
|
||
+ *
|
||
+ * Consequently, we must set per-process flag PF_MEMALLOC_NOIO so that
|
||
+ * all allocations done by this process (including pagetables) are done
|
||
+ * as if GFP_NOIO was specified.
|
||
+ */
|
||
+
|
||
+ if (gfp_mask & __GFP_NORETRY) {
|
||
+ noio_flag = current->flags & PF_MEMALLOC;
|
||
+ current->flags |= PF_MEMALLOC;
|
||
+ }
|
||
+
|
||
+ ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
|
||
+
|
||
+ if (gfp_mask & __GFP_NORETRY)
|
||
+ current->flags = (current->flags & ~PF_MEMALLOC) | noio_flag;
|
||
+
|
||
+ return ptr;
|
||
}
|
||
|
||
/*
|
||
@@ -1642,6 +1666,11 @@ static int __init dm_bufio_init(void)
|
||
{
|
||
__u64 mem;
|
||
|
||
+ dm_bufio_allocated_kmem_cache = 0;
|
||
+ dm_bufio_allocated_get_free_pages = 0;
|
||
+ dm_bufio_allocated_vmalloc = 0;
|
||
+ dm_bufio_current_allocated = 0;
|
||
+
|
||
memset(&dm_bufio_caches, 0, sizeof dm_bufio_caches);
|
||
memset(&dm_bufio_cache_names, 0, sizeof dm_bufio_cache_names);
|
||
|
||
diff --git a/drivers/md/dm-builtin.c b/drivers/md/dm-builtin.c
|
||
new file mode 100644
|
||
index 0000000..797daec
|
||
--- /dev/null
|
||
+++ b/drivers/md/dm-builtin.c
|
||
@@ -0,0 +1,50 @@
|
||
+#include "dm.h"
|
||
+
|
||
+#include <linux/export.h>
|
||
+
|
||
+/*
|
||
+ * The kobject release method must not be placed in the module itself,
|
||
+ * otherwise we are subject to module unload races.
|
||
+ *
|
||
+ * The release method is called when the last reference to the kobject is
|
||
+ * dropped. It may be called by any other kernel code that drops the last
|
||
+ * reference.
|
||
+ *
|
||
+ * The release method suffers from module unload race. We may prevent the
|
||
+ * module from being unloaded at the start of the release method (using
|
||
+ * increased module reference count or synchronizing against the release
|
||
+ * method), however there is no way to prevent the module from being
|
||
+ * unloaded at the end of the release method.
|
||
+ *
|
||
+ * If this code were placed in the dm module, the following race may
|
||
+ * happen:
|
||
+ * 1. Some other process takes a reference to dm kobject
|
||
+ * 2. The user issues ioctl function to unload the dm device
|
||
+ * 3. dm_sysfs_exit calls kobject_put, however the object is not released
|
||
+ * because of the other reference taken at step 1
|
||
+ * 4. dm_sysfs_exit waits on the completion
|
||
+ * 5. The other process that took the reference in step 1 drops it,
|
||
+ * dm_kobject_release is called from this process
|
||
+ * 6. dm_kobject_release calls complete()
|
||
+ * 7. a reschedule happens before dm_kobject_release returns
|
||
+ * 8. dm_sysfs_exit continues, the dm device is unloaded, module reference
|
||
+ * count is decremented
|
||
+ * 9. The user unloads the dm module
|
||
+ * 10. The other process that was rescheduled in step 7 continues to run,
|
||
+ * it is now executing code in unloaded module, so it crashes
|
||
+ *
|
||
+ * Note that if the process that takes the foreign reference to dm kobject
|
||
+ * has a low priority and the system is sufficiently loaded with
|
||
+ * higher-priority processes that prevent the low-priority process from
|
||
+ * being scheduled long enough, this bug may really happen.
|
||
+ *
|
||
+ * In order to fix this module unload race, we place the release method
|
||
+ * into a helper code that is compiled directly into the kernel.
|
||
+ */
|
||
+
|
||
+void dm_kobject_release(struct kobject *kobj)
|
||
+{
|
||
+ complete(dm_get_completion_from_kobject(kobj));
|
||
+}
|
||
+
|
||
+EXPORT_SYMBOL(dm_kobject_release);
|
||
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
|
||
index d749d92..19391c1 100644
|
||
--- a/drivers/md/dm-crypt.c
|
||
+++ b/drivers/md/dm-crypt.c
|
||
@@ -1538,6 +1538,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||
unsigned int key_size, opt_params;
|
||
unsigned long long tmpll;
|
||
int ret;
|
||
+ size_t iv_size_padding;
|
||
struct dm_arg_set as;
|
||
const char *opt_string;
|
||
char dummy;
|
||
@@ -1574,12 +1575,23 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||
|
||
cc->dmreq_start = sizeof(struct ablkcipher_request);
|
||
cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc));
|
||
- cc->dmreq_start = ALIGN(cc->dmreq_start, crypto_tfm_ctx_alignment());
|
||
- cc->dmreq_start += crypto_ablkcipher_alignmask(any_tfm(cc)) &
|
||
- ~(crypto_tfm_ctx_alignment() - 1);
|
||
+ cc->dmreq_start = ALIGN(cc->dmreq_start, __alignof__(struct dm_crypt_request));
|
||
+
|
||
+ if (crypto_ablkcipher_alignmask(any_tfm(cc)) < CRYPTO_MINALIGN) {
|
||
+ /* Allocate the padding exactly */
|
||
+ iv_size_padding = -(cc->dmreq_start + sizeof(struct dm_crypt_request))
|
||
+ & crypto_ablkcipher_alignmask(any_tfm(cc));
|
||
+ } else {
|
||
+ /*
|
||
+ * If the cipher requires greater alignment than kmalloc
|
||
+ * alignment, we don't know the exact position of the
|
||
+ * initialization vector. We must assume worst case.
|
||
+ */
|
||
+ iv_size_padding = crypto_ablkcipher_alignmask(any_tfm(cc));
|
||
+ }
|
||
|
||
cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start +
|
||
- sizeof(struct dm_crypt_request) + cc->iv_size);
|
||
+ sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size);
|
||
if (!cc->req_pool) {
|
||
ti->error = "Cannot allocate crypt request mempool";
|
||
goto bad;
|
||
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
|
||
index 2dc22dd..a13a5d0 100644
|
||
--- a/drivers/md/dm-delay.c
|
||
+++ b/drivers/md/dm-delay.c
|
||
@@ -20,6 +20,7 @@
|
||
struct delay_c {
|
||
struct timer_list delay_timer;
|
||
struct mutex timer_lock;
|
||
+ struct workqueue_struct *kdelayd_wq;
|
||
struct work_struct flush_expired_bios;
|
||
struct list_head delayed_bios;
|
||
atomic_t may_delay;
|
||
@@ -45,14 +46,13 @@ struct dm_delay_info {
|
||
|
||
static DEFINE_MUTEX(delayed_bios_lock);
|
||
|
||
-static struct workqueue_struct *kdelayd_wq;
|
||
static struct kmem_cache *delayed_cache;
|
||
|
||
static void handle_delayed_timer(unsigned long data)
|
||
{
|
||
struct delay_c *dc = (struct delay_c *)data;
|
||
|
||
- queue_work(kdelayd_wq, &dc->flush_expired_bios);
|
||
+ queue_work(dc->kdelayd_wq, &dc->flush_expired_bios);
|
||
}
|
||
|
||
static void queue_timeout(struct delay_c *dc, unsigned long expires)
|
||
@@ -191,6 +191,12 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||
goto bad_dev_write;
|
||
}
|
||
|
||
+ dc->kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0);
|
||
+ if (!dc->kdelayd_wq) {
|
||
+ DMERR("Couldn't start kdelayd");
|
||
+ goto bad_queue;
|
||
+ }
|
||
+
|
||
setup_timer(&dc->delay_timer, handle_delayed_timer, (unsigned long)dc);
|
||
|
||
INIT_WORK(&dc->flush_expired_bios, flush_expired_bios);
|
||
@@ -203,6 +209,8 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||
ti->private = dc;
|
||
return 0;
|
||
|
||
+bad_queue:
|
||
+ mempool_destroy(dc->delayed_pool);
|
||
bad_dev_write:
|
||
if (dc->dev_write)
|
||
dm_put_device(ti, dc->dev_write);
|
||
@@ -217,7 +225,7 @@ static void delay_dtr(struct dm_target *ti)
|
||
{
|
||
struct delay_c *dc = ti->private;
|
||
|
||
- flush_workqueue(kdelayd_wq);
|
||
+ destroy_workqueue(dc->kdelayd_wq);
|
||
|
||
dm_put_device(ti, dc->dev_read);
|
||
|
||
@@ -353,12 +361,6 @@ static int __init dm_delay_init(void)
|
||
{
|
||
int r = -ENOMEM;
|
||
|
||
- kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0);
|
||
- if (!kdelayd_wq) {
|
||
- DMERR("Couldn't start kdelayd");
|
||
- goto bad_queue;
|
||
- }
|
||
-
|
||
delayed_cache = KMEM_CACHE(dm_delay_info, 0);
|
||
if (!delayed_cache) {
|
||
DMERR("Couldn't create delayed bio cache.");
|
||
@@ -376,8 +378,6 @@ static int __init dm_delay_init(void)
|
||
bad_register:
|
||
kmem_cache_destroy(delayed_cache);
|
||
bad_memcache:
|
||
- destroy_workqueue(kdelayd_wq);
|
||
-bad_queue:
|
||
return r;
|
||
}
|
||
|
||
@@ -385,7 +385,6 @@ static void __exit dm_delay_exit(void)
|
||
{
|
||
dm_unregister_target(&delay_target);
|
||
kmem_cache_destroy(delayed_cache);
|
||
- destroy_workqueue(kdelayd_wq);
|
||
}
|
||
|
||
/* Module hooks */
|
||
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
|
||
index 754f38f..495df03 100644
|
||
--- a/drivers/md/dm-mpath.c
|
||
+++ b/drivers/md/dm-mpath.c
|
||
@@ -84,6 +84,7 @@ struct multipath {
|
||
unsigned queue_io; /* Must we queue all I/O? */
|
||
unsigned queue_if_no_path; /* Queue I/O if last path fails? */
|
||
unsigned saved_queue_if_no_path;/* Saved state during suspension */
|
||
+ unsigned pg_init_disabled:1; /* pg_init is not currently allowed */
|
||
unsigned pg_init_retries; /* Number of times to retry pg_init */
|
||
unsigned pg_init_count; /* Number of times pg_init called */
|
||
unsigned pg_init_delay_msecs; /* Number of msecs before pg_init retry */
|
||
@@ -493,7 +494,8 @@ static void process_queued_ios(struct work_struct *work)
|
||
(!pgpath && !m->queue_if_no_path))
|
||
must_queue = 0;
|
||
|
||
- if (m->pg_init_required && !m->pg_init_in_progress && pgpath)
|
||
+ if (m->pg_init_required && !m->pg_init_in_progress && pgpath &&
|
||
+ !m->pg_init_disabled)
|
||
__pg_init_all_paths(m);
|
||
|
||
out:
|
||
@@ -907,10 +909,20 @@ static void multipath_wait_for_pg_init_completion(struct multipath *m)
|
||
|
||
static void flush_multipath_work(struct multipath *m)
|
||
{
|
||
+ unsigned long flags;
|
||
+
|
||
+ spin_lock_irqsave(&m->lock, flags);
|
||
+ m->pg_init_disabled = 1;
|
||
+ spin_unlock_irqrestore(&m->lock, flags);
|
||
+
|
||
flush_workqueue(kmpath_handlerd);
|
||
multipath_wait_for_pg_init_completion(m);
|
||
flush_workqueue(kmultipathd);
|
||
flush_work_sync(&m->trigger_event);
|
||
+
|
||
+ spin_lock_irqsave(&m->lock, flags);
|
||
+ m->pg_init_disabled = 0;
|
||
+ spin_unlock_irqrestore(&m->lock, flags);
|
||
}
|
||
|
||
static void multipath_dtr(struct dm_target *ti)
|
||
@@ -1129,7 +1141,7 @@ static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)
|
||
|
||
spin_lock_irqsave(&m->lock, flags);
|
||
|
||
- if (m->pg_init_count <= m->pg_init_retries)
|
||
+ if (m->pg_init_count <= m->pg_init_retries && !m->pg_init_disabled)
|
||
m->pg_init_required = 1;
|
||
else
|
||
limit_reached = 1;
|
||
@@ -1543,8 +1555,11 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
|
||
/*
|
||
* Only pass ioctls through if the device sizes match exactly.
|
||
*/
|
||
- if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
|
||
- r = scsi_verify_blk_ioctl(NULL, cmd);
|
||
+ if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) {
|
||
+ int err = scsi_verify_blk_ioctl(NULL, cmd);
|
||
+ if (err)
|
||
+ r = err;
|
||
+ }
|
||
|
||
return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||
}
|
||
@@ -1643,7 +1658,7 @@ static int multipath_busy(struct dm_target *ti)
|
||
*---------------------------------------------------------------*/
|
||
static struct target_type multipath_target = {
|
||
.name = "multipath",
|
||
- .version = {1, 3, 0},
|
||
+ .version = {1, 3, 2},
|
||
.module = THIS_MODULE,
|
||
.ctr = multipath_ctr,
|
||
.dtr = multipath_dtr,
|
||
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
|
||
index 4caa8e6..2d2b1b7 100644
|
||
--- a/drivers/md/dm-snap-persistent.c
|
||
+++ b/drivers/md/dm-snap-persistent.c
|
||
@@ -269,6 +269,14 @@ static chunk_t area_location(struct pstore *ps, chunk_t area)
|
||
return NUM_SNAPSHOT_HDR_CHUNKS + ((ps->exceptions_per_area + 1) * area);
|
||
}
|
||
|
||
+static void skip_metadata(struct pstore *ps)
|
||
+{
|
||
+ uint32_t stride = ps->exceptions_per_area + 1;
|
||
+ chunk_t next_free = ps->next_free;
|
||
+ if (sector_div(next_free, stride) == NUM_SNAPSHOT_HDR_CHUNKS)
|
||
+ ps->next_free++;
|
||
+}
|
||
+
|
||
/*
|
||
* Read or write a metadata area. Remembering to skip the first
|
||
* chunk which holds the header.
|
||
@@ -502,6 +510,8 @@ static int read_exceptions(struct pstore *ps,
|
||
|
||
ps->current_area--;
|
||
|
||
+ skip_metadata(ps);
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
@@ -616,8 +626,6 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
|
||
struct dm_exception *e)
|
||
{
|
||
struct pstore *ps = get_info(store);
|
||
- uint32_t stride;
|
||
- chunk_t next_free;
|
||
sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev);
|
||
|
||
/* Is there enough room ? */
|
||
@@ -630,10 +638,8 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
|
||
* Move onto the next free pending, making sure to take
|
||
* into account the location of the metadata chunks.
|
||
*/
|
||
- stride = (ps->exceptions_per_area + 1);
|
||
- next_free = ++ps->next_free;
|
||
- if (sector_div(next_free, stride) == 1)
|
||
- ps->next_free++;
|
||
+ ps->next_free++;
|
||
+ skip_metadata(ps);
|
||
|
||
atomic_inc(&ps->pending_count);
|
||
return 0;
|
||
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
|
||
index 448050c..39ca4a4 100644
|
||
--- a/drivers/md/dm-snap.c
|
||
+++ b/drivers/md/dm-snap.c
|
||
@@ -66,6 +66,18 @@ struct dm_snapshot {
|
||
|
||
atomic_t pending_exceptions_count;
|
||
|
||
+ /* Protected by "lock" */
|
||
+ sector_t exception_start_sequence;
|
||
+
|
||
+ /* Protected by kcopyd single-threaded callback */
|
||
+ sector_t exception_complete_sequence;
|
||
+
|
||
+ /*
|
||
+ * A list of pending exceptions that completed out of order.
|
||
+ * Protected by kcopyd single-threaded callback.
|
||
+ */
|
||
+ struct list_head out_of_order_list;
|
||
+
|
||
mempool_t *pending_pool;
|
||
|
||
struct dm_exception_table pending;
|
||
@@ -171,6 +183,14 @@ struct dm_snap_pending_exception {
|
||
*/
|
||
int started;
|
||
|
||
+ /* There was copying error. */
|
||
+ int copy_error;
|
||
+
|
||
+ /* A sequence number, it is used for in-order completion. */
|
||
+ sector_t exception_sequence;
|
||
+
|
||
+ struct list_head out_of_order_entry;
|
||
+
|
||
/*
|
||
* For writing a complete chunk, bypassing the copy.
|
||
*/
|
||
@@ -1090,6 +1110,9 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||
s->valid = 1;
|
||
s->active = 0;
|
||
atomic_set(&s->pending_exceptions_count, 0);
|
||
+ s->exception_start_sequence = 0;
|
||
+ s->exception_complete_sequence = 0;
|
||
+ INIT_LIST_HEAD(&s->out_of_order_list);
|
||
init_rwsem(&s->lock);
|
||
INIT_LIST_HEAD(&s->list);
|
||
spin_lock_init(&s->pe_lock);
|
||
@@ -1448,6 +1471,19 @@ static void commit_callback(void *context, int success)
|
||
pending_complete(pe, success);
|
||
}
|
||
|
||
+static void complete_exception(struct dm_snap_pending_exception *pe)
|
||
+{
|
||
+ struct dm_snapshot *s = pe->snap;
|
||
+
|
||
+ if (unlikely(pe->copy_error))
|
||
+ pending_complete(pe, 0);
|
||
+
|
||
+ else
|
||
+ /* Update the metadata if we are persistent */
|
||
+ s->store->type->commit_exception(s->store, &pe->e,
|
||
+ commit_callback, pe);
|
||
+}
|
||
+
|
||
/*
|
||
* Called when the copy I/O has finished. kcopyd actually runs
|
||
* this code so don't block.
|
||
@@ -1457,13 +1493,32 @@ static void copy_callback(int read_err, unsigned long write_err, void *context)
|
||
struct dm_snap_pending_exception *pe = context;
|
||
struct dm_snapshot *s = pe->snap;
|
||
|
||
- if (read_err || write_err)
|
||
- pending_complete(pe, 0);
|
||
+ pe->copy_error = read_err || write_err;
|
||
|
||
- else
|
||
- /* Update the metadata if we are persistent */
|
||
- s->store->type->commit_exception(s->store, &pe->e,
|
||
- commit_callback, pe);
|
||
+ if (pe->exception_sequence == s->exception_complete_sequence) {
|
||
+ s->exception_complete_sequence++;
|
||
+ complete_exception(pe);
|
||
+
|
||
+ while (!list_empty(&s->out_of_order_list)) {
|
||
+ pe = list_entry(s->out_of_order_list.next,
|
||
+ struct dm_snap_pending_exception, out_of_order_entry);
|
||
+ if (pe->exception_sequence != s->exception_complete_sequence)
|
||
+ break;
|
||
+ s->exception_complete_sequence++;
|
||
+ list_del(&pe->out_of_order_entry);
|
||
+ complete_exception(pe);
|
||
+ }
|
||
+ } else {
|
||
+ struct list_head *lh;
|
||
+ struct dm_snap_pending_exception *pe2;
|
||
+
|
||
+ list_for_each_prev(lh, &s->out_of_order_list) {
|
||
+ pe2 = list_entry(lh, struct dm_snap_pending_exception, out_of_order_entry);
|
||
+ if (pe2->exception_sequence < pe->exception_sequence)
|
||
+ break;
|
||
+ }
|
||
+ list_add(&pe->out_of_order_entry, lh);
|
||
+ }
|
||
}
|
||
|
||
/*
|
||
@@ -1558,6 +1613,8 @@ __find_pending_exception(struct dm_snapshot *s,
|
||
return NULL;
|
||
}
|
||
|
||
+ pe->exception_sequence = s->exception_start_sequence++;
|
||
+
|
||
dm_insert_exception(&s->pending, &pe->e);
|
||
|
||
return pe;
|
||
@@ -2204,7 +2261,7 @@ static struct target_type origin_target = {
|
||
|
||
static struct target_type snapshot_target = {
|
||
.name = "snapshot",
|
||
- .version = {1, 10, 0},
|
||
+ .version = {1, 10, 2},
|
||
.module = THIS_MODULE,
|
||
.ctr = snapshot_ctr,
|
||
.dtr = snapshot_dtr,
|
||
@@ -2327,3 +2384,5 @@ module_exit(dm_snapshot_exit);
|
||
MODULE_DESCRIPTION(DM_NAME " snapshot target");
|
||
MODULE_AUTHOR("Joe Thornber");
|
||
MODULE_LICENSE("GPL");
|
||
+MODULE_ALIAS("dm-snapshot-origin");
|
||
+MODULE_ALIAS("dm-snapshot-merge");
|
||
diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c
|
||
index 84d2b91..c62c5ab 100644
|
||
--- a/drivers/md/dm-sysfs.c
|
||
+++ b/drivers/md/dm-sysfs.c
|
||
@@ -86,6 +86,7 @@ static const struct sysfs_ops dm_sysfs_ops = {
|
||
static struct kobj_type dm_ktype = {
|
||
.sysfs_ops = &dm_sysfs_ops,
|
||
.default_attrs = dm_attrs,
|
||
+ .release = dm_kobject_release,
|
||
};
|
||
|
||
/*
|
||
@@ -104,5 +105,7 @@ int dm_sysfs_init(struct mapped_device *md)
|
||
*/
|
||
void dm_sysfs_exit(struct mapped_device *md)
|
||
{
|
||
- kobject_put(dm_kobject(md));
|
||
+ struct kobject *kobj = dm_kobject(md);
|
||
+ kobject_put(kobj);
|
||
+ wait_for_completion(dm_get_completion_from_kobject(kobj));
|
||
}
|
||
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
|
||
index f220a69..43e19b7 100644
|
||
--- a/drivers/md/dm-table.c
|
||
+++ b/drivers/md/dm-table.c
|
||
@@ -215,6 +215,11 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
|
||
|
||
num_targets = dm_round_up(num_targets, KEYS_PER_NODE);
|
||
|
||
+ if (!num_targets) {
|
||
+ kfree(t);
|
||
+ return -ENOMEM;
|
||
+ }
|
||
+
|
||
if (alloc_targets(t, num_targets)) {
|
||
kfree(t);
|
||
t = NULL;
|
||
@@ -581,14 +586,28 @@ static int adjoin(struct dm_table *table, struct dm_target *ti)
|
||
|
||
/*
|
||
* Used to dynamically allocate the arg array.
|
||
+ *
|
||
+ * We do first allocation with GFP_NOIO because dm-mpath and dm-thin must
|
||
+ * process messages even if some device is suspended. These messages have a
|
||
+ * small fixed number of arguments.
|
||
+ *
|
||
+ * On the other hand, dm-switch needs to process bulk data using messages and
|
||
+ * excessive use of GFP_NOIO could cause trouble.
|
||
*/
|
||
static char **realloc_argv(unsigned *array_size, char **old_argv)
|
||
{
|
||
char **argv;
|
||
unsigned new_size;
|
||
+ gfp_t gfp;
|
||
|
||
- new_size = *array_size ? *array_size * 2 : 64;
|
||
- argv = kmalloc(new_size * sizeof(*argv), GFP_KERNEL);
|
||
+ if (*array_size) {
|
||
+ new_size = *array_size * 2;
|
||
+ gfp = GFP_KERNEL;
|
||
+ } else {
|
||
+ new_size = 8;
|
||
+ gfp = GFP_NOIO;
|
||
+ }
|
||
+ argv = kmalloc(new_size * sizeof(*argv), gfp);
|
||
if (argv) {
|
||
memcpy(argv, old_argv, *array_size * sizeof(*argv));
|
||
*array_size = new_size;
|
||
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
|
||
index 7c3ab8f..46e0204 100644
|
||
--- a/drivers/md/dm-thin.c
|
||
+++ b/drivers/md/dm-thin.c
|
||
@@ -1446,9 +1446,9 @@ static void process_deferred_bios(struct pool *pool)
|
||
*/
|
||
if (ensure_next_mapping(pool)) {
|
||
spin_lock_irqsave(&pool->lock, flags);
|
||
+ bio_list_add(&pool->deferred_bios, bio);
|
||
bio_list_merge(&pool->deferred_bios, &bios);
|
||
spin_unlock_irqrestore(&pool->lock, flags);
|
||
-
|
||
break;
|
||
}
|
||
|
||
@@ -2461,7 +2461,7 @@ static struct target_type pool_target = {
|
||
.name = "thin-pool",
|
||
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
|
||
DM_TARGET_IMMUTABLE,
|
||
- .version = {1, 1, 0},
|
||
+ .version = {1, 1, 1},
|
||
.module = THIS_MODULE,
|
||
.ctr = pool_ctr,
|
||
.dtr = pool_dtr,
|
||
@@ -2734,7 +2734,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
|
||
|
||
static struct target_type thin_target = {
|
||
.name = "thin",
|
||
- .version = {1, 1, 0},
|
||
+ .version = {1, 1, 1},
|
||
.module = THIS_MODULE,
|
||
.ctr = thin_ctr,
|
||
.dtr = thin_dtr,
|
||
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
|
||
index 903cb1e..794fa3a 100644
|
||
--- a/drivers/md/dm.c
|
||
+++ b/drivers/md/dm.c
|
||
@@ -191,8 +191,8 @@ struct mapped_device {
|
||
/* forced geometry settings */
|
||
struct hd_geometry geometry;
|
||
|
||
- /* sysfs handle */
|
||
- struct kobject kobj;
|
||
+ /* kobject and completion */
|
||
+ struct dm_kobject_holder kobj_holder;
|
||
|
||
/* zero-length flush that will be cloned and submitted to targets */
|
||
struct bio flush_bio;
|
||
@@ -1891,6 +1891,7 @@ static struct mapped_device *alloc_dev(int minor)
|
||
init_waitqueue_head(&md->wait);
|
||
INIT_WORK(&md->work, dm_wq_work);
|
||
init_waitqueue_head(&md->eventq);
|
||
+ init_completion(&md->kobj_holder.completion);
|
||
|
||
md->disk->major = _major;
|
||
md->disk->first_minor = minor;
|
||
@@ -2682,20 +2683,14 @@ struct gendisk *dm_disk(struct mapped_device *md)
|
||
|
||
struct kobject *dm_kobject(struct mapped_device *md)
|
||
{
|
||
- return &md->kobj;
|
||
+ return &md->kobj_holder.kobj;
|
||
}
|
||
|
||
-/*
|
||
- * struct mapped_device should not be exported outside of dm.c
|
||
- * so use this check to verify that kobj is part of md structure
|
||
- */
|
||
struct mapped_device *dm_get_from_kobject(struct kobject *kobj)
|
||
{
|
||
struct mapped_device *md;
|
||
|
||
- md = container_of(kobj, struct mapped_device, kobj);
|
||
- if (&md->kobj != kobj)
|
||
- return NULL;
|
||
+ md = container_of(kobj, struct mapped_device, kobj_holder.kobj);
|
||
|
||
if (test_bit(DMF_FREEING, &md->flags) ||
|
||
dm_deleting_md(md))
|
||
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
|
||
index b7dacd5..9db80c9 100644
|
||
--- a/drivers/md/dm.h
|
||
+++ b/drivers/md/dm.h
|
||
@@ -15,6 +15,8 @@
|
||
#include <linux/list.h>
|
||
#include <linux/blkdev.h>
|
||
#include <linux/hdreg.h>
|
||
+#include <linux/completion.h>
|
||
+#include <linux/kobject.h>
|
||
|
||
/*
|
||
* Suspend feature flags
|
||
@@ -119,12 +121,27 @@ void dm_interface_exit(void);
|
||
/*
|
||
* sysfs interface
|
||
*/
|
||
+struct dm_kobject_holder {
|
||
+ struct kobject kobj;
|
||
+ struct completion completion;
|
||
+};
|
||
+
|
||
+static inline struct completion *dm_get_completion_from_kobject(struct kobject *kobj)
|
||
+{
|
||
+ return &container_of(kobj, struct dm_kobject_holder, kobj)->completion;
|
||
+}
|
||
+
|
||
int dm_sysfs_init(struct mapped_device *md);
|
||
void dm_sysfs_exit(struct mapped_device *md);
|
||
struct kobject *dm_kobject(struct mapped_device *md);
|
||
struct mapped_device *dm_get_from_kobject(struct kobject *kobj);
|
||
|
||
/*
|
||
+ * The kobject helper
|
||
+ */
|
||
+void dm_kobject_release(struct kobject *kobj);
|
||
+
|
||
+/*
|
||
* Targets for linear and striped mappings
|
||
*/
|
||
int dm_linear_init(void);
|
||
diff --git a/drivers/md/md.c b/drivers/md/md.c
|
||
index 7b45b5e..17e2f52 100644
|
||
--- a/drivers/md/md.c
|
||
+++ b/drivers/md/md.c
|
||
@@ -3507,6 +3507,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
|
||
mddev->in_sync = 1;
|
||
del_timer_sync(&mddev->safemode_timer);
|
||
}
|
||
+ blk_set_stacking_limits(&mddev->queue->limits);
|
||
pers->run(mddev);
|
||
mddev_resume(mddev);
|
||
set_bit(MD_CHANGE_DEVS, &mddev->flags);
|
||
@@ -7070,8 +7071,10 @@ void md_do_sync(struct mddev *mddev)
|
||
/* just incase thread restarts... */
|
||
if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
|
||
return;
|
||
- if (mddev->ro) /* never try to sync a read-only array */
|
||
+ if (mddev->ro) {/* never try to sync a read-only array */
|
||
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
|
||
return;
|
||
+ }
|
||
|
||
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
|
||
if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
|
||
@@ -7177,6 +7180,19 @@ void md_do_sync(struct mddev *mddev)
|
||
rdev->recovery_offset < j)
|
||
j = rdev->recovery_offset;
|
||
rcu_read_unlock();
|
||
+
|
||
+ /* If there is a bitmap, we need to make sure all
|
||
+ * writes that started before we added a spare
|
||
+ * complete before we start doing a recovery.
|
||
+ * Otherwise the write might complete and (via
|
||
+ * bitmap_endwrite) set a bit in the bitmap after the
|
||
+ * recovery has checked that bit and skipped that
|
||
+ * region.
|
||
+ */
|
||
+ if (mddev->bitmap) {
|
||
+ mddev->pers->quiesce(mddev, 1);
|
||
+ mddev->pers->quiesce(mddev, 0);
|
||
+ }
|
||
}
|
||
|
||
printk(KERN_INFO "md: %s of RAID array %s\n", desc, mdname(mddev));
|
||
@@ -8166,7 +8182,8 @@ static int md_notify_reboot(struct notifier_block *this,
|
||
if (mddev_trylock(mddev)) {
|
||
if (mddev->pers)
|
||
__md_stop_writes(mddev);
|
||
- mddev->safemode = 2;
|
||
+ if (mddev->persistent)
|
||
+ mddev->safemode = 2;
|
||
mddev_unlock(mddev);
|
||
}
|
||
need_delay = 1;
|
||
diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c
|
||
index c4f2813..b88757c 100644
|
||
--- a/drivers/md/persistent-data/dm-btree-remove.c
|
||
+++ b/drivers/md/persistent-data/dm-btree-remove.c
|
||
@@ -139,15 +139,8 @@ struct child {
|
||
struct btree_node *n;
|
||
};
|
||
|
||
-static struct dm_btree_value_type le64_type = {
|
||
- .context = NULL,
|
||
- .size = sizeof(__le64),
|
||
- .inc = NULL,
|
||
- .dec = NULL,
|
||
- .equal = NULL
|
||
-};
|
||
-
|
||
-static int init_child(struct dm_btree_info *info, struct btree_node *parent,
|
||
+static int init_child(struct dm_btree_info *info, struct dm_btree_value_type *vt,
|
||
+ struct btree_node *parent,
|
||
unsigned index, struct child *result)
|
||
{
|
||
int r, inc;
|
||
@@ -164,7 +157,7 @@ static int init_child(struct dm_btree_info *info, struct btree_node *parent,
|
||
result->n = dm_block_data(result->block);
|
||
|
||
if (inc)
|
||
- inc_children(info->tm, result->n, &le64_type);
|
||
+ inc_children(info->tm, result->n, vt);
|
||
|
||
*((__le64 *) value_ptr(parent, index)) =
|
||
cpu_to_le64(dm_block_location(result->block));
|
||
@@ -236,7 +229,7 @@ static void __rebalance2(struct dm_btree_info *info, struct btree_node *parent,
|
||
}
|
||
|
||
static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info,
|
||
- unsigned left_index)
|
||
+ struct dm_btree_value_type *vt, unsigned left_index)
|
||
{
|
||
int r;
|
||
struct btree_node *parent;
|
||
@@ -244,11 +237,11 @@ static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info,
|
||
|
||
parent = dm_block_data(shadow_current(s));
|
||
|
||
- r = init_child(info, parent, left_index, &left);
|
||
+ r = init_child(info, vt, parent, left_index, &left);
|
||
if (r)
|
||
return r;
|
||
|
||
- r = init_child(info, parent, left_index + 1, &right);
|
||
+ r = init_child(info, vt, parent, left_index + 1, &right);
|
||
if (r) {
|
||
exit_child(info, &left);
|
||
return r;
|
||
@@ -368,7 +361,7 @@ static void __rebalance3(struct dm_btree_info *info, struct btree_node *parent,
|
||
}
|
||
|
||
static int rebalance3(struct shadow_spine *s, struct dm_btree_info *info,
|
||
- unsigned left_index)
|
||
+ struct dm_btree_value_type *vt, unsigned left_index)
|
||
{
|
||
int r;
|
||
struct btree_node *parent = dm_block_data(shadow_current(s));
|
||
@@ -377,17 +370,17 @@ static int rebalance3(struct shadow_spine *s, struct dm_btree_info *info,
|
||
/*
|
||
* FIXME: fill out an array?
|
||
*/
|
||
- r = init_child(info, parent, left_index, &left);
|
||
+ r = init_child(info, vt, parent, left_index, &left);
|
||
if (r)
|
||
return r;
|
||
|
||
- r = init_child(info, parent, left_index + 1, ¢er);
|
||
+ r = init_child(info, vt, parent, left_index + 1, ¢er);
|
||
if (r) {
|
||
exit_child(info, &left);
|
||
return r;
|
||
}
|
||
|
||
- r = init_child(info, parent, left_index + 2, &right);
|
||
+ r = init_child(info, vt, parent, left_index + 2, &right);
|
||
if (r) {
|
||
exit_child(info, &left);
|
||
exit_child(info, ¢er);
|
||
@@ -434,7 +427,8 @@ static int get_nr_entries(struct dm_transaction_manager *tm,
|
||
}
|
||
|
||
static int rebalance_children(struct shadow_spine *s,
|
||
- struct dm_btree_info *info, uint64_t key)
|
||
+ struct dm_btree_info *info,
|
||
+ struct dm_btree_value_type *vt, uint64_t key)
|
||
{
|
||
int i, r, has_left_sibling, has_right_sibling;
|
||
uint32_t child_entries;
|
||
@@ -472,13 +466,13 @@ static int rebalance_children(struct shadow_spine *s,
|
||
has_right_sibling = i < (le32_to_cpu(n->header.nr_entries) - 1);
|
||
|
||
if (!has_left_sibling)
|
||
- r = rebalance2(s, info, i);
|
||
+ r = rebalance2(s, info, vt, i);
|
||
|
||
else if (!has_right_sibling)
|
||
- r = rebalance2(s, info, i - 1);
|
||
+ r = rebalance2(s, info, vt, i - 1);
|
||
|
||
else
|
||
- r = rebalance3(s, info, i - 1);
|
||
+ r = rebalance3(s, info, vt, i - 1);
|
||
|
||
return r;
|
||
}
|
||
@@ -529,7 +523,7 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
|
||
if (le32_to_cpu(n->header.flags) & LEAF_NODE)
|
||
return do_leaf(n, key, index);
|
||
|
||
- r = rebalance_children(s, info, key);
|
||
+ r = rebalance_children(s, info, vt, key);
|
||
if (r)
|
||
break;
|
||
|
||
@@ -550,6 +544,14 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
|
||
return r;
|
||
}
|
||
|
||
+static struct dm_btree_value_type le64_type = {
|
||
+ .context = NULL,
|
||
+ .size = sizeof(__le64),
|
||
+ .inc = NULL,
|
||
+ .dec = NULL,
|
||
+ .equal = NULL
|
||
+};
|
||
+
|
||
int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
|
||
uint64_t *keys, dm_block_t *new_root)
|
||
{
|
||
diff --git a/drivers/md/persistent-data/dm-space-map-common.c b/drivers/md/persistent-data/dm-space-map-common.c
|
||
index ff3beed..79c02d9 100644
|
||
--- a/drivers/md/persistent-data/dm-space-map-common.c
|
||
+++ b/drivers/md/persistent-data/dm-space-map-common.c
|
||
@@ -244,6 +244,10 @@ int sm_ll_extend(struct ll_disk *ll, dm_block_t extra_blocks)
|
||
return -EINVAL;
|
||
}
|
||
|
||
+ /*
|
||
+ * We need to set this before the dm_tm_new_block() call below.
|
||
+ */
|
||
+ ll->nr_blocks = nr_blocks;
|
||
for (i = old_blocks; i < blocks; i++) {
|
||
struct dm_block *b;
|
||
struct disk_index_entry idx;
|
||
@@ -251,6 +255,7 @@ int sm_ll_extend(struct ll_disk *ll, dm_block_t extra_blocks)
|
||
r = dm_tm_new_block(ll->tm, &dm_sm_bitmap_validator, &b);
|
||
if (r < 0)
|
||
return r;
|
||
+
|
||
idx.blocknr = cpu_to_le64(dm_block_location(b));
|
||
|
||
r = dm_tm_unlock(ll->tm, b);
|
||
@@ -265,7 +270,6 @@ int sm_ll_extend(struct ll_disk *ll, dm_block_t extra_blocks)
|
||
return r;
|
||
}
|
||
|
||
- ll->nr_blocks = nr_blocks;
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
|
||
index ce5f044..75e66c6 100644
|
||
--- a/drivers/md/raid1.c
|
||
+++ b/drivers/md/raid1.c
|
||
@@ -1357,6 +1357,7 @@ static int raid1_spare_active(struct mddev *mddev)
|
||
}
|
||
}
|
||
if (rdev
|
||
+ && rdev->recovery_offset == MaxSector
|
||
&& !test_bit(Faulty, &rdev->flags)
|
||
&& !test_and_set_bit(In_sync, &rdev->flags)) {
|
||
count++;
|
||
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
|
||
index f7febd8..149426c 100644
|
||
--- a/drivers/md/raid10.c
|
||
+++ b/drivers/md/raid10.c
|
||
@@ -1117,7 +1117,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
|
||
/* Could not read all from this device, so we will
|
||
* need another r10_bio.
|
||
*/
|
||
- sectors_handled = (r10_bio->sectors + max_sectors
|
||
+ sectors_handled = (r10_bio->sector + max_sectors
|
||
- bio->bi_sector);
|
||
r10_bio->sectors = max_sectors;
|
||
spin_lock_irq(&conf->device_lock);
|
||
@@ -1125,7 +1125,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
|
||
bio->bi_phys_segments = 2;
|
||
else
|
||
bio->bi_phys_segments++;
|
||
- spin_unlock(&conf->device_lock);
|
||
+ spin_unlock_irq(&conf->device_lock);
|
||
/* Cannot call generic_make_request directly
|
||
* as that will be queued in __generic_make_request
|
||
* and subsequent mempool_alloc might block
|
||
@@ -1419,14 +1419,16 @@ static int enough(struct r10conf *conf, int ignore)
|
||
do {
|
||
int n = conf->copies;
|
||
int cnt = 0;
|
||
+ int this = first;
|
||
while (n--) {
|
||
- if (conf->mirrors[first].rdev &&
|
||
- first != ignore)
|
||
+ if (conf->mirrors[this].rdev &&
|
||
+ this != ignore)
|
||
cnt++;
|
||
- first = (first+1) % conf->raid_disks;
|
||
+ this = (this+1) % conf->raid_disks;
|
||
}
|
||
if (cnt == 0)
|
||
return 0;
|
||
+ first = (first + conf->near_copies) % conf->raid_disks;
|
||
} while (first != 0);
|
||
return 1;
|
||
}
|
||
@@ -1534,6 +1536,7 @@ static int raid10_spare_active(struct mddev *mddev)
|
||
}
|
||
sysfs_notify_dirent_safe(tmp->replacement->sysfs_state);
|
||
} else if (tmp->rdev
|
||
+ && tmp->rdev->recovery_offset == MaxSector
|
||
&& !test_bit(Faulty, &tmp->rdev->flags)
|
||
&& !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
|
||
count++;
|
||
@@ -2942,10 +2945,6 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
|
||
if (j == conf->copies) {
|
||
/* Cannot recover, so abort the recovery or
|
||
* record a bad block */
|
||
- put_buf(r10_bio);
|
||
- if (rb2)
|
||
- atomic_dec(&rb2->remaining);
|
||
- r10_bio = rb2;
|
||
if (any_working) {
|
||
/* problem is that there are bad blocks
|
||
* on other device(s)
|
||
@@ -2977,6 +2976,10 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
|
||
mirror->recovery_disabled
|
||
= mddev->recovery_disabled;
|
||
}
|
||
+ put_buf(r10_bio);
|
||
+ if (rb2)
|
||
+ atomic_dec(&rb2->remaining);
|
||
+ r10_bio = rb2;
|
||
break;
|
||
}
|
||
}
|
||
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
|
||
index 6155c8b..c276ad0 100644
|
||
--- a/drivers/md/raid5.c
|
||
+++ b/drivers/md/raid5.c
|
||
@@ -1805,6 +1805,7 @@ static void raid5_end_write_request(struct bio *bi, int error)
|
||
set_bit(R5_MadeGoodRepl, &sh->dev[i].flags);
|
||
} else {
|
||
if (!uptodate) {
|
||
+ set_bit(STRIPE_DEGRADED, &sh->state);
|
||
set_bit(WriteErrorSeen, &rdev->flags);
|
||
set_bit(R5_WriteError, &sh->dev[i].flags);
|
||
if (!test_and_set_bit(WantReplacement, &rdev->flags))
|
||
@@ -3432,6 +3433,8 @@ static void handle_stripe(struct stripe_head *sh)
|
||
set_bit(R5_Wantwrite, &dev->flags);
|
||
if (prexor)
|
||
continue;
|
||
+ if (s.failed > 1)
|
||
+ continue;
|
||
if (!test_bit(R5_Insync, &dev->flags) ||
|
||
((i == sh->pd_idx || i == sh->qd_idx) &&
|
||
s.failed == 0))
|
||
@@ -4677,23 +4680,43 @@ raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks)
|
||
return sectors * (raid_disks - conf->max_degraded);
|
||
}
|
||
|
||
+static void free_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu)
|
||
+{
|
||
+ safe_put_page(percpu->spare_page);
|
||
+ kfree(percpu->scribble);
|
||
+ percpu->spare_page = NULL;
|
||
+ percpu->scribble = NULL;
|
||
+}
|
||
+
|
||
+static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu)
|
||
+{
|
||
+ if (conf->level == 6 && !percpu->spare_page)
|
||
+ percpu->spare_page = alloc_page(GFP_KERNEL);
|
||
+ if (!percpu->scribble)
|
||
+ percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
|
||
+
|
||
+ if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) {
|
||
+ free_scratch_buffer(conf, percpu);
|
||
+ return -ENOMEM;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
static void raid5_free_percpu(struct r5conf *conf)
|
||
{
|
||
- struct raid5_percpu *percpu;
|
||
unsigned long cpu;
|
||
|
||
if (!conf->percpu)
|
||
return;
|
||
|
||
- get_online_cpus();
|
||
- for_each_possible_cpu(cpu) {
|
||
- percpu = per_cpu_ptr(conf->percpu, cpu);
|
||
- safe_put_page(percpu->spare_page);
|
||
- kfree(percpu->scribble);
|
||
- }
|
||
#ifdef CONFIG_HOTPLUG_CPU
|
||
unregister_cpu_notifier(&conf->cpu_notify);
|
||
#endif
|
||
+
|
||
+ get_online_cpus();
|
||
+ for_each_possible_cpu(cpu)
|
||
+ free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
|
||
put_online_cpus();
|
||
|
||
free_percpu(conf->percpu);
|
||
@@ -4719,15 +4742,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
|
||
switch (action) {
|
||
case CPU_UP_PREPARE:
|
||
case CPU_UP_PREPARE_FROZEN:
|
||
- if (conf->level == 6 && !percpu->spare_page)
|
||
- percpu->spare_page = alloc_page(GFP_KERNEL);
|
||
- if (!percpu->scribble)
|
||
- percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
|
||
-
|
||
- if (!percpu->scribble ||
|
||
- (conf->level == 6 && !percpu->spare_page)) {
|
||
- safe_put_page(percpu->spare_page);
|
||
- kfree(percpu->scribble);
|
||
+ if (alloc_scratch_buffer(conf, percpu)) {
|
||
pr_err("%s: failed memory allocation for cpu%ld\n",
|
||
__func__, cpu);
|
||
return notifier_from_errno(-ENOMEM);
|
||
@@ -4735,10 +4750,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
|
||
break;
|
||
case CPU_DEAD:
|
||
case CPU_DEAD_FROZEN:
|
||
- safe_put_page(percpu->spare_page);
|
||
- kfree(percpu->scribble);
|
||
- percpu->spare_page = NULL;
|
||
- percpu->scribble = NULL;
|
||
+ free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
|
||
break;
|
||
default:
|
||
break;
|
||
@@ -4750,40 +4762,29 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
|
||
static int raid5_alloc_percpu(struct r5conf *conf)
|
||
{
|
||
unsigned long cpu;
|
||
- struct page *spare_page;
|
||
- struct raid5_percpu __percpu *allcpus;
|
||
- void *scribble;
|
||
- int err;
|
||
+ int err = 0;
|
||
|
||
- allcpus = alloc_percpu(struct raid5_percpu);
|
||
- if (!allcpus)
|
||
+ conf->percpu = alloc_percpu(struct raid5_percpu);
|
||
+ if (!conf->percpu)
|
||
return -ENOMEM;
|
||
- conf->percpu = allcpus;
|
||
+
|
||
+#ifdef CONFIG_HOTPLUG_CPU
|
||
+ conf->cpu_notify.notifier_call = raid456_cpu_notify;
|
||
+ conf->cpu_notify.priority = 0;
|
||
+ err = register_cpu_notifier(&conf->cpu_notify);
|
||
+ if (err)
|
||
+ return err;
|
||
+#endif
|
||
|
||
get_online_cpus();
|
||
- err = 0;
|
||
for_each_present_cpu(cpu) {
|
||
- if (conf->level == 6) {
|
||
- spare_page = alloc_page(GFP_KERNEL);
|
||
- if (!spare_page) {
|
||
- err = -ENOMEM;
|
||
- break;
|
||
- }
|
||
- per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page;
|
||
- }
|
||
- scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
|
||
- if (!scribble) {
|
||
- err = -ENOMEM;
|
||
+ err = alloc_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
|
||
+ if (err) {
|
||
+ pr_err("%s: failed memory allocation for cpu%ld\n",
|
||
+ __func__, cpu);
|
||
break;
|
||
}
|
||
- per_cpu_ptr(conf->percpu, cpu)->scribble = scribble;
|
||
}
|
||
-#ifdef CONFIG_HOTPLUG_CPU
|
||
- conf->cpu_notify.notifier_call = raid456_cpu_notify;
|
||
- conf->cpu_notify.priority = 0;
|
||
- if (err == 0)
|
||
- err = register_cpu_notifier(&conf->cpu_notify);
|
||
-#endif
|
||
put_online_cpus();
|
||
|
||
return err;
|
||
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
|
||
index 7d97c26..01f00b4 100644
|
||
--- a/drivers/media/media-device.c
|
||
+++ b/drivers/media/media-device.c
|
||
@@ -90,6 +90,7 @@ static long media_device_enum_entities(struct media_device *mdev,
|
||
struct media_entity *ent;
|
||
struct media_entity_desc u_ent;
|
||
|
||
+ memset(&u_ent, 0, sizeof(u_ent));
|
||
if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id)))
|
||
return -EFAULT;
|
||
|
||
diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c
|
||
index e8e8f2f..bfbc228 100644
|
||
--- a/drivers/media/video/gspca/kinect.c
|
||
+++ b/drivers/media/video/gspca/kinect.c
|
||
@@ -390,6 +390,7 @@ static const struct sd_desc sd_desc = {
|
||
/* -- module initialisation -- */
|
||
static const struct usb_device_id device_table[] = {
|
||
{USB_DEVICE(0x045e, 0x02ae)},
|
||
+ {USB_DEVICE(0x045e, 0x02bf)},
|
||
{}
|
||
};
|
||
|
||
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
|
||
index 6510110..e09c4b6 100644
|
||
--- a/drivers/media/video/hdpvr/hdpvr-core.c
|
||
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
|
||
@@ -309,6 +309,11 @@ static int hdpvr_probe(struct usb_interface *interface,
|
||
|
||
dev->workqueue = 0;
|
||
|
||
+ /* init video transfer queues first of all */
|
||
+ /* to prevent oops in hdpvr_delete() on error paths */
|
||
+ INIT_LIST_HEAD(&dev->free_buff_list);
|
||
+ INIT_LIST_HEAD(&dev->rec_buff_list);
|
||
+
|
||
/* register v4l2_device early so it can be used for printks */
|
||
if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
|
||
err("v4l2_device_register failed");
|
||
@@ -331,10 +336,6 @@ static int hdpvr_probe(struct usb_interface *interface,
|
||
if (!dev->workqueue)
|
||
goto error;
|
||
|
||
- /* init video transfer queues */
|
||
- INIT_LIST_HEAD(&dev->free_buff_list);
|
||
- INIT_LIST_HEAD(&dev->rec_buff_list);
|
||
-
|
||
dev->options = hdpvr_default_options;
|
||
|
||
if (default_video_input < HDPVR_VIDEO_INPUTS)
|
||
@@ -385,12 +386,6 @@ static int hdpvr_probe(struct usb_interface *interface,
|
||
}
|
||
mutex_unlock(&dev->io_mutex);
|
||
|
||
- if (hdpvr_register_videodev(dev, &interface->dev,
|
||
- video_nr[atomic_inc_return(&dev_nr)])) {
|
||
- v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
|
||
- goto error;
|
||
- }
|
||
-
|
||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||
retval = hdpvr_register_i2c_adapter(dev);
|
||
if (retval < 0) {
|
||
@@ -411,6 +406,13 @@ static int hdpvr_probe(struct usb_interface *interface,
|
||
}
|
||
#endif
|
||
|
||
+ retval = hdpvr_register_videodev(dev, &interface->dev,
|
||
+ video_nr[atomic_inc_return(&dev_nr)]);
|
||
+ if (retval < 0) {
|
||
+ v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
|
||
+ goto reg_fail;
|
||
+ }
|
||
+
|
||
/* let the user know what node this device is now attached to */
|
||
v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
|
||
video_device_node_name(dev->video_dev));
|
||
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
|
||
index 88cf9d9..89f354e 100644
|
||
--- a/drivers/media/video/omap/omap_vout.c
|
||
+++ b/drivers/media/video/omap/omap_vout.c
|
||
@@ -206,19 +206,21 @@ static u32 omap_vout_uservirt_to_phys(u32 virtp)
|
||
struct vm_area_struct *vma;
|
||
struct mm_struct *mm = current->mm;
|
||
|
||
- vma = find_vma(mm, virtp);
|
||
/* For kernel direct-mapped memory, take the easy way */
|
||
- if (virtp >= PAGE_OFFSET) {
|
||
- physp = virt_to_phys((void *) virtp);
|
||
- } else if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
|
||
+ if (virtp >= PAGE_OFFSET)
|
||
+ return virt_to_phys((void *) virtp);
|
||
+
|
||
+ down_read(¤t->mm->mmap_sem);
|
||
+ vma = find_vma(mm, virtp);
|
||
+ if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
|
||
/* this will catch, kernel-allocated, mmaped-to-usermode
|
||
addresses */
|
||
physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
|
||
+ up_read(¤t->mm->mmap_sem);
|
||
} else {
|
||
/* otherwise, use get_user_pages() for general userland pages */
|
||
int res, nr_pages = 1;
|
||
struct page *pages;
|
||
- down_read(¤t->mm->mmap_sem);
|
||
|
||
res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
|
||
0, &pages, NULL);
|
||
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
|
||
index 10460fd..dbcdfbf 100644
|
||
--- a/drivers/media/video/saa7134/saa7134-alsa.c
|
||
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
|
||
@@ -172,7 +172,9 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev,
|
||
dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count,
|
||
dev->dmasound.bufsize, dev->dmasound.blocks);
|
||
spin_unlock(&dev->slock);
|
||
+ snd_pcm_stream_lock(dev->dmasound.substream);
|
||
snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN);
|
||
+ snd_pcm_stream_unlock(dev->dmasound.substream);
|
||
return;
|
||
}
|
||
|
||
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c
|
||
index 3b7d7b4..8f3c47e 100644
|
||
--- a/drivers/media/video/saa7164/saa7164-core.c
|
||
+++ b/drivers/media/video/saa7164/saa7164-core.c
|
||
@@ -1386,9 +1386,11 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
|
||
if (fw_debug) {
|
||
dev->kthread = kthread_run(saa7164_thread_function, dev,
|
||
"saa7164 debug");
|
||
- if (!dev->kthread)
|
||
+ if (IS_ERR(dev->kthread)) {
|
||
+ dev->kthread = NULL;
|
||
printk(KERN_ERR "%s() Failed to create "
|
||
"debug kernel thread\n", __func__);
|
||
+ }
|
||
}
|
||
|
||
} /* != BOARD_UNKNOWN */
|
||
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
|
||
index 1f203b8..683ae99 100644
|
||
--- a/drivers/media/video/v4l2-device.c
|
||
+++ b/drivers/media/video/v4l2-device.c
|
||
@@ -159,31 +159,21 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
|
||
sd->v4l2_dev = v4l2_dev;
|
||
if (sd->internal_ops && sd->internal_ops->registered) {
|
||
err = sd->internal_ops->registered(sd);
|
||
- if (err) {
|
||
- module_put(sd->owner);
|
||
- return err;
|
||
- }
|
||
+ if (err)
|
||
+ goto error_module;
|
||
}
|
||
|
||
/* This just returns 0 if either of the two args is NULL */
|
||
err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
|
||
- if (err) {
|
||
- if (sd->internal_ops && sd->internal_ops->unregistered)
|
||
- sd->internal_ops->unregistered(sd);
|
||
- module_put(sd->owner);
|
||
- return err;
|
||
- }
|
||
+ if (err)
|
||
+ goto error_unregister;
|
||
|
||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||
/* Register the entity. */
|
||
if (v4l2_dev->mdev) {
|
||
err = media_device_register_entity(v4l2_dev->mdev, entity);
|
||
- if (err < 0) {
|
||
- if (sd->internal_ops && sd->internal_ops->unregistered)
|
||
- sd->internal_ops->unregistered(sd);
|
||
- module_put(sd->owner);
|
||
- return err;
|
||
- }
|
||
+ if (err < 0)
|
||
+ goto error_unregister;
|
||
}
|
||
#endif
|
||
|
||
@@ -192,6 +182,14 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
|
||
spin_unlock(&v4l2_dev->lock);
|
||
|
||
return 0;
|
||
+
|
||
+error_unregister:
|
||
+ if (sd->internal_ops && sd->internal_ops->unregistered)
|
||
+ sd->internal_ops->unregistered(sd);
|
||
+error_module:
|
||
+ module_put(sd->owner);
|
||
+ sd->v4l2_dev = NULL;
|
||
+ return err;
|
||
}
|
||
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
|
||
|
||
diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
|
||
index d9e4b36..6d71067 100644
|
||
--- a/drivers/mfd/max8925-i2c.c
|
||
+++ b/drivers/mfd/max8925-i2c.c
|
||
@@ -156,9 +156,18 @@ static int __devinit max8925_probe(struct i2c_client *client,
|
||
mutex_init(&chip->io_lock);
|
||
|
||
chip->rtc = i2c_new_dummy(chip->i2c->adapter, RTC_I2C_ADDR);
|
||
+ if (!chip->rtc) {
|
||
+ dev_err(chip->dev, "Failed to allocate I2C device for RTC\n");
|
||
+ return -ENODEV;
|
||
+ }
|
||
i2c_set_clientdata(chip->rtc, chip);
|
||
|
||
chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR);
|
||
+ if (!chip->adc) {
|
||
+ dev_err(chip->dev, "Failed to allocate I2C device for ADC\n");
|
||
+ i2c_unregister_device(chip->rtc);
|
||
+ return -ENODEV;
|
||
+ }
|
||
i2c_set_clientdata(chip->adc, chip);
|
||
|
||
device_init_wakeup(&client->dev, 1);
|
||
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
|
||
index cb83a7a..b4d48af 100644
|
||
--- a/drivers/mfd/max8997.c
|
||
+++ b/drivers/mfd/max8997.c
|
||
@@ -149,10 +149,26 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
|
||
mutex_init(&max8997->iolock);
|
||
|
||
max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
|
||
+ if (!max8997->rtc) {
|
||
+ dev_err(max8997->dev, "Failed to allocate I2C device for RTC\n");
|
||
+ return -ENODEV;
|
||
+ }
|
||
i2c_set_clientdata(max8997->rtc, max8997);
|
||
+
|
||
max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
|
||
+ if (!max8997->haptic) {
|
||
+ dev_err(max8997->dev, "Failed to allocate I2C device for Haptic\n");
|
||
+ ret = -ENODEV;
|
||
+ goto err_i2c_haptic;
|
||
+ }
|
||
i2c_set_clientdata(max8997->haptic, max8997);
|
||
+
|
||
max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC);
|
||
+ if (!max8997->muic) {
|
||
+ dev_err(max8997->dev, "Failed to allocate I2C device for MUIC\n");
|
||
+ ret = -ENODEV;
|
||
+ goto err_i2c_muic;
|
||
+ }
|
||
i2c_set_clientdata(max8997->muic, max8997);
|
||
|
||
pm_runtime_set_active(max8997->dev);
|
||
@@ -179,7 +195,9 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
|
||
err_mfd:
|
||
mfd_remove_devices(max8997->dev);
|
||
i2c_unregister_device(max8997->muic);
|
||
+err_i2c_muic:
|
||
i2c_unregister_device(max8997->haptic);
|
||
+err_i2c_haptic:
|
||
i2c_unregister_device(max8997->rtc);
|
||
err:
|
||
kfree(max8997);
|
||
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
|
||
index 6ef56d2..0a44816 100644
|
||
--- a/drivers/mfd/max8998.c
|
||
+++ b/drivers/mfd/max8998.c
|
||
@@ -152,6 +152,10 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
|
||
mutex_init(&max8998->iolock);
|
||
|
||
max8998->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
|
||
+ if (!max8998->rtc) {
|
||
+ dev_err(&i2c->dev, "Failed to allocate I2C device for RTC\n");
|
||
+ return -ENODEV;
|
||
+ }
|
||
i2c_set_clientdata(max8998->rtc, max8998);
|
||
|
||
max8998_irq_init(max8998);
|
||
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
|
||
index 00e5fcac8..cbee842 100644
|
||
--- a/drivers/misc/enclosure.c
|
||
+++ b/drivers/misc/enclosure.c
|
||
@@ -198,6 +198,13 @@ static void enclosure_remove_links(struct enclosure_component *cdev)
|
||
{
|
||
char name[ENCLOSURE_NAME_SIZE];
|
||
|
||
+ /*
|
||
+ * In odd circumstances, like multipath devices, something else may
|
||
+ * already have removed the links, so check for this condition first.
|
||
+ */
|
||
+ if (!cdev->dev->kobj.sd)
|
||
+ return;
|
||
+
|
||
enclosure_link_name(cdev, name);
|
||
sysfs_remove_link(&cdev->dev->kobj, name);
|
||
sysfs_remove_link(&cdev->cdev.kobj, "device");
|
||
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
|
||
index fffc227..9c99680 100644
|
||
--- a/drivers/misc/hpilo.c
|
||
+++ b/drivers/misc/hpilo.c
|
||
@@ -735,7 +735,14 @@ static void ilo_remove(struct pci_dev *pdev)
|
||
free_irq(pdev->irq, ilo_hw);
|
||
ilo_unmap_device(pdev, ilo_hw);
|
||
pci_release_regions(pdev);
|
||
- pci_disable_device(pdev);
|
||
+ /*
|
||
+ * pci_disable_device(pdev) used to be here. But this PCI device has
|
||
+ * two functions with interrupt lines connected to a single pin. The
|
||
+ * other one is a USB host controller. So when we disable the PIN here
|
||
+ * e.g. by rmmod hpilo, the controller stops working. It is because
|
||
+ * the interrupt link is disabled in ACPI since it is not refcounted
|
||
+ * yet. See acpi_pci_link_free_irq called from acpi_pci_irq_disable.
|
||
+ */
|
||
kfree(ilo_hw);
|
||
ilo_hwdev[(minor / MAX_CCB)] = 0;
|
||
}
|
||
@@ -820,7 +827,7 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
|
||
free_regions:
|
||
pci_release_regions(pdev);
|
||
disable:
|
||
- pci_disable_device(pdev);
|
||
+/* pci_disable_device(pdev); see comment in ilo_remove */
|
||
free:
|
||
kfree(ilo_hw);
|
||
out:
|
||
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
|
||
index 2a822d9e..e6f08d9 100644
|
||
--- a/drivers/mmc/host/atmel-mci.c
|
||
+++ b/drivers/mmc/host/atmel-mci.c
|
||
@@ -1022,11 +1022,22 @@ static void atmci_start_request(struct atmel_mci *host,
|
||
iflags |= ATMCI_CMDRDY;
|
||
cmd = mrq->cmd;
|
||
cmdflags = atmci_prepare_command(slot->mmc, cmd);
|
||
- atmci_send_command(host, cmd, cmdflags);
|
||
+
|
||
+ /*
|
||
+ * DMA transfer should be started before sending the command to avoid
|
||
+ * unexpected errors especially for read operations in SDIO mode.
|
||
+ * Unfortunately, in PDC mode, command has to be sent before starting
|
||
+ * the transfer.
|
||
+ */
|
||
+ if (host->submit_data != &atmci_submit_data_dma)
|
||
+ atmci_send_command(host, cmd, cmdflags);
|
||
|
||
if (data)
|
||
host->submit_data(host, data);
|
||
|
||
+ if (host->submit_data == &atmci_submit_data_dma)
|
||
+ atmci_send_command(host, cmd, cmdflags);
|
||
+
|
||
if (mrq->stop) {
|
||
host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
|
||
host->stop_cmdr |= ATMCI_CMDR_STOP_XFER;
|
||
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
|
||
index b6def20..13ce63b 100644
|
||
--- a/drivers/mmc/host/mxs-mmc.c
|
||
+++ b/drivers/mmc/host/mxs-mmc.c
|
||
@@ -639,10 +639,6 @@ static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||
host->base + HW_SSP_CTRL0 + MXS_SET_ADDR);
|
||
writel(BM_SSP_CTRL1_SDIO_IRQ_EN,
|
||
host->base + HW_SSP_CTRL1 + MXS_SET_ADDR);
|
||
-
|
||
- if (readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_SDIO_IRQ)
|
||
- mmc_signal_sdio_irq(host->mmc);
|
||
-
|
||
} else {
|
||
writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK,
|
||
host->base + HW_SSP_CTRL0 + MXS_CLR_ADDR);
|
||
@@ -651,6 +647,10 @@ static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||
}
|
||
|
||
spin_unlock_irqrestore(&host->lock, flags);
|
||
+
|
||
+ if (enable && readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_SDIO_IRQ)
|
||
+ mmc_signal_sdio_irq(host->mmc);
|
||
+
|
||
}
|
||
|
||
static const struct mmc_host_ops mxs_mmc_ops = {
|
||
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
|
||
index 1924d24..797860e 100644
|
||
--- a/drivers/mtd/devices/m25p80.c
|
||
+++ b/drivers/mtd/devices/m25p80.c
|
||
@@ -71,7 +71,7 @@
|
||
|
||
/* Define max times to check status register before we give up. */
|
||
#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
|
||
-#define MAX_CMD_SIZE 5
|
||
+#define MAX_CMD_SIZE 6
|
||
|
||
#ifdef CONFIG_M25PXX_USE_FAST_READ
|
||
#define OPCODE_READ OPCODE_FAST_READ
|
||
@@ -843,14 +843,13 @@ static int __devinit m25p_probe(struct spi_device *spi)
|
||
}
|
||
}
|
||
|
||
- flash = kzalloc(sizeof *flash, GFP_KERNEL);
|
||
+ flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
|
||
if (!flash)
|
||
return -ENOMEM;
|
||
- flash->command = kmalloc(MAX_CMD_SIZE + FAST_READ_DUMMY_BYTE, GFP_KERNEL);
|
||
- if (!flash->command) {
|
||
- kfree(flash);
|
||
+
|
||
+ flash->command = devm_kzalloc(&spi->dev, MAX_CMD_SIZE, GFP_KERNEL);
|
||
+ if (!flash->command)
|
||
return -ENOMEM;
|
||
- }
|
||
|
||
flash->spi = spi;
|
||
mutex_init(&flash->lock);
|
||
@@ -947,14 +946,10 @@ static int __devinit m25p_probe(struct spi_device *spi)
|
||
static int __devexit m25p_remove(struct spi_device *spi)
|
||
{
|
||
struct m25p *flash = dev_get_drvdata(&spi->dev);
|
||
- int status;
|
||
|
||
/* Clean up MTD stuff. */
|
||
- status = mtd_device_unregister(&flash->mtd);
|
||
- if (status == 0) {
|
||
- kfree(flash->command);
|
||
- kfree(flash);
|
||
- }
|
||
+ mtd_device_unregister(&flash->mtd);
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
|
||
index 9ec51ce..0f000e6 100644
|
||
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
|
||
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
|
||
@@ -227,8 +227,6 @@ static void dma_irq_callback(void *param)
|
||
struct gpmi_nand_data *this = param;
|
||
struct completion *dma_c = &this->dma_done;
|
||
|
||
- complete(dma_c);
|
||
-
|
||
switch (this->dma_type) {
|
||
case DMA_FOR_COMMAND:
|
||
dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE);
|
||
@@ -253,6 +251,8 @@ static void dma_irq_callback(void *param)
|
||
default:
|
||
pr_err("in wrong DMA operation.\n");
|
||
}
|
||
+
|
||
+ complete(dma_c);
|
||
}
|
||
|
||
int start_dma_without_bch_irq(struct gpmi_nand_data *this,
|
||
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
|
||
index 6f87c74..a06231f 100644
|
||
--- a/drivers/mtd/nand/mxc_nand.c
|
||
+++ b/drivers/mtd/nand/mxc_nand.c
|
||
@@ -596,7 +596,6 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
|
||
ecc_stat >>= 4;
|
||
} while (--no_subpages);
|
||
|
||
- mtd->ecc_stats.corrected += ret;
|
||
pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
|
||
|
||
return ret;
|
||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
|
||
index eb9f5fb..e50a0b4 100644
|
||
--- a/drivers/mtd/nand/nand_base.c
|
||
+++ b/drivers/mtd/nand/nand_base.c
|
||
@@ -2888,10 +2888,21 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||
sanitize_string(p->model, sizeof(p->model));
|
||
if (!mtd->name)
|
||
mtd->name = p->model;
|
||
+
|
||
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
||
- mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
||
+
|
||
+ /*
|
||
+ * pages_per_block and blocks_per_lun may not be a power-of-2 size
|
||
+ * (don't ask me who thought of this...). MTD assumes that these
|
||
+ * dimensions will be power-of-2, so just truncate the remaining area.
|
||
+ */
|
||
+ mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
|
||
+ mtd->erasesize *= mtd->writesize;
|
||
+
|
||
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
||
- chip->chipsize = le32_to_cpu(p->blocks_per_lun);
|
||
+
|
||
+ /* See erasesize comment */
|
||
+ chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
|
||
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
|
||
*busw = 0;
|
||
if (le16_to_cpu(p->features) & 1)
|
||
diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c
|
||
index 8febe46..9f55d40 100644
|
||
--- a/drivers/mtd/nand/nuc900_nand.c
|
||
+++ b/drivers/mtd/nand/nuc900_nand.c
|
||
@@ -250,7 +250,7 @@ static void nuc900_nand_enable(struct nuc900_nand *nand)
|
||
val = __raw_readl(nand->reg + REG_FMICSR);
|
||
|
||
if (!(val & NAND_EN))
|
||
- __raw_writel(val | NAND_EN, REG_FMICSR);
|
||
+ __raw_writel(val | NAND_EN, nand->reg + REG_FMICSR);
|
||
|
||
val = __raw_readl(nand->reg + REG_SMCSR);
|
||
|
||
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
|
||
index def50ca..fd11af4 100644
|
||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||
@@ -93,10 +93,10 @@
|
||
|
||
/* macros for registers read/write */
|
||
#define nand_writel(info, off, val) \
|
||
- __raw_writel((val), (info)->mmio_base + (off))
|
||
+ writel_relaxed((val), (info)->mmio_base + (off))
|
||
|
||
#define nand_readl(info, off) \
|
||
- __raw_readl((info)->mmio_base + (off))
|
||
+ readl_relaxed((info)->mmio_base + (off))
|
||
|
||
/* error code and state */
|
||
enum {
|
||
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
|
||
index 9e2dfd5..539835f 100644
|
||
--- a/drivers/mtd/sm_ftl.c
|
||
+++ b/drivers/mtd/sm_ftl.c
|
||
@@ -59,15 +59,12 @@ struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
|
||
struct attribute_group *attr_group;
|
||
struct attribute **attributes;
|
||
struct sm_sysfs_attribute *vendor_attribute;
|
||
+ char *vendor;
|
||
|
||
- int vendor_len = strnlen(ftl->cis_buffer + SM_CIS_VENDOR_OFFSET,
|
||
- SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET);
|
||
-
|
||
- char *vendor = kmalloc(vendor_len, GFP_KERNEL);
|
||
+ vendor = kstrndup(ftl->cis_buffer + SM_CIS_VENDOR_OFFSET,
|
||
+ SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET, GFP_KERNEL);
|
||
if (!vendor)
|
||
goto error1;
|
||
- memcpy(vendor, ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, vendor_len);
|
||
- vendor[vendor_len] = 0;
|
||
|
||
/* Initialize sysfs attributes */
|
||
vendor_attribute =
|
||
@@ -78,7 +75,7 @@ struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
|
||
sysfs_attr_init(&vendor_attribute->dev_attr.attr);
|
||
|
||
vendor_attribute->data = vendor;
|
||
- vendor_attribute->len = vendor_len;
|
||
+ vendor_attribute->len = strlen(vendor);
|
||
vendor_attribute->dev_attr.attr.name = "vendor";
|
||
vendor_attribute->dev_attr.attr.mode = S_IRUGO;
|
||
vendor_attribute->dev_attr.show = sm_attr_show;
|
||
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
|
||
index 12c43b4..4f71793 100644
|
||
--- a/drivers/mtd/ubi/scan.c
|
||
+++ b/drivers/mtd/ubi/scan.c
|
||
@@ -997,7 +997,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
|
||
return err;
|
||
goto adjust_mean_ec;
|
||
case UBI_IO_FF:
|
||
- if (ec_err)
|
||
+ if (ec_err || bitflips)
|
||
err = add_to_list(si, pnum, ec, 1, &si->erase);
|
||
else
|
||
err = add_to_list(si, pnum, ec, 0, &si->free);
|
||
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
|
||
index 3463b46..184be29 100644
|
||
--- a/drivers/net/bonding/bond_3ad.c
|
||
+++ b/drivers/net/bonding/bond_3ad.c
|
||
@@ -1854,8 +1854,6 @@ void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
|
||
BOND_AD_INFO(bond).agg_select_timer = timeout;
|
||
}
|
||
|
||
-static u16 aggregator_identifier;
|
||
-
|
||
/**
|
||
* bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures
|
||
* @bond: bonding struct to work on
|
||
@@ -1869,7 +1867,7 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
|
||
if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr),
|
||
bond->dev->dev_addr)) {
|
||
|
||
- aggregator_identifier = 0;
|
||
+ BOND_AD_INFO(bond).aggregator_identifier = 0;
|
||
|
||
BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
|
||
BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
|
||
@@ -1941,7 +1939,7 @@ int bond_3ad_bind_slave(struct slave *slave)
|
||
ad_initialize_agg(aggregator);
|
||
|
||
aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr);
|
||
- aggregator->aggregator_identifier = (++aggregator_identifier);
|
||
+ aggregator->aggregator_identifier = ++BOND_AD_INFO(bond).aggregator_identifier;
|
||
aggregator->slave = slave;
|
||
aggregator->is_active = 0;
|
||
aggregator->num_of_ports = 0;
|
||
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
|
||
index 5ee7e3c..656b2f5 100644
|
||
--- a/drivers/net/bonding/bond_3ad.h
|
||
+++ b/drivers/net/bonding/bond_3ad.h
|
||
@@ -253,6 +253,7 @@ struct ad_system {
|
||
struct ad_bond_info {
|
||
struct ad_system system; /* 802.3ad system structure */
|
||
u32 agg_select_timer; // Timer to select aggregator after all adapter's hand shakes
|
||
+ u16 aggregator_identifier;
|
||
};
|
||
|
||
struct ad_slave_info {
|
||
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
|
||
index 098581a..2402af3 100644
|
||
--- a/drivers/net/bonding/bond_main.c
|
||
+++ b/drivers/net/bonding/bond_main.c
|
||
@@ -4930,6 +4930,7 @@ static int __init bonding_init(void)
|
||
out:
|
||
return res;
|
||
err:
|
||
+ bond_destroy_debugfs();
|
||
rtnl_link_unregister(&bond_link_ops);
|
||
err_link:
|
||
unregister_pernet_subsys(&bond_net_ops);
|
||
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
|
||
index c40c0a8..f42a00a 100644
|
||
--- a/drivers/net/bonding/bond_sysfs.c
|
||
+++ b/drivers/net/bonding/bond_sysfs.c
|
||
@@ -533,8 +533,9 @@ static ssize_t bonding_store_arp_interval(struct device *d,
|
||
goto out;
|
||
}
|
||
if (bond->params.mode == BOND_MODE_ALB ||
|
||
- bond->params.mode == BOND_MODE_TLB) {
|
||
- pr_info("%s: ARP monitoring cannot be used with ALB/TLB. Only MII monitoring is supported on %s.\n",
|
||
+ bond->params.mode == BOND_MODE_TLB ||
|
||
+ bond->params.mode == BOND_MODE_8023AD) {
|
||
+ pr_info("%s: ARP monitoring cannot be used with ALB/TLB/802.3ad. Only MII monitoring is supported on %s.\n",
|
||
bond->dev->name, bond->dev->name);
|
||
ret = -EINVAL;
|
||
goto out;
|
||
@@ -692,6 +693,8 @@ static ssize_t bonding_store_downdelay(struct device *d,
|
||
int new_value, ret = count;
|
||
struct bonding *bond = to_bond(d);
|
||
|
||
+ if (!rtnl_trylock())
|
||
+ return restart_syscall();
|
||
if (!(bond->params.miimon)) {
|
||
pr_err("%s: Unable to set down delay as MII monitoring is disabled\n",
|
||
bond->dev->name);
|
||
@@ -725,6 +728,7 @@ static ssize_t bonding_store_downdelay(struct device *d,
|
||
}
|
||
|
||
out:
|
||
+ rtnl_unlock();
|
||
return ret;
|
||
}
|
||
static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR,
|
||
@@ -747,6 +751,8 @@ static ssize_t bonding_store_updelay(struct device *d,
|
||
int new_value, ret = count;
|
||
struct bonding *bond = to_bond(d);
|
||
|
||
+ if (!rtnl_trylock())
|
||
+ return restart_syscall();
|
||
if (!(bond->params.miimon)) {
|
||
pr_err("%s: Unable to set up delay as MII monitoring is disabled\n",
|
||
bond->dev->name);
|
||
@@ -780,6 +786,7 @@ static ssize_t bonding_store_updelay(struct device *d,
|
||
}
|
||
|
||
out:
|
||
+ rtnl_unlock();
|
||
return ret;
|
||
}
|
||
static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR,
|
||
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
|
||
index 6ea905c..12328068 100644
|
||
--- a/drivers/net/can/at91_can.c
|
||
+++ b/drivers/net/can/at91_can.c
|
||
@@ -1115,7 +1115,9 @@ static int at91_open(struct net_device *dev)
|
||
struct at91_priv *priv = netdev_priv(dev);
|
||
int err;
|
||
|
||
- clk_enable(priv->clk);
|
||
+ err = clk_prepare_enable(priv->clk);
|
||
+ if (err)
|
||
+ return err;
|
||
|
||
/* check or determine and set bittime */
|
||
err = open_candev(dev);
|
||
@@ -1139,7 +1141,7 @@ static int at91_open(struct net_device *dev)
|
||
out_close:
|
||
close_candev(dev);
|
||
out:
|
||
- clk_disable(priv->clk);
|
||
+ clk_disable_unprepare(priv->clk);
|
||
|
||
return err;
|
||
}
|
||
@@ -1156,7 +1158,7 @@ static int at91_close(struct net_device *dev)
|
||
at91_chip_stop(dev, CAN_STATE_STOPPED);
|
||
|
||
free_irq(dev->irq, dev);
|
||
- clk_disable(priv->clk);
|
||
+ clk_disable_unprepare(priv->clk);
|
||
|
||
close_candev(dev);
|
||
|
||
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
|
||
index 21a3d77..91d1b5a 100644
|
||
--- a/drivers/net/can/c_can/c_can.c
|
||
+++ b/drivers/net/can/c_can/c_can.c
|
||
@@ -446,8 +446,12 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface,
|
||
|
||
priv->write_reg(priv, &priv->regs->ifregs[iface].mask1,
|
||
IFX_WRITE_LOW_16BIT(mask));
|
||
+
|
||
+ /* According to C_CAN documentation, the reserved bit
|
||
+ * in IFx_MASK2 register is fixed 1
|
||
+ */
|
||
priv->write_reg(priv, &priv->regs->ifregs[iface].mask2,
|
||
- IFX_WRITE_HIGH_16BIT(mask));
|
||
+ IFX_WRITE_HIGH_16BIT(mask) | BIT(13));
|
||
|
||
priv->write_reg(priv, &priv->regs->ifregs[iface].arb1,
|
||
IFX_WRITE_LOW_16BIT(id));
|
||
@@ -760,9 +764,6 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
|
||
msg_ctrl_save = priv->read_reg(priv,
|
||
&priv->regs->ifregs[0].msg_cntrl);
|
||
|
||
- if (msg_ctrl_save & IF_MCONT_EOB)
|
||
- return num_rx_pkts;
|
||
-
|
||
if (msg_ctrl_save & IF_MCONT_MSGLST) {
|
||
c_can_handle_lost_msg_obj(dev, 0, msg_obj);
|
||
num_rx_pkts++;
|
||
@@ -770,6 +771,9 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
|
||
continue;
|
||
}
|
||
|
||
+ if (msg_ctrl_save & IF_MCONT_EOB)
|
||
+ return num_rx_pkts;
|
||
+
|
||
if (!(msg_ctrl_save & IF_MCONT_NEWDAT))
|
||
continue;
|
||
|
||
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
|
||
index e86f4c3..c2cdefa 100644
|
||
--- a/drivers/net/can/dev.c
|
||
+++ b/drivers/net/can/dev.c
|
||
@@ -665,14 +665,14 @@ static size_t can_get_size(const struct net_device *dev)
|
||
size_t size;
|
||
|
||
size = nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
|
||
- size += sizeof(struct can_ctrlmode); /* IFLA_CAN_CTRLMODE */
|
||
+ size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */
|
||
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
|
||
- size += sizeof(struct can_bittiming); /* IFLA_CAN_BITTIMING */
|
||
- size += sizeof(struct can_clock); /* IFLA_CAN_CLOCK */
|
||
+ size += nla_total_size(sizeof(struct can_bittiming)); /* IFLA_CAN_BITTIMING */
|
||
+ size += nla_total_size(sizeof(struct can_clock)); /* IFLA_CAN_CLOCK */
|
||
if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
|
||
- size += sizeof(struct can_berr_counter);
|
||
+ size += nla_total_size(sizeof(struct can_berr_counter));
|
||
if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */
|
||
- size += sizeof(struct can_bittiming_const);
|
||
+ size += nla_total_size(sizeof(struct can_bittiming_const));
|
||
|
||
return size;
|
||
}
|
||
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
|
||
index 00baa7e..b523e65 100644
|
||
--- a/drivers/net/can/flexcan.c
|
||
+++ b/drivers/net/can/flexcan.c
|
||
@@ -60,7 +60,7 @@
|
||
#define FLEXCAN_MCR_BCC BIT(16)
|
||
#define FLEXCAN_MCR_LPRIO_EN BIT(13)
|
||
#define FLEXCAN_MCR_AEN BIT(12)
|
||
-#define FLEXCAN_MCR_MAXMB(x) ((x) & 0xf)
|
||
+#define FLEXCAN_MCR_MAXMB(x) ((x) & 0x1f)
|
||
#define FLEXCAN_MCR_IDAM_A (0 << 8)
|
||
#define FLEXCAN_MCR_IDAM_B (1 << 8)
|
||
#define FLEXCAN_MCR_IDAM_C (2 << 8)
|
||
@@ -123,7 +123,9 @@
|
||
FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT)
|
||
|
||
/* FLEXCAN interrupt flag register (IFLAG) bits */
|
||
-#define FLEXCAN_TX_BUF_ID 8
|
||
+/* Errata ERR005829 step7: Reserve first valid MB */
|
||
+#define FLEXCAN_TX_BUF_RESERVED 8
|
||
+#define FLEXCAN_TX_BUF_ID 9
|
||
#define FLEXCAN_IFLAG_BUF(x) BIT(x)
|
||
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
|
||
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
|
||
@@ -134,6 +136,17 @@
|
||
|
||
/* FLEXCAN message buffers */
|
||
#define FLEXCAN_MB_CNT_CODE(x) (((x) & 0xf) << 24)
|
||
+#define FLEXCAN_MB_CODE_RX_INACTIVE (0x0 << 24)
|
||
+#define FLEXCAN_MB_CODE_RX_EMPTY (0x4 << 24)
|
||
+#define FLEXCAN_MB_CODE_RX_FULL (0x2 << 24)
|
||
+#define FLEXCAN_MB_CODE_RX_OVERRRUN (0x6 << 24)
|
||
+#define FLEXCAN_MB_CODE_RX_RANSWER (0xa << 24)
|
||
+
|
||
+#define FLEXCAN_MB_CODE_TX_INACTIVE (0x8 << 24)
|
||
+#define FLEXCAN_MB_CODE_TX_ABORT (0x9 << 24)
|
||
+#define FLEXCAN_MB_CODE_TX_DATA (0xc << 24)
|
||
+#define FLEXCAN_MB_CODE_TX_TANSWER (0xe << 24)
|
||
+
|
||
#define FLEXCAN_MB_CNT_SRR BIT(22)
|
||
#define FLEXCAN_MB_CNT_IDE BIT(21)
|
||
#define FLEXCAN_MB_CNT_RTR BIT(20)
|
||
@@ -306,6 +319,14 @@ static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||
flexcan_write(can_id, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
|
||
flexcan_write(ctrl, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
|
||
|
||
+ /* Errata ERR005829 step8:
|
||
+ * Write twice INACTIVE(0x8) code to first MB.
|
||
+ */
|
||
+ flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
||
+ ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
|
||
+ flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
||
+ ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
|
||
+
|
||
return NETDEV_TX_OK;
|
||
}
|
||
|
||
@@ -612,6 +633,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
||
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
|
||
stats->tx_bytes += can_get_echo_skb(dev, 0);
|
||
stats->tx_packets++;
|
||
+ /* after sending a RTR frame mailbox is in RX mode */
|
||
+ flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
||
+ ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
|
||
flexcan_write((1 << FLEXCAN_TX_BUF_ID), ®s->iflag1);
|
||
netif_wake_queue(dev);
|
||
}
|
||
@@ -667,9 +691,9 @@ static int flexcan_chip_start(struct net_device *dev)
|
||
{
|
||
struct flexcan_priv *priv = netdev_priv(dev);
|
||
struct flexcan_regs __iomem *regs = priv->base;
|
||
- unsigned int i;
|
||
int err;
|
||
u32 reg_mcr, reg_ctrl;
|
||
+ int i;
|
||
|
||
/* enable module */
|
||
flexcan_chip_enable(priv);
|
||
@@ -701,9 +725,11 @@ static int flexcan_chip_start(struct net_device *dev)
|
||
*
|
||
*/
|
||
reg_mcr = flexcan_read(®s->mcr);
|
||
+ reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
|
||
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
|
||
FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
|
||
- FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS;
|
||
+ FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
|
||
+ FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
|
||
netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
|
||
flexcan_write(reg_mcr, ®s->mcr);
|
||
|
||
@@ -733,17 +759,20 @@ static int flexcan_chip_start(struct net_device *dev)
|
||
netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
|
||
flexcan_write(reg_ctrl, ®s->ctrl);
|
||
|
||
- for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
|
||
- flexcan_write(0, ®s->cantxfg[i].can_ctrl);
|
||
- flexcan_write(0, ®s->cantxfg[i].can_id);
|
||
- flexcan_write(0, ®s->cantxfg[i].data[0]);
|
||
- flexcan_write(0, ®s->cantxfg[i].data[1]);
|
||
-
|
||
- /* put MB into rx queue */
|
||
- flexcan_write(FLEXCAN_MB_CNT_CODE(0x4),
|
||
- ®s->cantxfg[i].can_ctrl);
|
||
+ /* clear and invalidate all mailboxes first */
|
||
+ for (i = FLEXCAN_TX_BUF_ID; i < ARRAY_SIZE(regs->cantxfg); i++) {
|
||
+ flexcan_write(FLEXCAN_MB_CODE_RX_INACTIVE,
|
||
+ ®s->cantxfg[i].can_ctrl);
|
||
}
|
||
|
||
+ /* Errata ERR005829: mark first TX mailbox as INACTIVE */
|
||
+ flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
||
+ ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
|
||
+
|
||
+ /* mark TX mailbox as INACTIVE */
|
||
+ flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
||
+ ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
|
||
+
|
||
/* acceptance mask/acceptance code (accept everything) */
|
||
flexcan_write(0x0, ®s->rxgmask);
|
||
flexcan_write(0x0, ®s->rx14mask);
|
||
@@ -811,7 +840,7 @@ static int flexcan_open(struct net_device *dev)
|
||
|
||
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
|
||
if (err)
|
||
- goto out_close;
|
||
+ goto out_free_irq;
|
||
|
||
/* start chip and queuing */
|
||
err = flexcan_chip_start(dev);
|
||
@@ -822,6 +851,8 @@ static int flexcan_open(struct net_device *dev)
|
||
|
||
return 0;
|
||
|
||
+ out_free_irq:
|
||
+ free_irq(dev->irq, dev);
|
||
out_close:
|
||
close_candev(dev);
|
||
out:
|
||
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
|
||
index 5f92b86..a28c5d3 100644
|
||
--- a/drivers/net/can/sja1000/peak_pci.c
|
||
+++ b/drivers/net/can/sja1000/peak_pci.c
|
||
@@ -547,7 +547,7 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
|
||
{
|
||
struct sja1000_priv *priv;
|
||
struct peak_pci_chan *chan;
|
||
- struct net_device *dev;
|
||
+ struct net_device *dev, *prev_dev;
|
||
void __iomem *cfg_base, *reg_base;
|
||
u16 sub_sys_id, icr;
|
||
int i, err, channels;
|
||
@@ -681,11 +681,13 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
|
||
writew(0x0, cfg_base + PITA_ICR + 2);
|
||
|
||
chan = NULL;
|
||
- for (dev = pci_get_drvdata(pdev); dev; dev = chan->prev_dev) {
|
||
- unregister_sja1000dev(dev);
|
||
- free_sja1000dev(dev);
|
||
+ for (dev = pci_get_drvdata(pdev); dev; dev = prev_dev) {
|
||
priv = netdev_priv(dev);
|
||
chan = priv->priv;
|
||
+ prev_dev = chan->prev_dev;
|
||
+
|
||
+ unregister_sja1000dev(dev);
|
||
+ free_sja1000dev(dev);
|
||
}
|
||
|
||
/* free any PCIeC resources too */
|
||
@@ -719,10 +721,12 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
|
||
|
||
/* Loop over all registered devices */
|
||
while (1) {
|
||
+ struct net_device *prev_dev = chan->prev_dev;
|
||
+
|
||
dev_info(&pdev->dev, "removing device %s\n", dev->name);
|
||
unregister_sja1000dev(dev);
|
||
free_sja1000dev(dev);
|
||
- dev = chan->prev_dev;
|
||
+ dev = prev_dev;
|
||
|
||
if (!dev) {
|
||
/* do that only for first channel */
|
||
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
|
||
index c2309ec..2d3ad72 100644
|
||
--- a/drivers/net/can/sja1000/sja1000.c
|
||
+++ b/drivers/net/can/sja1000/sja1000.c
|
||
@@ -487,19 +487,19 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
|
||
uint8_t isrc, status;
|
||
int n = 0;
|
||
|
||
- /* Shared interrupts and IRQ off? */
|
||
- if (priv->read_reg(priv, REG_IER) == IRQ_OFF)
|
||
- return IRQ_NONE;
|
||
-
|
||
if (priv->pre_irq)
|
||
priv->pre_irq(priv);
|
||
|
||
+ /* Shared interrupts and IRQ off? */
|
||
+ if (priv->read_reg(priv, REG_IER) == IRQ_OFF)
|
||
+ goto out;
|
||
+
|
||
while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
|
||
- n++;
|
||
+
|
||
status = priv->read_reg(priv, SJA1000_REG_SR);
|
||
/* check for absent controller due to hw unplug */
|
||
if (status == 0xFF && sja1000_is_absent(priv))
|
||
- return IRQ_NONE;
|
||
+ goto out;
|
||
|
||
if (isrc & IRQ_WUI)
|
||
netdev_warn(dev, "wakeup interrupt\n");
|
||
@@ -518,7 +518,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
|
||
status = priv->read_reg(priv, SJA1000_REG_SR);
|
||
/* check for absent controller */
|
||
if (status == 0xFF && sja1000_is_absent(priv))
|
||
- return IRQ_NONE;
|
||
+ goto out;
|
||
}
|
||
}
|
||
if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
|
||
@@ -526,8 +526,9 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
|
||
if (sja1000_err(dev, isrc, status))
|
||
break;
|
||
}
|
||
+ n++;
|
||
}
|
||
-
|
||
+out:
|
||
if (priv->post_irq)
|
||
priv->post_irq(priv);
|
||
|
||
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
|
||
index acd8246..0f05cef 100644
|
||
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
|
||
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
|
||
@@ -71,6 +71,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
|
||
struct sk_buff *skb = tx_buf->skb;
|
||
u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons;
|
||
int nbd;
|
||
+ u16 split_bd_len = 0;
|
||
|
||
/* prefetch skb end pointer to speedup dev_kfree_skb() */
|
||
prefetch(&skb->end);
|
||
@@ -78,10 +79,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
|
||
DP(NETIF_MSG_TX_DONE, "fp[%d]: pkt_idx %d buff @(%p)->skb %p\n",
|
||
txdata->txq_index, idx, tx_buf, skb);
|
||
|
||
- /* unmap first bd */
|
||
tx_start_bd = &txdata->tx_desc_ring[bd_idx].start_bd;
|
||
- dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
|
||
- BD_UNMAP_LEN(tx_start_bd), DMA_TO_DEVICE);
|
||
|
||
|
||
nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
|
||
@@ -100,12 +98,19 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
|
||
--nbd;
|
||
bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
|
||
|
||
- /* ...and the TSO split header bd since they have no mapping */
|
||
+ /* TSO headers+data bds share a common mapping. See bnx2x_tx_split() */
|
||
if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) {
|
||
+ tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd;
|
||
+ split_bd_len = BD_UNMAP_LEN(tx_data_bd);
|
||
--nbd;
|
||
bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
|
||
}
|
||
|
||
+ /* unmap first bd */
|
||
+ dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
|
||
+ BD_UNMAP_LEN(tx_start_bd) + split_bd_len,
|
||
+ DMA_TO_DEVICE);
|
||
+
|
||
/* now free frags */
|
||
while (nbd > 0) {
|
||
|
||
@@ -547,6 +552,7 @@ static inline void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
|
||
skb, cqe, cqe_idx)) {
|
||
if (tpa_info->parsing_flags & PARSING_FLAGS_VLAN)
|
||
__vlan_hwaccel_put_tag(skb, tpa_info->vlan_tag);
|
||
+ skb_record_rx_queue(skb, fp->rx_queue);
|
||
napi_gro_receive(&fp->napi, skb);
|
||
} else {
|
||
DP(NETIF_MSG_RX_STATUS,
|
||
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
|
||
index 3551ad8..cbc6a62 100644
|
||
--- a/drivers/net/ethernet/broadcom/tg3.c
|
||
+++ b/drivers/net/ethernet/broadcom/tg3.c
|
||
@@ -1631,6 +1631,9 @@ static int tg3_poll_fw(struct tg3 *tp)
|
||
int i;
|
||
u32 val;
|
||
|
||
+ if (tg3_flag(tp, NO_FWARE_REPORTED))
|
||
+ return 0;
|
||
+
|
||
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
|
||
/* Wait up to 20ms for init done. */
|
||
for (i = 0; i < 200; i++) {
|
||
@@ -2737,6 +2740,31 @@ static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed)
|
||
return 0;
|
||
}
|
||
|
||
+static bool tg3_phy_power_bug(struct tg3 *tp)
|
||
+{
|
||
+ switch (GET_ASIC_REV(tp->pci_chip_rev_id)) {
|
||
+ case ASIC_REV_5700:
|
||
+ case ASIC_REV_5704:
|
||
+ return true;
|
||
+ case ASIC_REV_5780:
|
||
+ if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
|
||
+ return true;
|
||
+ return false;
|
||
+ case ASIC_REV_5717:
|
||
+ if (!tp->pci_fn)
|
||
+ return true;
|
||
+ return false;
|
||
+ case ASIC_REV_5719:
|
||
+ case ASIC_REV_5720:
|
||
+ if ((tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
|
||
+ !tp->pci_fn)
|
||
+ return true;
|
||
+ return false;
|
||
+ }
|
||
+
|
||
+ return false;
|
||
+}
|
||
+
|
||
static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
|
||
{
|
||
u32 val;
|
||
@@ -2793,12 +2821,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
|
||
/* The PHY should not be powered down on some chips because
|
||
* of bugs.
|
||
*/
|
||
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
|
||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
|
||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
|
||
- (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) ||
|
||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
|
||
- !tp->pci_fn))
|
||
+ if (tg3_phy_power_bug(tp))
|
||
return;
|
||
|
||
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
|
||
@@ -5844,8 +5867,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
|
||
|
||
work_mask |= opaque_key;
|
||
|
||
- if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
|
||
- (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) {
|
||
+ if (desc->err_vlan & RXD_ERR_MASK) {
|
||
drop_it:
|
||
tg3_recycle_rx(tnapi, tpr, opaque_key,
|
||
desc_idx, *post_ptr);
|
||
@@ -8526,6 +8548,14 @@ static void tg3_rss_write_indir_tbl(struct tg3 *tp)
|
||
}
|
||
}
|
||
|
||
+static inline u32 tg3_lso_rd_dma_workaround_bit(struct tg3 *tp)
|
||
+{
|
||
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
|
||
+ return TG3_LSO_RD_DMA_TX_LENGTH_WA_5719;
|
||
+ else
|
||
+ return TG3_LSO_RD_DMA_TX_LENGTH_WA_5720;
|
||
+}
|
||
+
|
||
/* tp->lock is held. */
|
||
static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
|
||
{
|
||
@@ -9162,6 +9192,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
|
||
tw32_f(RDMAC_MODE, rdmac_mode);
|
||
udelay(40);
|
||
|
||
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
|
||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
|
||
+ for (i = 0; i < TG3_NUM_RDMA_CHANNELS; i++) {
|
||
+ if (tr32(TG3_RDMA_LENGTH + (i << 2)) > TG3_MAX_MTU(tp))
|
||
+ break;
|
||
+ }
|
||
+ if (i < TG3_NUM_RDMA_CHANNELS) {
|
||
+ val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
|
||
+ val |= tg3_lso_rd_dma_workaround_bit(tp);
|
||
+ tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val);
|
||
+ tg3_flag_set(tp, 5719_5720_RDMA_BUG);
|
||
+ }
|
||
+ }
|
||
+
|
||
tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
|
||
if (!tg3_flag(tp, 5705_PLUS))
|
||
tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
|
||
@@ -9383,6 +9427,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
|
||
*/
|
||
static int tg3_init_hw(struct tg3 *tp, int reset_phy)
|
||
{
|
||
+ /* Chip may have been just powered on. If so, the boot code may still
|
||
+ * be running initialization. Wait for it to finish to avoid races in
|
||
+ * accessing the hardware.
|
||
+ */
|
||
+ tg3_enable_register_access(tp);
|
||
+ tg3_poll_fw(tp);
|
||
+
|
||
tg3_switch_clocks(tp);
|
||
|
||
tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
|
||
@@ -9417,6 +9468,16 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp)
|
||
TG3_STAT_ADD32(&sp->tx_ucast_packets, MAC_TX_STATS_UCAST);
|
||
TG3_STAT_ADD32(&sp->tx_mcast_packets, MAC_TX_STATS_MCAST);
|
||
TG3_STAT_ADD32(&sp->tx_bcast_packets, MAC_TX_STATS_BCAST);
|
||
+ if (unlikely(tg3_flag(tp, 5719_5720_RDMA_BUG) &&
|
||
+ (sp->tx_ucast_packets.low + sp->tx_mcast_packets.low +
|
||
+ sp->tx_bcast_packets.low) > TG3_NUM_RDMA_CHANNELS)) {
|
||
+ u32 val;
|
||
+
|
||
+ val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
|
||
+ val &= ~tg3_lso_rd_dma_workaround_bit(tp);
|
||
+ tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val);
|
||
+ tg3_flag_clear(tp, 5719_5720_RDMA_BUG);
|
||
+ }
|
||
|
||
TG3_STAT_ADD32(&sp->rx_octets, MAC_RX_STATS_OCTETS);
|
||
TG3_STAT_ADD32(&sp->rx_fragments, MAC_RX_STATS_FRAGMENTS);
|
||
@@ -10800,7 +10861,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
|
||
if (tg3_flag(tp, MAX_RXPEND_64) &&
|
||
tp->rx_pending > 63)
|
||
tp->rx_pending = 63;
|
||
- tp->rx_jumbo_pending = ering->rx_jumbo_pending;
|
||
+
|
||
+ if (tg3_flag(tp, JUMBO_RING_ENABLE))
|
||
+ tp->rx_jumbo_pending = ering->rx_jumbo_pending;
|
||
|
||
for (i = 0; i < tp->irq_max; i++)
|
||
tp->napi[i].tx_pending = ering->tx_pending;
|
||
@@ -12343,12 +12406,12 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
|
||
|
||
tg3_netif_stop(tp);
|
||
|
||
+ tg3_set_mtu(dev, tp, new_mtu);
|
||
+
|
||
tg3_full_lock(tp, 1);
|
||
|
||
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
|
||
|
||
- tg3_set_mtu(dev, tp, new_mtu);
|
||
-
|
||
/* Reset PHY, otherwise the read DMA engine will be in a mode that
|
||
* breaks all requests to 256 bytes.
|
||
*/
|
||
@@ -14671,6 +14734,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
|
||
/* Clear this out for sanity. */
|
||
tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
|
||
|
||
+ /* Clear TG3PCI_REG_BASE_ADDR to prevent hangs. */
|
||
+ tw32(TG3PCI_REG_BASE_ADDR, 0);
|
||
+
|
||
pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
|
||
&pci_state_reg);
|
||
if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0 &&
|
||
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
|
||
index 93865f8..6639a63 100644
|
||
--- a/drivers/net/ethernet/broadcom/tg3.h
|
||
+++ b/drivers/net/ethernet/broadcom/tg3.h
|
||
@@ -1376,7 +1376,12 @@
|
||
#define TG3_LSO_RD_DMA_CRPTEN_CTRL 0x00004910
|
||
#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K 0x00030000
|
||
#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K 0x000c0000
|
||
-/* 0x4914 --> 0x4c00 unused */
|
||
+#define TG3_LSO_RD_DMA_TX_LENGTH_WA_5719 0x02000000
|
||
+#define TG3_LSO_RD_DMA_TX_LENGTH_WA_5720 0x00200000
|
||
+/* 0x4914 --> 0x4be0 unused */
|
||
+
|
||
+#define TG3_NUM_RDMA_CHANNELS 4
|
||
+#define TG3_RDMA_LENGTH 0x00004be0
|
||
|
||
/* Write DMA control registers */
|
||
#define WDMAC_MODE 0x00004c00
|
||
@@ -2484,7 +2489,11 @@ struct tg3_rx_buffer_desc {
|
||
#define RXD_ERR_TOO_SMALL 0x00400000
|
||
#define RXD_ERR_NO_RESOURCES 0x00800000
|
||
#define RXD_ERR_HUGE_FRAME 0x01000000
|
||
-#define RXD_ERR_MASK 0xffff0000
|
||
+
|
||
+#define RXD_ERR_MASK (RXD_ERR_BAD_CRC | RXD_ERR_COLLISION | \
|
||
+ RXD_ERR_LINK_LOST | RXD_ERR_PHY_DECODE | \
|
||
+ RXD_ERR_MAC_ABRT | RXD_ERR_TOO_SMALL | \
|
||
+ RXD_ERR_NO_RESOURCES | RXD_ERR_HUGE_FRAME)
|
||
|
||
u32 reserved;
|
||
u32 opaque;
|
||
@@ -2920,6 +2929,7 @@ enum TG3_FLAGS {
|
||
TG3_FLAG_L1PLLPD_EN,
|
||
TG3_FLAG_APE_HAS_NCSI,
|
||
TG3_FLAG_4K_FIFO_LIMIT,
|
||
+ TG3_FLAG_5719_5720_RDMA_BUG,
|
||
TG3_FLAG_RESET_TASK_PENDING,
|
||
TG3_FLAG_5705_PLUS,
|
||
TG3_FLAG_IS_5788,
|
||
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
|
||
index 4ebbe6f..5699105 100644
|
||
--- a/drivers/net/ethernet/calxeda/xgmac.c
|
||
+++ b/drivers/net/ethernet/calxeda/xgmac.c
|
||
@@ -1776,7 +1776,7 @@ static int xgmac_probe(struct platform_device *pdev)
|
||
if (device_can_wakeup(priv->device))
|
||
priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */
|
||
|
||
- ndev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA;
|
||
+ ndev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA;
|
||
if (readl(priv->base + XGMAC_DMA_HW_FEATURE) & DMA_HW_FEAT_TXCOESEL)
|
||
ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
|
||
NETIF_F_RXCSUM;
|
||
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
|
||
index ef1f940..b2740f1 100644
|
||
--- a/drivers/net/ethernet/emulex/benet/be_main.c
|
||
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
|
||
@@ -2411,7 +2411,7 @@ static int be_open(struct net_device *netdev)
|
||
|
||
for_all_evt_queues(adapter, eqo, i) {
|
||
napi_enable(&eqo->napi);
|
||
- be_eq_notify(adapter, eqo->q.id, true, false, 0);
|
||
+ be_eq_notify(adapter, eqo->q.id, true, true, 0);
|
||
}
|
||
|
||
status = be_cmd_link_status_query(adapter, NULL, NULL,
|
||
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
|
||
index f4d2da0..8b3da6e 100644
|
||
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
|
||
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
|
||
@@ -3029,7 +3029,7 @@ static struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
|
||
|
||
dev->hw_features = NETIF_F_SG | NETIF_F_TSO
|
||
| NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO;
|
||
- dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
|
||
+ dev->features = NETIF_F_SG | NETIF_F_TSO
|
||
| NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX
|
||
| NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
|
||
| NETIF_F_RXCSUM;
|
||
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
|
||
index 33a1760..b2b715f 100644
|
||
--- a/drivers/net/ethernet/ibm/ibmveth.c
|
||
+++ b/drivers/net/ethernet/ibm/ibmveth.c
|
||
@@ -293,6 +293,18 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter,
|
||
atomic_add(buffers_added, &(pool->available));
|
||
}
|
||
|
||
+/*
|
||
+ * The final 8 bytes of the buffer list is a counter of frames dropped
|
||
+ * because there was not a buffer in the buffer list capable of holding
|
||
+ * the frame.
|
||
+ */
|
||
+static void ibmveth_update_rx_no_buffer(struct ibmveth_adapter *adapter)
|
||
+{
|
||
+ __be64 *p = adapter->buffer_list_addr + 4096 - 8;
|
||
+
|
||
+ adapter->rx_no_buffer = be64_to_cpup(p);
|
||
+}
|
||
+
|
||
/* replenish routine */
|
||
static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
|
||
{
|
||
@@ -308,8 +320,7 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
|
||
ibmveth_replenish_buffer_pool(adapter, pool);
|
||
}
|
||
|
||
- adapter->rx_no_buffer = *(u64 *)(((char*)adapter->buffer_list_addr) +
|
||
- 4096 - 8);
|
||
+ ibmveth_update_rx_no_buffer(adapter);
|
||
}
|
||
|
||
/* empty and free ana buffer pool - also used to do cleanup in error paths */
|
||
@@ -692,8 +703,7 @@ static int ibmveth_close(struct net_device *netdev)
|
||
|
||
free_irq(netdev->irq, netdev);
|
||
|
||
- adapter->rx_no_buffer = *(u64 *)(((char *)adapter->buffer_list_addr) +
|
||
- 4096 - 8);
|
||
+ ibmveth_update_rx_no_buffer(adapter);
|
||
|
||
ibmveth_cleanup(adapter);
|
||
|
||
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
|
||
index 1ab8067..21c058b 100644
|
||
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
|
||
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
|
||
@@ -309,6 +309,7 @@ struct e1000_adapter {
|
||
*/
|
||
struct e1000_ring *tx_ring /* One per active queue */
|
||
____cacheline_aligned_in_smp;
|
||
+ u32 tx_fifo_limit;
|
||
|
||
struct napi_struct napi;
|
||
|
||
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
|
||
index c80b4b4..e65f529 100644
|
||
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
|
||
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
|
||
@@ -3498,6 +3498,15 @@ void e1000e_reset(struct e1000_adapter *adapter)
|
||
}
|
||
|
||
/*
|
||
+ * Alignment of Tx data is on an arbitrary byte boundary with the
|
||
+ * maximum size per Tx descriptor limited only to the transmit
|
||
+ * allocation of the packet buffer minus 96 bytes with an upper
|
||
+ * limit of 24KB due to receive synchronization limitations.
|
||
+ */
|
||
+ adapter->tx_fifo_limit = min_t(u32, ((er32(PBA) >> 16) << 10) - 96,
|
||
+ 24 << 10);
|
||
+
|
||
+ /*
|
||
* Disable Adaptive Interrupt Moderation if 2 full packets cannot
|
||
* fit in receive buffer.
|
||
*/
|
||
@@ -4766,12 +4775,9 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb)
|
||
return 1;
|
||
}
|
||
|
||
-#define E1000_MAX_PER_TXD 8192
|
||
-#define E1000_MAX_TXD_PWR 12
|
||
-
|
||
static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
|
||
unsigned int first, unsigned int max_per_txd,
|
||
- unsigned int nr_frags, unsigned int mss)
|
||
+ unsigned int nr_frags)
|
||
{
|
||
struct e1000_adapter *adapter = tx_ring->adapter;
|
||
struct pci_dev *pdev = adapter->pdev;
|
||
@@ -5004,20 +5010,19 @@ static int __e1000_maybe_stop_tx(struct e1000_ring *tx_ring, int size)
|
||
|
||
static int e1000_maybe_stop_tx(struct e1000_ring *tx_ring, int size)
|
||
{
|
||
+ BUG_ON(size > tx_ring->count);
|
||
+
|
||
if (e1000_desc_unused(tx_ring) >= size)
|
||
return 0;
|
||
return __e1000_maybe_stop_tx(tx_ring, size);
|
||
}
|
||
|
||
-#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1)
|
||
static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||
struct net_device *netdev)
|
||
{
|
||
struct e1000_adapter *adapter = netdev_priv(netdev);
|
||
struct e1000_ring *tx_ring = adapter->tx_ring;
|
||
unsigned int first;
|
||
- unsigned int max_per_txd = E1000_MAX_PER_TXD;
|
||
- unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
|
||
unsigned int tx_flags = 0;
|
||
unsigned int len = skb_headlen(skb);
|
||
unsigned int nr_frags;
|
||
@@ -5037,18 +5042,8 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||
}
|
||
|
||
mss = skb_shinfo(skb)->gso_size;
|
||
- /*
|
||
- * The controller does a simple calculation to
|
||
- * make sure there is enough room in the FIFO before
|
||
- * initiating the DMA for each buffer. The calc is:
|
||
- * 4 = ceil(buffer len/mss). To make sure we don't
|
||
- * overrun the FIFO, adjust the max buffer len if mss
|
||
- * drops.
|
||
- */
|
||
if (mss) {
|
||
u8 hdr_len;
|
||
- max_per_txd = min(mss << 2, max_per_txd);
|
||
- max_txd_pwr = fls(max_per_txd) - 1;
|
||
|
||
/*
|
||
* TSO Workaround for 82571/2/3 Controllers -- if skb->data
|
||
@@ -5078,12 +5073,12 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||
count++;
|
||
count++;
|
||
|
||
- count += TXD_USE_COUNT(len, max_txd_pwr);
|
||
+ count += DIV_ROUND_UP(len, adapter->tx_fifo_limit);
|
||
|
||
nr_frags = skb_shinfo(skb)->nr_frags;
|
||
for (f = 0; f < nr_frags; f++)
|
||
- count += TXD_USE_COUNT(skb_frag_size(&skb_shinfo(skb)->frags[f]),
|
||
- max_txd_pwr);
|
||
+ count += DIV_ROUND_UP(skb_frag_size(&skb_shinfo(skb)->frags[f]),
|
||
+ adapter->tx_fifo_limit);
|
||
|
||
if (adapter->hw.mac.tx_pkt_filtering)
|
||
e1000_transfer_dhcp_info(adapter, skb);
|
||
@@ -5125,13 +5120,16 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||
tx_flags |= E1000_TX_FLAGS_NO_FCS;
|
||
|
||
/* if count is 0 then mapping error has occurred */
|
||
- count = e1000_tx_map(tx_ring, skb, first, max_per_txd, nr_frags, mss);
|
||
+ count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit,
|
||
+ nr_frags);
|
||
if (count) {
|
||
netdev_sent_queue(netdev, skb->len);
|
||
e1000_tx_queue(tx_ring, tx_flags, count);
|
||
/* Make sure there is space in the ring for the next send. */
|
||
- e1000_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS + 2);
|
||
-
|
||
+ e1000_maybe_stop_tx(tx_ring,
|
||
+ (MAX_SKB_FRAGS *
|
||
+ DIV_ROUND_UP(PAGE_SIZE,
|
||
+ adapter->tx_fifo_limit) + 2));
|
||
} else {
|
||
dev_kfree_skb_any(skb);
|
||
tx_ring->buffer_info[first].time_stamp = 0;
|
||
@@ -6303,8 +6301,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
|
||
adapter->hw.phy.autoneg_advertised = 0x2f;
|
||
|
||
/* ring size defaults */
|
||
- adapter->rx_ring->count = 256;
|
||
- adapter->tx_ring->count = 256;
|
||
+ adapter->rx_ring->count = E1000_DEFAULT_RXD;
|
||
+ adapter->tx_ring->count = E1000_DEFAULT_TXD;
|
||
|
||
/*
|
||
* Initial Wake on LAN setting - If APM wake is enabled in
|
||
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
|
||
index 8f95545..8611409 100644
|
||
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
|
||
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
|
||
@@ -7464,12 +7464,15 @@ static int __init ixgbe_init_module(void)
|
||
pr_info("%s - version %s\n", ixgbe_driver_string, ixgbe_driver_version);
|
||
pr_info("%s\n", ixgbe_copyright);
|
||
|
||
+ ret = pci_register_driver(&ixgbe_driver);
|
||
+ if (ret)
|
||
+ return ret;
|
||
+
|
||
#ifdef CONFIG_IXGBE_DCA
|
||
dca_register_notify(&dca_notifier);
|
||
#endif
|
||
|
||
- ret = pci_register_driver(&ixgbe_driver);
|
||
- return ret;
|
||
+ return 0;
|
||
}
|
||
|
||
module_init(ixgbe_init_module);
|
||
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
|
||
index 307611a..d8e4562 100644
|
||
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
|
||
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
|
||
@@ -969,8 +969,6 @@ static irqreturn_t ixgbevf_msix_clean_tx(int irq, void *data)
|
||
r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
|
||
for (i = 0; i < q_vector->txr_count; i++) {
|
||
tx_ring = &(adapter->tx_ring[r_idx]);
|
||
- tx_ring->total_bytes = 0;
|
||
- tx_ring->total_packets = 0;
|
||
ixgbevf_clean_tx_irq(adapter, tx_ring);
|
||
r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
|
||
r_idx + 1);
|
||
@@ -994,16 +992,6 @@ static irqreturn_t ixgbevf_msix_clean_rx(int irq, void *data)
|
||
struct ixgbe_hw *hw = &adapter->hw;
|
||
struct ixgbevf_ring *rx_ring;
|
||
int r_idx;
|
||
- int i;
|
||
-
|
||
- r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
|
||
- for (i = 0; i < q_vector->rxr_count; i++) {
|
||
- rx_ring = &(adapter->rx_ring[r_idx]);
|
||
- rx_ring->total_bytes = 0;
|
||
- rx_ring->total_packets = 0;
|
||
- r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
|
||
- r_idx + 1);
|
||
- }
|
||
|
||
if (!q_vector->rxr_count)
|
||
return IRQ_HANDLED;
|
||
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
|
||
index 5e1ca0f..ffa6a72 100644
|
||
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
|
||
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
|
||
@@ -1274,15 +1274,13 @@ static void mib_counters_update(struct mv643xx_eth_private *mp)
|
||
p->rx_discard += rdlp(mp, RX_DISCARD_FRAME_CNT);
|
||
p->rx_overrun += rdlp(mp, RX_OVERRUN_FRAME_CNT);
|
||
spin_unlock_bh(&mp->mib_counters_lock);
|
||
-
|
||
- mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ);
|
||
}
|
||
|
||
static void mib_counters_timer_wrapper(unsigned long _mp)
|
||
{
|
||
struct mv643xx_eth_private *mp = (void *)_mp;
|
||
-
|
||
mib_counters_update(mp);
|
||
+ mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ);
|
||
}
|
||
|
||
|
||
@@ -2370,6 +2368,7 @@ static int mv643xx_eth_open(struct net_device *dev)
|
||
mp->int_mask |= INT_TX_END_0 << i;
|
||
}
|
||
|
||
+ add_timer(&mp->mib_counters_timer);
|
||
port_start(mp);
|
||
|
||
wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX);
|
||
@@ -2911,7 +2910,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
|
||
mp->mib_counters_timer.data = (unsigned long)mp;
|
||
mp->mib_counters_timer.function = mib_counters_timer_wrapper;
|
||
mp->mib_counters_timer.expires = jiffies + 30 * HZ;
|
||
- add_timer(&mp->mib_counters_timer);
|
||
|
||
spin_lock_init(&mp->mib_counters_lock);
|
||
|
||
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
|
||
index 00b8127..174b622 100644
|
||
--- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c
|
||
+++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
|
||
@@ -55,7 +55,6 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv,
|
||
|
||
cq->ring = ring;
|
||
cq->is_tx = mode;
|
||
- spin_lock_init(&cq->lock);
|
||
|
||
err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres,
|
||
cq->buf_size, 2 * PAGE_SIZE);
|
||
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
|
||
index 31b455a..467a511 100644
|
||
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
|
||
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
|
||
@@ -370,15 +370,11 @@ static void mlx4_en_netpoll(struct net_device *dev)
|
||
{
|
||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||
struct mlx4_en_cq *cq;
|
||
- unsigned long flags;
|
||
int i;
|
||
|
||
for (i = 0; i < priv->rx_ring_num; i++) {
|
||
cq = &priv->rx_cq[i];
|
||
- spin_lock_irqsave(&cq->lock, flags);
|
||
- napi_synchronize(&cq->napi);
|
||
- mlx4_en_process_rx_cq(dev, cq, 0);
|
||
- spin_unlock_irqrestore(&cq->lock, flags);
|
||
+ napi_schedule(&cq->napi);
|
||
}
|
||
}
|
||
#endif
|
||
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
|
||
index 1995cb0..6e49bb4 100644
|
||
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
|
||
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
|
||
@@ -92,8 +92,6 @@ MODULE_PARM_DESC(log_num_mgm_entry_size, "log mgm size, that defines the num"
|
||
" 10 gives 248.range: 9<="
|
||
" log_num_mgm_entry_size <= 12");
|
||
|
||
-#define MLX4_VF (1 << 0)
|
||
-
|
||
#define HCA_GLOBAL_CAP_MASK 0
|
||
#define PF_CONTEXT_BEHAVIOUR_MASK 0
|
||
|
||
@@ -1731,7 +1729,7 @@ static void mlx4_free_ownership(struct mlx4_dev *dev)
|
||
iounmap(owner);
|
||
}
|
||
|
||
-static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||
+static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
|
||
{
|
||
struct mlx4_priv *priv;
|
||
struct mlx4_dev *dev;
|
||
@@ -1754,12 +1752,11 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||
/*
|
||
* Check for BARs.
|
||
*/
|
||
- if (((id == NULL) || !(id->driver_data & MLX4_VF)) &&
|
||
+ if (!(pci_dev_data & MLX4_PCI_DEV_IS_VF) &&
|
||
!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
|
||
dev_err(&pdev->dev, "Missing DCS, aborting."
|
||
- "(id == 0X%p, id->driver_data: 0x%lx,"
|
||
- " pci_resource_flags(pdev, 0):0x%lx)\n", id,
|
||
- id ? id->driver_data : 0, pci_resource_flags(pdev, 0));
|
||
+ "(driver_data: 0x%x, pci_resource_flags(pdev, 0):0x%lx)\n",
|
||
+ pci_dev_data, pci_resource_flags(pdev, 0));
|
||
err = -ENODEV;
|
||
goto err_disable_pdev;
|
||
}
|
||
@@ -1801,15 +1798,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||
/* Allow large DMA segments, up to the firmware limit of 1 GB */
|
||
dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024);
|
||
|
||
- priv = kzalloc(sizeof *priv, GFP_KERNEL);
|
||
- if (!priv) {
|
||
- dev_err(&pdev->dev, "Device struct alloc failed, "
|
||
- "aborting.\n");
|
||
- err = -ENOMEM;
|
||
- goto err_release_regions;
|
||
- }
|
||
-
|
||
- dev = &priv->dev;
|
||
+ dev = pci_get_drvdata(pdev);
|
||
+ priv = mlx4_priv(dev);
|
||
dev->pdev = pdev;
|
||
INIT_LIST_HEAD(&priv->ctx_list);
|
||
spin_lock_init(&priv->ctx_lock);
|
||
@@ -1824,7 +1814,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||
|
||
dev->rev_id = pdev->revision;
|
||
/* Detect if this device is a virtual function */
|
||
- if (id && id->driver_data & MLX4_VF) {
|
||
+ if (pci_dev_data & MLX4_PCI_DEV_IS_VF) {
|
||
/* When acting as pf, we normally skip vfs unless explicitly
|
||
* requested to probe them. */
|
||
if (num_vfs && extended_func_num(pdev) > probe_vf) {
|
||
@@ -1970,7 +1960,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||
mlx4_sense_init(dev);
|
||
mlx4_start_sense(dev);
|
||
|
||
- pci_set_drvdata(pdev, dev);
|
||
+ priv->removed = 0;
|
||
|
||
return 0;
|
||
|
||
@@ -2037,79 +2027,111 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||
static int __devinit mlx4_init_one(struct pci_dev *pdev,
|
||
const struct pci_device_id *id)
|
||
{
|
||
+ struct mlx4_priv *priv;
|
||
+ struct mlx4_dev *dev;
|
||
+
|
||
printk_once(KERN_INFO "%s", mlx4_version);
|
||
|
||
- return __mlx4_init_one(pdev, id);
|
||
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||
+ if (!priv)
|
||
+ return -ENOMEM;
|
||
+
|
||
+ dev = &priv->dev;
|
||
+ pci_set_drvdata(pdev, dev);
|
||
+ priv->pci_dev_data = id->driver_data;
|
||
+
|
||
+ return __mlx4_init_one(pdev, id->driver_data);
|
||
}
|
||
|
||
-static void mlx4_remove_one(struct pci_dev *pdev)
|
||
+static void __mlx4_remove_one(struct pci_dev *pdev)
|
||
{
|
||
struct mlx4_dev *dev = pci_get_drvdata(pdev);
|
||
struct mlx4_priv *priv = mlx4_priv(dev);
|
||
+ int pci_dev_data;
|
||
int p;
|
||
|
||
- if (dev) {
|
||
- /* in SRIOV it is not allowed to unload the pf's
|
||
- * driver while there are alive vf's */
|
||
- if (mlx4_is_master(dev)) {
|
||
- if (mlx4_how_many_lives_vf(dev))
|
||
- printk(KERN_ERR "Removing PF when there are assigned VF's !!!\n");
|
||
- }
|
||
- mlx4_stop_sense(dev);
|
||
- mlx4_unregister_device(dev);
|
||
+ if (priv->removed)
|
||
+ return;
|
||
|
||
- for (p = 1; p <= dev->caps.num_ports; p++) {
|
||
- mlx4_cleanup_port_info(&priv->port[p]);
|
||
- mlx4_CLOSE_PORT(dev, p);
|
||
- }
|
||
+ pci_dev_data = priv->pci_dev_data;
|
||
|
||
- mlx4_cleanup_counters_table(dev);
|
||
- mlx4_cleanup_mcg_table(dev);
|
||
- mlx4_cleanup_qp_table(dev);
|
||
- mlx4_cleanup_srq_table(dev);
|
||
- mlx4_cleanup_cq_table(dev);
|
||
- mlx4_cmd_use_polling(dev);
|
||
- mlx4_cleanup_eq_table(dev);
|
||
- mlx4_cleanup_mr_table(dev);
|
||
- mlx4_cleanup_xrcd_table(dev);
|
||
- mlx4_cleanup_pd_table(dev);
|
||
+ /* in SRIOV it is not allowed to unload the pf's
|
||
+ * driver while there are alive vf's */
|
||
+ if (mlx4_is_master(dev)) {
|
||
+ if (mlx4_how_many_lives_vf(dev))
|
||
+ printk(KERN_ERR "Removing PF when there are assigned VF's !!!\n");
|
||
+ }
|
||
+ mlx4_stop_sense(dev);
|
||
+ mlx4_unregister_device(dev);
|
||
|
||
- if (mlx4_is_master(dev))
|
||
- mlx4_free_resource_tracker(dev);
|
||
-
|
||
- iounmap(priv->kar);
|
||
- mlx4_uar_free(dev, &priv->driver_uar);
|
||
- mlx4_cleanup_uar_table(dev);
|
||
- if (!mlx4_is_slave(dev))
|
||
- mlx4_clear_steering(dev);
|
||
- mlx4_free_eq_table(dev);
|
||
- if (mlx4_is_master(dev))
|
||
- mlx4_multi_func_cleanup(dev);
|
||
- mlx4_close_hca(dev);
|
||
- if (mlx4_is_slave(dev))
|
||
- mlx4_multi_func_cleanup(dev);
|
||
- mlx4_cmd_cleanup(dev);
|
||
-
|
||
- if (dev->flags & MLX4_FLAG_MSI_X)
|
||
- pci_disable_msix(pdev);
|
||
- if (num_vfs && (dev->flags & MLX4_FLAG_SRIOV)) {
|
||
- mlx4_warn(dev, "Disabling sriov\n");
|
||
- pci_disable_sriov(pdev);
|
||
- }
|
||
+ for (p = 1; p <= dev->caps.num_ports; p++) {
|
||
+ mlx4_cleanup_port_info(&priv->port[p]);
|
||
+ mlx4_CLOSE_PORT(dev, p);
|
||
+ }
|
||
+
|
||
+ mlx4_cleanup_counters_table(dev);
|
||
+ mlx4_cleanup_mcg_table(dev);
|
||
+ mlx4_cleanup_qp_table(dev);
|
||
+ mlx4_cleanup_srq_table(dev);
|
||
+ mlx4_cleanup_cq_table(dev);
|
||
+ mlx4_cmd_use_polling(dev);
|
||
+ mlx4_cleanup_eq_table(dev);
|
||
+ mlx4_cleanup_mr_table(dev);
|
||
+ mlx4_cleanup_xrcd_table(dev);
|
||
+ mlx4_cleanup_pd_table(dev);
|
||
+
|
||
+ if (mlx4_is_master(dev))
|
||
+ mlx4_free_resource_tracker(dev);
|
||
+
|
||
+ iounmap(priv->kar);
|
||
+ mlx4_uar_free(dev, &priv->driver_uar);
|
||
+ mlx4_cleanup_uar_table(dev);
|
||
+ if (!mlx4_is_slave(dev))
|
||
+ mlx4_clear_steering(dev);
|
||
+ mlx4_free_eq_table(dev);
|
||
+ if (mlx4_is_master(dev))
|
||
+ mlx4_multi_func_cleanup(dev);
|
||
+ mlx4_close_hca(dev);
|
||
+ if (mlx4_is_slave(dev))
|
||
+ mlx4_multi_func_cleanup(dev);
|
||
+ mlx4_cmd_cleanup(dev);
|
||
|
||
- if (!mlx4_is_slave(dev))
|
||
- mlx4_free_ownership(dev);
|
||
- kfree(priv);
|
||
- pci_release_regions(pdev);
|
||
- pci_disable_device(pdev);
|
||
- pci_set_drvdata(pdev, NULL);
|
||
+ if (dev->flags & MLX4_FLAG_MSI_X)
|
||
+ pci_disable_msix(pdev);
|
||
+ if (num_vfs && (dev->flags & MLX4_FLAG_SRIOV)) {
|
||
+ mlx4_warn(dev, "Disabling sriov\n");
|
||
+ pci_disable_sriov(pdev);
|
||
}
|
||
+
|
||
+ if (!mlx4_is_slave(dev))
|
||
+ mlx4_free_ownership(dev);
|
||
+
|
||
+ pci_release_regions(pdev);
|
||
+ pci_disable_device(pdev);
|
||
+ memset(priv, 0, sizeof(*priv));
|
||
+ priv->pci_dev_data = pci_dev_data;
|
||
+ priv->removed = 1;
|
||
+}
|
||
+
|
||
+static void mlx4_remove_one(struct pci_dev *pdev)
|
||
+{
|
||
+ struct mlx4_dev *dev = pci_get_drvdata(pdev);
|
||
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
||
+
|
||
+ __mlx4_remove_one(pdev);
|
||
+ kfree(priv);
|
||
+ pci_set_drvdata(pdev, NULL);
|
||
}
|
||
|
||
int mlx4_restart_one(struct pci_dev *pdev)
|
||
{
|
||
- mlx4_remove_one(pdev);
|
||
- return __mlx4_init_one(pdev, NULL);
|
||
+ struct mlx4_dev *dev = pci_get_drvdata(pdev);
|
||
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
||
+ int pci_dev_data;
|
||
+
|
||
+ pci_dev_data = priv->pci_dev_data;
|
||
+ __mlx4_remove_one(pdev);
|
||
+ return __mlx4_init_one(pdev, pci_dev_data);
|
||
}
|
||
|
||
static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = {
|
||
@@ -2138,11 +2160,11 @@ static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = {
|
||
/* MT26478 ConnectX2 40GigE PCIe gen2 */
|
||
{ PCI_VDEVICE(MELLANOX, 0x676e), 0 },
|
||
/* MT25400 Family [ConnectX-2 Virtual Function] */
|
||
- { PCI_VDEVICE(MELLANOX, 0x1002), MLX4_VF },
|
||
+ { PCI_VDEVICE(MELLANOX, 0x1002), MLX4_PCI_DEV_IS_VF },
|
||
/* MT27500 Family [ConnectX-3] */
|
||
{ PCI_VDEVICE(MELLANOX, 0x1003), 0 },
|
||
/* MT27500 Family [ConnectX-3 Virtual Function] */
|
||
- { PCI_VDEVICE(MELLANOX, 0x1004), MLX4_VF },
|
||
+ { PCI_VDEVICE(MELLANOX, 0x1004), MLX4_PCI_DEV_IS_VF },
|
||
{ PCI_VDEVICE(MELLANOX, 0x1005), 0 }, /* MT27510 Family */
|
||
{ PCI_VDEVICE(MELLANOX, 0x1006), 0 }, /* MT27511 Family */
|
||
{ PCI_VDEVICE(MELLANOX, 0x1007), 0 }, /* MT27520 Family */
|
||
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
|
||
index 2a0ff2c..a3ef1df 100644
|
||
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
|
||
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
|
||
@@ -711,6 +711,10 @@ struct mlx4_steer {
|
||
struct list_head steer_entries[MLX4_NUM_STEERS];
|
||
};
|
||
|
||
+enum {
|
||
+ MLX4_PCI_DEV_IS_VF = 1 << 0,
|
||
+};
|
||
+
|
||
struct mlx4_priv {
|
||
struct mlx4_dev dev;
|
||
|
||
@@ -718,6 +722,9 @@ struct mlx4_priv {
|
||
struct list_head ctx_list;
|
||
spinlock_t ctx_lock;
|
||
|
||
+ int pci_dev_data;
|
||
+ int removed;
|
||
+
|
||
struct list_head pgdir_list;
|
||
struct mutex pgdir_mutex;
|
||
|
||
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
|
||
index d69fee4..8df3c4b 100644
|
||
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
|
||
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
|
||
@@ -301,7 +301,6 @@ struct mlx4_en_cq {
|
||
struct mlx4_cq mcq;
|
||
struct mlx4_hwq_resources wqres;
|
||
int ring;
|
||
- spinlock_t lock;
|
||
struct net_device *dev;
|
||
struct napi_struct napi;
|
||
/* Per-core Tx cq processing support */
|
||
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
|
||
index 1b44047..effb3b7 100644
|
||
--- a/drivers/net/ethernet/realtek/8139cp.c
|
||
+++ b/drivers/net/ethernet/realtek/8139cp.c
|
||
@@ -1232,6 +1232,7 @@ static void cp_tx_timeout(struct net_device *dev)
|
||
cp_clean_rings(cp);
|
||
rc = cp_init_rings(cp);
|
||
cp_start_hw(cp);
|
||
+ cp_enable_irq(cp);
|
||
|
||
netif_wake_queue(dev);
|
||
|
||
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
|
||
index 8e2ac64..ed6ec51 100644
|
||
--- a/drivers/net/ethernet/sun/sunvnet.c
|
||
+++ b/drivers/net/ethernet/sun/sunvnet.c
|
||
@@ -1086,6 +1086,24 @@ static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
|
||
return vp;
|
||
}
|
||
|
||
+static void vnet_cleanup(void)
|
||
+{
|
||
+ struct vnet *vp;
|
||
+ struct net_device *dev;
|
||
+
|
||
+ mutex_lock(&vnet_list_mutex);
|
||
+ while (!list_empty(&vnet_list)) {
|
||
+ vp = list_first_entry(&vnet_list, struct vnet, list);
|
||
+ list_del(&vp->list);
|
||
+ dev = vp->dev;
|
||
+ /* vio_unregister_driver() should have cleaned up port_list */
|
||
+ BUG_ON(!list_empty(&vp->port_list));
|
||
+ unregister_netdev(dev);
|
||
+ free_netdev(dev);
|
||
+ }
|
||
+ mutex_unlock(&vnet_list_mutex);
|
||
+}
|
||
+
|
||
static const char *local_mac_prop = "local-mac-address";
|
||
|
||
static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
|
||
@@ -1244,7 +1262,6 @@ static int vnet_port_remove(struct vio_dev *vdev)
|
||
|
||
kfree(port);
|
||
|
||
- unregister_netdev(vp->dev);
|
||
}
|
||
return 0;
|
||
}
|
||
@@ -1272,6 +1289,7 @@ static int __init vnet_init(void)
|
||
static void __exit vnet_exit(void)
|
||
{
|
||
vio_unregister_driver(&vnet_port_driver);
|
||
+ vnet_cleanup();
|
||
}
|
||
|
||
module_init(vnet_init);
|
||
diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c
|
||
index ad973ff..32f0bcd 100644
|
||
--- a/drivers/net/ethernet/tehuti/tehuti.c
|
||
+++ b/drivers/net/ethernet/tehuti/tehuti.c
|
||
@@ -1995,7 +1995,6 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||
ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO
|
||
| NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
|
||
NETIF_F_HW_VLAN_FILTER | NETIF_F_RXCSUM
|
||
- /*| NETIF_F_FRAGLIST */
|
||
;
|
||
ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
|
||
NETIF_F_TSO | NETIF_F_HW_VLAN_TX;
|
||
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
|
||
index 43fada5..c336d36 100644
|
||
--- a/drivers/net/ethernet/ti/davinci_emac.c
|
||
+++ b/drivers/net/ethernet/ti/davinci_emac.c
|
||
@@ -875,8 +875,7 @@ static void emac_dev_mcast_set(struct net_device *ndev)
|
||
netdev_mc_count(ndev) > EMAC_DEF_MAX_MULTICAST_ADDRESSES) {
|
||
mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST);
|
||
emac_add_mcast(priv, EMAC_ALL_MULTI_SET, NULL);
|
||
- }
|
||
- if (!netdev_mc_empty(ndev)) {
|
||
+ } else if (!netdev_mc_empty(ndev)) {
|
||
struct netdev_hw_addr *ha;
|
||
|
||
mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST);
|
||
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
|
||
index 5fa0880..60f4a51 100644
|
||
--- a/drivers/net/ethernet/via/via-rhine.c
|
||
+++ b/drivers/net/ethernet/via/via-rhine.c
|
||
@@ -1601,6 +1601,7 @@ static void rhine_reset_task(struct work_struct *work)
|
||
goto out_unlock;
|
||
|
||
napi_disable(&rp->napi);
|
||
+ netif_tx_disable(dev);
|
||
spin_lock_bh(&rp->lock);
|
||
|
||
/* clear all descriptors */
|
||
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
|
||
index 5e5b791..d240c06 100644
|
||
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
|
||
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
|
||
@@ -1026,7 +1026,7 @@ static int __devinit temac_of_probe(struct platform_device *op)
|
||
dev_set_drvdata(&op->dev, ndev);
|
||
SET_NETDEV_DEV(ndev, &op->dev);
|
||
ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
|
||
- ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
|
||
+ ndev->features = NETIF_F_SG;
|
||
ndev->netdev_ops = &temac_netdev_ops;
|
||
ndev->ethtool_ops = &temac_ethtool_ops;
|
||
#if 0
|
||
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
|
||
index 9c365e1..fde716d 100644
|
||
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
|
||
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
|
||
@@ -1494,7 +1494,7 @@ static int __devinit axienet_of_probe(struct platform_device *op)
|
||
|
||
SET_NETDEV_DEV(ndev, &op->dev);
|
||
ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
|
||
- ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
|
||
+ ndev->features = NETIF_F_SG;
|
||
ndev->netdev_ops = &axienet_netdev_ops;
|
||
ndev->ethtool_ops = &axienet_ethtool_ops;
|
||
|
||
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
|
||
index a4a3516..3b3a7e0 100644
|
||
--- a/drivers/net/hamradio/hdlcdrv.c
|
||
+++ b/drivers/net/hamradio/hdlcdrv.c
|
||
@@ -571,6 +571,8 @@ static int hdlcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||
case HDLCDRVCTL_CALIBRATE:
|
||
if(!capable(CAP_SYS_RAWIO))
|
||
return -EPERM;
|
||
+ if (bi.data.calibrate > INT_MAX / s->par.bitrate)
|
||
+ return -EINVAL;
|
||
s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16;
|
||
return 0;
|
||
|
||
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
|
||
index 5a6412e..d8faeb6 100644
|
||
--- a/drivers/net/hamradio/yam.c
|
||
+++ b/drivers/net/hamradio/yam.c
|
||
@@ -1058,6 +1058,7 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||
break;
|
||
|
||
case SIOCYAMGCFG:
|
||
+ memset(&yi, 0, sizeof(yi));
|
||
yi.cfg.mask = 0xffffffff;
|
||
yi.cfg.iobase = yp->iobase;
|
||
yi.cfg.irq = yp->irq;
|
||
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
|
||
index 2d59138..a6ed382 100644
|
||
--- a/drivers/net/hyperv/netvsc_drv.c
|
||
+++ b/drivers/net/hyperv/netvsc_drv.c
|
||
@@ -321,7 +321,6 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
|
||
return -EINVAL;
|
||
|
||
nvdev->start_remove = true;
|
||
- cancel_delayed_work_sync(&ndevctx->dwork);
|
||
cancel_work_sync(&ndevctx->work);
|
||
netif_tx_disable(ndev);
|
||
rndis_filter_device_remove(hdev);
|
||
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
|
||
index 7160523..6749acf 100644
|
||
--- a/drivers/net/macvlan.c
|
||
+++ b/drivers/net/macvlan.c
|
||
@@ -237,11 +237,9 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
|
||
const struct macvlan_dev *vlan = netdev_priv(dev);
|
||
const struct macvlan_port *port = vlan->port;
|
||
const struct macvlan_dev *dest;
|
||
- __u8 ip_summed = skb->ip_summed;
|
||
|
||
if (vlan->mode == MACVLAN_MODE_BRIDGE) {
|
||
const struct ethhdr *eth = (void *)skb->data;
|
||
- skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||
|
||
/* send to other bridge ports directly */
|
||
if (is_multicast_ether_addr(eth->h_dest)) {
|
||
@@ -259,7 +257,6 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
|
||
}
|
||
|
||
xmit_world:
|
||
- skb->ip_summed = ip_summed;
|
||
skb->dev = vlan->lowerdev;
|
||
return dev_queue_xmit(skb);
|
||
}
|
||
@@ -458,6 +455,7 @@ static int macvlan_init(struct net_device *dev)
|
||
(lowerdev->state & MACVLAN_STATE_MASK);
|
||
dev->features = lowerdev->features & MACVLAN_FEATURES;
|
||
dev->features |= NETIF_F_LLTX;
|
||
+ dev->vlan_features = lowerdev->vlan_features & MACVLAN_FEATURES;
|
||
dev->gso_max_size = lowerdev->gso_max_size;
|
||
dev->iflink = lowerdev->ifindex;
|
||
dev->hard_header_len = lowerdev->hard_header_len;
|
||
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
|
||
index 77ce8b2..f5b9de4 100644
|
||
--- a/drivers/net/macvtap.c
|
||
+++ b/drivers/net/macvtap.c
|
||
@@ -797,11 +797,10 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
|
||
const struct sk_buff *skb,
|
||
const struct iovec *iv, int len)
|
||
{
|
||
- struct macvlan_dev *vlan;
|
||
int ret;
|
||
int vnet_hdr_len = 0;
|
||
int vlan_offset = 0;
|
||
- int copied;
|
||
+ int copied, total;
|
||
|
||
if (q->flags & IFF_VNET_HDR) {
|
||
struct virtio_net_hdr vnet_hdr;
|
||
@@ -816,7 +815,8 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
|
||
if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr)))
|
||
return -EFAULT;
|
||
}
|
||
- copied = vnet_hdr_len;
|
||
+ total = copied = vnet_hdr_len;
|
||
+ total += skb->len;
|
||
|
||
if (!vlan_tx_tag_present(skb))
|
||
len = min_t(int, skb->len, len);
|
||
@@ -831,6 +831,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
|
||
|
||
vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
|
||
len = min_t(int, skb->len + VLAN_HLEN, len);
|
||
+ total += VLAN_HLEN;
|
||
|
||
copy = min_t(int, vlan_offset, len);
|
||
ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy);
|
||
@@ -848,16 +849,9 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
|
||
}
|
||
|
||
ret = skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len);
|
||
- copied += len;
|
||
|
||
done:
|
||
- rcu_read_lock_bh();
|
||
- vlan = rcu_dereference_bh(q->vlan);
|
||
- if (vlan)
|
||
- macvlan_count_rx(vlan, copied - vnet_hdr_len, ret == 0, 0);
|
||
- rcu_read_unlock_bh();
|
||
-
|
||
- return ret ? ret : copied;
|
||
+ return ret ? ret : total;
|
||
}
|
||
|
||
static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
|
||
@@ -911,7 +905,9 @@ static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv,
|
||
}
|
||
|
||
ret = macvtap_do_read(q, iocb, iv, len, file->f_flags & O_NONBLOCK);
|
||
- ret = min_t(ssize_t, ret, len); /* XXX copied from tun.c. Why? */
|
||
+ ret = min_t(ssize_t, ret, len);
|
||
+ if (ret > 0)
|
||
+ iocb->ki_pos = ret;
|
||
out:
|
||
return ret;
|
||
}
|
||
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
|
||
index 2e0d876..fbe75a7 100644
|
||
--- a/drivers/net/ppp/pppoe.c
|
||
+++ b/drivers/net/ppp/pppoe.c
|
||
@@ -681,7 +681,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
|
||
po->chan.hdrlen = (sizeof(struct pppoe_hdr) +
|
||
dev->hard_header_len);
|
||
|
||
- po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr);
|
||
+ po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
|
||
po->chan.private = sk;
|
||
po->chan.ops = &pppoe_chan_ops;
|
||
|
||
@@ -985,8 +985,6 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (error < 0)
|
||
goto end;
|
||
|
||
- m->msg_namelen = 0;
|
||
-
|
||
if (skb) {
|
||
total_len = min_t(size_t, total_len, skb->len);
|
||
error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
|
||
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
|
||
index 8f81805..d16800f 100644
|
||
--- a/drivers/net/team/team.c
|
||
+++ b/drivers/net/team/team.c
|
||
@@ -889,6 +889,7 @@ static int team_change_mtu(struct net_device *dev, int new_mtu)
|
||
* to traverse list in reverse under rcu_read_lock
|
||
*/
|
||
mutex_lock(&team->lock);
|
||
+ team->port_mtu_change_allowed = true;
|
||
list_for_each_entry(port, &team->port_list, list) {
|
||
err = dev_set_mtu(port->dev, new_mtu);
|
||
if (err) {
|
||
@@ -897,6 +898,7 @@ static int team_change_mtu(struct net_device *dev, int new_mtu)
|
||
goto unwind;
|
||
}
|
||
}
|
||
+ team->port_mtu_change_allowed = false;
|
||
mutex_unlock(&team->lock);
|
||
|
||
dev->mtu = new_mtu;
|
||
@@ -906,6 +908,7 @@ static int team_change_mtu(struct net_device *dev, int new_mtu)
|
||
unwind:
|
||
list_for_each_entry_continue_reverse(port, &team->port_list, list)
|
||
dev_set_mtu(port->dev, dev->mtu);
|
||
+ team->port_mtu_change_allowed = false;
|
||
mutex_unlock(&team->lock);
|
||
|
||
return err;
|
||
@@ -1671,7 +1674,9 @@ static int team_device_event(struct notifier_block *unused,
|
||
break;
|
||
case NETDEV_CHANGEMTU:
|
||
/* Forbid to change mtu of underlaying device */
|
||
- return NOTIFY_BAD;
|
||
+ if (!port->team->port_mtu_change_allowed)
|
||
+ return NOTIFY_BAD;
|
||
+ break;
|
||
case NETDEV_PRE_TYPE_CHANGE:
|
||
/* Forbid to change type of underlaying device */
|
||
return NOTIFY_BAD;
|
||
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
|
||
index b463b84..19e451b 100644
|
||
--- a/drivers/net/tun.c
|
||
+++ b/drivers/net/tun.c
|
||
@@ -903,6 +903,8 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
|
||
|
||
ret = tun_do_read(tun, iocb, iv, len, file->f_flags & O_NONBLOCK);
|
||
ret = min_t(ssize_t, ret, len);
|
||
+ if (ret > 0)
|
||
+ iocb->ki_pos = ret;
|
||
out:
|
||
tun_put(tun);
|
||
return ret;
|
||
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
|
||
index ef84a58..e3e0ca1 100644
|
||
--- a/drivers/net/usb/asix.c
|
||
+++ b/drivers/net/usb/asix.c
|
||
@@ -183,6 +183,17 @@ struct ax88172_int_data {
|
||
__le16 res3;
|
||
} __packed;
|
||
|
||
+struct asix_rx_fixup_info {
|
||
+ struct sk_buff *ax_skb;
|
||
+ u32 header;
|
||
+ u16 size;
|
||
+ bool split_head;
|
||
+};
|
||
+
|
||
+struct asix_common_private {
|
||
+ struct asix_rx_fixup_info rx_fixup_info;
|
||
+};
|
||
+
|
||
static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
|
||
u16 size, void *data)
|
||
{
|
||
@@ -304,49 +315,89 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
|
||
}
|
||
}
|
||
|
||
-static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||
+static int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
|
||
+ struct asix_rx_fixup_info *rx)
|
||
{
|
||
int offset = 0;
|
||
|
||
- while (offset + sizeof(u32) < skb->len) {
|
||
- struct sk_buff *ax_skb;
|
||
- u16 size;
|
||
- u32 header = get_unaligned_le32(skb->data + offset);
|
||
-
|
||
- offset += sizeof(u32);
|
||
-
|
||
- /* get the packet length */
|
||
- size = (u16) (header & 0x7ff);
|
||
- if (size != ((~header >> 16) & 0x07ff)) {
|
||
- netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
|
||
- return 0;
|
||
+ while (offset + sizeof(u16) <= skb->len) {
|
||
+ u16 remaining = 0;
|
||
+ unsigned char *data;
|
||
+
|
||
+ if (!rx->size) {
|
||
+ if ((skb->len - offset == sizeof(u16)) ||
|
||
+ rx->split_head) {
|
||
+ if (!rx->split_head) {
|
||
+ rx->header = get_unaligned_le16(
|
||
+ skb->data + offset);
|
||
+ rx->split_head = true;
|
||
+ offset += sizeof(u16);
|
||
+ break;
|
||
+ } else {
|
||
+ rx->header |= (get_unaligned_le16(
|
||
+ skb->data + offset)
|
||
+ << 16);
|
||
+ rx->split_head = false;
|
||
+ offset += sizeof(u16);
|
||
+ }
|
||
+ } else {
|
||
+ rx->header = get_unaligned_le32(skb->data +
|
||
+ offset);
|
||
+ offset += sizeof(u32);
|
||
+ }
|
||
+
|
||
+ /* get the packet length */
|
||
+ rx->size = (u16) (rx->header & 0x7ff);
|
||
+ if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
|
||
+ netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
|
||
+ rx->header, offset);
|
||
+ rx->size = 0;
|
||
+ return 0;
|
||
+ }
|
||
+ rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
|
||
+ rx->size);
|
||
+ if (!rx->ax_skb)
|
||
+ return 0;
|
||
}
|
||
|
||
- if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
|
||
- (size + offset > skb->len)) {
|
||
+ if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
|
||
netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
|
||
- size);
|
||
+ rx->size);
|
||
+ kfree_skb(rx->ax_skb);
|
||
return 0;
|
||
}
|
||
- ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
|
||
- if (!ax_skb)
|
||
- return 0;
|
||
|
||
- skb_put(ax_skb, size);
|
||
- memcpy(ax_skb->data, skb->data + offset, size);
|
||
- usbnet_skb_return(dev, ax_skb);
|
||
+ if (rx->size > skb->len - offset) {
|
||
+ remaining = rx->size - (skb->len - offset);
|
||
+ rx->size = skb->len - offset;
|
||
+ }
|
||
+
|
||
+ data = skb_put(rx->ax_skb, rx->size);
|
||
+ memcpy(data, skb->data + offset, rx->size);
|
||
+ if (!remaining)
|
||
+ usbnet_skb_return(dev, rx->ax_skb);
|
||
|
||
- offset += (size + 1) & 0xfffe;
|
||
+ offset += (rx->size + 1) & 0xfffe;
|
||
+ rx->size = remaining;
|
||
}
|
||
|
||
if (skb->len != offset) {
|
||
- netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
|
||
- skb->len);
|
||
+ netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
|
||
+ skb->len, offset);
|
||
return 0;
|
||
}
|
||
+
|
||
return 1;
|
||
}
|
||
|
||
+static int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
|
||
+{
|
||
+ struct asix_common_private *dp = dev->driver_priv;
|
||
+ struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
|
||
+
|
||
+ return asix_rx_fixup_internal(dev, skb, rx);
|
||
+}
|
||
+
|
||
static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
||
gfp_t flags)
|
||
{
|
||
@@ -1110,9 +1161,19 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
|
||
dev->rx_urb_size = 2048;
|
||
}
|
||
|
||
+ dev->driver_priv = kzalloc(sizeof(struct asix_common_private),
|
||
+ GFP_KERNEL);
|
||
+ if (!dev->driver_priv)
|
||
+ return -ENOMEM;
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
+static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
|
||
+{
|
||
+ kfree(dev->driver_priv);
|
||
+}
|
||
+
|
||
static const struct ethtool_ops ax88178_ethtool_ops = {
|
||
.get_drvinfo = asix_get_drvinfo,
|
||
.get_link = asix_get_link,
|
||
@@ -1445,6 +1506,11 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
|
||
dev->rx_urb_size = 2048;
|
||
}
|
||
|
||
+ dev->driver_priv = kzalloc(sizeof(struct asix_common_private),
|
||
+ GFP_KERNEL);
|
||
+ if (!dev->driver_priv)
|
||
+ return -ENOMEM;
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
@@ -1491,22 +1557,26 @@ static const struct driver_info hawking_uf200_info = {
|
||
static const struct driver_info ax88772_info = {
|
||
.description = "ASIX AX88772 USB 2.0 Ethernet",
|
||
.bind = ax88772_bind,
|
||
+ .unbind = ax88772_unbind,
|
||
.status = asix_status,
|
||
.link_reset = ax88772_link_reset,
|
||
.reset = ax88772_reset,
|
||
- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
|
||
- .rx_fixup = asix_rx_fixup,
|
||
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
|
||
+ FLAG_MULTI_PACKET,
|
||
+ .rx_fixup = asix_rx_fixup_common,
|
||
.tx_fixup = asix_tx_fixup,
|
||
};
|
||
|
||
static const struct driver_info ax88178_info = {
|
||
.description = "ASIX AX88178 USB 2.0 Ethernet",
|
||
.bind = ax88178_bind,
|
||
+ .unbind = ax88772_unbind,
|
||
.status = asix_status,
|
||
.link_reset = ax88178_link_reset,
|
||
.reset = ax88178_reset,
|
||
- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
|
||
- .rx_fixup = asix_rx_fixup,
|
||
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
|
||
+ FLAG_MULTI_PACKET,
|
||
+ .rx_fixup = asix_rx_fixup_common,
|
||
.tx_fixup = asix_tx_fixup,
|
||
};
|
||
|
||
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
|
||
index 905b16f..1785183 100644
|
||
--- a/drivers/net/usb/dm9601.c
|
||
+++ b/drivers/net/usb/dm9601.c
|
||
@@ -445,7 +445,12 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
|
||
dev->net->ethtool_ops = &dm9601_ethtool_ops;
|
||
dev->net->hard_header_len += DM_TX_OVERHEAD;
|
||
dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
|
||
- dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD;
|
||
+
|
||
+ /* dm9620/21a require room for 4 byte padding, even in dm9601
|
||
+ * mode, so we need +1 to be able to receive full size
|
||
+ * ethernet frames.
|
||
+ */
|
||
+ dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD + 1;
|
||
|
||
dev->mii.dev = dev->net;
|
||
dev->mii.mdio_read = dm9601_mdio_read;
|
||
@@ -531,7 +536,7 @@ static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||
static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
||
gfp_t flags)
|
||
{
|
||
- int len;
|
||
+ int len, pad;
|
||
|
||
/* format:
|
||
b1: packet length low
|
||
@@ -539,12 +544,23 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
||
b3..n: packet data
|
||
*/
|
||
|
||
- len = skb->len;
|
||
+ len = skb->len + DM_TX_OVERHEAD;
|
||
|
||
- if (skb_headroom(skb) < DM_TX_OVERHEAD) {
|
||
+ /* workaround for dm962x errata with tx fifo getting out of
|
||
+ * sync if a USB bulk transfer retry happens right after a
|
||
+ * packet with odd / maxpacket length by adding up to 3 bytes
|
||
+ * padding.
|
||
+ */
|
||
+ while ((len & 1) || !(len % dev->maxpacket))
|
||
+ len++;
|
||
+
|
||
+ len -= DM_TX_OVERHEAD; /* hw header doesn't count as part of length */
|
||
+ pad = len - skb->len;
|
||
+
|
||
+ if (skb_headroom(skb) < DM_TX_OVERHEAD || skb_tailroom(skb) < pad) {
|
||
struct sk_buff *skb2;
|
||
|
||
- skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags);
|
||
+ skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, pad, flags);
|
||
dev_kfree_skb_any(skb);
|
||
skb = skb2;
|
||
if (!skb)
|
||
@@ -553,10 +569,10 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
||
|
||
__skb_push(skb, DM_TX_OVERHEAD);
|
||
|
||
- /* usbnet adds padding if length is a multiple of packet size
|
||
- if so, adjust length value in header */
|
||
- if ((skb->len % dev->maxpacket) == 0)
|
||
- len++;
|
||
+ if (pad) {
|
||
+ memset(skb->data + skb->len, 0, pad);
|
||
+ __skb_put(skb, pad);
|
||
+ }
|
||
|
||
skb->data[0] = len;
|
||
skb->data[1] = len >> 8;
|
||
diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c
|
||
index 38266bd..71e0b99 100644
|
||
--- a/drivers/net/usb/gl620a.c
|
||
+++ b/drivers/net/usb/gl620a.c
|
||
@@ -86,6 +86,10 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||
u32 size;
|
||
u32 count;
|
||
|
||
+ /* This check is no longer done by usbnet */
|
||
+ if (skb->len < dev->net->hard_header_len)
|
||
+ return 0;
|
||
+
|
||
header = (struct gl_header *) skb->data;
|
||
|
||
// get the packet count of the received skb
|
||
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
|
||
index c434b6b..21a9377 100644
|
||
--- a/drivers/net/usb/mcs7830.c
|
||
+++ b/drivers/net/usb/mcs7830.c
|
||
@@ -601,8 +601,9 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||
{
|
||
u8 status;
|
||
|
||
- if (skb->len == 0) {
|
||
- dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
|
||
+ /* This check is no longer done by usbnet */
|
||
+ if (skb->len < dev->net->hard_header_len) {
|
||
+ dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
|
||
index 83f965c..006a142 100644
|
||
--- a/drivers/net/usb/net1080.c
|
||
+++ b/drivers/net/usb/net1080.c
|
||
@@ -419,6 +419,10 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||
struct nc_trailer *trailer;
|
||
u16 hdr_len, packet_len;
|
||
|
||
+ /* This check is no longer done by usbnet */
|
||
+ if (skb->len < dev->net->hard_header_len)
|
||
+ return 0;
|
||
+
|
||
if (!(skb->len & 0x01)) {
|
||
#ifdef DEBUG
|
||
struct net_device *net = dev->net;
|
||
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
|
||
index 3b6e932..387ecec 100644
|
||
--- a/drivers/net/usb/qmi_wwan.c
|
||
+++ b/drivers/net/usb/qmi_wwan.c
|
||
@@ -202,10 +202,10 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||
{
|
||
__be16 proto;
|
||
|
||
- /* usbnet rx_complete guarantees that skb->len is at least
|
||
- * hard_header_len, so we can inspect the dest address without
|
||
- * checking skb->len
|
||
- */
|
||
+ /* This check is no longer done by usbnet */
|
||
+ if (skb->len < dev->net->hard_header_len)
|
||
+ return 0;
|
||
+
|
||
switch (skb->data[0] & 0xf0) {
|
||
case 0x40:
|
||
proto = htons(ETH_P_IP);
|
||
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
|
||
index c8f1b5b..bf4c0979c 100644
|
||
--- a/drivers/net/usb/rndis_host.c
|
||
+++ b/drivers/net/usb/rndis_host.c
|
||
@@ -490,6 +490,10 @@ EXPORT_SYMBOL_GPL(rndis_unbind);
|
||
*/
|
||
int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||
{
|
||
+ /* This check is no longer done by usbnet */
|
||
+ if (skb->len < dev->net->hard_header_len)
|
||
+ return 0;
|
||
+
|
||
/* peripheral may have batched packets to us... */
|
||
while (likely(skb->len)) {
|
||
struct rndis_data_hdr *hdr = (void *)skb->data;
|
||
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
|
||
index d89747a..5a82fcd 100644
|
||
--- a/drivers/net/usb/smsc75xx.c
|
||
+++ b/drivers/net/usb/smsc75xx.c
|
||
@@ -1093,6 +1093,10 @@ static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb,
|
||
|
||
static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||
{
|
||
+ /* This check is no longer done by usbnet */
|
||
+ if (skb->len < dev->net->hard_header_len)
|
||
+ return 0;
|
||
+
|
||
while (skb->len > 0) {
|
||
u32 rx_cmd_a, rx_cmd_b, align_count, size;
|
||
struct sk_buff *ax_skb;
|
||
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
|
||
index 94ae669..13f5071 100644
|
||
--- a/drivers/net/usb/smsc95xx.c
|
||
+++ b/drivers/net/usb/smsc95xx.c
|
||
@@ -1041,6 +1041,10 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
|
||
|
||
static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||
{
|
||
+ /* This check is no longer done by usbnet */
|
||
+ if (skb->len < dev->net->hard_header_len)
|
||
+ return 0;
|
||
+
|
||
while (skb->len > 0) {
|
||
u32 header, align_count;
|
||
struct sk_buff *ax_skb;
|
||
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
|
||
index b42050c..4965b37 100644
|
||
--- a/drivers/net/usb/usbnet.c
|
||
+++ b/drivers/net/usb/usbnet.c
|
||
@@ -428,17 +428,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
|
||
}
|
||
// else network stack removes extra byte if we forced a short packet
|
||
|
||
- if (skb->len) {
|
||
- /* all data was already cloned from skb inside the driver */
|
||
- if (dev->driver_info->flags & FLAG_MULTI_PACKET)
|
||
- dev_kfree_skb_any(skb);
|
||
- else
|
||
- usbnet_skb_return(dev, skb);
|
||
+ /* all data was already cloned from skb inside the driver */
|
||
+ if (dev->driver_info->flags & FLAG_MULTI_PACKET)
|
||
+ goto done;
|
||
+
|
||
+ if (skb->len < ETH_HLEN) {
|
||
+ dev->net->stats.rx_errors++;
|
||
+ dev->net->stats.rx_length_errors++;
|
||
+ netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len);
|
||
+ } else {
|
||
+ usbnet_skb_return(dev, skb);
|
||
return;
|
||
}
|
||
|
||
- netif_dbg(dev, rx_err, dev->net, "drop\n");
|
||
- dev->net->stats.rx_errors++;
|
||
done:
|
||
skb_queue_tail(&dev->done, skb);
|
||
}
|
||
@@ -460,13 +462,6 @@ void rx_complete(struct urb *urb)
|
||
switch (urb_status) {
|
||
/* success */
|
||
case 0:
|
||
- if (skb->len < dev->net->hard_header_len) {
|
||
- state = rx_cleanup;
|
||
- dev->net->stats.rx_errors++;
|
||
- dev->net->stats.rx_length_errors++;
|
||
- netif_dbg(dev, rx_err, dev->net,
|
||
- "rx length %d\n", skb->len);
|
||
- }
|
||
break;
|
||
|
||
/* stalls need manual reset. this is rare ... except that
|
||
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
|
||
index 795b80e..6de7ca0 100644
|
||
--- a/drivers/net/virtio_net.c
|
||
+++ b/drivers/net/virtio_net.c
|
||
@@ -1084,7 +1084,8 @@ static int virtnet_probe(struct virtio_device *vdev)
|
||
/* If we can receive ANY GSO packets, we must allocate large ones. */
|
||
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
|
||
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
|
||
- virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
|
||
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
|
||
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
|
||
vi->big_packets = true;
|
||
|
||
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
|
||
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
|
||
index 3f04ba0..d43df93 100644
|
||
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
|
||
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
|
||
@@ -1729,11 +1729,20 @@ vmxnet3_netpoll(struct net_device *netdev)
|
||
{
|
||
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
|
||
|
||
- if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
|
||
- vmxnet3_disable_all_intrs(adapter);
|
||
-
|
||
- vmxnet3_do_poll(adapter, adapter->rx_queue[0].rx_ring[0].size);
|
||
- vmxnet3_enable_all_intrs(adapter);
|
||
+ switch (adapter->intr.type) {
|
||
+#ifdef CONFIG_PCI_MSI
|
||
+ case VMXNET3_IT_MSIX: {
|
||
+ int i;
|
||
+ for (i = 0; i < adapter->num_rx_queues; i++)
|
||
+ vmxnet3_msix_rx(0, &adapter->rx_queue[i]);
|
||
+ break;
|
||
+ }
|
||
+#endif
|
||
+ case VMXNET3_IT_MSI:
|
||
+ default:
|
||
+ vmxnet3_intr(0, adapter->netdev);
|
||
+ break;
|
||
+ }
|
||
|
||
}
|
||
#endif /* CONFIG_NET_POLL_CONTROLLER */
|
||
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
|
||
index 1a62318..3710427 100644
|
||
--- a/drivers/net/wan/farsync.c
|
||
+++ b/drivers/net/wan/farsync.c
|
||
@@ -1972,6 +1972,7 @@ fst_get_iface(struct fst_card_info *card, struct fst_port_info *port,
|
||
}
|
||
|
||
i = port->index;
|
||
+ memset(&sync, 0, sizeof(sync));
|
||
sync.clock_rate = FST_RDL(card, portConfig[i].lineSpeed);
|
||
/* Lucky card and linux use same encoding here */
|
||
sync.clock_type = FST_RDB(card, portConfig[i].internalClock) ==
|
||
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
|
||
index feb7541..ccd496b 100644
|
||
--- a/drivers/net/wan/wanxl.c
|
||
+++ b/drivers/net/wan/wanxl.c
|
||
@@ -355,6 +355,7 @@ static int wanxl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||
ifr->ifr_settings.size = size; /* data size wanted */
|
||
return -ENOBUFS;
|
||
}
|
||
+ memset(&line, 0, sizeof(line));
|
||
line.clock_type = get_status(port)->clocking;
|
||
line.clock_rate = 0;
|
||
line.loopback = 0;
|
||
diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c
|
||
index e325768..b78ee67 100644
|
||
--- a/drivers/net/wimax/i2400m/usb-rx.c
|
||
+++ b/drivers/net/wimax/i2400m/usb-rx.c
|
||
@@ -277,7 +277,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
|
||
d_printf(1, dev, "RX: size changed to %d, received %d, "
|
||
"copied %d, capacity %ld\n",
|
||
rx_size, read_size, rx_skb->len,
|
||
- (long) (skb_end_pointer(new_skb) - new_skb->head));
|
||
+ (long) skb_end_offset(new_skb));
|
||
goto retry;
|
||
}
|
||
/* In most cases, it happens due to the hardware scheduling a
|
||
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
|
||
index aa2abaf..fa7581a 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
|
||
@@ -76,9 +76,16 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
|
||
mask2 |= ATH9K_INT_CST;
|
||
if (isr2 & AR_ISR_S2_TSFOOR)
|
||
mask2 |= ATH9K_INT_TSFOOR;
|
||
+
|
||
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
|
||
+ REG_WRITE(ah, AR_ISR_S2, isr2);
|
||
+ isr &= ~AR_ISR_BCNMISC;
|
||
+ }
|
||
}
|
||
|
||
- isr = REG_READ(ah, AR_ISR_RAC);
|
||
+ if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)
|
||
+ isr = REG_READ(ah, AR_ISR_RAC);
|
||
+
|
||
if (isr == 0xffffffff) {
|
||
*masked = 0;
|
||
return false;
|
||
@@ -97,11 +104,23 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
|
||
|
||
*masked |= ATH9K_INT_TX;
|
||
|
||
- s0_s = REG_READ(ah, AR_ISR_S0_S);
|
||
+ if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) {
|
||
+ s0_s = REG_READ(ah, AR_ISR_S0_S);
|
||
+ s1_s = REG_READ(ah, AR_ISR_S1_S);
|
||
+ } else {
|
||
+ s0_s = REG_READ(ah, AR_ISR_S0);
|
||
+ REG_WRITE(ah, AR_ISR_S0, s0_s);
|
||
+ s1_s = REG_READ(ah, AR_ISR_S1);
|
||
+ REG_WRITE(ah, AR_ISR_S1, s1_s);
|
||
+
|
||
+ isr &= ~(AR_ISR_TXOK |
|
||
+ AR_ISR_TXDESC |
|
||
+ AR_ISR_TXERR |
|
||
+ AR_ISR_TXEOL);
|
||
+ }
|
||
+
|
||
ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
|
||
ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
|
||
-
|
||
- s1_s = REG_READ(ah, AR_ISR_S1_S);
|
||
ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
|
||
ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
|
||
}
|
||
@@ -114,13 +133,15 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
|
||
*masked |= mask2;
|
||
}
|
||
|
||
- if (AR_SREV_9100(ah))
|
||
- return true;
|
||
-
|
||
- if (isr & AR_ISR_GENTMR) {
|
||
+ if (!AR_SREV_9100(ah) && (isr & AR_ISR_GENTMR)) {
|
||
u32 s5_s;
|
||
|
||
- s5_s = REG_READ(ah, AR_ISR_S5_S);
|
||
+ if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) {
|
||
+ s5_s = REG_READ(ah, AR_ISR_S5_S);
|
||
+ } else {
|
||
+ s5_s = REG_READ(ah, AR_ISR_S5);
|
||
+ }
|
||
+
|
||
ah->intr_gen_timer_trigger =
|
||
MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
|
||
|
||
@@ -133,8 +154,21 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
|
||
if ((s5_s & AR_ISR_S5_TIM_TIMER) &&
|
||
!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
|
||
*masked |= ATH9K_INT_TIM_TIMER;
|
||
+
|
||
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
|
||
+ REG_WRITE(ah, AR_ISR_S5, s5_s);
|
||
+ isr &= ~AR_ISR_GENTMR;
|
||
+ }
|
||
}
|
||
|
||
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
|
||
+ REG_WRITE(ah, AR_ISR, isr);
|
||
+ REG_READ(ah, AR_ISR);
|
||
+ }
|
||
+
|
||
+ if (AR_SREV_9100(ah))
|
||
+ return true;
|
||
+
|
||
if (sync_cause) {
|
||
fatal_int =
|
||
(sync_cause &
|
||
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
|
||
index 6bb4db0..6f2fff3 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
|
||
@@ -3592,7 +3592,7 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
|
||
static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
|
||
{
|
||
int chain;
|
||
- u32 regval;
|
||
+ u32 regval, value;
|
||
u32 ant_div_ctl1;
|
||
static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = {
|
||
AR_PHY_SWITCH_CHAIN_0,
|
||
@@ -3600,7 +3600,11 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
|
||
AR_PHY_SWITCH_CHAIN_2,
|
||
};
|
||
|
||
- u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
|
||
+ if (AR_SREV_9485(ah) && (ar9003_hw_get_rx_gain_idx(ah) == 0))
|
||
+ ath9k_hw_cfg_output(ah, AR9300_EXT_LNA_CTL_GPIO_AR9485,
|
||
+ AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED);
|
||
+
|
||
+ value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
|
||
|
||
if (AR_SREV_9462(ah)) {
|
||
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
|
||
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
|
||
index 0f56e32..42ad784 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
|
||
@@ -33,9 +33,6 @@
|
||
*/
|
||
static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
|
||
{
|
||
-#define PCIE_PLL_ON_CREQ_DIS_L1_2P0 \
|
||
- ar9462_pciephy_pll_on_clkreq_disable_L1_2p0
|
||
-
|
||
#define AR9462_BB_CTX_COEFJ(x) \
|
||
ar9462_##x##_baseband_core_txfir_coeff_japan_2484
|
||
|
||
@@ -312,13 +309,13 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
|
||
|
||
/* Awake -> Sleep Setting */
|
||
INIT_INI_ARRAY(&ah->iniPcieSerdes,
|
||
- PCIE_PLL_ON_CREQ_DIS_L1_2P0,
|
||
- ARRAY_SIZE(PCIE_PLL_ON_CREQ_DIS_L1_2P0),
|
||
+ ar9462_pciephy_clkreq_disable_L1_2p0,
|
||
+ ARRAY_SIZE(ar9462_pciephy_clkreq_disable_L1_2p0),
|
||
2);
|
||
/* Sleep -> Awake Setting */
|
||
INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
|
||
- PCIE_PLL_ON_CREQ_DIS_L1_2P0,
|
||
- ARRAY_SIZE(PCIE_PLL_ON_CREQ_DIS_L1_2P0),
|
||
+ ar9462_pciephy_clkreq_disable_L1_2p0,
|
||
+ ARRAY_SIZE(ar9462_pciephy_clkreq_disable_L1_2p0),
|
||
2);
|
||
|
||
/* Fast clock modal settings */
|
||
@@ -637,8 +634,8 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
|
||
2);
|
||
else if (AR_SREV_9485_11(ah))
|
||
INIT_INI_ARRAY(&ah->iniModesRxGain,
|
||
- ar9485Common_wo_xlna_rx_gain_1_1,
|
||
- ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
|
||
+ ar9485_common_rx_gain_1_1,
|
||
+ ARRAY_SIZE(ar9485_common_rx_gain_1_1),
|
||
2);
|
||
else if (AR_SREV_9580(ah))
|
||
INIT_INI_ARRAY(&ah->iniModesRxGain,
|
||
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||
index 503ff9f..8783500 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||
@@ -545,33 +545,20 @@ static void ar9003_hw_init_bb(struct ath_hw *ah,
|
||
|
||
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
|
||
{
|
||
- switch (rx) {
|
||
- case 0x5:
|
||
+ if (ah->caps.tx_chainmask == 5 || ah->caps.rx_chainmask == 5)
|
||
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
|
||
AR_PHY_SWAP_ALT_CHAIN);
|
||
- case 0x3:
|
||
- case 0x1:
|
||
- case 0x2:
|
||
- case 0x7:
|
||
- REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
|
||
- REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
|
||
- break;
|
||
- default:
|
||
- break;
|
||
- }
|
||
+
|
||
+ REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
|
||
+ REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
|
||
|
||
if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
|
||
- REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
|
||
+ tx = 3;
|
||
else if (AR_SREV_9462(ah))
|
||
/* xxx only when MCI support is enabled */
|
||
- REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
|
||
- else
|
||
- REG_WRITE(ah, AR_SELFGEN_MASK, tx);
|
||
+ tx = 3;
|
||
|
||
- if (tx == 0x5) {
|
||
- REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
|
||
- AR_PHY_SWAP_ALT_CHAIN);
|
||
- }
|
||
+ REG_WRITE(ah, AR_SELFGEN_MASK, tx);
|
||
}
|
||
|
||
/*
|
||
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
|
||
index d834d97..6402b9e 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
|
||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
|
||
@@ -339,6 +339,8 @@
|
||
|
||
#define AR_PHY_CCA_NOM_VAL_9330_2GHZ -118
|
||
|
||
+#define AR9300_EXT_LNA_CTL_GPIO_AR9485 9
|
||
+
|
||
/*
|
||
* AGC Field Definitions
|
||
*/
|
||
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
|
||
index b6ba1e8..1596002 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
|
||
+++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
|
||
@@ -55,7 +55,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
|
||
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x33795d5e},
|
||
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||
- {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||
+ {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},
|
||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
|
||
{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
|
||
@@ -94,7 +94,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
|
||
{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},
|
||
{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||
{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
|
||
- {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
|
||
+ {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa},
|
||
{0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
|
||
};
|
||
|
||
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
|
||
index 85e7453..a393e87 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/calib.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/calib.c
|
||
@@ -410,6 +410,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
|
||
|
||
ah->caldata->channel = chan->channel;
|
||
ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT;
|
||
+ ah->caldata->chanmode = chan->chanmode;
|
||
h = ah->caldata->nfCalHist;
|
||
default_nf = ath9k_hw_get_default_nf(ah, chan);
|
||
for (i = 0; i < NUM_NF_READINGS; i++) {
|
||
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
|
||
index 1357952..17f687b 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/htc.h
|
||
+++ b/drivers/net/wireless/ath/ath9k/htc.h
|
||
@@ -22,6 +22,7 @@
|
||
#include <linux/firmware.h>
|
||
#include <linux/skbuff.h>
|
||
#include <linux/netdevice.h>
|
||
+#include <linux/etherdevice.h>
|
||
#include <linux/leds.h>
|
||
#include <linux/slab.h>
|
||
#include <net/mac80211.h>
|
||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||
index abbd6ef..204619e 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||
@@ -139,21 +139,26 @@ static void ath9k_htc_bssid_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||
struct ath9k_vif_iter_data *iter_data = data;
|
||
int i;
|
||
|
||
- for (i = 0; i < ETH_ALEN; i++)
|
||
- iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
|
||
+ if (iter_data->hw_macaddr != NULL) {
|
||
+ for (i = 0; i < ETH_ALEN; i++)
|
||
+ iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
|
||
+ } else {
|
||
+ iter_data->hw_macaddr = mac;
|
||
+ }
|
||
}
|
||
|
||
-static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,
|
||
+static void ath9k_htc_set_mac_bssid_mask(struct ath9k_htc_priv *priv,
|
||
struct ieee80211_vif *vif)
|
||
{
|
||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||
struct ath9k_vif_iter_data iter_data;
|
||
|
||
/*
|
||
- * Use the hardware MAC address as reference, the hardware uses it
|
||
- * together with the BSSID mask when matching addresses.
|
||
+ * Pick the MAC address of the first interface as the new hardware
|
||
+ * MAC address. The hardware will use it together with the BSSID mask
|
||
+ * when matching addresses.
|
||
*/
|
||
- iter_data.hw_macaddr = common->macaddr;
|
||
+ iter_data.hw_macaddr = NULL;
|
||
memset(&iter_data.mask, 0xff, ETH_ALEN);
|
||
|
||
if (vif)
|
||
@@ -164,6 +169,10 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,
|
||
&iter_data);
|
||
|
||
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
|
||
+
|
||
+ if (iter_data.hw_macaddr)
|
||
+ memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN);
|
||
+
|
||
ath_hw_setbssidmask(common);
|
||
}
|
||
|
||
@@ -1091,7 +1100,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
|
||
goto out;
|
||
}
|
||
|
||
- ath9k_htc_set_bssid_mask(priv, vif);
|
||
+ ath9k_htc_set_mac_bssid_mask(priv, vif);
|
||
|
||
priv->vif_slot |= (1 << avp->index);
|
||
priv->nvifs++;
|
||
@@ -1154,7 +1163,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
|
||
|
||
ath9k_htc_set_opmode(priv);
|
||
|
||
- ath9k_htc_set_bssid_mask(priv, vif);
|
||
+ ath9k_htc_set_mac_bssid_mask(priv, vif);
|
||
|
||
/*
|
||
* Stop ANI only if there are no associated station interfaces.
|
||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
|
||
index b290a8e..6596a23 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
|
||
@@ -1077,15 +1077,19 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
|
||
|
||
last_rssi = priv->rx.last_rssi;
|
||
|
||
- if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
|
||
- rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi,
|
||
- ATH_RSSI_EP_MULTIPLIER);
|
||
+ if (ieee80211_is_beacon(hdr->frame_control) &&
|
||
+ !is_zero_ether_addr(common->curbssid) &&
|
||
+ compare_ether_addr(hdr->addr3, common->curbssid) == 0) {
|
||
+ s8 rssi = rxbuf->rxstatus.rs_rssi;
|
||
|
||
- if (rxbuf->rxstatus.rs_rssi < 0)
|
||
- rxbuf->rxstatus.rs_rssi = 0;
|
||
+ if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
|
||
+ rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
|
||
|
||
- if (ieee80211_is_beacon(fc))
|
||
- priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
|
||
+ if (rssi < 0)
|
||
+ rssi = 0;
|
||
+
|
||
+ priv->ah->stats.avgbrssi = rssi;
|
||
+ }
|
||
|
||
rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
|
||
rx_status->band = hw->conf.channel->band;
|
||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
|
||
index 20baf70..60ed50d 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||
@@ -1628,7 +1628,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||
if (caldata &&
|
||
(chan->channel != caldata->channel ||
|
||
(chan->channelFlags & ~CHANNEL_CW_INT) !=
|
||
- (caldata->channelFlags & ~CHANNEL_CW_INT))) {
|
||
+ (caldata->channelFlags & ~CHANNEL_CW_INT) ||
|
||
+ chan->chanmode != caldata->chanmode)) {
|
||
/* Operating channel changed, reset channel calibration data */
|
||
memset(caldata, 0, sizeof(*caldata));
|
||
ath9k_init_nfcal_hist_buffer(ah, chan);
|
||
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
|
||
index d5c5dca..f49be96 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||
@@ -361,6 +361,7 @@ struct ath9k_rtt_hist {
|
||
struct ath9k_hw_cal_data {
|
||
u16 channel;
|
||
u32 channelFlags;
|
||
+ u32 chanmode;
|
||
int32_t CalValid;
|
||
int8_t iCoff;
|
||
int8_t qCoff;
|
||
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
|
||
index f6a095f..ef26056 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||
@@ -1290,8 +1290,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
|
||
struct ath_common *common = ath9k_hw_common(ah);
|
||
|
||
/*
|
||
- * Use the hardware MAC address as reference, the hardware uses it
|
||
- * together with the BSSID mask when matching addresses.
|
||
+ * Pick the MAC address of the first interface as the new hardware
|
||
+ * MAC address. The hardware will use it together with the BSSID mask
|
||
+ * when matching addresses.
|
||
*/
|
||
memset(iter_data, 0, sizeof(*iter_data));
|
||
iter_data->hw_macaddr = common->macaddr;
|
||
@@ -1613,13 +1614,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||
ath_update_survey_stats(sc);
|
||
spin_unlock_irqrestore(&common->cc_lock, flags);
|
||
|
||
- /*
|
||
- * Preserve the current channel values, before updating
|
||
- * the same channel
|
||
- */
|
||
- if (ah->curchan && (old_pos == pos))
|
||
- ath9k_hw_getnf(ah, ah->curchan);
|
||
-
|
||
ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
|
||
curchan, conf->channel_type);
|
||
|
||
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
|
||
index 3d0aa47..1a5f275 100644
|
||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||
@@ -1242,14 +1242,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
|
||
for (tidno = 0, tid = &an->tid[tidno];
|
||
tidno < WME_NUM_TID; tidno++, tid++) {
|
||
|
||
- if (!tid->sched)
|
||
- continue;
|
||
-
|
||
ac = tid->ac;
|
||
txq = ac->txq;
|
||
|
||
ath_txq_lock(sc, txq);
|
||
|
||
+ if (!tid->sched) {
|
||
+ ath_txq_unlock(sc, txq);
|
||
+ continue;
|
||
+ }
|
||
+
|
||
buffered = !skb_queue_empty(&tid->buf_q);
|
||
|
||
tid->sched = false;
|
||
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
|
||
index 3876c7e..af40211 100644
|
||
--- a/drivers/net/wireless/b43/Kconfig
|
||
+++ b/drivers/net/wireless/b43/Kconfig
|
||
@@ -28,7 +28,7 @@ config B43
|
||
|
||
config B43_BCMA
|
||
bool "Support for BCMA bus"
|
||
- depends on B43 && BCMA
|
||
+ depends on B43 && (BCMA = y || BCMA = B43)
|
||
default y
|
||
|
||
config B43_BCMA_EXTRA
|
||
@@ -39,7 +39,7 @@ config B43_BCMA_EXTRA
|
||
|
||
config B43_SSB
|
||
bool
|
||
- depends on B43 && SSB
|
||
+ depends on B43 && (SSB = y || SSB = B43)
|
||
default y
|
||
|
||
# Auto-select SSB PCI-HOST support, if possible
|
||
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
|
||
index 05cb5f6..46389a0 100644
|
||
--- a/drivers/net/wireless/b43/b43.h
|
||
+++ b/drivers/net/wireless/b43/b43.h
|
||
@@ -719,8 +719,6 @@ enum b43_firmware_file_type {
|
||
struct b43_request_fw_context {
|
||
/* The device we are requesting the fw for. */
|
||
struct b43_wldev *dev;
|
||
- /* a completion event structure needed if this call is asynchronous */
|
||
- struct completion fw_load_complete;
|
||
/* a pointer to the firmware object */
|
||
const struct firmware *blob;
|
||
/* The type of firmware to request. */
|
||
@@ -797,6 +795,8 @@ enum {
|
||
struct b43_wldev {
|
||
struct b43_bus_dev *dev;
|
||
struct b43_wl *wl;
|
||
+ /* a completion event structure needed if this call is asynchronous */
|
||
+ struct completion fw_load_complete;
|
||
|
||
/* The device initialization status.
|
||
* Use b43_status() to query. */
|
||
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
|
||
index f8c4499..b91f559 100644
|
||
--- a/drivers/net/wireless/b43/main.c
|
||
+++ b/drivers/net/wireless/b43/main.c
|
||
@@ -2061,6 +2061,7 @@ void b43_do_release_fw(struct b43_firmware_file *fw)
|
||
|
||
static void b43_release_firmware(struct b43_wldev *dev)
|
||
{
|
||
+ complete(&dev->fw_load_complete);
|
||
b43_do_release_fw(&dev->fw.ucode);
|
||
b43_do_release_fw(&dev->fw.pcm);
|
||
b43_do_release_fw(&dev->fw.initvals);
|
||
@@ -2086,7 +2087,7 @@ static void b43_fw_cb(const struct firmware *firmware, void *context)
|
||
struct b43_request_fw_context *ctx = context;
|
||
|
||
ctx->blob = firmware;
|
||
- complete(&ctx->fw_load_complete);
|
||
+ complete(&ctx->dev->fw_load_complete);
|
||
}
|
||
|
||
int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
||
@@ -2133,7 +2134,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
||
}
|
||
if (async) {
|
||
/* do this part asynchronously */
|
||
- init_completion(&ctx->fw_load_complete);
|
||
+ init_completion(&ctx->dev->fw_load_complete);
|
||
err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname,
|
||
ctx->dev->dev->dev, GFP_KERNEL,
|
||
ctx, b43_fw_cb);
|
||
@@ -2141,12 +2142,11 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
||
pr_err("Unable to load firmware\n");
|
||
return err;
|
||
}
|
||
- /* stall here until fw ready */
|
||
- wait_for_completion(&ctx->fw_load_complete);
|
||
+ wait_for_completion(&ctx->dev->fw_load_complete);
|
||
if (ctx->blob)
|
||
goto fw_ready;
|
||
/* On some ARM systems, the async request will fail, but the next sync
|
||
- * request works. For this reason, we dall through here
|
||
+ * request works. For this reason, we fall through here
|
||
*/
|
||
}
|
||
err = request_firmware(&ctx->blob, ctx->fwname,
|
||
@@ -2413,6 +2413,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
|
||
|
||
static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl);
|
||
static void b43_one_core_detach(struct b43_bus_dev *dev);
|
||
+static int b43_rng_init(struct b43_wl *wl);
|
||
|
||
static void b43_request_firmware(struct work_struct *work)
|
||
{
|
||
@@ -2459,6 +2460,10 @@ static void b43_request_firmware(struct work_struct *work)
|
||
if (err)
|
||
goto err_one_core_detach;
|
||
b43_leds_register(wl->current_dev);
|
||
+
|
||
+ /* Register HW RNG driver */
|
||
+ b43_rng_init(wl);
|
||
+
|
||
goto out;
|
||
|
||
err_one_core_detach:
|
||
@@ -4583,9 +4588,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
|
||
if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
|
||
return;
|
||
|
||
- /* Unregister HW RNG driver */
|
||
- b43_rng_exit(dev->wl);
|
||
-
|
||
b43_set_status(dev, B43_STAT_UNINIT);
|
||
|
||
/* Stop the microcode PSM. */
|
||
@@ -4728,9 +4730,6 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
|
||
|
||
b43_set_status(dev, B43_STAT_INITIALIZED);
|
||
|
||
- /* Register HW RNG driver */
|
||
- b43_rng_init(dev->wl);
|
||
-
|
||
out:
|
||
return err;
|
||
|
||
@@ -5388,6 +5387,9 @@ static void b43_bcma_remove(struct bcma_device *core)
|
||
|
||
b43_one_core_detach(wldev->dev);
|
||
|
||
+ /* Unregister HW RNG driver */
|
||
+ b43_rng_exit(wl);
|
||
+
|
||
b43_leds_unregister(wl);
|
||
|
||
ieee80211_free_hw(wl->hw);
|
||
@@ -5468,6 +5470,9 @@ static void b43_ssb_remove(struct ssb_device *sdev)
|
||
|
||
b43_one_core_detach(dev);
|
||
|
||
+ /* Unregister HW RNG driver */
|
||
+ b43_rng_exit(wl);
|
||
+
|
||
if (list_empty(&wl->devlist)) {
|
||
b43_leds_unregister(wl);
|
||
/* Last core on the chip unregistered.
|
||
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
|
||
index 4ce3e1f..547964d 100644
|
||
--- a/drivers/net/wireless/b43/phy_n.c
|
||
+++ b/drivers/net/wireless/b43/phy_n.c
|
||
@@ -4599,22 +4599,22 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev,
|
||
int ch = new_channel->hw_value;
|
||
|
||
u16 old_band_5ghz;
|
||
- u32 tmp32;
|
||
+ u16 tmp16;
|
||
|
||
old_band_5ghz =
|
||
b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ;
|
||
if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
|
||
- tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
|
||
- b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
|
||
+ tmp16 = b43_read16(dev, B43_MMIO_PSM_PHY_HDR);
|
||
+ b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16 | 4);
|
||
b43_phy_set(dev, B43_PHY_B_BBCFG, 0xC000);
|
||
- b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32);
|
||
+ b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16);
|
||
b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
|
||
} else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) {
|
||
b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
|
||
- tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
|
||
- b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
|
||
+ tmp16 = b43_read16(dev, B43_MMIO_PSM_PHY_HDR);
|
||
+ b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16 | 4);
|
||
b43_phy_mask(dev, B43_PHY_B_BBCFG, 0x3FFF);
|
||
- b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32);
|
||
+ b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16);
|
||
}
|
||
|
||
b43_chantab_phy_upload(dev, e);
|
||
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
|
||
index 2c53678..ad39611 100644
|
||
--- a/drivers/net/wireless/b43/xmit.c
|
||
+++ b/drivers/net/wireless/b43/xmit.c
|
||
@@ -808,9 +808,13 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
||
break;
|
||
case B43_PHYTYPE_G:
|
||
status.band = IEEE80211_BAND_2GHZ;
|
||
- /* chanid is the radio channel cookie value as used
|
||
- * to tune the radio. */
|
||
- status.freq = chanid + 2400;
|
||
+ /* Somewhere between 478.104 and 508.1084 firmware for G-PHY
|
||
+ * has been modified to be compatible with N-PHY and others.
|
||
+ */
|
||
+ if (dev->fw.rev >= 508)
|
||
+ status.freq = ieee80211_channel_to_frequency(chanid, status.band);
|
||
+ else
|
||
+ status.freq = chanid + 2400;
|
||
break;
|
||
case B43_PHYTYPE_N:
|
||
case B43_PHYTYPE_LP:
|
||
@@ -819,10 +823,10 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
||
* channel number in b43. */
|
||
if (chanstat & B43_RX_CHAN_5GHZ) {
|
||
status.band = IEEE80211_BAND_5GHZ;
|
||
- status.freq = b43_freq_to_channel_5ghz(chanid);
|
||
+ status.freq = b43_channel_to_freq_5ghz(chanid);
|
||
} else {
|
||
status.band = IEEE80211_BAND_2GHZ;
|
||
- status.freq = b43_freq_to_channel_2ghz(chanid);
|
||
+ status.freq = b43_channel_to_freq_2ghz(chanid);
|
||
}
|
||
break;
|
||
default:
|
||
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
|
||
index 53696ef..ce72424 100644
|
||
--- a/drivers/net/wireless/b43legacy/main.c
|
||
+++ b/drivers/net/wireless/b43legacy/main.c
|
||
@@ -3915,6 +3915,7 @@ static void b43legacy_remove(struct ssb_device *dev)
|
||
* as the ieee80211 unreg will destroy the workqueue. */
|
||
cancel_work_sync(&wldev->restart_work);
|
||
cancel_work_sync(&wl->firmware_load);
|
||
+ complete(&wldev->fw_load_complete);
|
||
|
||
B43legacy_WARN_ON(!wl);
|
||
if (!wldev->fw.ucode)
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
|
||
index 2067bdff..dd6dce2 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
|
||
@@ -459,6 +459,12 @@ const struct iwl_cfg iwl6035_2agn_cfg = {
|
||
.ht_params = &iwl6000_ht_params,
|
||
};
|
||
|
||
+const struct iwl_cfg iwl6035_2agn_sff_cfg = {
|
||
+ .name = "Intel(R) Centrino(R) Ultimate-N 6235 AGN",
|
||
+ IWL_DEVICE_6035,
|
||
+ .ht_params = &iwl6000_ht_params,
|
||
+};
|
||
+
|
||
const struct iwl_cfg iwl1030_bgn_cfg = {
|
||
.name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
|
||
IWL_DEVICE_6030,
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
|
||
index 2a9a16f..69d2de1 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
|
||
@@ -680,7 +680,7 @@ int iwl_alive_start(struct iwl_priv *priv)
|
||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||
if (ret)
|
||
return ret;
|
||
- } else {
|
||
+ } else if (priv->shrd->cfg->bt_params) {
|
||
/*
|
||
* default is 2-wire BT coexexistence support
|
||
*/
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-cfg.h b/drivers/net/wireless/iwlwifi/iwl-cfg.h
|
||
index 82152311..a133e9e 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-cfg.h
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-cfg.h
|
||
@@ -106,6 +106,7 @@ extern const struct iwl_cfg iwl2000_2bgn_cfg;
|
||
extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
|
||
extern const struct iwl_cfg iwl2030_2bgn_cfg;
|
||
extern const struct iwl_cfg iwl6035_2agn_cfg;
|
||
+extern const struct iwl_cfg iwl6035_2agn_sff_cfg;
|
||
extern const struct iwl_cfg iwl105_bgn_cfg;
|
||
extern const struct iwl_cfg iwl105_bgn_d_cfg;
|
||
extern const struct iwl_cfg iwl135_bgn_cfg;
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
|
||
index 46490d3..75ebb82 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
|
||
@@ -801,7 +801,10 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
|
||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||
return;
|
||
|
||
- if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
|
||
+ if (!test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
|
||
+ return;
|
||
+
|
||
+ if (ctx->vif)
|
||
ieee80211_chswitch_done(ctx->vif, is_success);
|
||
}
|
||
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
|
||
index 2bbaebd..d587bcd 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
|
||
@@ -227,6 +227,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
||
const struct fw_img *img;
|
||
size_t bufsz;
|
||
|
||
+ if (!iwl_is_ready_rf(priv))
|
||
+ return -EAGAIN;
|
||
+
|
||
/* default is to dump the entire data segment */
|
||
if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
|
||
priv->dbgfs_sram_offset = 0x800000;
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c
|
||
index c5e339e..1b90471 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-pci.c
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-pci.c
|
||
@@ -138,13 +138,16 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
|
||
|
||
/* 6x00 Series */
|
||
{IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x422B, 0x1108, iwl6000_3agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x422B, 0x1128, iwl6000_3agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x422C, 0x1306, iwl6000i_2abg_cfg)},
|
||
{IWL_PCI_DEVICE(0x422C, 0x1307, iwl6000i_2bg_cfg)},
|
||
{IWL_PCI_DEVICE(0x422C, 0x1321, iwl6000i_2agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x422C, 0x1326, iwl6000i_2abg_cfg)},
|
||
{IWL_PCI_DEVICE(0x4238, 0x1111, iwl6000_3agn_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x4238, 0x1118, iwl6000_3agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
|
||
|
||
@@ -152,12 +155,16 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
|
||
{IWL_PCI_DEVICE(0x0082, 0x1301, iwl6005_2agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x0082, 0x1306, iwl6005_2abg_cfg)},
|
||
{IWL_PCI_DEVICE(0x0082, 0x1307, iwl6005_2bg_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x0082, 0x1308, iwl6005_2agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x0082, 0x1321, iwl6005_2agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x0082, 0x1328, iwl6005_2agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x0085, 0x1318, iwl6005_2agn_cfg)},
|
||
{IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
|
||
{IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
|
||
{IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x0085, 0xC228, iwl6005_2agn_sff_cfg)},
|
||
{IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)},
|
||
{IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */
|
||
{IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */
|
||
@@ -239,8 +246,11 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
|
||
|
||
/* 6x35 Series */
|
||
{IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x088E, 0x406A, iwl6035_2agn_sff_cfg)},
|
||
{IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x088F, 0x426A, iwl6035_2agn_sff_cfg)},
|
||
{IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
|
||
+ {IWL_PCI_DEVICE(0x088E, 0x446A, iwl6035_2agn_sff_cfg)},
|
||
{IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)},
|
||
|
||
/* 105 Series */
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
|
||
index 3b844b7..9ae2b49 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
|
||
@@ -209,6 +209,15 @@ struct iwl_queue {
|
||
#define TFD_TX_CMD_SLOTS 256
|
||
#define TFD_CMD_SLOTS 32
|
||
|
||
+/*
|
||
+ * The FH will write back to the first TB only, so we need
|
||
+ * to copy some data into the buffer regardless of whether
|
||
+ * it should be mapped or not. This indicates how much to
|
||
+ * copy, even for HCMDs it must be big enough to fit the
|
||
+ * DRAM scratch from the TX cmd, at least 16 bytes.
|
||
+ */
|
||
+#define IWL_HCMD_MIN_COPY_SIZE 16
|
||
+
|
||
struct iwl_tx_queue {
|
||
struct iwl_queue q;
|
||
struct iwl_tfd *tfds;
|
||
@@ -352,7 +361,7 @@ int iwl_queue_space(const struct iwl_queue *q);
|
||
******************************************************/
|
||
int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log,
|
||
char **buf, bool display);
|
||
-int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display);
|
||
+int iwl_dump_fh(struct iwl_trans *trans, char **buf);
|
||
void iwl_dump_csr(struct iwl_trans *trans);
|
||
|
||
/*****************************************************
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
|
||
index aa7aea1..7bcaeaf 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
|
||
@@ -315,6 +315,14 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
|
||
rxb->page_dma = dma_map_page(trans->dev, page, 0,
|
||
PAGE_SIZE << hw_params(trans).rx_page_order,
|
||
DMA_FROM_DEVICE);
|
||
+ if (dma_mapping_error(trans->dev, rxb->page_dma)) {
|
||
+ rxb->page = NULL;
|
||
+ spin_lock_irqsave(&rxq->lock, flags);
|
||
+ list_add(&rxb->list, &rxq->rx_used);
|
||
+ spin_unlock_irqrestore(&rxq->lock, flags);
|
||
+ __free_pages(page, hw_params(trans).rx_page_order);
|
||
+ return;
|
||
+ }
|
||
/* dma address must be no more than 36 bits */
|
||
BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
|
||
/* and also 256 byte aligned! */
|
||
@@ -450,8 +458,19 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
|
||
dma_map_page(trans->dev, rxb->page, 0,
|
||
PAGE_SIZE << hw_params(trans).rx_page_order,
|
||
DMA_FROM_DEVICE);
|
||
- list_add_tail(&rxb->list, &rxq->rx_free);
|
||
- rxq->free_count++;
|
||
+ if (dma_mapping_error(trans->dev, rxb->page_dma)) {
|
||
+ /*
|
||
+ * free the page(s) as well to not break
|
||
+ * the invariant that the items on the used
|
||
+ * list have no page(s)
|
||
+ */
|
||
+ __free_pages(rxb->page, hw_params(trans).rx_page_order);
|
||
+ rxb->page = NULL;
|
||
+ list_add_tail(&rxb->list, &rxq->rx_used);
|
||
+ } else {
|
||
+ list_add_tail(&rxb->list, &rxq->rx_free);
|
||
+ rxq->free_count++;
|
||
+ }
|
||
} else
|
||
list_add_tail(&rxb->list, &rxq->rx_used);
|
||
spin_unlock_irqrestore(&rxq->lock, flags);
|
||
@@ -695,7 +714,7 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
|
||
|
||
iwl_dump_nic_error_log(trans);
|
||
iwl_dump_csr(trans);
|
||
- iwl_dump_fh(trans, NULL, false);
|
||
+ iwl_dump_fh(trans, NULL);
|
||
iwl_dump_nic_event_log(trans, false, NULL, false);
|
||
|
||
iwl_op_mode_nic_error(trans->op_mode);
|
||
@@ -1264,12 +1283,20 @@ static irqreturn_t iwl_isr(int irq, void *data)
|
||
* back-to-back ISRs and sporadic interrupts from our NIC.
|
||
* If we have something to service, the tasklet will re-enable ints.
|
||
* If we *don't* have something, we'll re-enable before leaving here. */
|
||
- inta_mask = iwl_read32(trans, CSR_INT_MASK); /* just for debug */
|
||
+ inta_mask = iwl_read32(trans, CSR_INT_MASK);
|
||
iwl_write32(trans, CSR_INT_MASK, 0x00000000);
|
||
|
||
/* Discover which interrupts are active/pending */
|
||
inta = iwl_read32(trans, CSR_INT);
|
||
|
||
+ if (inta & (~inta_mask)) {
|
||
+ IWL_DEBUG_ISR(trans,
|
||
+ "We got a masked interrupt (0x%08x)...Ack and ignore\n",
|
||
+ inta & (~inta_mask));
|
||
+ iwl_write32(trans, CSR_INT, inta & (~inta_mask));
|
||
+ inta &= inta_mask;
|
||
+ }
|
||
+
|
||
/* Ignore interrupt if there's nothing in NIC to service.
|
||
* This may be due to IRQ shared with another device,
|
||
* or due to sporadic interrupts thrown from our NIC. */
|
||
@@ -1353,7 +1380,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
|
||
* If we have something to service, the tasklet will re-enable ints.
|
||
* If we *don't* have something, we'll re-enable before leaving here.
|
||
*/
|
||
- inta_mask = iwl_read32(trans, CSR_INT_MASK); /* just for debug */
|
||
+ inta_mask = iwl_read32(trans, CSR_INT_MASK);
|
||
iwl_write32(trans, CSR_INT_MASK, 0x00000000);
|
||
|
||
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
|
||
index d7964b1..ba38ace 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
|
||
@@ -677,10 +677,12 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
|
||
struct iwl_cmd_meta *out_meta;
|
||
dma_addr_t phys_addr;
|
||
u32 idx;
|
||
- u16 copy_size, cmd_size;
|
||
+ u16 copy_size, cmd_size, dma_size;
|
||
bool had_nocopy = false;
|
||
int i;
|
||
u8 *cmd_dest;
|
||
+ const u8 *cmddata[IWL_MAX_CMD_TFDS];
|
||
+ u16 cmdlen[IWL_MAX_CMD_TFDS];
|
||
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
|
||
const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
|
||
int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
|
||
@@ -699,15 +701,30 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
|
||
BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
|
||
|
||
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
|
||
+ cmddata[i] = cmd->data[i];
|
||
+ cmdlen[i] = cmd->len[i];
|
||
+
|
||
if (!cmd->len[i])
|
||
continue;
|
||
+
|
||
+ /* need at least IWL_HCMD_MIN_COPY_SIZE copied */
|
||
+ if (copy_size < IWL_HCMD_MIN_COPY_SIZE) {
|
||
+ int copy = IWL_HCMD_MIN_COPY_SIZE - copy_size;
|
||
+
|
||
+ if (copy > cmdlen[i])
|
||
+ copy = cmdlen[i];
|
||
+ cmdlen[i] -= copy;
|
||
+ cmddata[i] += copy;
|
||
+ copy_size += copy;
|
||
+ }
|
||
+
|
||
if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
|
||
had_nocopy = true;
|
||
} else {
|
||
/* NOCOPY must not be followed by normal! */
|
||
if (WARN_ON(had_nocopy))
|
||
return -EINVAL;
|
||
- copy_size += cmd->len[i];
|
||
+ copy_size += cmdlen[i];
|
||
}
|
||
cmd_size += cmd->len[i];
|
||
}
|
||
@@ -750,13 +767,30 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
|
||
/* and copy the data that needs to be copied */
|
||
|
||
cmd_dest = out_cmd->payload;
|
||
+ copy_size = sizeof(out_cmd->hdr);
|
||
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
|
||
- if (!cmd->len[i])
|
||
+ int copy = 0;
|
||
+
|
||
+ if (!cmd->len)
|
||
continue;
|
||
- if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
|
||
- break;
|
||
- memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
|
||
- cmd_dest += cmd->len[i];
|
||
+
|
||
+ /* need at least IWL_HCMD_MIN_COPY_SIZE copied */
|
||
+ if (copy_size < IWL_HCMD_MIN_COPY_SIZE) {
|
||
+ copy = IWL_HCMD_MIN_COPY_SIZE - copy_size;
|
||
+
|
||
+ if (copy > cmd->len[i])
|
||
+ copy = cmd->len[i];
|
||
+ }
|
||
+
|
||
+ /* copy everything if not nocopy/dup */
|
||
+ if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
|
||
+ copy = cmd->len[i];
|
||
+
|
||
+ if (copy) {
|
||
+ memcpy(cmd_dest, cmd->data[i], copy);
|
||
+ cmd_dest += copy;
|
||
+ copy_size += copy;
|
||
+ }
|
||
}
|
||
|
||
IWL_DEBUG_HC(trans, "Sending command %s (#%x), seq: 0x%04X, "
|
||
@@ -766,7 +800,14 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
|
||
le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
|
||
q->write_ptr, idx, trans_pcie->cmd_queue);
|
||
|
||
- phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,
|
||
+ /*
|
||
+ * If the entire command is smaller than IWL_HCMD_MIN_COPY_SIZE, we must
|
||
+ * still map at least that many bytes for the hardware to write back to.
|
||
+ * We have enough space, so that's not a problem.
|
||
+ */
|
||
+ dma_size = max_t(u16, copy_size, IWL_HCMD_MIN_COPY_SIZE);
|
||
+
|
||
+ phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, dma_size,
|
||
DMA_BIDIRECTIONAL);
|
||
if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
|
||
idx = -ENOMEM;
|
||
@@ -774,7 +815,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
|
||
}
|
||
|
||
dma_unmap_addr_set(out_meta, mapping, phys_addr);
|
||
- dma_unmap_len_set(out_meta, len, copy_size);
|
||
+ dma_unmap_len_set(out_meta, len, dma_size);
|
||
|
||
iwlagn_txq_attach_buf_to_tfd(trans, txq,
|
||
phys_addr, copy_size, 1);
|
||
@@ -784,14 +825,15 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
|
||
trace_idx = 1;
|
||
#endif
|
||
|
||
+ /* map the remaining (adjusted) nocopy/dup fragments */
|
||
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
|
||
- if (!cmd->len[i])
|
||
+ if (!cmdlen[i])
|
||
continue;
|
||
if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
|
||
continue;
|
||
phys_addr = dma_map_single(trans->dev,
|
||
- (void *)cmd->data[i],
|
||
- cmd->len[i], DMA_BIDIRECTIONAL);
|
||
+ (void *)cmddata[i],
|
||
+ cmdlen[i], DMA_BIDIRECTIONAL);
|
||
if (dma_mapping_error(trans->dev, phys_addr)) {
|
||
iwlagn_unmap_tfd(trans, out_meta,
|
||
&txq->tfds[q->write_ptr],
|
||
@@ -801,10 +843,10 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
|
||
}
|
||
|
||
iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
|
||
- cmd->len[i], 0);
|
||
+ cmdlen[i], 0);
|
||
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
|
||
- trace_bufs[trace_idx] = cmd->data[i];
|
||
- trace_lens[trace_idx] = cmd->len[i];
|
||
+ trace_bufs[trace_idx] = cmddata[i];
|
||
+ trace_lens[trace_idx] = cmdlen[i];
|
||
trace_idx++;
|
||
#endif
|
||
}
|
||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
|
||
index 8741048..1780d3f 100644
|
||
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
|
||
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
|
||
@@ -1768,13 +1768,9 @@ static const char *get_fh_string(int cmd)
|
||
}
|
||
}
|
||
|
||
-int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
|
||
+int iwl_dump_fh(struct iwl_trans *trans, char **buf)
|
||
{
|
||
int i;
|
||
-#ifdef CONFIG_IWLWIFI_DEBUG
|
||
- int pos = 0;
|
||
- size_t bufsz = 0;
|
||
-#endif
|
||
static const u32 fh_tbl[] = {
|
||
FH_RSCSR_CHNL0_STTS_WPTR_REG,
|
||
FH_RSCSR_CHNL0_RBDCB_BASE_REG,
|
||
@@ -1786,29 +1782,34 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
|
||
FH_TSSR_TX_STATUS_REG,
|
||
FH_TSSR_TX_ERROR_REG
|
||
};
|
||
-#ifdef CONFIG_IWLWIFI_DEBUG
|
||
- if (display) {
|
||
+
|
||
+#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||
+ if (buf) {
|
||
+ int pos = 0;
|
||
+ size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
|
||
+
|
||
bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
|
||
*buf = kmalloc(bufsz, GFP_KERNEL);
|
||
if (!*buf)
|
||
return -ENOMEM;
|
||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||
"FH register values:\n");
|
||
- for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
|
||
+
|
||
+ for (i = 0; i < ARRAY_SIZE(fh_tbl); i++)
|
||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||
" %34s: 0X%08x\n",
|
||
get_fh_string(fh_tbl[i]),
|
||
iwl_read_direct32(trans, fh_tbl[i]));
|
||
- }
|
||
+
|
||
return pos;
|
||
}
|
||
#endif
|
||
IWL_ERR(trans, "FH register values:\n");
|
||
- for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
|
||
+ for (i = 0; i < ARRAY_SIZE(fh_tbl); i++)
|
||
IWL_ERR(trans, " %34s: 0X%08x\n",
|
||
get_fh_string(fh_tbl[i]),
|
||
iwl_read_direct32(trans, fh_tbl[i]));
|
||
- }
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
@@ -2152,11 +2153,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
|
||
size_t count, loff_t *ppos)
|
||
{
|
||
struct iwl_trans *trans = file->private_data;
|
||
- char *buf;
|
||
+ char *buf = NULL;
|
||
int pos = 0;
|
||
ssize_t ret = -EFAULT;
|
||
|
||
- ret = pos = iwl_dump_fh(trans, &buf, true);
|
||
+ ret = pos = iwl_dump_fh(trans, &buf);
|
||
if (buf) {
|
||
ret = simple_read_from_buffer(user_buf,
|
||
count, ppos, buf, pos);
|
||
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
|
||
index a06cc28..0b48430 100644
|
||
--- a/drivers/net/wireless/libertas/debugfs.c
|
||
+++ b/drivers/net/wireless/libertas/debugfs.c
|
||
@@ -913,7 +913,10 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
|
||
char *p2;
|
||
struct debug_data *d = f->private_data;
|
||
|
||
- pdata = kmalloc(cnt, GFP_KERNEL);
|
||
+ if (cnt == 0)
|
||
+ return 0;
|
||
+
|
||
+ pdata = kmalloc(cnt + 1, GFP_KERNEL);
|
||
if (pdata == NULL)
|
||
return 0;
|
||
|
||
@@ -922,6 +925,7 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
|
||
kfree(pdata);
|
||
return 0;
|
||
}
|
||
+ pdata[cnt] = '\0';
|
||
|
||
p0 = pdata;
|
||
for (i = 0; i < num_of_items; i++) {
|
||
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
|
||
index a5e182b..6f882bc 100644
|
||
--- a/drivers/net/wireless/mwifiex/11n.c
|
||
+++ b/drivers/net/wireless/mwifiex/11n.c
|
||
@@ -340,8 +340,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
|
||
ht_cap->header.len =
|
||
cpu_to_le16(sizeof(struct ieee80211_ht_cap));
|
||
memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
|
||
- (u8 *) bss_desc->bcn_ht_cap +
|
||
- sizeof(struct ieee_types_header),
|
||
+ (u8 *)bss_desc->bcn_ht_cap,
|
||
le16_to_cpu(ht_cap->header.len));
|
||
|
||
mwifiex_fill_cap_info(priv, radio_type, ht_cap);
|
||
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
|
||
index 9d1b3ca..a884c32 100644
|
||
--- a/drivers/net/wireless/mwifiex/main.c
|
||
+++ b/drivers/net/wireless/mwifiex/main.c
|
||
@@ -457,6 +457,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||
}
|
||
|
||
tx_info = MWIFIEX_SKB_TXCB(skb);
|
||
+ memset(tx_info, 0, sizeof(*tx_info));
|
||
tx_info->bss_num = priv->bss_num;
|
||
tx_info->bss_type = priv->bss_type;
|
||
mwifiex_fill_buffer(skb);
|
||
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
|
||
index 4be8ccc..daf55ba 100644
|
||
--- a/drivers/net/wireless/mwifiex/sdio.c
|
||
+++ b/drivers/net/wireless/mwifiex/sdio.c
|
||
@@ -938,7 +938,10 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
|
||
struct sk_buff *skb, u32 upld_typ)
|
||
{
|
||
u8 *cmd_buf;
|
||
+ __le16 *curr_ptr = (__le16 *)skb->data;
|
||
+ u16 pkt_len = le16_to_cpu(*curr_ptr);
|
||
|
||
+ skb_trim(skb, pkt_len);
|
||
skb_pull(skb, INTF_HEADER_LEN);
|
||
|
||
switch (upld_typ) {
|
||
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
|
||
index a08a6f0..2933819 100644
|
||
--- a/drivers/net/wireless/p54/txrx.c
|
||
+++ b/drivers/net/wireless/p54/txrx.c
|
||
@@ -583,7 +583,7 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
|
||
chan = priv->curchan;
|
||
if (chan) {
|
||
struct survey_info *survey = &priv->survey[chan->hw_value];
|
||
- survey->noise = clamp_t(s8, priv->noise, -128, 127);
|
||
+ survey->noise = clamp(priv->noise, -128, 127);
|
||
survey->channel_time = priv->survey_raw.active;
|
||
survey->channel_time_tx = priv->survey_raw.tx;
|
||
survey->channel_time_busy = priv->survey_raw.tx +
|
||
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
|
||
index 5970ff6..d498b02 100644
|
||
--- a/drivers/net/wireless/prism54/islpci_dev.c
|
||
+++ b/drivers/net/wireless/prism54/islpci_dev.c
|
||
@@ -811,6 +811,10 @@ static const struct net_device_ops islpci_netdev_ops = {
|
||
.ndo_validate_addr = eth_validate_addr,
|
||
};
|
||
|
||
+static struct device_type wlan_type = {
|
||
+ .name = "wlan",
|
||
+};
|
||
+
|
||
struct net_device *
|
||
islpci_setup(struct pci_dev *pdev)
|
||
{
|
||
@@ -821,9 +825,8 @@ islpci_setup(struct pci_dev *pdev)
|
||
return ndev;
|
||
|
||
pci_set_drvdata(pdev, ndev);
|
||
-#if defined(SET_NETDEV_DEV)
|
||
SET_NETDEV_DEV(ndev, &pdev->dev);
|
||
-#endif
|
||
+ SET_NETDEV_DEVTYPE(ndev, &wlan_type);
|
||
|
||
/* setup the structure members */
|
||
ndev->base_addr = pci_resource_start(pdev, 0);
|
||
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
|
||
index 0ea85f4..131b22b 100644
|
||
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
|
||
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
|
||
@@ -1253,7 +1253,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry,
|
||
*/
|
||
rxdesc->timestamp = ((u64)rx_high << 32) | rx_low;
|
||
rxdesc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL) & ~0x08;
|
||
- rxdesc->rssi = rt2x00_get_field32(word2, RXD_W3_RSSI) -
|
||
+ rxdesc->rssi = rt2x00_get_field32(word3, RXD_W3_RSSI) -
|
||
entry->queue->rt2x00dev->rssi_offset;
|
||
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
|
||
|
||
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
|
||
index aa10c48..f8ea77c 100644
|
||
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
|
||
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
|
||
@@ -1679,8 +1679,13 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
|
||
/*
|
||
* Detect if this device has an hardware controlled radio.
|
||
*/
|
||
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
|
||
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) {
|
||
__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
|
||
+ /*
|
||
+ * On this device RFKILL initialized during probe does not work.
|
||
+ */
|
||
+ __set_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags);
|
||
+ }
|
||
|
||
/*
|
||
* Check if the BBP tuning should be enabled.
|
||
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
|
||
index e0a7efc..9e55deb 100644
|
||
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
|
||
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
|
||
@@ -1921,7 +1921,7 @@ static struct usb_device_id rt2500usb_device_table[] = {
|
||
{ USB_DEVICE(0x0b05, 0x1706) },
|
||
{ USB_DEVICE(0x0b05, 0x1707) },
|
||
/* Belkin */
|
||
- { USB_DEVICE(0x050d, 0x7050) },
|
||
+ { USB_DEVICE(0x050d, 0x7050) }, /* FCC ID: K7SF5D7050A ver. 2.x */
|
||
{ USB_DEVICE(0x050d, 0x7051) },
|
||
/* Cisco Systems */
|
||
{ USB_DEVICE(0x13b1, 0x000d) },
|
||
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
|
||
index 65cb425..664e93d 100644
|
||
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
|
||
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
|
||
@@ -143,6 +143,8 @@ static bool rt2800usb_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
|
||
return false;
|
||
}
|
||
|
||
+#define TXSTATUS_READ_INTERVAL 1000000
|
||
+
|
||
static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
|
||
int urb_status, u32 tx_status)
|
||
{
|
||
@@ -170,8 +172,9 @@ static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
|
||
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
|
||
|
||
if (rt2800usb_txstatus_pending(rt2x00dev)) {
|
||
- /* Read register after 250 us */
|
||
- hrtimer_start(&rt2x00dev->txstatus_timer, ktime_set(0, 250000),
|
||
+ /* Read register after 1 ms */
|
||
+ hrtimer_start(&rt2x00dev->txstatus_timer,
|
||
+ ktime_set(0, TXSTATUS_READ_INTERVAL),
|
||
HRTIMER_MODE_REL);
|
||
return false;
|
||
}
|
||
@@ -196,8 +199,9 @@ static void rt2800usb_async_read_tx_status(struct rt2x00_dev *rt2x00dev)
|
||
if (test_and_set_bit(TX_STATUS_READING, &rt2x00dev->flags))
|
||
return;
|
||
|
||
- /* Read TX_STA_FIFO register after 500 us */
|
||
- hrtimer_start(&rt2x00dev->txstatus_timer, ktime_set(0, 500000),
|
||
+ /* Read TX_STA_FIFO register after 2 ms */
|
||
+ hrtimer_start(&rt2x00dev->txstatus_timer,
|
||
+ ktime_set(0, 2*TXSTATUS_READ_INTERVAL),
|
||
HRTIMER_MODE_REL);
|
||
}
|
||
|
||
@@ -1005,6 +1009,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||
{ USB_DEVICE(0x07d1, 0x3c15) },
|
||
{ USB_DEVICE(0x07d1, 0x3c16) },
|
||
{ USB_DEVICE(0x2001, 0x3c1b) },
|
||
+ { USB_DEVICE(0x2001, 0x3c1e) },
|
||
/* Draytek */
|
||
{ USB_DEVICE(0x07fa, 0x7712) },
|
||
/* DVICO */
|
||
@@ -1136,6 +1141,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||
{ USB_DEVICE(0x177f, 0x0153) },
|
||
{ USB_DEVICE(0x177f, 0x0302) },
|
||
{ USB_DEVICE(0x177f, 0x0313) },
|
||
+ { USB_DEVICE(0x177f, 0x0323) },
|
||
/* U-Media */
|
||
{ USB_DEVICE(0x157e, 0x300e) },
|
||
{ USB_DEVICE(0x157e, 0x3013) },
|
||
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
|
||
index c264dfa..4be11e36 100644
|
||
--- a/drivers/net/wireless/rt2x00/rt2x00.h
|
||
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
|
||
@@ -717,6 +717,7 @@ enum rt2x00_capability_flags {
|
||
REQUIRE_SW_SEQNO,
|
||
REQUIRE_HT_TX_DESC,
|
||
REQUIRE_PS_AUTOWAKE,
|
||
+ REQUIRE_DELAYED_RFKILL,
|
||
|
||
/*
|
||
* Capabilities
|
||
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
|
||
index 8f2c88e..da65f8e 100644
|
||
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
|
||
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
|
||
@@ -1022,9 +1022,10 @@ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
|
||
return;
|
||
|
||
/*
|
||
- * Unregister extra components.
|
||
+ * Stop rfkill polling.
|
||
*/
|
||
- rt2x00rfkill_unregister(rt2x00dev);
|
||
+ if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
|
||
+ rt2x00rfkill_unregister(rt2x00dev);
|
||
|
||
/*
|
||
* Allow the HW to uninitialize.
|
||
@@ -1062,6 +1063,12 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
|
||
|
||
set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags);
|
||
|
||
+ /*
|
||
+ * Start rfkill polling.
|
||
+ */
|
||
+ if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
|
||
+ rt2x00rfkill_register(rt2x00dev);
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
@@ -1207,7 +1214,12 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
||
rt2x00link_register(rt2x00dev);
|
||
rt2x00leds_register(rt2x00dev);
|
||
rt2x00debug_register(rt2x00dev);
|
||
- rt2x00rfkill_register(rt2x00dev);
|
||
+
|
||
+ /*
|
||
+ * Start rfkill polling.
|
||
+ */
|
||
+ if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
|
||
+ rt2x00rfkill_register(rt2x00dev);
|
||
|
||
return 0;
|
||
|
||
@@ -1223,6 +1235,12 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
|
||
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
|
||
|
||
/*
|
||
+ * Stop rfkill polling.
|
||
+ */
|
||
+ if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
|
||
+ rt2x00rfkill_unregister(rt2x00dev);
|
||
+
|
||
+ /*
|
||
* Disable radio.
|
||
*/
|
||
rt2x00lib_disable_radio(rt2x00dev);
|
||
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
|
||
index a8885f0..e6daf12 100644
|
||
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
|
||
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
|
||
@@ -517,6 +517,8 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||
crypto.cipher = rt2x00crypto_key_to_cipher(key);
|
||
if (crypto.cipher == CIPHER_NONE)
|
||
return -EOPNOTSUPP;
|
||
+ if (crypto.cipher == CIPHER_TKIP && rt2x00_is_usb(rt2x00dev))
|
||
+ return -EOPNOTSUPP;
|
||
|
||
crypto.cmd = cmd;
|
||
|
||
@@ -651,20 +653,18 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
|
||
bss_conf->bssid);
|
||
|
||
/*
|
||
- * Update the beacon. This is only required on USB devices. PCI
|
||
- * devices fetch beacons periodically.
|
||
- */
|
||
- if (changes & BSS_CHANGED_BEACON && rt2x00_is_usb(rt2x00dev))
|
||
- rt2x00queue_update_beacon(rt2x00dev, vif);
|
||
-
|
||
- /*
|
||
* Start/stop beaconing.
|
||
*/
|
||
if (changes & BSS_CHANGED_BEACON_ENABLED) {
|
||
if (!bss_conf->enable_beacon && intf->enable_beacon) {
|
||
- rt2x00queue_clear_beacon(rt2x00dev, vif);
|
||
rt2x00dev->intf_beaconing--;
|
||
intf->enable_beacon = false;
|
||
+ /*
|
||
+ * Clear beacon in the H/W for this vif. This is needed
|
||
+ * to disable beaconing on this particular interface
|
||
+ * and keep it running on other interfaces.
|
||
+ */
|
||
+ rt2x00queue_clear_beacon(rt2x00dev, vif);
|
||
|
||
if (rt2x00dev->intf_beaconing == 0) {
|
||
/*
|
||
@@ -675,11 +675,15 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
|
||
rt2x00queue_stop_queue(rt2x00dev->bcn);
|
||
mutex_unlock(&intf->beacon_skb_mutex);
|
||
}
|
||
-
|
||
-
|
||
} else if (bss_conf->enable_beacon && !intf->enable_beacon) {
|
||
rt2x00dev->intf_beaconing++;
|
||
intf->enable_beacon = true;
|
||
+ /*
|
||
+ * Upload beacon to the H/W. This is only required on
|
||
+ * USB devices. PCI devices fetch beacons periodically.
|
||
+ */
|
||
+ if (rt2x00_is_usb(rt2x00dev))
|
||
+ rt2x00queue_update_beacon(rt2x00dev, vif);
|
||
|
||
if (rt2x00dev->intf_beaconing == 1) {
|
||
/*
|
||
@@ -771,6 +775,9 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
|
||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||
struct data_queue *queue;
|
||
|
||
+ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
|
||
+ return;
|
||
+
|
||
tx_queue_for_each(rt2x00dev, queue)
|
||
rt2x00queue_flush_queue(queue, drop);
|
||
}
|
||
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
|
||
index ffdd32e..ef4cd40 100644
|
||
--- a/drivers/net/wireless/rt2x00/rt73usb.c
|
||
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
|
||
@@ -2422,6 +2422,7 @@ static struct usb_device_id rt73usb_device_table[] = {
|
||
{ USB_DEVICE(0x0b05, 0x1723) },
|
||
{ USB_DEVICE(0x0b05, 0x1724) },
|
||
/* Belkin */
|
||
+ { USB_DEVICE(0x050d, 0x7050) }, /* FCC ID: K7SF5D7050B ver. 3.x */
|
||
{ USB_DEVICE(0x050d, 0x705a) },
|
||
{ USB_DEVICE(0x050d, 0x905b) },
|
||
{ USB_DEVICE(0x050d, 0x905c) },
|
||
diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
|
||
index e19a20a..ecd1ac4 100644
|
||
--- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
|
||
+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
|
||
@@ -15,6 +15,8 @@
|
||
#ifndef RTL8187_H
|
||
#define RTL8187_H
|
||
|
||
+#include <linux/cache.h>
|
||
+
|
||
#include "rtl818x.h"
|
||
#include "leds.h"
|
||
|
||
@@ -139,7 +141,10 @@ struct rtl8187_priv {
|
||
u8 aifsn[4];
|
||
u8 rfkill_mask;
|
||
struct {
|
||
- __le64 buf;
|
||
+ union {
|
||
+ __le64 buf;
|
||
+ u8 dummy1[L1_CACHE_BYTES];
|
||
+ } ____cacheline_aligned;
|
||
struct sk_buff_head queue;
|
||
} b_tx_status; /* This queue is used by both -b and non-b devices */
|
||
struct mutex io_mutex;
|
||
@@ -147,7 +152,8 @@ struct rtl8187_priv {
|
||
u8 bits8;
|
||
__le16 bits16;
|
||
__le32 bits32;
|
||
- } *io_dmabuf;
|
||
+ u8 dummy2[L1_CACHE_BYTES];
|
||
+ } *io_dmabuf ____cacheline_aligned;
|
||
bool rfkill_off;
|
||
u16 seqno;
|
||
};
|
||
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
|
||
index 18d9eb3a..b175793 100644
|
||
--- a/drivers/net/wireless/rtlwifi/base.c
|
||
+++ b/drivers/net/wireless/rtlwifi/base.c
|
||
@@ -37,6 +37,7 @@
|
||
|
||
#include <linux/ip.h>
|
||
#include <linux/module.h>
|
||
+#include <linux/udp.h>
|
||
|
||
/*
|
||
*NOTICE!!!: This file will be very big, we should
|
||
@@ -957,61 +958,51 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
|
||
if (!ieee80211_is_data(fc))
|
||
return false;
|
||
|
||
+ ip = (const struct iphdr *)(skb->data + mac_hdr_len +
|
||
+ SNAP_SIZE + PROTOC_TYPE_SIZE);
|
||
+ ether_type = be16_to_cpup((__be16 *)
|
||
+ (skb->data + mac_hdr_len + SNAP_SIZE));
|
||
|
||
- ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len +
|
||
- SNAP_SIZE + PROTOC_TYPE_SIZE);
|
||
- ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE);
|
||
- /* ether_type = ntohs(ether_type); */
|
||
-
|
||
- if (ETH_P_IP == ether_type) {
|
||
- if (IPPROTO_UDP == ip->protocol) {
|
||
- struct udphdr *udp = (struct udphdr *)((u8 *) ip +
|
||
- (ip->ihl << 2));
|
||
- if (((((u8 *) udp)[1] == 68) &&
|
||
- (((u8 *) udp)[3] == 67)) ||
|
||
- ((((u8 *) udp)[1] == 67) &&
|
||
- (((u8 *) udp)[3] == 68))) {
|
||
- /*
|
||
- * 68 : UDP BOOTP client
|
||
- * 67 : UDP BOOTP server
|
||
- */
|
||
- RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV),
|
||
- DBG_DMESG, "dhcp %s !!\n",
|
||
- is_tx ? "Tx" : "Rx");
|
||
-
|
||
- if (is_tx) {
|
||
- schedule_work(&rtlpriv->
|
||
- works.lps_leave_work);
|
||
- ppsc->last_delaylps_stamp_jiffies =
|
||
- jiffies;
|
||
- }
|
||
+ switch (ether_type) {
|
||
+ case ETH_P_IP: {
|
||
+ struct udphdr *udp;
|
||
+ u16 src;
|
||
+ u16 dst;
|
||
|
||
- return true;
|
||
- }
|
||
- }
|
||
- } else if (ETH_P_ARP == ether_type) {
|
||
- if (is_tx) {
|
||
- schedule_work(&rtlpriv->works.lps_leave_work);
|
||
- ppsc->last_delaylps_stamp_jiffies = jiffies;
|
||
- }
|
||
+ if (ip->protocol != IPPROTO_UDP)
|
||
+ return false;
|
||
+ udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2));
|
||
+ src = be16_to_cpu(udp->source);
|
||
+ dst = be16_to_cpu(udp->dest);
|
||
|
||
- return true;
|
||
- } else if (ETH_P_PAE == ether_type) {
|
||
+ /* If this case involves port 68 (UDP BOOTP client) connecting
|
||
+ * with port 67 (UDP BOOTP server), then return true so that
|
||
+ * the lowest speed is used.
|
||
+ */
|
||
+ if (!((src == 68 && dst == 67) || (src == 67 && dst == 68)))
|
||
+ return false;
|
||
+
|
||
+ RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
|
||
+ "dhcp %s !!\n", is_tx ? "Tx" : "Rx");
|
||
+ break;
|
||
+ }
|
||
+ case ETH_P_ARP:
|
||
+ break;
|
||
+ case ETH_P_PAE:
|
||
RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
|
||
"802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx");
|
||
-
|
||
- if (is_tx) {
|
||
- schedule_work(&rtlpriv->works.lps_leave_work);
|
||
- ppsc->last_delaylps_stamp_jiffies = jiffies;
|
||
- }
|
||
-
|
||
- return true;
|
||
- } else if (ETH_P_IPV6 == ether_type) {
|
||
- /* IPv6 */
|
||
- return true;
|
||
+ break;
|
||
+ case ETH_P_IPV6:
|
||
+ /* TODO: Is this right? */
|
||
+ return false;
|
||
+ default:
|
||
+ return false;
|
||
}
|
||
-
|
||
- return false;
|
||
+ if (is_tx) {
|
||
+ schedule_work(&rtlpriv->works.lps_leave_work);
|
||
+ ppsc->last_delaylps_stamp_jiffies = jiffies;
|
||
+ }
|
||
+ return true;
|
||
}
|
||
|
||
/*********************************************************
|
||
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
|
||
index 278e9f9..c3d3258 100644
|
||
--- a/drivers/net/wireless/rtlwifi/core.c
|
||
+++ b/drivers/net/wireless/rtlwifi/core.c
|
||
@@ -175,6 +175,7 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
|
||
rtlpriv->cfg->maps
|
||
[RTL_IBSS_INT_MASKS]);
|
||
}
|
||
+ mac->link_state = MAC80211_LINKED;
|
||
break;
|
||
case NL80211_IFTYPE_ADHOC:
|
||
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
|
||
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
|
||
index 67f9430..5c1379c 100644
|
||
--- a/drivers/net/wireless/rtlwifi/pci.c
|
||
+++ b/drivers/net/wireless/rtlwifi/pci.c
|
||
@@ -678,6 +678,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
|
||
};
|
||
int index = rtlpci->rx_ring[rx_queue_idx].idx;
|
||
|
||
+ if (rtlpci->driver_is_goingto_unload)
|
||
+ return;
|
||
/*RX NORMAL PKT */
|
||
while (count--) {
|
||
/*rx descriptor */
|
||
@@ -1553,6 +1555,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
|
||
*/
|
||
set_hal_stop(rtlhal);
|
||
|
||
+ rtlpci->driver_is_goingto_unload = true;
|
||
rtlpriv->cfg->ops->disable_interrupt(hw);
|
||
cancel_work_sync(&rtlpriv->works.lps_leave_work);
|
||
|
||
@@ -1570,7 +1573,6 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
|
||
ppsc->rfchange_inprogress = true;
|
||
spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags);
|
||
|
||
- rtlpci->driver_is_goingto_unload = true;
|
||
rtlpriv->cfg->ops->hw_disable(hw);
|
||
/* some things are not needed if firmware not available */
|
||
if (!rtlpriv->max_fw_size)
|
||
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
|
||
index 5b9c3b5..7fe4f91 100644
|
||
--- a/drivers/net/wireless/rtlwifi/ps.c
|
||
+++ b/drivers/net/wireless/rtlwifi/ps.c
|
||
@@ -48,7 +48,7 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
|
||
|
||
/*<2> Enable Adapter */
|
||
if (rtlpriv->cfg->ops->hw_init(hw))
|
||
- return 1;
|
||
+ return false;
|
||
RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
|
||
|
||
/*<3> Enable Interrupt */
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
|
||
index 1208b75..513baa0 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
|
||
@@ -1210,11 +1210,14 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
|
||
if (rtlhal->interface == INTF_PCI) {
|
||
rcu_read_lock();
|
||
sta = ieee80211_find_sta(mac->vif, mac->bssid);
|
||
+ if (!sta)
|
||
+ goto out_unlock;
|
||
}
|
||
rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
|
||
p_ra->ratr_state);
|
||
|
||
p_ra->pre_ratr_state = p_ra->ratr_state;
|
||
+ out_unlock:
|
||
if (rtlhal->interface == INTF_PCI)
|
||
rcu_read_unlock();
|
||
}
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
|
||
index 509f661..18ddf57 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
|
||
@@ -902,14 +902,26 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
|
||
bool is92c;
|
||
int err;
|
||
u8 tmp_u1b;
|
||
+ unsigned long flags;
|
||
|
||
rtlpci->being_init_adapter = true;
|
||
+
|
||
+ /* Since this function can take a very long time (up to 350 ms)
|
||
+ * and can be called with irqs disabled, reenable the irqs
|
||
+ * to let the other devices continue being serviced.
|
||
+ *
|
||
+ * It is safe doing so since our own interrupts will only be enabled
|
||
+ * in a subsequent step.
|
||
+ */
|
||
+ local_save_flags(flags);
|
||
+ local_irq_enable();
|
||
+
|
||
rtlpriv->intf_ops->disable_aspm(hw);
|
||
rtstatus = _rtl92ce_init_mac(hw);
|
||
if (!rtstatus) {
|
||
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
|
||
err = 1;
|
||
- return err;
|
||
+ goto exit;
|
||
}
|
||
|
||
err = rtl92c_download_fw(hw);
|
||
@@ -917,7 +929,7 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
|
||
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
|
||
"Failed to download FW. Init HW without FW now..\n");
|
||
err = 1;
|
||
- return err;
|
||
+ goto exit;
|
||
}
|
||
|
||
rtlhal->last_hmeboxnum = 0;
|
||
@@ -978,6 +990,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
|
||
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
|
||
}
|
||
rtl92c_dm_init(hw);
|
||
+exit:
|
||
+ local_irq_restore(flags);
|
||
rtlpci->being_init_adapter = false;
|
||
return err;
|
||
}
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
|
||
index 91d2e28..0908a3b 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
|
||
@@ -985,19 +985,30 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
|
||
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
|
||
int err = 0;
|
||
static bool iqk_initialized;
|
||
+ unsigned long flags;
|
||
+
|
||
+ /* As this function can take a very long time (up to 350 ms)
|
||
+ * and can be called with irqs disabled, reenable the irqs
|
||
+ * to let the other devices continue being serviced.
|
||
+ *
|
||
+ * It is safe doing so since our own interrupts will only be enabled
|
||
+ * in a subsequent step.
|
||
+ */
|
||
+ local_save_flags(flags);
|
||
+ local_irq_enable();
|
||
|
||
rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU;
|
||
err = _rtl92cu_init_mac(hw);
|
||
if (err) {
|
||
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "init mac failed!\n");
|
||
- return err;
|
||
+ goto exit;
|
||
}
|
||
err = rtl92c_download_fw(hw);
|
||
if (err) {
|
||
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
|
||
"Failed to download FW. Init HW without FW now..\n");
|
||
err = 1;
|
||
- return err;
|
||
+ goto exit;
|
||
}
|
||
rtlhal->last_hmeboxnum = 0; /* h2c */
|
||
_rtl92cu_phy_param_tab_init(hw);
|
||
@@ -1034,6 +1045,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
|
||
_InitPABias(hw);
|
||
_update_mac_setting(hw);
|
||
rtl92c_dm_init(hw);
|
||
+exit:
|
||
+ local_irq_restore(flags);
|
||
return err;
|
||
}
|
||
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
|
||
index 025bdc2..4f7f822 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
|
||
@@ -762,7 +762,7 @@ static long _rtl92c_signal_scale_mapping(struct ieee80211_hw *hw,
|
||
|
||
static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw,
|
||
struct rtl_stats *pstats,
|
||
- struct rx_desc_92c *pdesc,
|
||
+ struct rx_desc_92c *p_desc,
|
||
struct rx_fwinfo_92c *p_drvinfo,
|
||
bool packet_match_bssid,
|
||
bool packet_toself,
|
||
@@ -777,11 +777,11 @@ static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw,
|
||
u32 rssi, total_rssi = 0;
|
||
bool in_powersavemode = false;
|
||
bool is_cck_rate;
|
||
+ u8 *pdesc = (u8 *)p_desc;
|
||
|
||
- is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
|
||
+ is_cck_rate = RX_HAL_IS_CCK_RATE(p_desc);
|
||
pstats->packet_matchbssid = packet_match_bssid;
|
||
pstats->packet_toself = packet_toself;
|
||
- pstats->is_cck = is_cck_rate;
|
||
pstats->packet_beacon = packet_beacon;
|
||
pstats->is_cck = is_cck_rate;
|
||
pstats->RX_SIGQ[0] = -1;
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
|
||
index 4763426..bbe9a78 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
|
||
@@ -85,17 +85,15 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
|
||
if (mac->act_scanning) {
|
||
tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
|
||
tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
|
||
- if (turbo_scanoff) {
|
||
- for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
|
||
- tx_agc[idx1] = ppowerlevel[idx1] |
|
||
- (ppowerlevel[idx1] << 8) |
|
||
- (ppowerlevel[idx1] << 16) |
|
||
- (ppowerlevel[idx1] << 24);
|
||
- if (rtlhal->interface == INTF_USB) {
|
||
- if (tx_agc[idx1] > 0x20 &&
|
||
- rtlefuse->external_pa)
|
||
- tx_agc[idx1] = 0x20;
|
||
- }
|
||
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
|
||
+ tx_agc[idx1] = ppowerlevel[idx1] |
|
||
+ (ppowerlevel[idx1] << 8) |
|
||
+ (ppowerlevel[idx1] << 16) |
|
||
+ (ppowerlevel[idx1] << 24);
|
||
+ if (rtlhal->interface == INTF_USB) {
|
||
+ if (tx_agc[idx1] > 0x20 &&
|
||
+ rtlefuse->external_pa)
|
||
+ tx_agc[idx1] = 0x20;
|
||
}
|
||
}
|
||
} else {
|
||
@@ -107,7 +105,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
|
||
TXHIGHPWRLEVEL_LEVEL2) {
|
||
tx_agc[RF90_PATH_A] = 0x00000000;
|
||
tx_agc[RF90_PATH_B] = 0x00000000;
|
||
- } else{
|
||
+ } else {
|
||
for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
|
||
tx_agc[idx1] = ppowerlevel[idx1] |
|
||
(ppowerlevel[idx1] << 8) |
|
||
@@ -379,7 +377,12 @@ static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw,
|
||
regoffset == RTXAGC_B_MCS07_MCS04)
|
||
regoffset = 0xc98;
|
||
for (i = 0; i < 3; i++) {
|
||
- writeVal = (writeVal > 6) ? (writeVal - 6) : 0;
|
||
+ if (i != 2)
|
||
+ writeVal = (writeVal > 8) ?
|
||
+ (writeVal - 8) : 0;
|
||
+ else
|
||
+ writeVal = (writeVal > 6) ?
|
||
+ (writeVal - 6) : 0;
|
||
rtl_write_byte(rtlpriv, (u32)(regoffset + i),
|
||
(u8)writeVal);
|
||
}
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
|
||
index 3f869c9..2c4cdce 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
|
||
@@ -306,6 +306,8 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
|
||
{RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/
|
||
{RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
|
||
{RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
|
||
+ {RTL_USB_DEVICE(0x0df6, 0x0070, rtl92cu_hal_cfg)}, /*Sitecom - 150N */
|
||
+ {RTL_USB_DEVICE(0x0df6, 0x0077, rtl92cu_hal_cfg)}, /*Sitecom-WLA2100V2*/
|
||
{RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
|
||
{RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/
|
||
/* HP - Lite-On ,8188CUS Slim Combo */
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
|
||
index 21bc827..2fd8297 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
|
||
@@ -303,10 +303,10 @@ static enum rtl_desc_qsel _rtl8192cu_mq_to_descq(struct ieee80211_hw *hw,
|
||
bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
|
||
struct rtl_stats *stats,
|
||
struct ieee80211_rx_status *rx_status,
|
||
- u8 *p_desc, struct sk_buff *skb)
|
||
+ u8 *pdesc, struct sk_buff *skb)
|
||
{
|
||
struct rx_fwinfo_92c *p_drvinfo;
|
||
- struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc;
|
||
+ struct rx_desc_92c *p_desc = (struct rx_desc_92c *)pdesc;
|
||
u32 phystatus = GET_RX_DESC_PHY_STATUS(pdesc);
|
||
|
||
stats->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
|
||
@@ -343,12 +343,13 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
|
||
(bool)GET_RX_DESC_PAGGR(pdesc));
|
||
rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
|
||
if (phystatus) {
|
||
- p_drvinfo = (struct rx_fwinfo_92c *)(pdesc + RTL_RX_DESC_SIZE);
|
||
- rtl92c_translate_rx_signal_stuff(hw, skb, stats, pdesc,
|
||
+ p_drvinfo = (struct rx_fwinfo_92c *)(skb->data +
|
||
+ stats->rx_bufshift);
|
||
+ rtl92c_translate_rx_signal_stuff(hw, skb, stats, p_desc,
|
||
p_drvinfo);
|
||
}
|
||
/*rx_status->qual = stats->signal; */
|
||
- rx_status->signal = stats->rssi + 10;
|
||
+ rx_status->signal = stats->recvsignalpower + 10;
|
||
/*rx_status->noise = -stats->noise; */
|
||
return true;
|
||
}
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
|
||
index a7f6126..1a2bbc2 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
|
||
@@ -529,7 +529,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
|
||
p_drvinfo);
|
||
}
|
||
/*rx_status->qual = stats->signal; */
|
||
- rx_status->signal = stats->rssi + 10;
|
||
+ rx_status->signal = stats->recvsignalpower + 10;
|
||
/*rx_status->noise = -stats->noise; */
|
||
return true;
|
||
}
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
|
||
index b141c35..f90eb0c 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
|
||
@@ -922,7 +922,7 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
|
||
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
|
||
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
|
||
u8 tmp_byte = 0;
|
||
-
|
||
+ unsigned long flags;
|
||
bool rtstatus = true;
|
||
u8 tmp_u1b;
|
||
int err = false;
|
||
@@ -934,6 +934,16 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
|
||
|
||
rtlpci->being_init_adapter = true;
|
||
|
||
+ /* As this function can take a very long time (up to 350 ms)
|
||
+ * and can be called with irqs disabled, reenable the irqs
|
||
+ * to let the other devices continue being serviced.
|
||
+ *
|
||
+ * It is safe doing so since our own interrupts will only be enabled
|
||
+ * in a subsequent step.
|
||
+ */
|
||
+ local_save_flags(flags);
|
||
+ local_irq_enable();
|
||
+
|
||
rtlpriv->intf_ops->disable_aspm(hw);
|
||
|
||
/* 1. MAC Initialize */
|
||
@@ -951,7 +961,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
|
||
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
|
||
"Failed to download FW. Init HW without FW now... "
|
||
"Please copy FW into /lib/firmware/rtlwifi\n");
|
||
- return 1;
|
||
+ err = 1;
|
||
+ goto exit;
|
||
}
|
||
|
||
/* After FW download, we have to reset MAC register */
|
||
@@ -964,7 +975,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
|
||
/* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */
|
||
if (!rtl92s_phy_mac_config(hw)) {
|
||
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "MAC Config failed\n");
|
||
- return rtstatus;
|
||
+ err = rtstatus;
|
||
+ goto exit;
|
||
}
|
||
|
||
/* Make sure BB/RF write OK. We should prevent enter IPS. radio off. */
|
||
@@ -974,7 +986,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
|
||
/* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */
|
||
if (!rtl92s_phy_bb_config(hw)) {
|
||
RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "BB Config failed\n");
|
||
- return rtstatus;
|
||
+ err = rtstatus;
|
||
+ goto exit;
|
||
}
|
||
|
||
/* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */
|
||
@@ -1010,7 +1023,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
|
||
|
||
if (!rtl92s_phy_rf_config(hw)) {
|
||
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "RF Config failed\n");
|
||
- return rtstatus;
|
||
+ err = rtstatus;
|
||
+ goto exit;
|
||
}
|
||
|
||
/* After read predefined TXT, we must set BB/MAC/RF
|
||
@@ -1084,8 +1098,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
|
||
|
||
rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON);
|
||
rtl92s_dm_init(hw);
|
||
+exit:
|
||
+ local_irq_restore(flags);
|
||
rtlpci->being_init_adapter = false;
|
||
-
|
||
return err;
|
||
}
|
||
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
|
||
index 08c2f56..c405f96 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
|
||
@@ -268,7 +268,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
|
||
rtlefuse->pwrgroup_ht40
|
||
[RF90_PATH_A][chnl - 1]) {
|
||
pwrdiff_limit[i] =
|
||
- rtlefuse->pwrgroup_ht20
|
||
+ rtlefuse->pwrgroup_ht40
|
||
[RF90_PATH_A][chnl - 1];
|
||
}
|
||
} else {
|
||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
|
||
index 2fd3d13..94bbce8 100644
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
|
||
@@ -582,7 +582,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
|
||
}
|
||
|
||
/*rx_status->qual = stats->signal; */
|
||
- rx_status->signal = stats->rssi + 10;
|
||
+ rx_status->signal = stats->recvsignalpower + 10;
|
||
/*rx_status->noise = -stats->noise; */
|
||
|
||
return true;
|
||
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
|
||
index 38c51ea..905fec4 100644
|
||
--- a/drivers/net/wireless/rtlwifi/wifi.h
|
||
+++ b/drivers/net/wireless/rtlwifi/wifi.h
|
||
@@ -77,11 +77,7 @@
|
||
#define RTL_SLOT_TIME_9 9
|
||
#define RTL_SLOT_TIME_20 20
|
||
|
||
-/*related with tcp/ip. */
|
||
-/*if_ehther.h*/
|
||
-#define ETH_P_PAE 0x888E /*Port Access Entity (IEEE 802.1X) */
|
||
-#define ETH_P_IP 0x0800 /*Internet Protocol packet */
|
||
-#define ETH_P_ARP 0x0806 /*Address Resolution packet */
|
||
+/*related to tcp/ip. */
|
||
#define SNAP_SIZE 6
|
||
#define PROTOC_TYPE_SIZE 2
|
||
|
||
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
|
||
index 9d7f172..093bf0a 100644
|
||
--- a/drivers/net/xen-netback/common.h
|
||
+++ b/drivers/net/xen-netback/common.h
|
||
@@ -88,6 +88,7 @@ struct xenvif {
|
||
unsigned long credit_usec;
|
||
unsigned long remaining_credit;
|
||
struct timer_list credit_timeout;
|
||
+ u64 credit_window_start;
|
||
|
||
/* Statistics */
|
||
unsigned long rx_gso_checksum_fixup;
|
||
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
|
||
index 221f426..cfaaf68 100644
|
||
--- a/drivers/net/xen-netback/interface.c
|
||
+++ b/drivers/net/xen-netback/interface.c
|
||
@@ -273,8 +273,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
|
||
vif->credit_bytes = vif->remaining_credit = ~0UL;
|
||
vif->credit_usec = 0UL;
|
||
init_timer(&vif->credit_timeout);
|
||
- /* Initialize 'expires' now: it's used to track the credit window. */
|
||
- vif->credit_timeout.expires = jiffies;
|
||
+ vif->credit_window_start = get_jiffies_64();
|
||
|
||
dev->netdev_ops = &xenvif_netdev_ops;
|
||
dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
|
||
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
|
||
index 0d22cff..cd4966b 100644
|
||
--- a/drivers/net/xen-netback/netback.c
|
||
+++ b/drivers/net/xen-netback/netback.c
|
||
@@ -46,11 +46,25 @@
|
||
#include <asm/xen/hypercall.h>
|
||
#include <asm/xen/page.h>
|
||
|
||
+/*
|
||
+ * This is the maximum slots a skb can have. If a guest sends a skb
|
||
+ * which exceeds this limit it is considered malicious.
|
||
+ */
|
||
+#define MAX_SKB_SLOTS_DEFAULT 20
|
||
+static unsigned int max_skb_slots = MAX_SKB_SLOTS_DEFAULT;
|
||
+module_param(max_skb_slots, uint, 0444);
|
||
+
|
||
+typedef unsigned int pending_ring_idx_t;
|
||
+#define INVALID_PENDING_RING_IDX (~0U)
|
||
+
|
||
struct pending_tx_info {
|
||
- struct xen_netif_tx_request req;
|
||
+ struct xen_netif_tx_request req; /* coalesced tx request */
|
||
struct xenvif *vif;
|
||
+ pending_ring_idx_t head; /* head != INVALID_PENDING_RING_IDX
|
||
+ * if it is head of one or more tx
|
||
+ * reqs
|
||
+ */
|
||
};
|
||
-typedef unsigned int pending_ring_idx_t;
|
||
|
||
struct netbk_rx_meta {
|
||
int id;
|
||
@@ -101,7 +115,11 @@ struct xen_netbk {
|
||
atomic_t netfront_count;
|
||
|
||
struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
|
||
- struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
|
||
+ /* Coalescing tx requests before copying makes number of grant
|
||
+ * copy ops greater or equal to number of slots required. In
|
||
+ * worst case a tx request consumes 2 gnttab_copy.
|
||
+ */
|
||
+ struct gnttab_copy tx_copy_ops[2*MAX_PENDING_REQS];
|
||
|
||
u16 pending_ring[MAX_PENDING_REQS];
|
||
|
||
@@ -117,6 +135,16 @@ struct xen_netbk {
|
||
static struct xen_netbk *xen_netbk;
|
||
static int xen_netbk_group_nr;
|
||
|
||
+/*
|
||
+ * If head != INVALID_PENDING_RING_IDX, it means this tx request is head of
|
||
+ * one or more merged tx requests, otherwise it is the continuation of
|
||
+ * previous tx request.
|
||
+ */
|
||
+static inline int pending_tx_is_head(struct xen_netbk *netbk, RING_IDX idx)
|
||
+{
|
||
+ return netbk->pending_tx_info[idx].head != INVALID_PENDING_RING_IDX;
|
||
+}
|
||
+
|
||
void xen_netbk_add_xenvif(struct xenvif *vif)
|
||
{
|
||
int i;
|
||
@@ -249,6 +277,7 @@ static int max_required_rx_slots(struct xenvif *vif)
|
||
{
|
||
int max = DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE);
|
||
|
||
+ /* XXX FIXME: RX path dependent on MAX_SKB_FRAGS */
|
||
if (vif->can_sg || vif->gso || vif->gso_prefix)
|
||
max += MAX_SKB_FRAGS + 1; /* extra_info + frags */
|
||
|
||
@@ -309,8 +338,8 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head)
|
||
* into multiple copies tend to give large frags their
|
||
* own buffers as before.
|
||
*/
|
||
- if ((offset + size > MAX_BUFFER_OFFSET) &&
|
||
- (size <= MAX_BUFFER_OFFSET) && offset && !head)
|
||
+ BUG_ON(size > MAX_BUFFER_OFFSET);
|
||
+ if ((offset + size > MAX_BUFFER_OFFSET) && offset && !head)
|
||
return true;
|
||
|
||
return false;
|
||
@@ -627,6 +656,7 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk)
|
||
__skb_queue_tail(&rxq, skb);
|
||
|
||
/* Filled the batch queue? */
|
||
+ /* XXX FIXME: RX path dependent on MAX_SKB_FRAGS */
|
||
if (count + MAX_SKB_FRAGS >= XEN_NETIF_RX_RING_SIZE)
|
||
break;
|
||
}
|
||
@@ -870,47 +900,88 @@ static void netbk_fatal_tx_err(struct xenvif *vif)
|
||
|
||
static int netbk_count_requests(struct xenvif *vif,
|
||
struct xen_netif_tx_request *first,
|
||
+ RING_IDX first_idx,
|
||
struct xen_netif_tx_request *txp,
|
||
int work_to_do)
|
||
{
|
||
RING_IDX cons = vif->tx.req_cons;
|
||
- int frags = 0;
|
||
+ int slots = 0;
|
||
+ int drop_err = 0;
|
||
|
||
if (!(first->flags & XEN_NETTXF_more_data))
|
||
return 0;
|
||
|
||
do {
|
||
- if (frags >= work_to_do) {
|
||
- netdev_err(vif->dev, "Need more frags\n");
|
||
+ if (slots >= work_to_do) {
|
||
+ netdev_err(vif->dev,
|
||
+ "Asked for %d slots but exceeds this limit\n",
|
||
+ work_to_do);
|
||
netbk_fatal_tx_err(vif);
|
||
return -ENODATA;
|
||
}
|
||
|
||
- if (unlikely(frags >= MAX_SKB_FRAGS)) {
|
||
- netdev_err(vif->dev, "Too many frags\n");
|
||
+ /* This guest is really using too many slots and
|
||
+ * considered malicious.
|
||
+ */
|
||
+ if (unlikely(slots >= max_skb_slots)) {
|
||
+ netdev_err(vif->dev,
|
||
+ "Malicious frontend using %d slots, threshold %u\n",
|
||
+ slots, max_skb_slots);
|
||
netbk_fatal_tx_err(vif);
|
||
return -E2BIG;
|
||
}
|
||
|
||
- memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags),
|
||
+ /* Xen network protocol had implicit dependency on
|
||
+ * MAX_SKB_FRAGS. XEN_NETIF_NR_SLOTS_MIN is set to the
|
||
+ * historical MAX_SKB_FRAGS value 18 to honor the same
|
||
+ * behavior as before. Any packet using more than 18
|
||
+ * slots but less than max_skb_slots slots is dropped
|
||
+ */
|
||
+ if (!drop_err && slots >= XEN_NETIF_NR_SLOTS_MIN) {
|
||
+ if (net_ratelimit())
|
||
+ netdev_dbg(vif->dev,
|
||
+ "Too many slots (%d) exceeding limit (%d), dropping packet\n",
|
||
+ slots, XEN_NETIF_NR_SLOTS_MIN);
|
||
+ drop_err = -E2BIG;
|
||
+ }
|
||
+
|
||
+ memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + slots),
|
||
sizeof(*txp));
|
||
- if (txp->size > first->size) {
|
||
- netdev_err(vif->dev, "Frag is bigger than frame.\n");
|
||
- netbk_fatal_tx_err(vif);
|
||
- return -EIO;
|
||
+
|
||
+ /* If the guest submitted a frame >= 64 KiB then
|
||
+ * first->size overflowed and following slots will
|
||
+ * appear to be larger than the frame.
|
||
+ *
|
||
+ * This cannot be fatal error as there are buggy
|
||
+ * frontends that do this.
|
||
+ *
|
||
+ * Consume all slots and drop the packet.
|
||
+ */
|
||
+ if (!drop_err && txp->size > first->size) {
|
||
+ if (net_ratelimit())
|
||
+ netdev_dbg(vif->dev,
|
||
+ "Invalid tx request, slot size %u > remaining size %u\n",
|
||
+ txp->size, first->size);
|
||
+ drop_err = -EIO;
|
||
}
|
||
|
||
first->size -= txp->size;
|
||
- frags++;
|
||
+ slots++;
|
||
|
||
if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
|
||
- netdev_err(vif->dev, "txp->offset: %x, size: %u\n",
|
||
+ netdev_err(vif->dev, "Cross page boundary, txp->offset: %x, size: %u\n",
|
||
txp->offset, txp->size);
|
||
netbk_fatal_tx_err(vif);
|
||
return -EINVAL;
|
||
}
|
||
} while ((txp++)->flags & XEN_NETTXF_more_data);
|
||
- return frags;
|
||
+
|
||
+ if (drop_err) {
|
||
+ netbk_tx_err(vif, first, first_idx + slots);
|
||
+ return drop_err;
|
||
+ }
|
||
+
|
||
+ return slots;
|
||
}
|
||
|
||
static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
|
||
@@ -934,48 +1005,114 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
|
||
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
||
skb_frag_t *frags = shinfo->frags;
|
||
u16 pending_idx = *((u16 *)skb->data);
|
||
- int i, start;
|
||
+ u16 head_idx = 0;
|
||
+ int slot, start;
|
||
+ struct page *page;
|
||
+ pending_ring_idx_t index, start_idx = 0;
|
||
+ uint16_t dst_offset;
|
||
+ unsigned int nr_slots;
|
||
+ struct pending_tx_info *first = NULL;
|
||
+
|
||
+ /* At this point shinfo->nr_frags is in fact the number of
|
||
+ * slots, which can be as large as XEN_NETIF_NR_SLOTS_MIN.
|
||
+ */
|
||
+ nr_slots = shinfo->nr_frags;
|
||
|
||
/* Skip first skb fragment if it is on same page as header fragment. */
|
||
start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
|
||
|
||
- for (i = start; i < shinfo->nr_frags; i++, txp++) {
|
||
- struct page *page;
|
||
- pending_ring_idx_t index;
|
||
+ /* Coalesce tx requests, at this point the packet passed in
|
||
+ * should be <= 64K. Any packets larger than 64K have been
|
||
+ * handled in netbk_count_requests().
|
||
+ */
|
||
+ for (shinfo->nr_frags = slot = start; slot < nr_slots;
|
||
+ shinfo->nr_frags++) {
|
||
struct pending_tx_info *pending_tx_info =
|
||
netbk->pending_tx_info;
|
||
|
||
- index = pending_index(netbk->pending_cons++);
|
||
- pending_idx = netbk->pending_ring[index];
|
||
- page = xen_netbk_alloc_page(netbk, pending_idx);
|
||
+ page = alloc_page(GFP_KERNEL|__GFP_COLD);
|
||
if (!page)
|
||
goto err;
|
||
|
||
- gop->source.u.ref = txp->gref;
|
||
- gop->source.domid = vif->domid;
|
||
- gop->source.offset = txp->offset;
|
||
-
|
||
- gop->dest.u.gmfn = virt_to_mfn(page_address(page));
|
||
- gop->dest.domid = DOMID_SELF;
|
||
- gop->dest.offset = txp->offset;
|
||
-
|
||
- gop->len = txp->size;
|
||
- gop->flags = GNTCOPY_source_gref;
|
||
+ dst_offset = 0;
|
||
+ first = NULL;
|
||
+ while (dst_offset < PAGE_SIZE && slot < nr_slots) {
|
||
+ gop->flags = GNTCOPY_source_gref;
|
||
+
|
||
+ gop->source.u.ref = txp->gref;
|
||
+ gop->source.domid = vif->domid;
|
||
+ gop->source.offset = txp->offset;
|
||
+
|
||
+ gop->dest.domid = DOMID_SELF;
|
||
+
|
||
+ gop->dest.offset = dst_offset;
|
||
+ gop->dest.u.gmfn = virt_to_mfn(page_address(page));
|
||
+
|
||
+ if (dst_offset + txp->size > PAGE_SIZE) {
|
||
+ /* This page can only merge a portion
|
||
+ * of tx request. Do not increment any
|
||
+ * pointer / counter here. The txp
|
||
+ * will be dealt with in future
|
||
+ * rounds, eventually hitting the
|
||
+ * `else` branch.
|
||
+ */
|
||
+ gop->len = PAGE_SIZE - dst_offset;
|
||
+ txp->offset += gop->len;
|
||
+ txp->size -= gop->len;
|
||
+ dst_offset += gop->len; /* quit loop */
|
||
+ } else {
|
||
+ /* This tx request can be merged in the page */
|
||
+ gop->len = txp->size;
|
||
+ dst_offset += gop->len;
|
||
+
|
||
+ index = pending_index(netbk->pending_cons++);
|
||
+
|
||
+ pending_idx = netbk->pending_ring[index];
|
||
+
|
||
+ memcpy(&pending_tx_info[pending_idx].req, txp,
|
||
+ sizeof(*txp));
|
||
+ xenvif_get(vif);
|
||
+
|
||
+ pending_tx_info[pending_idx].vif = vif;
|
||
+
|
||
+ /* Poison these fields, corresponding
|
||
+ * fields for head tx req will be set
|
||
+ * to correct values after the loop.
|
||
+ */
|
||
+ netbk->mmap_pages[pending_idx] = (void *)(~0UL);
|
||
+ pending_tx_info[pending_idx].head =
|
||
+ INVALID_PENDING_RING_IDX;
|
||
+
|
||
+ if (!first) {
|
||
+ first = &pending_tx_info[pending_idx];
|
||
+ start_idx = index;
|
||
+ head_idx = pending_idx;
|
||
+ }
|
||
+
|
||
+ txp++;
|
||
+ slot++;
|
||
+ }
|
||
|
||
- gop++;
|
||
+ gop++;
|
||
+ }
|
||
|
||
- memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
|
||
- xenvif_get(vif);
|
||
- pending_tx_info[pending_idx].vif = vif;
|
||
- frag_set_pending_idx(&frags[i], pending_idx);
|
||
+ first->req.offset = 0;
|
||
+ first->req.size = dst_offset;
|
||
+ first->head = start_idx;
|
||
+ set_page_ext(page, netbk, head_idx);
|
||
+ netbk->mmap_pages[head_idx] = page;
|
||
+ frag_set_pending_idx(&frags[shinfo->nr_frags], head_idx);
|
||
}
|
||
|
||
+ BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS);
|
||
+
|
||
return gop;
|
||
err:
|
||
/* Unwind, freeing all pages and sending error responses. */
|
||
- while (i-- > start) {
|
||
- xen_netbk_idx_release(netbk, frag_get_pending_idx(&frags[i]),
|
||
- XEN_NETIF_RSP_ERROR);
|
||
+ while (shinfo->nr_frags-- > start) {
|
||
+ xen_netbk_idx_release(netbk,
|
||
+ frag_get_pending_idx(&frags[shinfo->nr_frags]),
|
||
+ XEN_NETIF_RSP_ERROR);
|
||
}
|
||
/* The head too, if necessary. */
|
||
if (start)
|
||
@@ -991,8 +1128,10 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
|
||
struct gnttab_copy *gop = *gopp;
|
||
u16 pending_idx = *((u16 *)skb->data);
|
||
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
||
+ struct pending_tx_info *tx_info;
|
||
int nr_frags = shinfo->nr_frags;
|
||
int i, err, start;
|
||
+ u16 peek; /* peek into next tx request */
|
||
|
||
/* Check status of header. */
|
||
err = gop->status;
|
||
@@ -1004,11 +1143,20 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
|
||
|
||
for (i = start; i < nr_frags; i++) {
|
||
int j, newerr;
|
||
+ pending_ring_idx_t head;
|
||
|
||
pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
|
||
+ tx_info = &netbk->pending_tx_info[pending_idx];
|
||
+ head = tx_info->head;
|
||
|
||
/* Check error status: if okay then remember grant handle. */
|
||
- newerr = (++gop)->status;
|
||
+ do {
|
||
+ newerr = (++gop)->status;
|
||
+ if (newerr)
|
||
+ break;
|
||
+ peek = netbk->pending_ring[pending_index(++head)];
|
||
+ } while (!pending_tx_is_head(netbk, peek));
|
||
+
|
||
if (likely(!newerr)) {
|
||
/* Had a previous error? Invalidate this fragment. */
|
||
if (unlikely(err))
|
||
@@ -1197,9 +1345,8 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
|
||
|
||
static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
|
||
{
|
||
- unsigned long now = jiffies;
|
||
- unsigned long next_credit =
|
||
- vif->credit_timeout.expires +
|
||
+ u64 now = get_jiffies_64();
|
||
+ u64 next_credit = vif->credit_window_start +
|
||
msecs_to_jiffies(vif->credit_usec / 1000);
|
||
|
||
/* Timer could already be pending in rare cases. */
|
||
@@ -1207,8 +1354,8 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
|
||
return true;
|
||
|
||
/* Passed the point where we can replenish credit? */
|
||
- if (time_after_eq(now, next_credit)) {
|
||
- vif->credit_timeout.expires = now;
|
||
+ if (time_after_eq64(now, next_credit)) {
|
||
+ vif->credit_window_start = now;
|
||
tx_add_credit(vif);
|
||
}
|
||
|
||
@@ -1220,6 +1367,7 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
|
||
tx_credit_callback;
|
||
mod_timer(&vif->credit_timeout,
|
||
next_credit);
|
||
+ vif->credit_window_start = next_credit;
|
||
|
||
return true;
|
||
}
|
||
@@ -1233,11 +1381,12 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
|
||
struct sk_buff *skb;
|
||
int ret;
|
||
|
||
- while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
|
||
+ while ((nr_pending_reqs(netbk) + XEN_NETIF_NR_SLOTS_MIN
|
||
+ < MAX_PENDING_REQS) &&
|
||
!list_empty(&netbk->net_schedule_list)) {
|
||
struct xenvif *vif;
|
||
struct xen_netif_tx_request txreq;
|
||
- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
|
||
+ struct xen_netif_tx_request txfrags[max_skb_slots];
|
||
struct page *page;
|
||
struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
|
||
u16 pending_idx;
|
||
@@ -1298,7 +1447,8 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
|
||
continue;
|
||
}
|
||
|
||
- ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do);
|
||
+ ret = netbk_count_requests(vif, &txreq, idx,
|
||
+ txfrags, work_to_do);
|
||
if (unlikely(ret < 0))
|
||
continue;
|
||
|
||
@@ -1325,7 +1475,7 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
|
||
pending_idx = netbk->pending_ring[index];
|
||
|
||
data_len = (txreq.size > PKT_PROT_LEN &&
|
||
- ret < MAX_SKB_FRAGS) ?
|
||
+ ret < XEN_NETIF_NR_SLOTS_MIN) ?
|
||
PKT_PROT_LEN : txreq.size;
|
||
|
||
skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
|
||
@@ -1375,6 +1525,7 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
|
||
memcpy(&netbk->pending_tx_info[pending_idx].req,
|
||
&txreq, sizeof(txreq));
|
||
netbk->pending_tx_info[pending_idx].vif = vif;
|
||
+ netbk->pending_tx_info[pending_idx].head = index;
|
||
*((u16 *)skb->data) = pending_idx;
|
||
|
||
__skb_put(skb, data_len);
|
||
@@ -1505,7 +1656,10 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx,
|
||
{
|
||
struct xenvif *vif;
|
||
struct pending_tx_info *pending_tx_info;
|
||
- pending_ring_idx_t index;
|
||
+ pending_ring_idx_t head;
|
||
+ u16 peek; /* peek into next tx request */
|
||
+
|
||
+ BUG_ON(netbk->mmap_pages[pending_idx] == (void *)(~0UL));
|
||
|
||
/* Already complete? */
|
||
if (netbk->mmap_pages[pending_idx] == NULL)
|
||
@@ -1514,19 +1668,40 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx,
|
||
pending_tx_info = &netbk->pending_tx_info[pending_idx];
|
||
|
||
vif = pending_tx_info->vif;
|
||
+ head = pending_tx_info->head;
|
||
|
||
- make_tx_response(vif, &pending_tx_info->req, status);
|
||
+ BUG_ON(!pending_tx_is_head(netbk, head));
|
||
+ BUG_ON(netbk->pending_ring[pending_index(head)] != pending_idx);
|
||
|
||
- index = pending_index(netbk->pending_prod++);
|
||
- netbk->pending_ring[index] = pending_idx;
|
||
+ do {
|
||
+ pending_ring_idx_t index;
|
||
+ pending_ring_idx_t idx = pending_index(head);
|
||
+ u16 info_idx = netbk->pending_ring[idx];
|
||
|
||
- xenvif_put(vif);
|
||
+ pending_tx_info = &netbk->pending_tx_info[info_idx];
|
||
+ make_tx_response(vif, &pending_tx_info->req, status);
|
||
+
|
||
+ /* Setting any number other than
|
||
+ * INVALID_PENDING_RING_IDX indicates this slot is
|
||
+ * starting a new packet / ending a previous packet.
|
||
+ */
|
||
+ pending_tx_info->head = 0;
|
||
+
|
||
+ index = pending_index(netbk->pending_prod++);
|
||
+ netbk->pending_ring[index] = netbk->pending_ring[info_idx];
|
||
+
|
||
+ xenvif_put(vif);
|
||
+
|
||
+ peek = netbk->pending_ring[pending_index(++head)];
|
||
+
|
||
+ } while (!pending_tx_is_head(netbk, peek));
|
||
|
||
netbk->mmap_pages[pending_idx]->mapping = 0;
|
||
put_page(netbk->mmap_pages[pending_idx]);
|
||
netbk->mmap_pages[pending_idx] = NULL;
|
||
}
|
||
|
||
+
|
||
static void make_tx_response(struct xenvif *vif,
|
||
struct xen_netif_tx_request *txp,
|
||
s8 st)
|
||
@@ -1579,8 +1754,9 @@ static inline int rx_work_todo(struct xen_netbk *netbk)
|
||
static inline int tx_work_todo(struct xen_netbk *netbk)
|
||
{
|
||
|
||
- if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
|
||
- !list_empty(&netbk->net_schedule_list))
|
||
+ if ((nr_pending_reqs(netbk) + XEN_NETIF_NR_SLOTS_MIN
|
||
+ < MAX_PENDING_REQS) &&
|
||
+ !list_empty(&netbk->net_schedule_list))
|
||
return 1;
|
||
|
||
return 0;
|
||
@@ -1663,6 +1839,13 @@ static int __init netback_init(void)
|
||
if (!xen_domain())
|
||
return -ENODEV;
|
||
|
||
+ if (max_skb_slots < XEN_NETIF_NR_SLOTS_MIN) {
|
||
+ printk(KERN_INFO
|
||
+ "xen-netback: max_skb_slots too small (%d), bump it to XEN_NETIF_NR_SLOTS_MIN (%d)\n",
|
||
+ max_skb_slots, XEN_NETIF_NR_SLOTS_MIN);
|
||
+ max_skb_slots = XEN_NETIF_NR_SLOTS_MIN;
|
||
+ }
|
||
+
|
||
xen_netbk_group_nr = num_online_cpus();
|
||
xen_netbk = vzalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
|
||
if (!xen_netbk)
|
||
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
|
||
index 796afbf..fe50f14 100644
|
||
--- a/drivers/net/xen-netfront.c
|
||
+++ b/drivers/net/xen-netfront.c
|
||
@@ -36,7 +36,7 @@
|
||
#include <linux/skbuff.h>
|
||
#include <linux/ethtool.h>
|
||
#include <linux/if_ether.h>
|
||
-#include <linux/tcp.h>
|
||
+#include <net/tcp.h>
|
||
#include <linux/udp.h>
|
||
#include <linux/moduleparam.h>
|
||
#include <linux/mm.h>
|
||
@@ -492,6 +492,16 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||
unsigned int len = skb_headlen(skb);
|
||
unsigned long flags;
|
||
|
||
+ /* If skb->len is too big for wire format, drop skb and alert
|
||
+ * user about misconfiguration.
|
||
+ */
|
||
+ if (unlikely(skb->len > XEN_NETIF_MAX_TX_SIZE)) {
|
||
+ net_alert_ratelimited(
|
||
+ "xennet: skb->len = %u, too big for wire format\n",
|
||
+ skb->len);
|
||
+ goto drop;
|
||
+ }
|
||
+
|
||
frags += DIV_ROUND_UP(offset + len, PAGE_SIZE);
|
||
if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
|
||
printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
|
||
@@ -1045,7 +1055,8 @@ static int xennet_poll(struct napi_struct *napi, int budget)
|
||
|
||
static int xennet_change_mtu(struct net_device *dev, int mtu)
|
||
{
|
||
- int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
|
||
+ int max = xennet_can_sg(dev) ?
|
||
+ XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER : ETH_DATA_LEN;
|
||
|
||
if (mtu > max)
|
||
return -EINVAL;
|
||
@@ -1349,6 +1360,8 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev
|
||
SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
|
||
SET_NETDEV_DEV(netdev, &dev->dev);
|
||
|
||
+ netif_set_gso_max_size(netdev, XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER);
|
||
+
|
||
np->netdev = netdev;
|
||
|
||
netif_carrier_off(netdev);
|
||
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
|
||
index 0cb64f5..a655ae2 100644
|
||
--- a/drivers/parport/parport_pc.c
|
||
+++ b/drivers/parport/parport_pc.c
|
||
@@ -2875,8 +2875,6 @@ enum parport_pc_pci_cards {
|
||
syba_2p_epp,
|
||
syba_1p_ecp,
|
||
titan_010l,
|
||
- titan_1284p1,
|
||
- titan_1284p2,
|
||
avlab_1p,
|
||
avlab_2p,
|
||
oxsemi_952,
|
||
@@ -2935,8 +2933,6 @@ static struct parport_pc_pci {
|
||
/* syba_2p_epp AP138B */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } },
|
||
/* syba_1p_ecp W83787 */ { 1, { { 0, 0x078 }, } },
|
||
/* titan_010l */ { 1, { { 3, -1 }, } },
|
||
- /* titan_1284p1 */ { 1, { { 0, 1 }, } },
|
||
- /* titan_1284p2 */ { 2, { { 0, 1 }, { 2, 3 }, } },
|
||
/* avlab_1p */ { 1, { { 0, 1}, } },
|
||
/* avlab_2p */ { 2, { { 0, 1}, { 2, 3 },} },
|
||
/* The Oxford Semi cards are unusual: 954 doesn't support ECP,
|
||
@@ -2952,8 +2948,8 @@ static struct parport_pc_pci {
|
||
/* netmos_9705 */ { 1, { { 0, -1 }, } },
|
||
/* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} },
|
||
/* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} },
|
||
- /* netmos_9805 */ { 1, { { 0, -1 }, } },
|
||
- /* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } },
|
||
+ /* netmos_9805 */ { 1, { { 0, 1 }, } },
|
||
+ /* netmos_9815 */ { 2, { { 0, 1 }, { 2, 3 }, } },
|
||
/* netmos_9901 */ { 1, { { 0, -1 }, } },
|
||
/* netmos_9865 */ { 1, { { 0, -1 }, } },
|
||
/* quatech_sppxp100 */ { 1, { { 0, 1 }, } },
|
||
@@ -2997,8 +2993,6 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
|
||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_1p_ecp },
|
||
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L,
|
||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l },
|
||
- { 0x9710, 0x9805, 0x1000, 0x0010, 0, 0, titan_1284p1 },
|
||
- { 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 },
|
||
/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
|
||
/* AFAVLAB_TK9902 */
|
||
{ 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p},
|
||
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
|
||
index 1b69d95..b849f995 100644
|
||
--- a/drivers/pci/hotplug/shpchp.h
|
||
+++ b/drivers/pci/hotplug/shpchp.h
|
||
@@ -46,7 +46,6 @@
|
||
extern bool shpchp_poll_mode;
|
||
extern int shpchp_poll_time;
|
||
extern bool shpchp_debug;
|
||
-extern struct workqueue_struct *shpchp_wq;
|
||
|
||
#define dbg(format, arg...) \
|
||
do { \
|
||
@@ -90,6 +89,7 @@ struct slot {
|
||
struct list_head slot_list;
|
||
struct delayed_work work; /* work for button event */
|
||
struct mutex lock;
|
||
+ struct workqueue_struct *wq;
|
||
u8 hp_slot;
|
||
};
|
||
|
||
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
|
||
index 5f1f0d9..dd37452 100644
|
||
--- a/drivers/pci/hotplug/shpchp_core.c
|
||
+++ b/drivers/pci/hotplug/shpchp_core.c
|
||
@@ -39,7 +39,6 @@
|
||
bool shpchp_debug;
|
||
bool shpchp_poll_mode;
|
||
int shpchp_poll_time;
|
||
-struct workqueue_struct *shpchp_wq;
|
||
|
||
#define DRIVER_VERSION "0.4"
|
||
#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
|
||
@@ -122,6 +121,14 @@ static int init_slots(struct controller *ctrl)
|
||
slot->device = ctrl->slot_device_offset + i;
|
||
slot->hpc_ops = ctrl->hpc_ops;
|
||
slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i);
|
||
+
|
||
+ snprintf(name, sizeof(name), "shpchp-%d", slot->number);
|
||
+ slot->wq = alloc_workqueue(name, 0, 0);
|
||
+ if (!slot->wq) {
|
||
+ retval = -ENOMEM;
|
||
+ goto error_info;
|
||
+ }
|
||
+
|
||
mutex_init(&slot->lock);
|
||
INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work);
|
||
|
||
@@ -141,7 +148,7 @@ static int init_slots(struct controller *ctrl)
|
||
if (retval) {
|
||
ctrl_err(ctrl, "pci_hp_register failed with error %d\n",
|
||
retval);
|
||
- goto error_info;
|
||
+ goto error_slotwq;
|
||
}
|
||
|
||
get_power_status(hotplug_slot, &info->power_status);
|
||
@@ -153,6 +160,8 @@ static int init_slots(struct controller *ctrl)
|
||
}
|
||
|
||
return 0;
|
||
+error_slotwq:
|
||
+ destroy_workqueue(slot->wq);
|
||
error_info:
|
||
kfree(info);
|
||
error_hpslot:
|
||
@@ -173,7 +182,7 @@ void cleanup_slots(struct controller *ctrl)
|
||
slot = list_entry(tmp, struct slot, slot_list);
|
||
list_del(&slot->slot_list);
|
||
cancel_delayed_work(&slot->work);
|
||
- flush_workqueue(shpchp_wq);
|
||
+ destroy_workqueue(slot->wq);
|
||
pci_hp_deregister(slot->hotplug_slot);
|
||
}
|
||
}
|
||
@@ -356,18 +365,12 @@ static struct pci_driver shpc_driver = {
|
||
|
||
static int __init shpcd_init(void)
|
||
{
|
||
- int retval = 0;
|
||
-
|
||
- shpchp_wq = alloc_ordered_workqueue("shpchp", 0);
|
||
- if (!shpchp_wq)
|
||
- return -ENOMEM;
|
||
+ int retval;
|
||
|
||
retval = pci_register_driver(&shpc_driver);
|
||
dbg("%s: pci_register_driver = %d\n", __func__, retval);
|
||
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
|
||
- if (retval) {
|
||
- destroy_workqueue(shpchp_wq);
|
||
- }
|
||
+
|
||
return retval;
|
||
}
|
||
|
||
@@ -375,7 +378,6 @@ static void __exit shpcd_cleanup(void)
|
||
{
|
||
dbg("unload_shpchpd()\n");
|
||
pci_unregister_driver(&shpc_driver);
|
||
- destroy_workqueue(shpchp_wq);
|
||
info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
|
||
}
|
||
|
||
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
|
||
index bba5b3e..b888675 100644
|
||
--- a/drivers/pci/hotplug/shpchp_ctrl.c
|
||
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
|
||
@@ -51,7 +51,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
|
||
info->p_slot = p_slot;
|
||
INIT_WORK(&info->work, interrupt_event_handler);
|
||
|
||
- queue_work(shpchp_wq, &info->work);
|
||
+ queue_work(p_slot->wq, &info->work);
|
||
|
||
return 0;
|
||
}
|
||
@@ -285,8 +285,8 @@ static int board_added(struct slot *p_slot)
|
||
return WRONG_BUS_FREQUENCY;
|
||
}
|
||
|
||
- bsp = ctrl->pci_dev->bus->cur_bus_speed;
|
||
- msp = ctrl->pci_dev->bus->max_bus_speed;
|
||
+ bsp = ctrl->pci_dev->subordinate->cur_bus_speed;
|
||
+ msp = ctrl->pci_dev->subordinate->max_bus_speed;
|
||
|
||
/* Check if there are other slots or devices on the same bus */
|
||
if (!list_empty(&ctrl->pci_dev->subordinate->devices))
|
||
@@ -456,7 +456,7 @@ void shpchp_queue_pushbutton_work(struct work_struct *work)
|
||
kfree(info);
|
||
goto out;
|
||
}
|
||
- queue_work(shpchp_wq, &info->work);
|
||
+ queue_work(p_slot->wq, &info->work);
|
||
out:
|
||
mutex_unlock(&p_slot->lock);
|
||
}
|
||
@@ -504,7 +504,7 @@ static void handle_button_press_event(struct slot *p_slot)
|
||
p_slot->hpc_ops->green_led_blink(p_slot);
|
||
p_slot->hpc_ops->set_attention_status(p_slot, 0);
|
||
|
||
- queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ);
|
||
+ queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
|
||
break;
|
||
case BLINKINGOFF_STATE:
|
||
case BLINKINGON_STATE:
|
||
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
|
||
index 2ab18ec..92f38e7 100644
|
||
--- a/drivers/pci/pci-driver.c
|
||
+++ b/drivers/pci/pci-driver.c
|
||
@@ -663,6 +663,7 @@ static int pci_pm_suspend(struct device *dev)
|
||
goto Fixup;
|
||
}
|
||
|
||
+ pci_dev->state_saved = false;
|
||
if (pm->suspend) {
|
||
pci_power_t prev = pci_dev->current_state;
|
||
int error;
|
||
@@ -809,6 +810,7 @@ static int pci_pm_freeze(struct device *dev)
|
||
return 0;
|
||
}
|
||
|
||
+ pci_dev->state_saved = false;
|
||
if (pm->freeze) {
|
||
int error;
|
||
|
||
@@ -897,6 +899,7 @@ static int pci_pm_poweroff(struct device *dev)
|
||
goto Fixup;
|
||
}
|
||
|
||
+ pci_dev->state_saved = false;
|
||
if (pm->poweroff) {
|
||
int error;
|
||
|
||
@@ -1015,6 +1018,7 @@ static int pci_pm_runtime_suspend(struct device *dev)
|
||
if (!pm || !pm->runtime_suspend)
|
||
return -ENOSYS;
|
||
|
||
+ pci_dev->state_saved = false;
|
||
error = pm->runtime_suspend(dev);
|
||
suspend_report_result(pm->runtime_suspend, error);
|
||
if (error)
|
||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
|
||
index d08c0d8..4cdd2bc 100644
|
||
--- a/drivers/pci/pci.c
|
||
+++ b/drivers/pci/pci.c
|
||
@@ -1984,10 +1984,6 @@ void pci_enable_ari(struct pci_dev *dev)
|
||
if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
|
||
return;
|
||
|
||
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
|
||
- if (!pos)
|
||
- return;
|
||
-
|
||
bridge = dev->bus->self;
|
||
if (!bridge || !pci_is_pcie(bridge))
|
||
return;
|
||
@@ -2006,10 +2002,14 @@ void pci_enable_ari(struct pci_dev *dev)
|
||
return;
|
||
|
||
pci_read_config_word(bridge, pos + PCI_EXP_DEVCTL2, &ctrl);
|
||
- ctrl |= PCI_EXP_DEVCTL2_ARI;
|
||
+ if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) {
|
||
+ ctrl |= PCI_EXP_DEVCTL2_ARI;
|
||
+ bridge->ari_enabled = 1;
|
||
+ } else {
|
||
+ ctrl &= ~PCI_EXP_DEVCTL2_ARI;
|
||
+ bridge->ari_enabled = 0;
|
||
+ }
|
||
pci_write_config_word(bridge, pos + PCI_EXP_DEVCTL2, ctrl);
|
||
-
|
||
- bridge->ari_enabled = 1;
|
||
}
|
||
|
||
/**
|
||
@@ -3610,7 +3610,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
|
||
u16 cmd;
|
||
int rc;
|
||
|
||
- WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
|
||
+ WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) && (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
|
||
|
||
/* ARCH specific VGA enables */
|
||
rc = pci_set_vga_state_arch(dev, decode, command_bits, flags);
|
||
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
|
||
index 474f22f..c9ce611 100644
|
||
--- a/drivers/pci/pcie/aspm.c
|
||
+++ b/drivers/pci/pcie/aspm.c
|
||
@@ -583,6 +583,9 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
||
struct pcie_link_state *link;
|
||
int blacklist = !!pcie_aspm_sanity_check(pdev);
|
||
|
||
+ if (!aspm_support_enabled)
|
||
+ return;
|
||
+
|
||
if (!pci_is_pcie(pdev) || pdev->link_state)
|
||
return;
|
||
if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
|
||
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
|
||
index e0610bd..7e41b70 100644
|
||
--- a/drivers/pci/pcie/portdrv_pci.c
|
||
+++ b/drivers/pci/pcie/portdrv_pci.c
|
||
@@ -151,7 +151,6 @@ static int __devinit pcie_portdrv_probe(struct pci_dev *dev,
|
||
static void pcie_portdrv_remove(struct pci_dev *dev)
|
||
{
|
||
pcie_port_device_remove(dev);
|
||
- pci_disable_device(dev);
|
||
}
|
||
|
||
static int error_detected_iter(struct device *device, void *data)
|
||
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
|
||
index 103c95e..61bc33e 100644
|
||
--- a/drivers/pci/quirks.c
|
||
+++ b/drivers/pci/quirks.c
|
||
@@ -2921,6 +2921,7 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev)
|
||
}
|
||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
|
||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
|
||
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
|
||
|
||
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
|
||
struct pci_fixup *end)
|
||
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
|
||
index eea85da..be76eba 100644
|
||
--- a/drivers/pci/setup-res.c
|
||
+++ b/drivers/pci/setup-res.c
|
||
@@ -206,7 +206,8 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
|
||
return ret;
|
||
}
|
||
|
||
-static int _pci_assign_resource(struct pci_dev *dev, int resno, int size, resource_size_t min_align)
|
||
+static int _pci_assign_resource(struct pci_dev *dev, int resno,
|
||
+ resource_size_t size, resource_size_t min_align)
|
||
{
|
||
struct resource *res = dev->resource + resno;
|
||
struct pci_bus *bus;
|
||
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
|
||
index fdacfce..0076fea 100644
|
||
--- a/drivers/platform/x86/hp_accel.c
|
||
+++ b/drivers/platform/x86/hp_accel.c
|
||
@@ -77,6 +77,7 @@ static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
|
||
static struct acpi_device_id lis3lv02d_device_ids[] = {
|
||
{"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
|
||
{"HPQ6000", 0}, /* HP Mobile Data Protection System PNP */
|
||
+ {"HPQ6007", 0}, /* HP Mobile Data Protection System PNP */
|
||
{"", 0},
|
||
};
|
||
MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
|
||
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
|
||
index 2264331..b96766b 100644
|
||
--- a/drivers/platform/x86/msi-wmi.c
|
||
+++ b/drivers/platform/x86/msi-wmi.c
|
||
@@ -176,7 +176,7 @@ static void msi_wmi_notify(u32 value, void *context)
|
||
pr_debug("Suppressed key event 0x%X - "
|
||
"Last press was %lld us ago\n",
|
||
key->code, ktime_to_us(diff));
|
||
- return;
|
||
+ goto msi_wmi_notify_exit;
|
||
}
|
||
last_pressed[key->code - SCANCODE_BASE] = cur;
|
||
|
||
@@ -195,6 +195,8 @@ static void msi_wmi_notify(u32 value, void *context)
|
||
pr_info("Unknown key pressed - %x\n", eventcode);
|
||
} else
|
||
pr_info("Unknown event received\n");
|
||
+
|
||
+msi_wmi_notify_exit:
|
||
kfree(response.pointer);
|
||
}
|
||
|
||
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
|
||
index f08aee6..aa232de 100644
|
||
--- a/drivers/platform/x86/thinkpad_acpi.c
|
||
+++ b/drivers/platform/x86/thinkpad_acpi.c
|
||
@@ -3402,7 +3402,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
||
/* Do not issue duplicate brightness change events to
|
||
* userspace. tpacpi_detect_brightness_capabilities() must have
|
||
* been called before this point */
|
||
- if (tp_features.bright_acpimode && acpi_video_backlight_support()) {
|
||
+ if (acpi_video_backlight_support()) {
|
||
pr_info("This ThinkPad has standard ACPI backlight "
|
||
"brightness control, supported by the ACPI "
|
||
"video driver\n");
|
||
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c
|
||
index c284143..ec8b948 100644
|
||
--- a/drivers/power/max17040_battery.c
|
||
+++ b/drivers/power/max17040_battery.c
|
||
@@ -148,7 +148,7 @@ static void max17040_get_online(struct i2c_client *client)
|
||
{
|
||
struct max17040_chip *chip = i2c_get_clientdata(client);
|
||
|
||
- if (chip->pdata->battery_online)
|
||
+ if (chip->pdata && chip->pdata->battery_online)
|
||
chip->online = chip->pdata->battery_online();
|
||
else
|
||
chip->online = 1;
|
||
@@ -158,7 +158,8 @@ static void max17040_get_status(struct i2c_client *client)
|
||
{
|
||
struct max17040_chip *chip = i2c_get_clientdata(client);
|
||
|
||
- if (!chip->pdata->charger_online || !chip->pdata->charger_enable) {
|
||
+ if (!chip->pdata || !chip->pdata->charger_online
|
||
+ || !chip->pdata->charger_enable) {
|
||
chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
|
||
return;
|
||
}
|
||
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
|
||
index 79451f2..60cee9e 100644
|
||
--- a/drivers/pps/clients/pps-ldisc.c
|
||
+++ b/drivers/pps/clients/pps-ldisc.c
|
||
@@ -31,7 +31,7 @@
|
||
static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
|
||
struct pps_event_time *ts)
|
||
{
|
||
- struct pps_device *pps = (struct pps_device *)tty->disc_data;
|
||
+ struct pps_device *pps = pps_lookup_dev(tty);
|
||
|
||
BUG_ON(pps == NULL);
|
||
|
||
@@ -67,9 +67,9 @@ static int pps_tty_open(struct tty_struct *tty)
|
||
pr_err("cannot register PPS source \"%s\"\n", info.path);
|
||
return -ENOMEM;
|
||
}
|
||
- tty->disc_data = pps;
|
||
+ pps->lookup_cookie = tty;
|
||
|
||
- /* Should open N_TTY ldisc too */
|
||
+ /* Now open the base class N_TTY ldisc */
|
||
ret = alias_n_tty_open(tty);
|
||
if (ret < 0) {
|
||
pr_err("cannot open tty ldisc \"%s\"\n", info.path);
|
||
@@ -81,7 +81,6 @@ static int pps_tty_open(struct tty_struct *tty)
|
||
return 0;
|
||
|
||
err_unregister:
|
||
- tty->disc_data = NULL;
|
||
pps_unregister_source(pps);
|
||
return ret;
|
||
}
|
||
@@ -90,11 +89,10 @@ static void (*alias_n_tty_close)(struct tty_struct *tty);
|
||
|
||
static void pps_tty_close(struct tty_struct *tty)
|
||
{
|
||
- struct pps_device *pps = (struct pps_device *)tty->disc_data;
|
||
+ struct pps_device *pps = pps_lookup_dev(tty);
|
||
|
||
alias_n_tty_close(tty);
|
||
|
||
- tty->disc_data = NULL;
|
||
dev_info(pps->dev, "removed\n");
|
||
pps_unregister_source(pps);
|
||
}
|
||
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
|
||
index 98fbe62..f129f4d 100644
|
||
--- a/drivers/pps/pps.c
|
||
+++ b/drivers/pps/pps.c
|
||
@@ -247,12 +247,15 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
|
||
struct pps_device *pps = container_of(inode->i_cdev,
|
||
struct pps_device, cdev);
|
||
file->private_data = pps;
|
||
-
|
||
+ kobject_get(&pps->dev->kobj);
|
||
return 0;
|
||
}
|
||
|
||
static int pps_cdev_release(struct inode *inode, struct file *file)
|
||
{
|
||
+ struct pps_device *pps = container_of(inode->i_cdev,
|
||
+ struct pps_device, cdev);
|
||
+ kobject_put(&pps->dev->kobj);
|
||
return 0;
|
||
}
|
||
|
||
@@ -274,8 +277,10 @@ static void pps_device_destruct(struct device *dev)
|
||
{
|
||
struct pps_device *pps = dev_get_drvdata(dev);
|
||
|
||
- /* release id here to protect others from using it while it's
|
||
- * still in use */
|
||
+ cdev_del(&pps->cdev);
|
||
+
|
||
+ /* Now we can release the ID for re-use */
|
||
+ pr_debug("deallocating pps%d\n", pps->id);
|
||
mutex_lock(&pps_idr_lock);
|
||
idr_remove(&pps_idr, pps->id);
|
||
mutex_unlock(&pps_idr_lock);
|
||
@@ -330,6 +335,7 @@ int pps_register_cdev(struct pps_device *pps)
|
||
if (IS_ERR(pps->dev))
|
||
goto del_cdev;
|
||
|
||
+ /* Override the release function with our own */
|
||
pps->dev->release = pps_device_destruct;
|
||
|
||
pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
|
||
@@ -350,11 +356,44 @@ int pps_register_cdev(struct pps_device *pps)
|
||
|
||
void pps_unregister_cdev(struct pps_device *pps)
|
||
{
|
||
+ pr_debug("unregistering pps%d\n", pps->id);
|
||
+ pps->lookup_cookie = NULL;
|
||
device_destroy(pps_class, pps->dev->devt);
|
||
- cdev_del(&pps->cdev);
|
||
}
|
||
|
||
/*
|
||
+ * Look up a pps device by magic cookie.
|
||
+ * The cookie is usually a pointer to some enclosing device, but this
|
||
+ * code doesn't care; you should never be dereferencing it.
|
||
+ *
|
||
+ * This is a bit of a kludge that is currently used only by the PPS
|
||
+ * serial line discipline. It may need to be tweaked when a second user
|
||
+ * is found.
|
||
+ *
|
||
+ * There is no function interface for setting the lookup_cookie field.
|
||
+ * It's initialized to NULL when the pps device is created, and if a
|
||
+ * client wants to use it, just fill it in afterward.
|
||
+ *
|
||
+ * The cookie is automatically set to NULL in pps_unregister_source()
|
||
+ * so that it will not be used again, even if the pps device cannot
|
||
+ * be removed from the idr due to pending references holding the minor
|
||
+ * number in use.
|
||
+ */
|
||
+struct pps_device *pps_lookup_dev(void const *cookie)
|
||
+{
|
||
+ struct pps_device *pps;
|
||
+ unsigned id;
|
||
+
|
||
+ rcu_read_lock();
|
||
+ idr_for_each_entry(&pps_idr, pps, id)
|
||
+ if (cookie == pps->lookup_cookie)
|
||
+ break;
|
||
+ rcu_read_unlock();
|
||
+ return pps;
|
||
+}
|
||
+EXPORT_SYMBOL(pps_lookup_dev);
|
||
+
|
||
+/*
|
||
* Module stuff
|
||
*/
|
||
|
||
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
|
||
index 33471e1..84eab3f 100644
|
||
--- a/drivers/rapidio/devices/tsi721.c
|
||
+++ b/drivers/rapidio/devices/tsi721.c
|
||
@@ -475,6 +475,10 @@ static irqreturn_t tsi721_irqhandler(int irq, void *ptr)
|
||
u32 intval;
|
||
u32 ch_inte;
|
||
|
||
+ /* For MSI mode disable all device-level interrupts */
|
||
+ if (priv->flags & TSI721_USING_MSI)
|
||
+ iowrite32(0, priv->regs + TSI721_DEV_INTE);
|
||
+
|
||
dev_int = ioread32(priv->regs + TSI721_DEV_INT);
|
||
if (!dev_int)
|
||
return IRQ_NONE;
|
||
@@ -548,6 +552,13 @@ static irqreturn_t tsi721_irqhandler(int irq, void *ptr)
|
||
tsi721_pw_handler(mport);
|
||
}
|
||
|
||
+ /* For MSI mode re-enable device-level interrupts */
|
||
+ if (priv->flags & TSI721_USING_MSI) {
|
||
+ dev_int = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO |
|
||
+ TSI721_DEV_INT_SMSG_CH;
|
||
+ iowrite32(dev_int, priv->regs + TSI721_DEV_INTE);
|
||
+ }
|
||
+
|
||
return IRQ_HANDLED;
|
||
}
|
||
|
||
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
|
||
index 17a58c5..8350f50 100644
|
||
--- a/drivers/regulator/max8997.c
|
||
+++ b/drivers/regulator/max8997.c
|
||
@@ -71,26 +71,26 @@ struct voltage_map_desc {
|
||
unsigned int n_bits;
|
||
};
|
||
|
||
-/* Voltage maps in mV */
|
||
+/* Voltage maps in uV */
|
||
static const struct voltage_map_desc ldo_voltage_map_desc = {
|
||
- .min = 800, .max = 3950, .step = 50, .n_bits = 6,
|
||
+ .min = 800000, .max = 3950000, .step = 50000, .n_bits = 6,
|
||
}; /* LDO1 ~ 18, 21 all */
|
||
|
||
static const struct voltage_map_desc buck1245_voltage_map_desc = {
|
||
- .min = 650, .max = 2225, .step = 25, .n_bits = 6,
|
||
+ .min = 650000, .max = 2225000, .step = 25000, .n_bits = 6,
|
||
}; /* Buck1, 2, 4, 5 */
|
||
|
||
static const struct voltage_map_desc buck37_voltage_map_desc = {
|
||
- .min = 750, .max = 3900, .step = 50, .n_bits = 6,
|
||
+ .min = 750000, .max = 3900000, .step = 50000, .n_bits = 6,
|
||
}; /* Buck3, 7 */
|
||
|
||
-/* current map in mA */
|
||
+/* current map in uA */
|
||
static const struct voltage_map_desc charger_current_map_desc = {
|
||
- .min = 200, .max = 950, .step = 50, .n_bits = 4,
|
||
+ .min = 200000, .max = 950000, .step = 50000, .n_bits = 4,
|
||
};
|
||
|
||
static const struct voltage_map_desc topoff_current_map_desc = {
|
||
- .min = 50, .max = 200, .step = 10, .n_bits = 4,
|
||
+ .min = 50000, .max = 200000, .step = 10000, .n_bits = 4,
|
||
};
|
||
|
||
static const struct voltage_map_desc *reg_voltage_map[] = {
|
||
@@ -194,7 +194,7 @@ static int max8997_list_voltage(struct regulator_dev *rdev,
|
||
if (val > desc->max)
|
||
return -EINVAL;
|
||
|
||
- return val * 1000;
|
||
+ return val;
|
||
}
|
||
|
||
static int max8997_get_enable_register(struct regulator_dev *rdev,
|
||
@@ -496,7 +496,6 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
|
||
{
|
||
struct max8997_data *max8997 = rdev_get_drvdata(rdev);
|
||
struct i2c_client *i2c = max8997->iodev->i2c;
|
||
- int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
|
||
const struct voltage_map_desc *desc;
|
||
int rid = rdev_get_id(rdev);
|
||
int reg, shift = 0, mask, ret;
|
||
@@ -522,7 +521,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
|
||
|
||
desc = reg_voltage_map[rid];
|
||
|
||
- i = max8997_get_voltage_proper_val(desc, min_vol, max_vol);
|
||
+ i = max8997_get_voltage_proper_val(desc, min_uV, max_uV);
|
||
if (i < 0)
|
||
return i;
|
||
|
||
@@ -541,7 +540,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
|
||
/* If the voltage is increasing */
|
||
if (org < i)
|
||
udelay(DIV_ROUND_UP(desc->step * (i - org),
|
||
- max8997->ramp_delay));
|
||
+ max8997->ramp_delay * 1000));
|
||
}
|
||
|
||
return ret;
|
||
@@ -640,7 +639,6 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev,
|
||
const struct voltage_map_desc *desc;
|
||
int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg;
|
||
bool gpio_dvs_mode = false;
|
||
- int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
|
||
|
||
if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7)
|
||
return -EINVAL;
|
||
@@ -665,7 +663,7 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev,
|
||
selector);
|
||
|
||
desc = reg_voltage_map[rid];
|
||
- new_val = max8997_get_voltage_proper_val(desc, min_vol, max_vol);
|
||
+ new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV);
|
||
if (new_val < 0)
|
||
return new_val;
|
||
|
||
@@ -997,8 +995,8 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
|
||
max8997->buck1_vol[i] = ret =
|
||
max8997_get_voltage_proper_val(
|
||
&buck1245_voltage_map_desc,
|
||
- pdata->buck1_voltage[i] / 1000,
|
||
- pdata->buck1_voltage[i] / 1000 +
|
||
+ pdata->buck1_voltage[i],
|
||
+ pdata->buck1_voltage[i] +
|
||
buck1245_voltage_map_desc.step);
|
||
if (ret < 0)
|
||
goto err_alloc;
|
||
@@ -1006,8 +1004,8 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
|
||
max8997->buck2_vol[i] = ret =
|
||
max8997_get_voltage_proper_val(
|
||
&buck1245_voltage_map_desc,
|
||
- pdata->buck2_voltage[i] / 1000,
|
||
- pdata->buck2_voltage[i] / 1000 +
|
||
+ pdata->buck2_voltage[i],
|
||
+ pdata->buck2_voltage[i] +
|
||
buck1245_voltage_map_desc.step);
|
||
if (ret < 0)
|
||
goto err_alloc;
|
||
@@ -1015,8 +1013,8 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
|
||
max8997->buck5_vol[i] = ret =
|
||
max8997_get_voltage_proper_val(
|
||
&buck1245_voltage_map_desc,
|
||
- pdata->buck5_voltage[i] / 1000,
|
||
- pdata->buck5_voltage[i] / 1000 +
|
||
+ pdata->buck5_voltage[i],
|
||
+ pdata->buck5_voltage[i] +
|
||
buck1245_voltage_map_desc.step);
|
||
if (ret < 0)
|
||
goto err_alloc;
|
||
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
|
||
index 5890265..1300383 100644
|
||
--- a/drivers/regulator/max8998.c
|
||
+++ b/drivers/regulator/max8998.c
|
||
@@ -492,7 +492,7 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
|
||
|
||
difference = desc->min + desc->step*i - previous_vol/1000;
|
||
if (difference > 0)
|
||
- udelay(difference / ((val & 0x0f) + 1));
|
||
+ udelay(DIV_ROUND_UP(difference, (val & 0x0f) + 1));
|
||
|
||
return ret;
|
||
}
|
||
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
|
||
index dc474bc..7029c80 100644
|
||
--- a/drivers/rtc/rtc-at91rm9200.c
|
||
+++ b/drivers/rtc/rtc-at91rm9200.c
|
||
@@ -162,6 +162,8 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||
|
||
at91_alarm_year = tm.tm_year;
|
||
|
||
+ tm.tm_mon = alrm->time.tm_mon;
|
||
+ tm.tm_mday = alrm->time.tm_mday;
|
||
tm.tm_hour = alrm->time.tm_hour;
|
||
tm.tm_min = alrm->time.tm_min;
|
||
tm.tm_sec = alrm->time.tm_sec;
|
||
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
|
||
index 5f8844c..5f2eddb 100644
|
||
--- a/drivers/rtc/rtc-cmos.c
|
||
+++ b/drivers/rtc/rtc-cmos.c
|
||
@@ -34,11 +34,11 @@
|
||
#include <linux/interrupt.h>
|
||
#include <linux/spinlock.h>
|
||
#include <linux/platform_device.h>
|
||
-#include <linux/mod_devicetable.h>
|
||
#include <linux/log2.h>
|
||
#include <linux/pm.h>
|
||
#include <linux/of.h>
|
||
#include <linux/of_platform.h>
|
||
+#include <linux/dmi.h>
|
||
|
||
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
|
||
#include <asm-generic/rtc.h>
|
||
@@ -377,6 +377,51 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||
return 0;
|
||
}
|
||
|
||
+/*
|
||
+ * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes.
|
||
+ */
|
||
+static bool alarm_disable_quirk;
|
||
+
|
||
+static int __init set_alarm_disable_quirk(const struct dmi_system_id *id)
|
||
+{
|
||
+ alarm_disable_quirk = true;
|
||
+ pr_info("rtc-cmos: BIOS has alarm-disable quirk. ");
|
||
+ pr_info("RTC alarms disabled\n");
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static const struct dmi_system_id rtc_quirks[] __initconst = {
|
||
+ /* https://bugzilla.novell.com/show_bug.cgi?id=805740 */
|
||
+ {
|
||
+ .callback = set_alarm_disable_quirk,
|
||
+ .ident = "IBM Truman",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "4852570"),
|
||
+ },
|
||
+ },
|
||
+ /* https://bugzilla.novell.com/show_bug.cgi?id=812592 */
|
||
+ {
|
||
+ .callback = set_alarm_disable_quirk,
|
||
+ .ident = "Gigabyte GA-990XA-UD3",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR,
|
||
+ "Gigabyte Technology Co., Ltd."),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"),
|
||
+ },
|
||
+ },
|
||
+ /* http://permalink.gmane.org/gmane.linux.kernel/1604474 */
|
||
+ {
|
||
+ .callback = set_alarm_disable_quirk,
|
||
+ .ident = "Toshiba Satellite L300",
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"),
|
||
+ },
|
||
+ },
|
||
+ {}
|
||
+};
|
||
+
|
||
static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||
{
|
||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||
@@ -385,6 +430,9 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||
if (!is_valid_irq(cmos->irq))
|
||
return -EINVAL;
|
||
|
||
+ if (alarm_disable_quirk)
|
||
+ return 0;
|
||
+
|
||
spin_lock_irqsave(&rtc_lock, flags);
|
||
|
||
if (enabled)
|
||
@@ -1166,6 +1214,8 @@ static int __init cmos_init(void)
|
||
platform_driver_registered = true;
|
||
}
|
||
|
||
+ dmi_check_system(rtc_quirks);
|
||
+
|
||
if (retval == 0)
|
||
return 0;
|
||
|
||
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
|
||
index f027c06..65ef56f 100644
|
||
--- a/drivers/rtc/rtc-pl031.c
|
||
+++ b/drivers/rtc/rtc-pl031.c
|
||
@@ -44,6 +44,7 @@
|
||
#define RTC_YMR 0x34 /* Year match register */
|
||
#define RTC_YLR 0x38 /* Year data load register */
|
||
|
||
+#define RTC_CR_EN (1 << 0) /* counter enable bit */
|
||
#define RTC_CR_CWEN (1 << 26) /* Clockwatch enable bit */
|
||
|
||
#define RTC_TCR_EN (1 << 1) /* Periodic timer enable bit */
|
||
@@ -312,7 +313,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
|
||
int ret;
|
||
struct pl031_local *ldata;
|
||
struct rtc_class_ops *ops = id->data;
|
||
- unsigned long time;
|
||
+ unsigned long time, data;
|
||
|
||
ret = amba_request_regions(adev, NULL);
|
||
if (ret)
|
||
@@ -339,10 +340,13 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
|
||
dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer);
|
||
dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision);
|
||
|
||
+ data = readl(ldata->base + RTC_CR);
|
||
/* Enable the clockwatch on ST Variants */
|
||
if (ldata->hw_designer == AMBA_VENDOR_ST)
|
||
- writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
|
||
- ldata->base + RTC_CR);
|
||
+ data |= RTC_CR_CWEN;
|
||
+ else
|
||
+ data |= RTC_CR_EN;
|
||
+ writel(data, ldata->base + RTC_CR);
|
||
|
||
/*
|
||
* On ST PL031 variants, the RTC reset value does not provide correct
|
||
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
|
||
index 8334dad..be56590 100644
|
||
--- a/drivers/s390/net/qeth_core_main.c
|
||
+++ b/drivers/s390/net/qeth_core_main.c
|
||
@@ -4357,7 +4357,7 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata)
|
||
struct qeth_cmd_buffer *iob;
|
||
struct qeth_ipa_cmd *cmd;
|
||
struct qeth_snmp_ureq *ureq;
|
||
- int req_len;
|
||
+ unsigned int req_len;
|
||
struct qeth_arp_query_info qinfo = {0, };
|
||
int rc = 0;
|
||
|
||
@@ -4373,6 +4373,10 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata)
|
||
/* skip 4 bytes (data_len struct member) to get req_len */
|
||
if (copy_from_user(&req_len, udata + sizeof(int), sizeof(int)))
|
||
return -EFAULT;
|
||
+ if (req_len > (QETH_BUFSIZE - IPA_PDU_HEADER_SIZE -
|
||
+ sizeof(struct qeth_ipacmd_hdr) -
|
||
+ sizeof(struct qeth_ipacmd_setadpparms_hdr)))
|
||
+ return -EINVAL;
|
||
ureq = memdup_user(udata, req_len + sizeof(struct qeth_snmp_ureq_hdr));
|
||
if (IS_ERR(ureq)) {
|
||
QETH_CARD_TEXT(card, 2, "snmpnome");
|
||
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
|
||
index 160e751..0787b97 100644
|
||
--- a/drivers/sbus/char/bbc_envctrl.c
|
||
+++ b/drivers/sbus/char/bbc_envctrl.c
|
||
@@ -452,6 +452,9 @@ static void attach_one_temp(struct bbc_i2c_bus *bp, struct platform_device *op,
|
||
if (!tp)
|
||
return;
|
||
|
||
+ INIT_LIST_HEAD(&tp->bp_list);
|
||
+ INIT_LIST_HEAD(&tp->glob_list);
|
||
+
|
||
tp->client = bbc_i2c_attach(bp, op);
|
||
if (!tp->client) {
|
||
kfree(tp);
|
||
@@ -497,6 +500,9 @@ static void attach_one_fan(struct bbc_i2c_bus *bp, struct platform_device *op,
|
||
if (!fp)
|
||
return;
|
||
|
||
+ INIT_LIST_HEAD(&fp->bp_list);
|
||
+ INIT_LIST_HEAD(&fp->glob_list);
|
||
+
|
||
fp->client = bbc_i2c_attach(bp, op);
|
||
if (!fp->client) {
|
||
kfree(fp);
|
||
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
|
||
index 5426682..7179f72 100644
|
||
--- a/drivers/sbus/char/bbc_i2c.c
|
||
+++ b/drivers/sbus/char/bbc_i2c.c
|
||
@@ -301,13 +301,18 @@ static struct bbc_i2c_bus * __init attach_one_i2c(struct platform_device *op, in
|
||
if (!bp)
|
||
return NULL;
|
||
|
||
+ INIT_LIST_HEAD(&bp->temps);
|
||
+ INIT_LIST_HEAD(&bp->fans);
|
||
+
|
||
bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs");
|
||
if (!bp->i2c_control_regs)
|
||
goto fail;
|
||
|
||
- bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel");
|
||
- if (!bp->i2c_bussel_reg)
|
||
- goto fail;
|
||
+ if (op->num_resources == 2) {
|
||
+ bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel");
|
||
+ if (!bp->i2c_bussel_reg)
|
||
+ goto fail;
|
||
+ }
|
||
|
||
bp->waiting = 0;
|
||
init_waitqueue_head(&bp->wq);
|
||
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
|
||
index 0bd38da..05fbc3d 100644
|
||
--- a/drivers/scsi/aacraid/commctrl.c
|
||
+++ b/drivers/scsi/aacraid/commctrl.c
|
||
@@ -508,7 +508,8 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
|
||
goto cleanup;
|
||
}
|
||
|
||
- if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))) {
|
||
+ if ((fibsize < (sizeof(struct user_aac_srb) - sizeof(struct user_sgentry))) ||
|
||
+ (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))) {
|
||
rcode = -EINVAL;
|
||
goto cleanup;
|
||
}
|
||
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
|
||
index 0d279c44..e9313f8 100644
|
||
--- a/drivers/scsi/aacraid/linit.c
|
||
+++ b/drivers/scsi/aacraid/linit.c
|
||
@@ -777,6 +777,8 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
|
||
static int aac_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
|
||
{
|
||
struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
|
||
+ if (!capable(CAP_SYS_RAWIO))
|
||
+ return -EPERM;
|
||
return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg);
|
||
}
|
||
|
||
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
|
||
index cbde1dc..937561f 100644
|
||
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
|
||
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
|
||
@@ -2500,16 +2500,15 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
|
||
static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
|
||
{
|
||
uint32_t cdb_phyaddr, cdb_phyaddr_hi32;
|
||
- dma_addr_t dma_coherent_handle;
|
||
+
|
||
/*
|
||
********************************************************************
|
||
** here we need to tell iop 331 our freeccb.HighPart
|
||
** if freeccb.HighPart is not zero
|
||
********************************************************************
|
||
*/
|
||
- dma_coherent_handle = acb->dma_coherent_handle;
|
||
- cdb_phyaddr = (uint32_t)(dma_coherent_handle);
|
||
- cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
|
||
+ cdb_phyaddr = lower_32_bits(acb->dma_coherent_handle);
|
||
+ cdb_phyaddr_hi32 = upper_32_bits(acb->dma_coherent_handle);
|
||
acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
|
||
/*
|
||
***********************************************************************
|
||
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
|
||
index 404fd10..e991c61 100644
|
||
--- a/drivers/scsi/bfa/bfad.c
|
||
+++ b/drivers/scsi/bfa/bfad.c
|
||
@@ -1615,7 +1615,7 @@ bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
|
||
static u32 *
|
||
bfad_load_fwimg(struct pci_dev *pdev)
|
||
{
|
||
- if (pdev->device == BFA_PCI_DEVICE_ID_CT2) {
|
||
+ if (bfa_asic_id_ct2(pdev->device)) {
|
||
if (bfi_image_ct2_size == 0)
|
||
bfad_read_firmware(pdev, &bfi_image_ct2,
|
||
&bfi_image_ct2_size, BFAD_FW_FILE_CT2);
|
||
@@ -1625,12 +1625,14 @@ bfad_load_fwimg(struct pci_dev *pdev)
|
||
bfad_read_firmware(pdev, &bfi_image_ct,
|
||
&bfi_image_ct_size, BFAD_FW_FILE_CT);
|
||
return bfi_image_ct;
|
||
- } else {
|
||
+ } else if (bfa_asic_id_cb(pdev->device)) {
|
||
if (bfi_image_cb_size == 0)
|
||
bfad_read_firmware(pdev, &bfi_image_cb,
|
||
&bfi_image_cb_size, BFAD_FW_FILE_CB);
|
||
return bfi_image_cb;
|
||
}
|
||
+
|
||
+ return NULL;
|
||
}
|
||
|
||
static void
|
||
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
|
||
index b0fefc4..bc88cab 100644
|
||
--- a/drivers/scsi/hpsa.c
|
||
+++ b/drivers/scsi/hpsa.c
|
||
@@ -99,6 +99,15 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
|
||
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3354},
|
||
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3355},
|
||
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3356},
|
||
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1920},
|
||
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1921},
|
||
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1922},
|
||
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1923},
|
||
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1924},
|
||
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1925},
|
||
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1926},
|
||
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1928},
|
||
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x334d},
|
||
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
|
||
{0,}
|
||
@@ -118,13 +127,22 @@ static struct board_type products[] = {
|
||
{0x3249103C, "Smart Array P812", &SA5_access},
|
||
{0x324a103C, "Smart Array P712m", &SA5_access},
|
||
{0x324b103C, "Smart Array P711m", &SA5_access},
|
||
- {0x3350103C, "Smart Array", &SA5_access},
|
||
- {0x3351103C, "Smart Array", &SA5_access},
|
||
- {0x3352103C, "Smart Array", &SA5_access},
|
||
- {0x3353103C, "Smart Array", &SA5_access},
|
||
- {0x3354103C, "Smart Array", &SA5_access},
|
||
- {0x3355103C, "Smart Array", &SA5_access},
|
||
- {0x3356103C, "Smart Array", &SA5_access},
|
||
+ {0x3350103C, "Smart Array P222", &SA5_access},
|
||
+ {0x3351103C, "Smart Array P420", &SA5_access},
|
||
+ {0x3352103C, "Smart Array P421", &SA5_access},
|
||
+ {0x3353103C, "Smart Array P822", &SA5_access},
|
||
+ {0x3354103C, "Smart Array P420i", &SA5_access},
|
||
+ {0x3355103C, "Smart Array P220i", &SA5_access},
|
||
+ {0x3356103C, "Smart Array P721m", &SA5_access},
|
||
+ {0x1920103C, "Smart Array", &SA5_access},
|
||
+ {0x1921103C, "Smart Array", &SA5_access},
|
||
+ {0x1922103C, "Smart Array", &SA5_access},
|
||
+ {0x1923103C, "Smart Array", &SA5_access},
|
||
+ {0x1924103C, "Smart Array", &SA5_access},
|
||
+ {0x1925103C, "Smart Array", &SA5_access},
|
||
+ {0x1926103C, "Smart Array", &SA5_access},
|
||
+ {0x1928103C, "Smart Array", &SA5_access},
|
||
+ {0x334d103C, "Smart Array P822se", &SA5_access},
|
||
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
|
||
};
|
||
|
||
@@ -1219,7 +1237,7 @@ static void complete_scsi_command(struct CommandList *cp)
|
||
"has check condition: aborted command: "
|
||
"ASC: 0x%x, ASCQ: 0x%x\n",
|
||
cp, asc, ascq);
|
||
- cmd->result = DID_SOFT_ERROR << 16;
|
||
+ cmd->result |= DID_SOFT_ERROR << 16;
|
||
break;
|
||
}
|
||
/* Must be some other type of check condition */
|
||
@@ -4466,7 +4484,7 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
|
||
hpsa_hba_inquiry(h);
|
||
hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */
|
||
start_controller_lockup_detector(h);
|
||
- return 1;
|
||
+ return 0;
|
||
|
||
clean4:
|
||
hpsa_free_sg_chain_blocks(h);
|
||
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
|
||
index 337e8b3..ac58ee3 100644
|
||
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
|
||
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
|
||
@@ -484,7 +484,8 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
|
||
evt->hostdata->dev);
|
||
if (evt->cmnd_done)
|
||
evt->cmnd_done(evt->cmnd);
|
||
- } else if (evt->done)
|
||
+ } else if (evt->done && evt->crq.format != VIOSRP_MAD_FORMAT &&
|
||
+ evt->iu.srp.login_req.opcode != SRP_LOGIN_REQ)
|
||
evt->done(evt);
|
||
free_event_struct(&evt->hostdata->pool, evt);
|
||
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
||
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
|
||
index adbad69..15bd1a4 100644
|
||
--- a/drivers/scsi/isci/host.h
|
||
+++ b/drivers/scsi/isci/host.h
|
||
@@ -310,9 +310,8 @@ static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
|
||
}
|
||
|
||
#define for_each_isci_host(id, ihost, pdev) \
|
||
- for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
|
||
- id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
|
||
- ihost = to_pci_info(pdev)->hosts[++id])
|
||
+ for (id = 0; id < SCI_MAX_CONTROLLERS && \
|
||
+ (ihost = to_pci_info(pdev)->hosts[id]); id++)
|
||
|
||
static inline enum isci_status isci_host_get_state(struct isci_host *isci_host)
|
||
{
|
||
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
|
||
index 6d1e954..b81f34d 100644
|
||
--- a/drivers/scsi/isci/port_config.c
|
||
+++ b/drivers/scsi/isci/port_config.c
|
||
@@ -619,13 +619,6 @@ static void sci_apc_agent_link_up(struct isci_host *ihost,
|
||
SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
|
||
} else {
|
||
/* the phy is already the part of the port */
|
||
- u32 port_state = iport->sm.current_state_id;
|
||
-
|
||
- /* if the PORT'S state is resetting then the link up is from
|
||
- * port hard reset in this case, we need to tell the port
|
||
- * that link up is recieved
|
||
- */
|
||
- BUG_ON(port_state != SCI_PORT_RESETTING);
|
||
port_agent->phy_ready_mask |= 1 << phy_index;
|
||
sci_port_link_up(iport, iphy);
|
||
}
|
||
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
|
||
index 374254e..b53becf 100644
|
||
--- a/drivers/scsi/isci/task.c
|
||
+++ b/drivers/scsi/isci/task.c
|
||
@@ -956,6 +956,7 @@ int isci_task_abort_task(struct sas_task *task)
|
||
int ret = TMF_RESP_FUNC_FAILED;
|
||
unsigned long flags;
|
||
int perform_termination = 0;
|
||
+ int target_done_already = 0;
|
||
|
||
/* Get the isci_request reference from the task. Note that
|
||
* this check does not depend on the pending request list
|
||
@@ -970,9 +971,11 @@ int isci_task_abort_task(struct sas_task *task)
|
||
/* If task is already done, the request isn't valid */
|
||
if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
|
||
(task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
|
||
- old_request)
|
||
+ old_request) {
|
||
isci_device = isci_lookup_device(task->dev);
|
||
-
|
||
+ target_done_already = test_bit(IREQ_COMPLETE_IN_TARGET,
|
||
+ &old_request->flags);
|
||
+ }
|
||
spin_unlock(&task->task_state_lock);
|
||
spin_unlock_irqrestore(&isci_host->scic_lock, flags);
|
||
|
||
@@ -1031,7 +1034,7 @@ int isci_task_abort_task(struct sas_task *task)
|
||
}
|
||
if (task->task_proto == SAS_PROTOCOL_SMP ||
|
||
sas_protocol_ata(task->task_proto) ||
|
||
- test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
|
||
+ target_done_already) {
|
||
|
||
spin_unlock_irqrestore(&isci_host->scic_lock, flags);
|
||
|
||
@@ -1312,7 +1315,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
|
||
/* XXX: need to cleanup any ireqs targeting this
|
||
* domain_device
|
||
*/
|
||
- ret = TMF_RESP_FUNC_COMPLETE;
|
||
+ ret = -ENODEV;
|
||
goto out;
|
||
}
|
||
|
||
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
|
||
index 82c3fd4..1243d2f 100644
|
||
--- a/drivers/scsi/libiscsi.c
|
||
+++ b/drivers/scsi/libiscsi.c
|
||
@@ -718,11 +718,21 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
||
return NULL;
|
||
}
|
||
|
||
+ if (data_size > ISCSI_DEF_MAX_RECV_SEG_LEN) {
|
||
+ iscsi_conn_printk(KERN_ERR, conn, "Invalid buffer len of %u for login task. Max len is %u\n", data_size, ISCSI_DEF_MAX_RECV_SEG_LEN);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
task = conn->login_task;
|
||
} else {
|
||
if (session->state != ISCSI_STATE_LOGGED_IN)
|
||
return NULL;
|
||
|
||
+ if (data_size != 0) {
|
||
+ iscsi_conn_printk(KERN_ERR, conn, "Can not send data buffer of len %u for op 0x%x\n", data_size, opcode);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
|
||
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
|
||
|
||
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
|
||
index 722b3ea..ec96c5f 100644
|
||
--- a/drivers/scsi/libsas/sas_ata.c
|
||
+++ b/drivers/scsi/libsas/sas_ata.c
|
||
@@ -211,7 +211,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
|
||
qc->tf.nsect = 0;
|
||
}
|
||
|
||
- ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis);
|
||
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, (u8 *)&task->ata_task.fis);
|
||
task->uldd_task = qc;
|
||
if (ata_is_atapi(qc->tf.protocol)) {
|
||
memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
|
||
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
|
||
index 25506c7..9bec171 100644
|
||
--- a/drivers/scsi/megaraid/megaraid_mm.c
|
||
+++ b/drivers/scsi/megaraid/megaraid_mm.c
|
||
@@ -486,6 +486,8 @@ mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc)
|
||
|
||
pthru32->dataxferaddr = kioc->buf_paddr;
|
||
if (kioc->data_dir & UIOC_WR) {
|
||
+ if (pthru32->dataxferlen > kioc->xferlen)
|
||
+ return -EINVAL;
|
||
if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
|
||
pthru32->dataxferlen)) {
|
||
return (-EFAULT);
|
||
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
|
||
index e5f416f..1a7955a 100644
|
||
--- a/drivers/scsi/megaraid/megaraid_sas.h
|
||
+++ b/drivers/scsi/megaraid/megaraid_sas.h
|
||
@@ -1294,7 +1294,6 @@ struct megasas_instance {
|
||
u32 *reply_queue;
|
||
dma_addr_t reply_queue_h;
|
||
|
||
- unsigned long base_addr;
|
||
struct megasas_register_set __iomem *reg_set;
|
||
|
||
struct megasas_pd_list pd_list[MEGASAS_MAX_PD];
|
||
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
|
||
index 7926162..6188700 100644
|
||
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
|
||
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
|
||
@@ -3445,6 +3445,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
|
||
u32 max_sectors_1;
|
||
u32 max_sectors_2;
|
||
u32 tmp_sectors, msix_enable;
|
||
+ resource_size_t base_addr;
|
||
struct megasas_register_set __iomem *reg_set;
|
||
struct megasas_ctrl_info *ctrl_info;
|
||
unsigned long bar_list;
|
||
@@ -3453,14 +3454,14 @@ static int megasas_init_fw(struct megasas_instance *instance)
|
||
/* Find first memory bar */
|
||
bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
|
||
instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
|
||
- instance->base_addr = pci_resource_start(instance->pdev, instance->bar);
|
||
if (pci_request_selected_regions(instance->pdev, instance->bar,
|
||
"megasas: LSI")) {
|
||
printk(KERN_DEBUG "megasas: IO memory region busy!\n");
|
||
return -EBUSY;
|
||
}
|
||
|
||
- instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
|
||
+ base_addr = pci_resource_start(instance->pdev, instance->bar);
|
||
+ instance->reg_set = ioremap_nocache(base_addr, 8192);
|
||
|
||
if (!instance->reg_set) {
|
||
printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
|
||
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
|
||
index db79362..f98cae7 100644
|
||
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
|
||
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
|
||
@@ -80,10 +80,6 @@ static int msix_disable = -1;
|
||
module_param(msix_disable, int, 0);
|
||
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
|
||
|
||
-static int missing_delay[2] = {-1, -1};
|
||
-module_param_array(missing_delay, int, NULL, 0);
|
||
-MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay");
|
||
-
|
||
static int mpt2sas_fwfault_debug;
|
||
MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault "
|
||
"and halt firmware - (default=0)");
|
||
@@ -2168,7 +2164,7 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
|
||
}
|
||
|
||
/**
|
||
- * _base_update_missing_delay - change the missing delay timers
|
||
+ * mpt2sas_base_update_missing_delay - change the missing delay timers
|
||
* @ioc: per adapter object
|
||
* @device_missing_delay: amount of time till device is reported missing
|
||
* @io_missing_delay: interval IO is returned when there is a missing device
|
||
@@ -2179,8 +2175,8 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
|
||
* delay, as well as the io missing delay. This should be called at driver
|
||
* load time.
|
||
*/
|
||
-static void
|
||
-_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
|
||
+void
|
||
+mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
|
||
u16 device_missing_delay, u8 io_missing_delay)
|
||
{
|
||
u16 dmd, dmd_new, dmd_orignal;
|
||
@@ -4371,9 +4367,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
||
if (r)
|
||
goto out_free_resources;
|
||
|
||
- if (missing_delay[0] != -1 && missing_delay[1] != -1)
|
||
- _base_update_missing_delay(ioc, missing_delay[0],
|
||
- missing_delay[1]);
|
||
|
||
return 0;
|
||
|
||
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
|
||
index c7459fd..04968be 100644
|
||
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
|
||
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
|
||
@@ -1047,6 +1047,9 @@ void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_ty
|
||
|
||
void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);
|
||
|
||
+void mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
|
||
+ u16 device_missing_delay, u8 io_missing_delay);
|
||
+
|
||
int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc);
|
||
|
||
/* scsih shared API */
|
||
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
|
||
index 35a05d1d..a16bc61 100644
|
||
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
|
||
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
|
||
@@ -101,6 +101,10 @@ static ushort max_sectors = 0xFFFF;
|
||
module_param(max_sectors, ushort, 0);
|
||
MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767");
|
||
|
||
+static int missing_delay[2] = {-1, -1};
|
||
+module_param_array(missing_delay, int, NULL, 0);
|
||
+MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay");
|
||
+
|
||
/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
|
||
#define MPT2SAS_MAX_LUN (16895)
|
||
static int max_lun = MPT2SAS_MAX_LUN;
|
||
@@ -7039,11 +7043,14 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||
struct _sas_device *sas_device;
|
||
struct _sas_node *expander_device;
|
||
static struct _raid_device *raid_device;
|
||
+ u8 retry_count;
|
||
|
||
printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name);
|
||
|
||
_scsih_sas_host_refresh(ioc);
|
||
|
||
+ printk(MPT2SAS_INFO_FMT "\tscan devices: expanders start\n",
|
||
+ ioc->name);
|
||
/* expanders */
|
||
handle = 0xFFFF;
|
||
while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
|
||
@@ -7052,19 +7059,39 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||
MPI2_IOCSTATUS_MASK;
|
||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||
break;
|
||
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||
+ printk(MPT2SAS_INFO_FMT "\tbreak from expander scan: "
|
||
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||
+ ioc->name, ioc_status,
|
||
+ le32_to_cpu(mpi_reply.IOCLogInfo));
|
||
+ break;
|
||
+ }
|
||
handle = le16_to_cpu(expander_pg0.DevHandle);
|
||
expander_device = mpt2sas_scsih_expander_find_by_sas_address(
|
||
ioc, le64_to_cpu(expander_pg0.SASAddress));
|
||
if (expander_device)
|
||
_scsih_refresh_expander_links(ioc, expander_device,
|
||
handle);
|
||
- else
|
||
+ else {
|
||
+ printk(MPT2SAS_INFO_FMT "\tBEFORE adding expander: "
|
||
+ "handle (0x%04x), sas_addr(0x%016llx)\n",
|
||
+ ioc->name, handle, (unsigned long long)
|
||
+ le64_to_cpu(expander_pg0.SASAddress));
|
||
_scsih_expander_add(ioc, handle);
|
||
+ printk(MPT2SAS_INFO_FMT "\tAFTER adding expander: "
|
||
+ "handle (0x%04x), sas_addr(0x%016llx)\n",
|
||
+ ioc->name, handle, (unsigned long long)
|
||
+ le64_to_cpu(expander_pg0.SASAddress));
|
||
+ }
|
||
}
|
||
|
||
+ printk(MPT2SAS_INFO_FMT "\tscan devices: expanders complete\n",
|
||
+ ioc->name);
|
||
+
|
||
if (!ioc->ir_firmware)
|
||
goto skip_to_sas;
|
||
|
||
+ printk(MPT2SAS_INFO_FMT "\tscan devices phys disk start\n", ioc->name);
|
||
/* phys disk */
|
||
phys_disk_num = 0xFF;
|
||
while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
|
||
@@ -7074,6 +7101,13 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||
MPI2_IOCSTATUS_MASK;
|
||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||
break;
|
||
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||
+ printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan:"
|
||
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||
+ ioc->name, ioc_status,
|
||
+ le32_to_cpu(mpi_reply.IOCLogInfo));
|
||
+ break;
|
||
+ }
|
||
phys_disk_num = pd_pg0.PhysDiskNum;
|
||
handle = le16_to_cpu(pd_pg0.DevHandle);
|
||
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
|
||
@@ -7083,17 +7117,46 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
|
||
handle) != 0)
|
||
continue;
|
||
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||
+ MPI2_IOCSTATUS_MASK;
|
||
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||
+ printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan "
|
||
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||
+ ioc->name, ioc_status,
|
||
+ le32_to_cpu(mpi_reply.IOCLogInfo));
|
||
+ break;
|
||
+ }
|
||
parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
|
||
if (!_scsih_get_sas_address(ioc, parent_handle,
|
||
&sas_address)) {
|
||
+ printk(MPT2SAS_INFO_FMT "\tBEFORE adding phys disk: "
|
||
+ " handle (0x%04x), sas_addr(0x%016llx)\n",
|
||
+ ioc->name, handle, (unsigned long long)
|
||
+ le64_to_cpu(sas_device_pg0.SASAddress));
|
||
mpt2sas_transport_update_links(ioc, sas_address,
|
||
handle, sas_device_pg0.PhyNum,
|
||
MPI2_SAS_NEG_LINK_RATE_1_5);
|
||
set_bit(handle, ioc->pd_handles);
|
||
- _scsih_add_device(ioc, handle, 0, 1);
|
||
+ retry_count = 0;
|
||
+ /* This will retry adding the end device.
|
||
+ * _scsih_add_device() will decide on retries and
|
||
+ * return "1" when it should be retried
|
||
+ */
|
||
+ while (_scsih_add_device(ioc, handle, retry_count++,
|
||
+ 1)) {
|
||
+ ssleep(1);
|
||
+ }
|
||
+ printk(MPT2SAS_INFO_FMT "\tAFTER adding phys disk: "
|
||
+ " handle (0x%04x), sas_addr(0x%016llx)\n",
|
||
+ ioc->name, handle, (unsigned long long)
|
||
+ le64_to_cpu(sas_device_pg0.SASAddress));
|
||
}
|
||
}
|
||
|
||
+ printk(MPT2SAS_INFO_FMT "\tscan devices: phys disk complete\n",
|
||
+ ioc->name);
|
||
+
|
||
+ printk(MPT2SAS_INFO_FMT "\tscan devices: volumes start\n", ioc->name);
|
||
/* volumes */
|
||
handle = 0xFFFF;
|
||
while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
|
||
@@ -7102,6 +7165,13 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||
MPI2_IOCSTATUS_MASK;
|
||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||
break;
|
||
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||
+ printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: "
|
||
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||
+ ioc->name, ioc_status,
|
||
+ le32_to_cpu(mpi_reply.IOCLogInfo));
|
||
+ break;
|
||
+ }
|
||
handle = le16_to_cpu(volume_pg1.DevHandle);
|
||
raid_device = _scsih_raid_device_find_by_wwid(ioc,
|
||
le64_to_cpu(volume_pg1.WWID));
|
||
@@ -7111,18 +7181,38 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||
&volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
|
||
sizeof(Mpi2RaidVolPage0_t)))
|
||
continue;
|
||
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||
+ MPI2_IOCSTATUS_MASK;
|
||
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||
+ printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: "
|
||
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||
+ ioc->name, ioc_status,
|
||
+ le32_to_cpu(mpi_reply.IOCLogInfo));
|
||
+ break;
|
||
+ }
|
||
if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
|
||
volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
|
||
volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) {
|
||
memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t));
|
||
element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED;
|
||
element.VolDevHandle = volume_pg1.DevHandle;
|
||
+ printk(MPT2SAS_INFO_FMT "\tBEFORE adding volume: "
|
||
+ " handle (0x%04x)\n", ioc->name,
|
||
+ volume_pg1.DevHandle);
|
||
_scsih_sas_volume_add(ioc, &element);
|
||
+ printk(MPT2SAS_INFO_FMT "\tAFTER adding volume: "
|
||
+ " handle (0x%04x)\n", ioc->name,
|
||
+ volume_pg1.DevHandle);
|
||
}
|
||
}
|
||
|
||
+ printk(MPT2SAS_INFO_FMT "\tscan devices: volumes complete\n",
|
||
+ ioc->name);
|
||
+
|
||
skip_to_sas:
|
||
|
||
+ printk(MPT2SAS_INFO_FMT "\tscan devices: end devices start\n",
|
||
+ ioc->name);
|
||
/* sas devices */
|
||
handle = 0xFFFF;
|
||
while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
|
||
@@ -7132,6 +7222,13 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||
MPI2_IOCSTATUS_MASK;
|
||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||
break;
|
||
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||
+ printk(MPT2SAS_INFO_FMT "\tbreak from end device scan:"
|
||
+ " ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||
+ ioc->name, ioc_status,
|
||
+ le32_to_cpu(mpi_reply.IOCLogInfo));
|
||
+ break;
|
||
+ }
|
||
handle = le16_to_cpu(sas_device_pg0.DevHandle);
|
||
if (!(_scsih_is_end_device(
|
||
le32_to_cpu(sas_device_pg0.DeviceInfo))))
|
||
@@ -7142,12 +7239,31 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||
continue;
|
||
parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
|
||
if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) {
|
||
+ printk(MPT2SAS_INFO_FMT "\tBEFORE adding end device: "
|
||
+ "handle (0x%04x), sas_addr(0x%016llx)\n",
|
||
+ ioc->name, handle, (unsigned long long)
|
||
+ le64_to_cpu(sas_device_pg0.SASAddress));
|
||
mpt2sas_transport_update_links(ioc, sas_address, handle,
|
||
sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
|
||
- _scsih_add_device(ioc, handle, 0, 0);
|
||
+ retry_count = 0;
|
||
+ /* This will retry adding the end device.
|
||
+ * _scsih_add_device() will decide on retries and
|
||
+ * return "1" when it should be retried
|
||
+ */
|
||
+ while (_scsih_add_device(ioc, handle, retry_count++,
|
||
+ 0)) {
|
||
+ ssleep(1);
|
||
+ }
|
||
+ printk(MPT2SAS_INFO_FMT "\tAFTER adding end device: "
|
||
+ "handle (0x%04x), sas_addr(0x%016llx)\n",
|
||
+ ioc->name, handle, (unsigned long long)
|
||
+ le64_to_cpu(sas_device_pg0.SASAddress));
|
||
}
|
||
}
|
||
|
||
+ printk(MPT2SAS_INFO_FMT "\tscan devices: end devices complete\n",
|
||
+ ioc->name);
|
||
+
|
||
printk(MPT2SAS_INFO_FMT "scan devices: complete\n", ioc->name);
|
||
}
|
||
|
||
@@ -7239,7 +7355,9 @@ _firmware_event_work(struct work_struct *work)
|
||
case MPT2SAS_PORT_ENABLE_COMPLETE:
|
||
ioc->start_scan = 0;
|
||
|
||
-
|
||
+ if (missing_delay[0] != -1 && missing_delay[1] != -1)
|
||
+ mpt2sas_base_update_missing_delay(ioc, missing_delay[0],
|
||
+ missing_delay[1]);
|
||
|
||
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "port enable: complete "
|
||
"from worker thread\n", ioc->name));
|
||
@@ -8086,7 +8204,6 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)
|
||
|
||
mpt2sas_base_free_resources(ioc);
|
||
pci_save_state(pdev);
|
||
- pci_disable_device(pdev);
|
||
pci_set_power_state(pdev, device_state);
|
||
return 0;
|
||
}
|
||
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
|
||
index a244303..09bedb7 100644
|
||
--- a/drivers/scsi/qla2xxx/qla_def.h
|
||
+++ b/drivers/scsi/qla2xxx/qla_def.h
|
||
@@ -2600,8 +2600,7 @@ struct qla_hw_data {
|
||
IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
|
||
IS_QLA82XX(ha) || IS_QLA83XX(ha))
|
||
#define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
|
||
-#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
|
||
- IS_QLA83XX(ha)) && (ha)->flags.msix_enabled)
|
||
+#define IS_NOPOLLING_TYPE(ha) (IS_QLA81XX(ha) && (ha)->flags.msix_enabled)
|
||
#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
|
||
#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
|
||
#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
|
||
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
|
||
index b3f0b0f..dcc39b6 100644
|
||
--- a/drivers/scsi/scsi_error.c
|
||
+++ b/drivers/scsi/scsi_error.c
|
||
@@ -916,6 +916,15 @@ int scsi_eh_get_sense(struct list_head *work_q,
|
||
SCSI_SENSE_VALID(scmd))
|
||
continue;
|
||
|
||
+ if (status_byte(scmd->result) != CHECK_CONDITION)
|
||
+ /*
|
||
+ * don't request sense if there's no check condition
|
||
+ * status because the error we're processing isn't one
|
||
+ * that has a sense code (and some devices get
|
||
+ * confused by sense requests out of the blue)
|
||
+ */
|
||
+ continue;
|
||
+
|
||
SCSI_LOG_ERROR_RECOVERY(2, scmd_printk(KERN_INFO, scmd,
|
||
"%s: requesting sense\n",
|
||
current->comm));
|
||
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
|
||
index 099e4b3..fd01f77 100644
|
||
--- a/drivers/scsi/scsi_lib.c
|
||
+++ b/drivers/scsi/scsi_lib.c
|
||
@@ -794,6 +794,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
|
||
scsi_next_command(cmd);
|
||
return;
|
||
}
|
||
+ } else if (blk_rq_bytes(req) == 0 && result && !sense_deferred) {
|
||
+ /*
|
||
+ * Certain non BLOCK_PC requests are commands that don't
|
||
+ * actually transfer anything (FLUSH), so cannot use
|
||
+ * good_bytes != blk_rq_bytes(req) as the signal for an error.
|
||
+ * This sets the error explicitly for the problem case.
|
||
+ */
|
||
+ error = __scsi_error_from_host_byte(cmd, result);
|
||
}
|
||
|
||
/* no bidi support for !REQ_TYPE_BLOCK_PC yet */
|
||
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
|
||
index f9986cc..446c023 100644
|
||
--- a/drivers/scsi/storvsc_drv.c
|
||
+++ b/drivers/scsi/storvsc_drv.c
|
||
@@ -1131,6 +1131,9 @@ static void storvsc_device_destroy(struct scsi_device *sdevice)
|
||
{
|
||
struct stor_mem_pools *memp = sdevice->hostdata;
|
||
|
||
+ if (!memp)
|
||
+ return;
|
||
+
|
||
mempool_destroy(memp->request_mempool);
|
||
kmem_cache_destroy(memp->request_pool);
|
||
kfree(memp);
|
||
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
|
||
index d92fe40..6b349e3 100644
|
||
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
|
||
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
|
||
@@ -3000,7 +3000,11 @@ sym_dequeue_from_squeue(struct sym_hcb *np, int i, int target, int lun, int task
|
||
if ((target == -1 || cp->target == target) &&
|
||
(lun == -1 || cp->lun == lun) &&
|
||
(task == -1 || cp->tag == task)) {
|
||
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
|
||
sym_set_cam_status(cp->cmd, DID_SOFT_ERROR);
|
||
+#else
|
||
+ sym_set_cam_status(cp->cmd, DID_REQUEUE);
|
||
+#endif
|
||
sym_remque(&cp->link_ccbq);
|
||
sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
|
||
}
|
||
diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c
|
||
index cf30592..c0d612f 100644
|
||
--- a/drivers/staging/bcm/Bcmchar.c
|
||
+++ b/drivers/staging/bcm/Bcmchar.c
|
||
@@ -1957,6 +1957,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
|
||
|
||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n");
|
||
|
||
+ memset(&DevInfo, 0, sizeof(DevInfo));
|
||
DevInfo.MaxRDMBufferSize = BUFFER_4K;
|
||
DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START;
|
||
DevInfo.u32RxAlignmentCorrection = 0;
|
||
diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c
|
||
index 8e3c586..e0f40ae 100644
|
||
--- a/drivers/staging/bcm/InterfaceInit.c
|
||
+++ b/drivers/staging/bcm/InterfaceInit.c
|
||
@@ -4,10 +4,12 @@ static struct usb_device_id InterfaceUsbtable[] = {
|
||
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },
|
||
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },
|
||
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) },
|
||
- { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SM250) },
|
||
+ { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SYM) },
|
||
{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
|
||
{ USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
|
||
{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) },
|
||
+ { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_226) },
|
||
+ { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_326) },
|
||
{ }
|
||
};
|
||
MODULE_DEVICE_TABLE(usb, InterfaceUsbtable);
|
||
diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h
|
||
index 058315a..6fa4f09 100644
|
||
--- a/drivers/staging/bcm/InterfaceInit.h
|
||
+++ b/drivers/staging/bcm/InterfaceInit.h
|
||
@@ -8,10 +8,11 @@
|
||
#define BCM_USB_PRODUCT_ID_T3 0x0300
|
||
#define BCM_USB_PRODUCT_ID_T3B 0x0210
|
||
#define BCM_USB_PRODUCT_ID_T3L 0x0220
|
||
-#define BCM_USB_PRODUCT_ID_SM250 0xbccd
|
||
#define BCM_USB_PRODUCT_ID_SYM 0x15E
|
||
#define BCM_USB_PRODUCT_ID_1901 0xe017
|
||
-#define BCM_USB_PRODUCT_ID_226 0x0132
|
||
+#define BCM_USB_PRODUCT_ID_226 0x0132 /* not sure if this is valid */
|
||
+#define BCM_USB_PRODUCT_ID_ZTE_226 0x172
|
||
+#define BCM_USB_PRODUCT_ID_ZTE_326 0x173 /* ZTE AX326 */
|
||
#define BCM_USB_PRODUCT_ID_ZTE_TU25 0x0007
|
||
|
||
#define BCM_USB_MINOR_BASE 192
|
||
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
|
||
index 50dc93e..fff2757 100644
|
||
--- a/drivers/staging/comedi/comedi_fops.c
|
||
+++ b/drivers/staging/comedi/comedi_fops.c
|
||
@@ -1078,22 +1078,19 @@ static int do_cmd_ioctl(struct comedi_device *dev,
|
||
DPRINTK("subdevice busy\n");
|
||
return -EBUSY;
|
||
}
|
||
- s->busy = file;
|
||
|
||
/* make sure channel/gain list isn't too long */
|
||
if (user_cmd.chanlist_len > s->len_chanlist) {
|
||
DPRINTK("channel/gain list too long %u > %d\n",
|
||
user_cmd.chanlist_len, s->len_chanlist);
|
||
- ret = -EINVAL;
|
||
- goto cleanup;
|
||
+ return -EINVAL;
|
||
}
|
||
|
||
/* make sure channel/gain list isn't too short */
|
||
if (user_cmd.chanlist_len < 1) {
|
||
DPRINTK("channel/gain list too short %u < 1\n",
|
||
user_cmd.chanlist_len);
|
||
- ret = -EINVAL;
|
||
- goto cleanup;
|
||
+ return -EINVAL;
|
||
}
|
||
|
||
async->cmd = user_cmd;
|
||
@@ -1103,8 +1100,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
|
||
kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
|
||
if (!async->cmd.chanlist) {
|
||
DPRINTK("allocation failed\n");
|
||
- ret = -ENOMEM;
|
||
- goto cleanup;
|
||
+ return -ENOMEM;
|
||
}
|
||
|
||
if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
|
||
@@ -1156,6 +1152,9 @@ static int do_cmd_ioctl(struct comedi_device *dev,
|
||
|
||
comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
|
||
|
||
+ /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
|
||
+ * comedi_read() or comedi_write() */
|
||
+ s->busy = file;
|
||
ret = s->do_cmd(dev, s);
|
||
if (ret == 0)
|
||
return 0;
|
||
@@ -1658,6 +1657,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
|
||
|
||
if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
|
||
if (count == 0) {
|
||
+ mutex_lock(&dev->mutex);
|
||
if (comedi_get_subdevice_runflags(s) &
|
||
SRF_ERROR) {
|
||
retval = -EPIPE;
|
||
@@ -1665,6 +1665,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
|
||
retval = 0;
|
||
}
|
||
do_become_nonbusy(dev, s);
|
||
+ mutex_unlock(&dev->mutex);
|
||
}
|
||
break;
|
||
}
|
||
@@ -1779,6 +1780,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
|
||
|
||
if (n == 0) {
|
||
if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
|
||
+ mutex_lock(&dev->mutex);
|
||
do_become_nonbusy(dev, s);
|
||
if (comedi_get_subdevice_runflags(s) &
|
||
SRF_ERROR) {
|
||
@@ -1786,6 +1788,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
|
||
} else {
|
||
retval = 0;
|
||
}
|
||
+ mutex_unlock(&dev->mutex);
|
||
break;
|
||
}
|
||
if (file->f_flags & O_NONBLOCK) {
|
||
@@ -1823,9 +1826,11 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
|
||
buf += n;
|
||
break; /* makes device work like a pipe */
|
||
}
|
||
- if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
|
||
- async->buf_read_count - async->buf_write_count == 0) {
|
||
- do_become_nonbusy(dev, s);
|
||
+ if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING))) {
|
||
+ mutex_lock(&dev->mutex);
|
||
+ if (async->buf_read_count - async->buf_write_count == 0)
|
||
+ do_become_nonbusy(dev, s);
|
||
+ mutex_unlock(&dev->mutex);
|
||
}
|
||
set_current_state(TASK_RUNNING);
|
||
remove_wait_queue(&async->wait_head, &wait);
|
||
diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c
|
||
index 8f32152..453ea2d 100644
|
||
--- a/drivers/staging/comedi/drivers/cb_pcidio.c
|
||
+++ b/drivers/staging/comedi/drivers/cb_pcidio.c
|
||
@@ -56,10 +56,6 @@ struct pcidio_board {
|
||
const char *name; /* name of the board */
|
||
int dev_id;
|
||
int n_8255; /* number of 8255 chips on board */
|
||
-
|
||
- /* indices of base address regions */
|
||
- int pcicontroler_badrindex;
|
||
- int dioregs_badrindex;
|
||
};
|
||
|
||
static const struct pcidio_board pcidio_boards[] = {
|
||
@@ -67,22 +63,16 @@ static const struct pcidio_board pcidio_boards[] = {
|
||
.name = "pci-dio24",
|
||
.dev_id = 0x0028,
|
||
.n_8255 = 1,
|
||
- .pcicontroler_badrindex = 1,
|
||
- .dioregs_badrindex = 2,
|
||
},
|
||
{
|
||
.name = "pci-dio24h",
|
||
.dev_id = 0x0014,
|
||
.n_8255 = 1,
|
||
- .pcicontroler_badrindex = 1,
|
||
- .dioregs_badrindex = 2,
|
||
},
|
||
{
|
||
.name = "pci-dio48h",
|
||
.dev_id = 0x000b,
|
||
.n_8255 = 2,
|
||
- .pcicontroler_badrindex = 0,
|
||
- .dioregs_badrindex = 1,
|
||
},
|
||
};
|
||
|
||
@@ -239,10 +229,15 @@ static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
|
||
if (comedi_pci_enable(pcidev, thisboard->name))
|
||
return -EIO;
|
||
|
||
- devpriv->dio_reg_base
|
||
- =
|
||
+ /*
|
||
+ * Use PCI BAR 2 region if non-zero length, else use PCI BAR 1 region.
|
||
+ * PCI BAR 1 is only used for older PCI-DIO48H boards. At some point
|
||
+ * the PCI-DIO48H was redesigned to use the same PCI interface chip
|
||
+ * (and same PCI BAR region) as the other boards.
|
||
+ */
|
||
+ devpriv->dio_reg_base =
|
||
pci_resource_start(devpriv->pci_dev,
|
||
- pcidio_boards[index].dioregs_badrindex);
|
||
+ (pci_resource_len(pcidev, 2) ? 2 : 1));
|
||
|
||
/*
|
||
* Allocate the subdevice structures. alloc_subdevice() is a
|
||
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
|
||
index d2dd75e..e16d1f3 100644
|
||
--- a/drivers/staging/comedi/drivers/das08.c
|
||
+++ b/drivers/staging/comedi/drivers/das08.c
|
||
@@ -385,7 +385,7 @@ static const struct das08_board_struct das08_boards[] = {
|
||
.ai = das08_ai_rinsn,
|
||
.ai_nbits = 16,
|
||
.ai_pg = das08_pg_none,
|
||
- .ai_encoding = das08_encode12,
|
||
+ .ai_encoding = das08_encode16,
|
||
.ao = das08jr_ao_winsn,
|
||
.ao_nbits = 16,
|
||
.di = das08jr_di_rbits,
|
||
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
|
||
index 661ba2e..6e936c5 100644
|
||
--- a/drivers/staging/comedi/drivers/pcmuio.c
|
||
+++ b/drivers/staging/comedi/drivers/pcmuio.c
|
||
@@ -464,13 +464,13 @@ static int pcmuio_detach(struct comedi_device *dev)
|
||
if (dev->iobase)
|
||
release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
|
||
|
||
- for (i = 0; i < MAX_ASICS; ++i) {
|
||
- if (devpriv->asics[i].irq)
|
||
- free_irq(devpriv->asics[i].irq, dev);
|
||
- }
|
||
-
|
||
- if (devpriv && devpriv->sprivs)
|
||
+ if (devpriv) {
|
||
+ for (i = 0; i < MAX_ASICS; ++i) {
|
||
+ if (devpriv->asics[i].irq)
|
||
+ free_irq(devpriv->asics[i].irq, dev);
|
||
+ }
|
||
kfree(devpriv->sprivs);
|
||
+ }
|
||
|
||
return 0;
|
||
}
|
||
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
|
||
index 526de2e..0316780 100644
|
||
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
|
||
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
|
||
@@ -251,11 +251,11 @@ static int dnp_dio_insn_bits(struct comedi_device *dev,
|
||
|
||
/* on return, data[1] contains the value of the digital input lines. */
|
||
outb(PADR, CSCIR);
|
||
- data[0] = inb(CSCDR);
|
||
+ data[1] = inb(CSCDR);
|
||
outb(PBDR, CSCIR);
|
||
- data[0] += inb(CSCDR) << 8;
|
||
+ data[1] += inb(CSCDR) << 8;
|
||
outb(PCDR, CSCIR);
|
||
- data[0] += ((inb(CSCDR) & 0xF0) << 12);
|
||
+ data[1] += ((inb(CSCDR) & 0xF0) << 12);
|
||
|
||
return 2;
|
||
|
||
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
|
||
index 886f565..6a271e9 100644
|
||
--- a/drivers/staging/et131x/et131x.c
|
||
+++ b/drivers/staging/et131x/et131x.c
|
||
@@ -1478,22 +1478,16 @@ static int et131x_mii_read(struct et131x_adapter *adapter, u8 reg, u16 *value)
|
||
*
|
||
* Return 0 on success, errno on failure (as defined in errno.h)
|
||
*/
|
||
-static int et131x_mii_write(struct et131x_adapter *adapter, u8 reg, u16 value)
|
||
+static int et131x_mii_write(struct et131x_adapter *adapter, u8 addr, u8 reg,
|
||
+ u16 value)
|
||
{
|
||
struct mac_regs __iomem *mac = &adapter->regs->mac;
|
||
- struct phy_device *phydev = adapter->phydev;
|
||
int status = 0;
|
||
- u8 addr;
|
||
u32 delay = 0;
|
||
u32 mii_addr;
|
||
u32 mii_cmd;
|
||
u32 mii_indicator;
|
||
|
||
- if (!phydev)
|
||
- return -EIO;
|
||
-
|
||
- addr = phydev->addr;
|
||
-
|
||
/* Save a local copy of the registers we are dealing with so we can
|
||
* set them back
|
||
*/
|
||
@@ -1550,6 +1544,7 @@ static void et1310_phy_access_mii_bit(struct et131x_adapter *adapter,
|
||
{
|
||
u16 reg;
|
||
u16 mask = 0x0001 << bitnum;
|
||
+ struct phy_device *phydev = adapter->phydev;
|
||
|
||
/* Read the requested register */
|
||
et131x_mii_read(adapter, regnum, ®);
|
||
@@ -1560,11 +1555,11 @@ static void et1310_phy_access_mii_bit(struct et131x_adapter *adapter,
|
||
break;
|
||
|
||
case TRUEPHY_BIT_SET:
|
||
- et131x_mii_write(adapter, regnum, reg | mask);
|
||
+ et131x_mii_write(adapter, phydev->addr, regnum, reg | mask);
|
||
break;
|
||
|
||
case TRUEPHY_BIT_CLEAR:
|
||
- et131x_mii_write(adapter, regnum, reg & ~mask);
|
||
+ et131x_mii_write(adapter, phydev->addr, regnum, reg & ~mask);
|
||
break;
|
||
|
||
default:
|
||
@@ -1715,17 +1710,7 @@ static int et131x_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 val
|
||
struct net_device *netdev = bus->priv;
|
||
struct et131x_adapter *adapter = netdev_priv(netdev);
|
||
|
||
- return et131x_mii_write(adapter, reg, value);
|
||
-}
|
||
-
|
||
-static int et131x_mdio_reset(struct mii_bus *bus)
|
||
-{
|
||
- struct net_device *netdev = bus->priv;
|
||
- struct et131x_adapter *adapter = netdev_priv(netdev);
|
||
-
|
||
- et131x_mii_write(adapter, MII_BMCR, BMCR_RESET);
|
||
-
|
||
- return 0;
|
||
+ return et131x_mii_write(adapter, phy_addr, reg, value);
|
||
}
|
||
|
||
/**
|
||
@@ -1741,12 +1726,13 @@ static int et131x_mdio_reset(struct mii_bus *bus)
|
||
static void et1310_phy_power_down(struct et131x_adapter *adapter, bool down)
|
||
{
|
||
u16 data;
|
||
+ struct phy_device *phydev = adapter->phydev;
|
||
|
||
et131x_mii_read(adapter, MII_BMCR, &data);
|
||
data &= ~BMCR_PDOWN;
|
||
if (down)
|
||
data |= BMCR_PDOWN;
|
||
- et131x_mii_write(adapter, MII_BMCR, data);
|
||
+ et131x_mii_write(adapter, phydev->addr, MII_BMCR, data);
|
||
}
|
||
|
||
/**
|
||
@@ -1759,6 +1745,7 @@ static void et131x_xcvr_init(struct et131x_adapter *adapter)
|
||
u16 imr;
|
||
u16 isr;
|
||
u16 lcr2;
|
||
+ struct phy_device *phydev = adapter->phydev;
|
||
|
||
et131x_mii_read(adapter, PHY_INTERRUPT_STATUS, &isr);
|
||
et131x_mii_read(adapter, PHY_INTERRUPT_MASK, &imr);
|
||
@@ -1770,7 +1757,7 @@ static void et131x_xcvr_init(struct et131x_adapter *adapter)
|
||
ET_PHY_INT_MASK_LINKSTAT &
|
||
ET_PHY_INT_MASK_ENABLE);
|
||
|
||
- et131x_mii_write(adapter, PHY_INTERRUPT_MASK, imr);
|
||
+ et131x_mii_write(adapter, phydev->addr, PHY_INTERRUPT_MASK, imr);
|
||
|
||
/* Set the LED behavior such that LED 1 indicates speed (off =
|
||
* 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates
|
||
@@ -1791,7 +1778,7 @@ static void et131x_xcvr_init(struct et131x_adapter *adapter)
|
||
else
|
||
lcr2 |= (LED_VAL_LINKON << LED_TXRX_SHIFT);
|
||
|
||
- et131x_mii_write(adapter, PHY_LED_2, lcr2);
|
||
+ et131x_mii_write(adapter, phydev->addr, PHY_LED_2, lcr2);
|
||
}
|
||
}
|
||
|
||
@@ -4202,14 +4189,14 @@ static void et131x_adjust_link(struct net_device *netdev)
|
||
|
||
et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG,
|
||
®ister18);
|
||
- et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG,
|
||
- register18 | 0x4);
|
||
- et131x_mii_write(adapter, PHY_INDEX_REG,
|
||
+ et131x_mii_write(adapter, phydev->addr,
|
||
+ PHY_MPHY_CONTROL_REG, register18 | 0x4);
|
||
+ et131x_mii_write(adapter, phydev->addr, PHY_INDEX_REG,
|
||
register18 | 0x8402);
|
||
- et131x_mii_write(adapter, PHY_DATA_REG,
|
||
+ et131x_mii_write(adapter, phydev->addr, PHY_DATA_REG,
|
||
register18 | 511);
|
||
- et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG,
|
||
- register18);
|
||
+ et131x_mii_write(adapter, phydev->addr,
|
||
+ PHY_MPHY_CONTROL_REG, register18);
|
||
}
|
||
|
||
et1310_config_flow_control(adapter);
|
||
@@ -4221,7 +4208,8 @@ static void et131x_adjust_link(struct net_device *netdev)
|
||
et131x_mii_read(adapter, PHY_CONFIG, ®);
|
||
reg &= ~ET_PHY_CONFIG_TX_FIFO_DEPTH;
|
||
reg |= ET_PHY_CONFIG_FIFO_DEPTH_32;
|
||
- et131x_mii_write(adapter, PHY_CONFIG, reg);
|
||
+ et131x_mii_write(adapter, phydev->addr, PHY_CONFIG,
|
||
+ reg);
|
||
}
|
||
|
||
et131x_set_rx_dma_timer(adapter);
|
||
@@ -4254,14 +4242,17 @@ static void et131x_adjust_link(struct net_device *netdev)
|
||
|
||
et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG,
|
||
®ister18);
|
||
- et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG,
|
||
- register18 | 0x4);
|
||
- et131x_mii_write(adapter, PHY_INDEX_REG,
|
||
- register18 | 0x8402);
|
||
- et131x_mii_write(adapter, PHY_DATA_REG,
|
||
- register18 | 511);
|
||
- et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG,
|
||
- register18);
|
||
+ et131x_mii_write(adapter, phydev->addr,
|
||
+ PHY_MPHY_CONTROL_REG,
|
||
+ register18 | 0x4);
|
||
+ et131x_mii_write(adapter, phydev->addr,
|
||
+ PHY_INDEX_REG,
|
||
+ register18 | 0x8402);
|
||
+ et131x_mii_write(adapter, phydev->addr,
|
||
+ PHY_DATA_REG, register18 | 511);
|
||
+ et131x_mii_write(adapter, phydev->addr,
|
||
+ PHY_MPHY_CONTROL_REG,
|
||
+ register18);
|
||
}
|
||
|
||
/* Free the packets being actively sent & stopped */
|
||
@@ -5343,10 +5334,6 @@ static int __devinit et131x_pci_setup(struct pci_dev *pdev,
|
||
/* Copy address into the net_device struct */
|
||
memcpy(netdev->dev_addr, adapter->addr, ETH_ALEN);
|
||
|
||
- /* Init variable for counting how long we do not have link status */
|
||
- adapter->boot_coma = 0;
|
||
- et1310_disable_phy_coma(adapter);
|
||
-
|
||
rc = -ENOMEM;
|
||
|
||
/* Setup the mii_bus struct */
|
||
@@ -5362,7 +5349,6 @@ static int __devinit et131x_pci_setup(struct pci_dev *pdev,
|
||
adapter->mii_bus->priv = netdev;
|
||
adapter->mii_bus->read = et131x_mdio_read;
|
||
adapter->mii_bus->write = et131x_mdio_write;
|
||
- adapter->mii_bus->reset = et131x_mdio_reset;
|
||
adapter->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
|
||
if (!adapter->mii_bus->irq) {
|
||
dev_err(&pdev->dev, "mii_bus irq allocation failed\n");
|
||
@@ -5387,6 +5373,10 @@ static int __devinit et131x_pci_setup(struct pci_dev *pdev,
|
||
/* Setup et1310 as per the documentation */
|
||
et131x_adapter_setup(adapter);
|
||
|
||
+ /* Init variable for counting how long we do not have link status */
|
||
+ adapter->boot_coma = 0;
|
||
+ et1310_disable_phy_coma(adapter);
|
||
+
|
||
/* We can enable interrupts now
|
||
*
|
||
* NOTE - Because registration of interrupt handler is done in the
|
||
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
|
||
index a845866..0cad467 100644
|
||
--- a/drivers/staging/iio/adc/ad799x_core.c
|
||
+++ b/drivers/staging/iio/adc/ad799x_core.c
|
||
@@ -873,7 +873,8 @@ static int __devinit ad799x_probe(struct i2c_client *client,
|
||
return 0;
|
||
|
||
error_free_irq:
|
||
- free_irq(client->irq, indio_dev);
|
||
+ if (client->irq > 0)
|
||
+ free_irq(client->irq, indio_dev);
|
||
error_cleanup_ring:
|
||
ad799x_ring_cleanup(indio_dev);
|
||
error_disable_reg:
|
||
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
|
||
index 90d2d44..3f71e9e 100644
|
||
--- a/drivers/staging/line6/pcm.c
|
||
+++ b/drivers/staging/line6/pcm.c
|
||
@@ -378,8 +378,11 @@ static int snd_line6_pcm_free(struct snd_device *device)
|
||
*/
|
||
static void pcm_disconnect_substream(struct snd_pcm_substream *substream)
|
||
{
|
||
- if (substream->runtime && snd_pcm_running(substream))
|
||
+ if (substream->runtime && snd_pcm_running(substream)) {
|
||
+ snd_pcm_stream_lock_irq(substream);
|
||
snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
|
||
+ snd_pcm_stream_unlock_irq(substream);
|
||
+ }
|
||
}
|
||
|
||
/*
|
||
diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c
|
||
index 76ea4a8..56a96d3 100644
|
||
--- a/drivers/staging/media/lirc/lirc_zilog.c
|
||
+++ b/drivers/staging/media/lirc/lirc_zilog.c
|
||
@@ -61,6 +61,9 @@
|
||
#include <media/lirc_dev.h>
|
||
#include <media/lirc.h>
|
||
|
||
+/* Max transfer size done by I2C transfer functions */
|
||
+#define MAX_XFER_SIZE 64
|
||
+
|
||
struct IR;
|
||
|
||
struct IR_rx {
|
||
@@ -942,7 +945,14 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
|
||
schedule();
|
||
set_current_state(TASK_INTERRUPTIBLE);
|
||
} else {
|
||
- unsigned char buf[rbuf->chunk_size];
|
||
+ unsigned char buf[MAX_XFER_SIZE];
|
||
+
|
||
+ if (rbuf->chunk_size > sizeof(buf)) {
|
||
+ zilog_error("chunk_size is too big (%d)!\n",
|
||
+ rbuf->chunk_size);
|
||
+ ret = -EINVAL;
|
||
+ break;
|
||
+ }
|
||
m = lirc_buffer_read(rbuf, buf);
|
||
if (m == rbuf->chunk_size) {
|
||
ret = copy_to_user((void *)outbuf+written, buf,
|
||
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
|
||
index 91a97b3..5877b2c 100644
|
||
--- a/drivers/staging/octeon/ethernet-tx.c
|
||
+++ b/drivers/staging/octeon/ethernet-tx.c
|
||
@@ -345,7 +345,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
|
||
}
|
||
if (unlikely
|
||
(skb->truesize !=
|
||
- sizeof(*skb) + skb_end_pointer(skb) - skb->head)) {
|
||
+ sizeof(*skb) + skb_end_offset(skb))) {
|
||
/*
|
||
printk("TX buffer truesize has been changed\n");
|
||
*/
|
||
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
|
||
index 1c380d6..1c92451 100644
|
||
--- a/drivers/staging/ozwpan/ozcdev.c
|
||
+++ b/drivers/staging/ozwpan/ozcdev.c
|
||
@@ -153,6 +153,9 @@ ssize_t oz_cdev_write(struct file *filp, const char __user *buf, size_t count,
|
||
struct oz_app_hdr *app_hdr;
|
||
struct oz_serial_ctx *ctx;
|
||
|
||
+ if (count > sizeof(ei->data) - sizeof(*elt) - sizeof(*app_hdr))
|
||
+ return -EINVAL;
|
||
+
|
||
spin_lock_bh(&g_cdev.lock);
|
||
pd = g_cdev.active_pd;
|
||
if (pd)
|
||
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
|
||
index 5b03b40..79f3b97 100644
|
||
--- a/drivers/staging/rtl8712/rtl871x_recv.c
|
||
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
|
||
@@ -253,7 +253,7 @@ union recv_frame *r8712_portctrl(struct _adapter *adapter,
|
||
struct sta_info *psta;
|
||
struct sta_priv *pstapriv;
|
||
union recv_frame *prtnframe;
|
||
- u16 ether_type = 0;
|
||
+ u16 ether_type;
|
||
|
||
pstapriv = &adapter->stapriv;
|
||
ptr = get_recvframe_data(precv_frame);
|
||
@@ -262,15 +262,14 @@ union recv_frame *r8712_portctrl(struct _adapter *adapter,
|
||
psta = r8712_get_stainfo(pstapriv, psta_addr);
|
||
auth_alg = adapter->securitypriv.AuthAlgrthm;
|
||
if (auth_alg == 2) {
|
||
+ /* get ether_type */
|
||
+ ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE;
|
||
+ memcpy(ðer_type, ptr, 2);
|
||
+ ether_type = ntohs((unsigned short)ether_type);
|
||
+
|
||
if ((psta != NULL) && (psta->ieee8021x_blocked)) {
|
||
/* blocked
|
||
* only accept EAPOL frame */
|
||
- prtnframe = precv_frame;
|
||
- /*get ether_type */
|
||
- ptr = ptr + pfhdr->attrib.hdrlen +
|
||
- pfhdr->attrib.iv_len + LLC_HEADER_SIZE;
|
||
- memcpy(ðer_type, ptr, 2);
|
||
- ether_type = ntohs((unsigned short)ether_type);
|
||
if (ether_type == 0x888e)
|
||
prtnframe = precv_frame;
|
||
else {
|
||
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
|
||
index 7b3ae00..1b1bf38 100644
|
||
--- a/drivers/staging/rtl8712/usb_intf.c
|
||
+++ b/drivers/staging/rtl8712/usb_intf.c
|
||
@@ -361,6 +361,10 @@ static u8 key_2char2num(u8 hch, u8 lch)
|
||
return (hex_to_bin(hch) << 4) | hex_to_bin(lch);
|
||
}
|
||
|
||
+static const struct device_type wlan_type = {
|
||
+ .name = "wlan",
|
||
+};
|
||
+
|
||
/*
|
||
* drv_init() - a device potentially for us
|
||
*
|
||
@@ -396,6 +400,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
|
||
padapter->pusb_intf = pusb_intf;
|
||
usb_set_intfdata(pusb_intf, pnetdev);
|
||
SET_NETDEV_DEV(pnetdev, &pusb_intf->dev);
|
||
+ pnetdev->dev.type = &wlan_type;
|
||
/* step 2. */
|
||
padapter->dvobj_init = &r8712_usb_dvobj_init;
|
||
padapter->dvobj_deinit = &r8712_usb_dvobj_deinit;
|
||
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
|
||
index ae1d815..a85d5c9 100644
|
||
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
|
||
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
|
||
@@ -771,7 +771,7 @@ static int qt_startup(struct usb_serial *serial)
|
||
goto startup_error;
|
||
}
|
||
|
||
- switch (serial->dev->descriptor.idProduct) {
|
||
+ switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
|
||
case QUATECH_DSU100:
|
||
case QUATECH_QSU100:
|
||
case QUATECH_ESU100A:
|
||
diff --git a/drivers/staging/speakup/i18n.c b/drivers/staging/speakup/i18n.c
|
||
index c211943..7656014 100644
|
||
--- a/drivers/staging/speakup/i18n.c
|
||
+++ b/drivers/staging/speakup/i18n.c
|
||
@@ -390,7 +390,7 @@ static struct msg_group_t all_groups[] = {
|
||
|
||
static const int num_groups = sizeof(all_groups) / sizeof(struct msg_group_t);
|
||
|
||
-char *msg_get(enum msg_index_t index)
|
||
+char *spk_msg_get(enum msg_index_t index)
|
||
{
|
||
char *ch;
|
||
|
||
@@ -540,7 +540,7 @@ static int fmt_validate(char *template, char *user)
|
||
* -EINVAL - Invalid format specifiers in formatted message or illegal index.
|
||
* -ENOMEM - Unable to allocate memory.
|
||
*/
|
||
-ssize_t msg_set(enum msg_index_t index, char *text, size_t length)
|
||
+ssize_t spk_msg_set(enum msg_index_t index, char *text, size_t length)
|
||
{
|
||
int rc = 0;
|
||
char *newstr = NULL;
|
||
@@ -575,7 +575,7 @@ ssize_t msg_set(enum msg_index_t index, char *text, size_t length)
|
||
* Find a message group, given its name. Return a pointer to the structure
|
||
* if found, or NULL otherwise.
|
||
*/
|
||
-struct msg_group_t *find_msg_group(const char *group_name)
|
||
+struct msg_group_t *spk_find_msg_group(const char *group_name)
|
||
{
|
||
struct msg_group_t *group = NULL;
|
||
int i;
|
||
@@ -589,7 +589,7 @@ struct msg_group_t *find_msg_group(const char *group_name)
|
||
return group;
|
||
}
|
||
|
||
-void reset_msg_group(struct msg_group_t *group)
|
||
+void spk_reset_msg_group(struct msg_group_t *group)
|
||
{
|
||
unsigned long flags;
|
||
enum msg_index_t i;
|
||
@@ -605,14 +605,14 @@ void reset_msg_group(struct msg_group_t *group)
|
||
}
|
||
|
||
/* Called at initialization time, to establish default messages. */
|
||
-void initialize_msgs(void)
|
||
+void spk_initialize_msgs(void)
|
||
{
|
||
memcpy(speakup_msgs, speakup_default_msgs,
|
||
sizeof(speakup_default_msgs));
|
||
}
|
||
|
||
/* Free user-supplied strings when module is unloaded: */
|
||
-void free_user_msgs(void)
|
||
+void spk_free_user_msgs(void)
|
||
{
|
||
enum msg_index_t index;
|
||
unsigned long flags;
|
||
diff --git a/drivers/staging/speakup/i18n.h b/drivers/staging/speakup/i18n.h
|
||
index 65caa80..dd338f4 100644
|
||
--- a/drivers/staging/speakup/i18n.h
|
||
+++ b/drivers/staging/speakup/i18n.h
|
||
@@ -218,11 +218,11 @@ struct msg_group_t {
|
||
enum msg_index_t end;
|
||
};
|
||
|
||
-extern char *msg_get(enum msg_index_t index);
|
||
-extern ssize_t msg_set(enum msg_index_t index, char *text, size_t length);
|
||
-extern struct msg_group_t *find_msg_group(const char *group_name);
|
||
-extern void reset_msg_group(struct msg_group_t *group);
|
||
-extern void initialize_msgs(void);
|
||
-extern void free_user_msgs(void);
|
||
+extern char *spk_msg_get(enum msg_index_t index);
|
||
+extern ssize_t spk_msg_set(enum msg_index_t index, char *text, size_t length);
|
||
+extern struct msg_group_t *spk_find_msg_group(const char *group_name);
|
||
+extern void spk_reset_msg_group(struct msg_group_t *group);
|
||
+extern void spk_initialize_msgs(void);
|
||
+extern void spk_free_user_msgs(void);
|
||
|
||
#endif
|
||
diff --git a/drivers/staging/speakup/keyhelp.c b/drivers/staging/speakup/keyhelp.c
|
||
index 170f388..4c584ec 100644
|
||
--- a/drivers/staging/speakup/keyhelp.c
|
||
+++ b/drivers/staging/speakup/keyhelp.c
|
||
@@ -115,10 +115,10 @@ static void say_key(int key)
|
||
key &= 0xff;
|
||
for (i = 0; i < 6; i++) {
|
||
if (state & masks[i])
|
||
- synth_printf(" %s", msg_get(MSG_STATES_START + i));
|
||
+ synth_printf(" %s", spk_msg_get(MSG_STATES_START + i));
|
||
}
|
||
if ((key > 0) && (key <= num_key_names))
|
||
- synth_printf(" %s\n", msg_get(MSG_KEYNAMES_START + (key - 1)));
|
||
+ synth_printf(" %s\n", spk_msg_get(MSG_KEYNAMES_START + (key - 1)));
|
||
}
|
||
|
||
static int help_init(void)
|
||
@@ -126,9 +126,9 @@ static int help_init(void)
|
||
char start = SPACE;
|
||
int i;
|
||
int num_funcs = MSG_FUNCNAMES_END - MSG_FUNCNAMES_START + 1;
|
||
-state_tbl = our_keys[0]+SHIFT_TBL_SIZE+2;
|
||
+state_tbl = spk_our_keys[0]+SHIFT_TBL_SIZE+2;
|
||
for (i = 0; i < num_funcs; i++) {
|
||
- char *cur_funcname = msg_get(MSG_FUNCNAMES_START + i);
|
||
+ char *cur_funcname = spk_msg_get(MSG_FUNCNAMES_START + i);
|
||
if (start == *cur_funcname)
|
||
continue;
|
||
start = *cur_funcname;
|
||
@@ -137,7 +137,7 @@ state_tbl = our_keys[0]+SHIFT_TBL_SIZE+2;
|
||
return 0;
|
||
}
|
||
|
||
-int handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
+int spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
{
|
||
int i, n;
|
||
char *name;
|
||
@@ -147,15 +147,15 @@ int handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
help_init();
|
||
if (type == KT_LATIN) {
|
||
if (ch == SPACE) {
|
||
- special_handler = NULL;
|
||
- synth_printf("%s\n", msg_get(MSG_LEAVING_HELP));
|
||
+ spk_special_handler = NULL;
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_LEAVING_HELP));
|
||
return 1;
|
||
}
|
||
ch |= 32; /* lower case */
|
||
if (ch < 'a' || ch > 'z')
|
||
return -1;
|
||
if (letter_offsets[ch-'a'] == -1) {
|
||
- synth_printf(msg_get(MSG_NO_COMMAND), ch);
|
||
+ synth_printf(spk_msg_get(MSG_NO_COMMAND), ch);
|
||
synth_printf("\n");
|
||
return 1;
|
||
}
|
||
@@ -169,47 +169,47 @@ int handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
cur_item--;
|
||
else
|
||
return -1;
|
||
- } else if (type == KT_SPKUP && ch == SPEAKUP_HELP && !special_handler) {
|
||
- special_handler = handle_help;
|
||
- synth_printf("%s\n", msg_get(MSG_HELP_INFO));
|
||
+ } else if (type == KT_SPKUP && ch == SPEAKUP_HELP && !spk_special_handler) {
|
||
+ spk_special_handler = spk_handle_help;
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_HELP_INFO));
|
||
build_key_data(); /* rebuild each time in case new mapping */
|
||
return 1;
|
||
} else {
|
||
name = NULL;
|
||
if ((type != KT_SPKUP) && (key > 0) && (key <= num_key_names)) {
|
||
synth_printf("%s\n",
|
||
- msg_get(MSG_KEYNAMES_START + key-1));
|
||
+ spk_msg_get(MSG_KEYNAMES_START + key-1));
|
||
return 1;
|
||
}
|
||
for (i = 0; funcvals[i] != 0 && !name; i++) {
|
||
if (ch == funcvals[i])
|
||
- name = msg_get(MSG_FUNCNAMES_START + i);
|
||
+ name = spk_msg_get(MSG_FUNCNAMES_START + i);
|
||
}
|
||
if (!name)
|
||
return -1;
|
||
- kp = our_keys[key]+1;
|
||
+ kp = spk_our_keys[key]+1;
|
||
for (i = 0; i < nstates; i++) {
|
||
if (ch == kp[i])
|
||
break;
|
||
}
|
||
key += (state_tbl[i] << 8);
|
||
say_key(key);
|
||
- synth_printf(msg_get(MSG_KEYDESC), name);
|
||
+ synth_printf(spk_msg_get(MSG_KEYDESC), name);
|
||
synth_printf("\n");
|
||
return 1;
|
||
}
|
||
- name = msg_get(MSG_FUNCNAMES_START + cur_item);
|
||
+ name = spk_msg_get(MSG_FUNCNAMES_START + cur_item);
|
||
func = funcvals[cur_item];
|
||
synth_printf("%s", name);
|
||
if (key_offsets[func] == 0) {
|
||
- synth_printf(" %s\n", msg_get(MSG_IS_UNASSIGNED));
|
||
+ synth_printf(" %s\n", spk_msg_get(MSG_IS_UNASSIGNED));
|
||
return 1;
|
||
}
|
||
p_keys = key_data + key_offsets[func];
|
||
for (n = 0; p_keys[n]; n++) {
|
||
val = p_keys[n];
|
||
if (n > 0)
|
||
- synth_printf("%s ", msg_get(MSG_DISJUNCTION));
|
||
+ synth_printf("%s ", spk_msg_get(MSG_DISJUNCTION));
|
||
say_key(val);
|
||
}
|
||
return 1;
|
||
diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c
|
||
index 2093896..86387f4 100644
|
||
--- a/drivers/staging/speakup/kobjects.c
|
||
+++ b/drivers/staging/speakup/kobjects.c
|
||
@@ -41,7 +41,7 @@ static ssize_t chars_chartab_show(struct kobject *kobj,
|
||
break;
|
||
if (strcmp("characters", attr->attr.name) == 0) {
|
||
len = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
|
||
- i, characters[i]);
|
||
+ i, spk_characters[i]);
|
||
} else { /* show chartab entry */
|
||
if (IS_TYPE(i, B_CTL))
|
||
cp = "B_CTL";
|
||
@@ -185,12 +185,12 @@ static ssize_t chars_chartab_store(struct kobject *kobj,
|
||
outptr[desc_length] = '\0';
|
||
|
||
if (do_characters) {
|
||
- if (characters[index] != default_chars[index])
|
||
- kfree(characters[index]);
|
||
- characters[index] = desc;
|
||
+ if (spk_characters[index] != spk_default_chars[index])
|
||
+ kfree(spk_characters[index]);
|
||
+ spk_characters[index] = desc;
|
||
used++;
|
||
} else {
|
||
- charclass = chartab_get_value(keyword);
|
||
+ charclass = spk_chartab_get_value(keyword);
|
||
if (charclass == 0) {
|
||
rejected++;
|
||
cp = linefeed + 1;
|
||
@@ -206,9 +206,9 @@ static ssize_t chars_chartab_store(struct kobject *kobj,
|
||
|
||
if (reset) {
|
||
if (do_characters)
|
||
- reset_default_chars();
|
||
+ spk_reset_default_chars();
|
||
else
|
||
- reset_default_chartab();
|
||
+ spk_reset_default_chartab();
|
||
}
|
||
|
||
spk_unlock(flags);
|
||
@@ -232,7 +232,7 @@ static ssize_t keymap_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||
u_char ch;
|
||
unsigned long flags;
|
||
spk_lock(flags);
|
||
- cp1 = key_buf + SHIFT_TBL_SIZE;
|
||
+ cp1 = spk_key_buf + SHIFT_TBL_SIZE;
|
||
num_keys = (int)(*cp1);
|
||
nstates = (int)cp1[1];
|
||
cp += sprintf(cp, "%d, %d, %d,\n", KEY_MAP_VER, num_keys, nstates);
|
||
@@ -271,7 +271,7 @@ static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
return -ENOMEM;
|
||
}
|
||
if (strchr("dDrR", *in_buff)) {
|
||
- set_key_info(key_defaults, key_buf);
|
||
+ spk_set_key_info(spk_key_defaults, spk_key_buf);
|
||
pr_info("keymap set to default values\n");
|
||
kfree(in_buff);
|
||
spk_unlock(flags);
|
||
@@ -282,14 +282,14 @@ static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
cp = in_buff;
|
||
cp1 = (u_char *)in_buff;
|
||
for (i = 0; i < 3; i++) {
|
||
- cp = s2uchar(cp, cp1);
|
||
+ cp = spk_s2uchar(cp, cp1);
|
||
cp1++;
|
||
}
|
||
i = (int)cp1[-2]+1;
|
||
i *= (int)cp1[-1]+1;
|
||
i += 2; /* 0 and last map ver */
|
||
if (cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 ||
|
||
- i+SHIFT_TBL_SIZE+4 >= sizeof(key_buf)) {
|
||
+ i+SHIFT_TBL_SIZE+4 >= sizeof(spk_key_buf)) {
|
||
pr_warn("i %d %d %d %d\n", i,
|
||
(int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
|
||
kfree(in_buff);
|
||
@@ -297,7 +297,7 @@ static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
return -EINVAL;
|
||
}
|
||
while (--i >= 0) {
|
||
- cp = s2uchar(cp, cp1);
|
||
+ cp = spk_s2uchar(cp, cp1);
|
||
cp1++;
|
||
if (!(*cp))
|
||
break;
|
||
@@ -307,8 +307,8 @@ static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
pr_warn("end %d %d %d %d\n", i,
|
||
(int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
|
||
} else {
|
||
- if (set_key_info(in_buff, key_buf)) {
|
||
- set_key_info(key_defaults, key_buf);
|
||
+ if (spk_set_key_info(in_buff, spk_key_buf)) {
|
||
+ spk_set_key_info(spk_key_defaults, spk_key_buf);
|
||
ret = -EINVAL;
|
||
pr_warn("set key failed\n");
|
||
}
|
||
@@ -343,7 +343,7 @@ static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
spk_lock(flags);
|
||
if (ch&2) {
|
||
shut = 1;
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
} else {
|
||
shut = 0;
|
||
}
|
||
@@ -388,7 +388,7 @@ static ssize_t synth_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
if (new_synth_name[len - 1] == '\n')
|
||
len--;
|
||
new_synth_name[len] = '\0';
|
||
- strlwr(new_synth_name);
|
||
+ spk_strlwr(new_synth_name);
|
||
if ((synth != NULL) && (!strcmp(new_synth_name, synth->name))) {
|
||
pr_warn("%s already in use\n", new_synth_name);
|
||
} else if (synth_init(new_synth_name) != 0) {
|
||
@@ -417,7 +417,7 @@ static ssize_t synth_direct_store(struct kobject *kobj,
|
||
bytes = min_t(size_t, len, 250);
|
||
strncpy(tmp, ptr, bytes);
|
||
tmp[bytes] = '\0';
|
||
- xlate(tmp);
|
||
+ spk_xlate(tmp);
|
||
synth_printf("%s", tmp);
|
||
ptr += bytes;
|
||
len -= bytes;
|
||
@@ -455,14 +455,14 @@ static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||
short mask;
|
||
unsigned long flags;
|
||
|
||
- p_header = var_header_by_name(attr->attr.name);
|
||
+ p_header = spk_var_header_by_name(attr->attr.name);
|
||
if (p_header == NULL) {
|
||
pr_warn("p_header is null, attr->attr.name is %s\n",
|
||
attr->attr.name);
|
||
return -EINVAL;
|
||
}
|
||
|
||
- var = get_punc_var(p_header->var_id);
|
||
+ var = spk_get_punc_var(p_header->var_id);
|
||
if (var == NULL) {
|
||
pr_warn("var is null, p_header->var_id is %i\n",
|
||
p_header->var_id);
|
||
@@ -470,7 +470,7 @@ static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||
}
|
||
|
||
spk_lock(flags);
|
||
- pb = (struct st_bits_data *) &punc_info[var->value];
|
||
+ pb = (struct st_bits_data *) &spk_punc_info[var->value];
|
||
mask = pb->mask;
|
||
for (i = 33; i < 128; i++) {
|
||
if (!(spk_chartab[i]&mask))
|
||
@@ -497,14 +497,14 @@ static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
if (x < 1 || x > 99)
|
||
return -EINVAL;
|
||
|
||
- p_header = var_header_by_name(attr->attr.name);
|
||
+ p_header = spk_var_header_by_name(attr->attr.name);
|
||
if (p_header == NULL) {
|
||
pr_warn("p_header is null, attr->attr.name is %s\n",
|
||
attr->attr.name);
|
||
return -EINVAL;
|
||
}
|
||
|
||
- var = get_punc_var(p_header->var_id);
|
||
+ var = spk_get_punc_var(p_header->var_id);
|
||
if (var == NULL) {
|
||
pr_warn("var is null, p_header->var_id is %i\n",
|
||
p_header->var_id);
|
||
@@ -520,9 +520,9 @@ static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
spk_lock(flags);
|
||
|
||
if (*punc_buf == 'd' || *punc_buf == 'r')
|
||
- x = set_mask_bits(0, var->value, 3);
|
||
+ x = spk_set_mask_bits(0, var->value, 3);
|
||
else
|
||
- x = set_mask_bits(punc_buf, var->value, 3);
|
||
+ x = spk_set_mask_bits(punc_buf, var->value, 3);
|
||
|
||
spk_unlock(flags);
|
||
return count;
|
||
@@ -542,7 +542,7 @@ ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||
char ch;
|
||
unsigned long flags;
|
||
|
||
- param = var_header_by_name(attr->attr.name);
|
||
+ param = spk_var_header_by_name(attr->attr.name);
|
||
if (param == NULL)
|
||
return -EINVAL;
|
||
|
||
@@ -599,13 +599,13 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
int value;
|
||
unsigned long flags;
|
||
|
||
- param = var_header_by_name(attr->attr.name);
|
||
+ param = spk_var_header_by_name(attr->attr.name);
|
||
if (param == NULL)
|
||
return -EINVAL;
|
||
if (param->data == NULL)
|
||
return 0;
|
||
ret = 0;
|
||
- cp = xlate((char *) buf);
|
||
+ cp = spk_xlate((char *) buf);
|
||
|
||
spk_lock(flags);
|
||
switch (param->var_type) {
|
||
@@ -618,7 +618,7 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
else
|
||
len = E_SET;
|
||
speakup_s2i(cp, &value);
|
||
- ret = set_num_var(value, param, len);
|
||
+ ret = spk_set_num_var(value, param, len);
|
||
if (ret == E_RANGE) {
|
||
var_data = param->data;
|
||
pr_warn("value for %s out of range, expect %d to %d\n",
|
||
@@ -636,7 +636,7 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
}
|
||
cp = (char *) buf;
|
||
cp[len] = '\0';
|
||
- ret = set_string_var(buf, param, len);
|
||
+ ret = spk_set_string_var(buf, param, len);
|
||
if (ret == E_TOOLONG)
|
||
pr_warn("value too long for %s\n",
|
||
attr->attr.name);
|
||
@@ -652,19 +652,19 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
*/
|
||
if (strcmp(attr->attr.name, "voice") == 0) {
|
||
if (synth && synth->default_pitch) {
|
||
- param = var_header_by_name("pitch");
|
||
+ param = spk_var_header_by_name("pitch");
|
||
if (param) {
|
||
- set_num_var(synth->default_pitch[value], param,
|
||
+ spk_set_num_var(synth->default_pitch[value], param,
|
||
E_NEW_DEFAULT);
|
||
- set_num_var(0, param, E_DEFAULT);
|
||
+ spk_set_num_var(0, param, E_DEFAULT);
|
||
}
|
||
}
|
||
if (synth && synth->default_vol) {
|
||
- param = var_header_by_name("vol");
|
||
+ param = spk_var_header_by_name("vol");
|
||
if (param) {
|
||
- set_num_var(synth->default_vol[value], param,
|
||
+ spk_set_num_var(synth->default_vol[value], param,
|
||
E_NEW_DEFAULT);
|
||
- set_num_var(0, param, E_DEFAULT);
|
||
+ spk_set_num_var(0, param, E_DEFAULT);
|
||
}
|
||
}
|
||
}
|
||
@@ -694,7 +694,7 @@ static ssize_t message_show_helper(char *buf, enum msg_index_t first,
|
||
if (bufsize <= 1)
|
||
break;
|
||
printed = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
|
||
- index, msg_get(cursor));
|
||
+ index, spk_msg_get(cursor));
|
||
buf_pointer += printed;
|
||
bufsize -= printed;
|
||
}
|
||
@@ -788,7 +788,7 @@ static ssize_t message_store_helper(const char *buf, size_t count,
|
||
continue;
|
||
}
|
||
|
||
- msg_stored = msg_set(curmessage, temp, desc_length);
|
||
+ msg_stored = spk_msg_set(curmessage, temp, desc_length);
|
||
if (msg_stored < 0) {
|
||
retval = msg_stored;
|
||
if (msg_stored == -ENOMEM)
|
||
@@ -802,7 +802,7 @@ static ssize_t message_store_helper(const char *buf, size_t count,
|
||
}
|
||
|
||
if (reset)
|
||
- reset_msg_group(group);
|
||
+ spk_reset_msg_group(group);
|
||
|
||
report_msg_status(reset, received, used, rejected, group->name);
|
||
return retval;
|
||
@@ -812,7 +812,7 @@ static ssize_t message_show(struct kobject *kobj,
|
||
struct kobj_attribute *attr, char *buf)
|
||
{
|
||
ssize_t retval = 0;
|
||
- struct msg_group_t *group = find_msg_group(attr->attr.name);
|
||
+ struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
|
||
unsigned long flags;
|
||
|
||
BUG_ON(!group);
|
||
@@ -826,7 +826,7 @@ static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
const char *buf, size_t count)
|
||
{
|
||
ssize_t retval = 0;
|
||
- struct msg_group_t *group = find_msg_group(attr->attr.name);
|
||
+ struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
|
||
|
||
BUG_ON(!group);
|
||
retval = message_store_helper(buf, count, group);
|
||
diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c
|
||
index 40e2488..192218a 100644
|
||
--- a/drivers/staging/speakup/main.c
|
||
+++ b/drivers/staging/speakup/main.c
|
||
@@ -65,23 +65,23 @@ MODULE_VERSION(SPEAKUP_VERSION);
|
||
|
||
char *synth_name;
|
||
module_param_named(synth, synth_name, charp, S_IRUGO);
|
||
-module_param_named(quiet, quiet_boot, bool, S_IRUGO);
|
||
+module_param_named(quiet, spk_quiet_boot, bool, S_IRUGO);
|
||
|
||
MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
|
||
MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
|
||
|
||
-special_func special_handler;
|
||
+special_func spk_special_handler;
|
||
|
||
-short pitch_shift, synth_flags;
|
||
+short spk_pitch_shift, synth_flags;
|
||
static char buf[256];
|
||
-int attrib_bleep, bleeps, bleep_time = 10;
|
||
-int no_intr, spell_delay;
|
||
-int key_echo, say_word_ctl;
|
||
-int say_ctrl, bell_pos;
|
||
-short punc_mask;
|
||
-int punc_level, reading_punc;
|
||
-char str_caps_start[MAXVARLEN + 1] = "\0", str_caps_stop[MAXVARLEN + 1] = "\0";
|
||
-const struct st_bits_data punc_info[] = {
|
||
+int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
|
||
+int spk_no_intr, spk_spell_delay;
|
||
+int spk_key_echo, spk_say_word_ctl;
|
||
+int spk_say_ctrl, spk_bell_pos;
|
||
+short spk_punc_mask;
|
||
+int spk_punc_level, spk_reading_punc;
|
||
+char spk_str_caps_start[MAXVARLEN + 1] = "\0", spk_str_caps_stop[MAXVARLEN + 1] = "\0";
|
||
+const struct st_bits_data spk_punc_info[] = {
|
||
{"none", "", 0},
|
||
{"some", "/$%&@", SOME},
|
||
{"most", "$%&#()=+*/@^<>|\\", MOST},
|
||
@@ -95,9 +95,9 @@ const struct st_bits_data punc_info[] = {
|
||
|
||
static char mark_cut_flag;
|
||
#define MAX_KEY 160
|
||
-u_char *our_keys[MAX_KEY], *shift_table;
|
||
-u_char key_buf[600];
|
||
-const u_char key_defaults[] = {
|
||
+u_char *spk_our_keys[MAX_KEY], *spk_shift_table;
|
||
+u_char spk_key_buf[600];
|
||
+const u_char spk_key_defaults[] = {
|
||
#include "speakupmap.h"
|
||
};
|
||
|
||
@@ -129,9 +129,9 @@ static char *phonetic[] = {
|
||
/* array of 256 char pointers (one for each character description)
|
||
* initialized to default_chars and user selectable via
|
||
* /proc/speakup/characters */
|
||
-char *characters[256];
|
||
+char *spk_characters[256];
|
||
|
||
-char *default_chars[256] = {
|
||
+char *spk_default_chars[256] = {
|
||
/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
|
||
/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
|
||
/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
|
||
@@ -238,7 +238,7 @@ static u_short default_chartab[256] = {
|
||
};
|
||
|
||
struct task_struct *speakup_task;
|
||
-struct bleep unprocessed_sound;
|
||
+struct bleep spk_unprocessed_sound;
|
||
static int spk_keydown;
|
||
static u_char spk_lastkey, spk_close_press, keymap_flags;
|
||
static u_char last_keycode, this_speakup_key;
|
||
@@ -282,13 +282,13 @@ static void bleep(u_short val)
|
||
350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
|
||
};
|
||
short freq;
|
||
- int time = bleep_time;
|
||
+ int time = spk_bleep_time;
|
||
freq = vals[val % 12];
|
||
if (val > 11)
|
||
freq *= (1 << (val / 12));
|
||
- unprocessed_sound.freq = freq;
|
||
- unprocessed_sound.jiffies = msecs_to_jiffies(time);
|
||
- unprocessed_sound.active = 1;
|
||
+ spk_unprocessed_sound.freq = freq;
|
||
+ spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
|
||
+ spk_unprocessed_sound.active = 1;
|
||
/* We can only have 1 active sound at a time. */
|
||
}
|
||
|
||
@@ -300,7 +300,7 @@ static void speakup_shut_up(struct vc_data *vc)
|
||
spk_parked &= 0xfe;
|
||
speakup_date(vc);
|
||
if (synth != NULL)
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
}
|
||
|
||
static void speech_kill(struct vc_data *vc)
|
||
@@ -313,9 +313,9 @@ static void speech_kill(struct vc_data *vc)
|
||
if (val == 2 || spk_killed) {
|
||
/* dead */
|
||
spk_shut_up &= ~0x40;
|
||
- synth_printf("%s\n", msg_get(MSG_IAM_ALIVE));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
|
||
} else {
|
||
- synth_printf("%s\n", msg_get(MSG_YOU_KILLED_SPEAKUP));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
|
||
spk_shut_up |= 0x40;
|
||
}
|
||
}
|
||
@@ -324,10 +324,10 @@ static void speakup_off(struct vc_data *vc)
|
||
{
|
||
if (spk_shut_up & 0x80) {
|
||
spk_shut_up &= 0x7f;
|
||
- synth_printf("%s\n", msg_get(MSG_HEY_THATS_BETTER));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
|
||
} else {
|
||
spk_shut_up |= 0x80;
|
||
- synth_printf("%s\n", msg_get(MSG_YOU_TURNED_ME_OFF));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
|
||
}
|
||
speakup_date(vc);
|
||
}
|
||
@@ -336,10 +336,10 @@ static void speakup_parked(struct vc_data *vc)
|
||
{
|
||
if (spk_parked & 0x80) {
|
||
spk_parked = 0;
|
||
- synth_printf("%s\n", msg_get(MSG_UNPARKED));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
|
||
} else {
|
||
spk_parked |= 0x80;
|
||
- synth_printf("%s\n", msg_get(MSG_PARKED));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_PARKED));
|
||
}
|
||
}
|
||
|
||
@@ -350,16 +350,16 @@ static void speakup_cut(struct vc_data *vc)
|
||
|
||
if (!mark_cut_flag) {
|
||
mark_cut_flag = 1;
|
||
- xs = (u_short) spk_x;
|
||
- ys = (u_short) spk_y;
|
||
+ spk_xs = (u_short) spk_x;
|
||
+ spk_ys = (u_short) spk_y;
|
||
spk_sel_cons = vc;
|
||
- synth_printf("%s\n", msg_get(MSG_MARK));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_MARK));
|
||
return;
|
||
}
|
||
- xe = (u_short) spk_x;
|
||
- ye = (u_short) spk_y;
|
||
+ spk_xe = (u_short) spk_x;
|
||
+ spk_ye = (u_short) spk_y;
|
||
mark_cut_flag = 0;
|
||
- synth_printf("%s\n", msg_get(MSG_CUT));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_CUT));
|
||
|
||
speakup_clear_selection();
|
||
ret = speakup_set_selection(tty);
|
||
@@ -383,9 +383,9 @@ static void speakup_paste(struct vc_data *vc)
|
||
{
|
||
if (mark_cut_flag) {
|
||
mark_cut_flag = 0;
|
||
- synth_printf("%s\n", msg_get(MSG_MARK_CLEARED));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
|
||
} else {
|
||
- synth_printf("%s\n", msg_get(MSG_PASTE));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_PASTE));
|
||
speakup_paste_selection(tty);
|
||
}
|
||
}
|
||
@@ -395,16 +395,16 @@ static void say_attributes(struct vc_data *vc)
|
||
int fg = spk_attr & 0x0f;
|
||
int bg = spk_attr >> 4;
|
||
if (fg > 8) {
|
||
- synth_printf("%s ", msg_get(MSG_BRIGHT));
|
||
+ synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
|
||
fg -= 8;
|
||
}
|
||
- synth_printf("%s", msg_get(MSG_COLORS_START + fg));
|
||
+ synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
|
||
if (bg > 7) {
|
||
- synth_printf(" %s ", msg_get(MSG_ON_BLINKING));
|
||
+ synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
|
||
bg -= 8;
|
||
} else
|
||
- synth_printf(" %s ", msg_get(MSG_ON));
|
||
- synth_printf("%s\n", msg_get(MSG_COLORS_START + bg));
|
||
+ synth_printf(" %s ", spk_msg_get(MSG_ON));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
|
||
}
|
||
|
||
enum {
|
||
@@ -417,24 +417,24 @@ enum {
|
||
|
||
static void announce_edge(struct vc_data *vc, int msg_id)
|
||
{
|
||
- if (bleeps & 1)
|
||
+ if (spk_bleeps & 1)
|
||
bleep(spk_y);
|
||
- if ((bleeps & 2) && (msg_id < edge_quiet))
|
||
- synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
|
||
+ if ((spk_bleeps & 2) && (msg_id < edge_quiet))
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
|
||
}
|
||
|
||
static void speak_char(u_char ch)
|
||
{
|
||
- char *cp = characters[ch];
|
||
- struct var_t *direct = get_var(DIRECT);
|
||
+ char *cp = spk_characters[ch];
|
||
+ struct var_t *direct = spk_get_var(DIRECT);
|
||
if (direct && direct->u.n.value) {
|
||
if (IS_CHAR(ch, B_CAP)) {
|
||
- pitch_shift++;
|
||
- synth_printf("%s", str_caps_start);
|
||
+ spk_pitch_shift++;
|
||
+ synth_printf("%s", spk_str_caps_start);
|
||
}
|
||
synth_printf("%c", ch);
|
||
if (IS_CHAR(ch, B_CAP))
|
||
- synth_printf("%s", str_caps_stop);
|
||
+ synth_printf("%s", spk_str_caps_stop);
|
||
return;
|
||
}
|
||
if (cp == NULL) {
|
||
@@ -443,13 +443,13 @@ static void speak_char(u_char ch)
|
||
}
|
||
synth_buffer_add(SPACE);
|
||
if (IS_CHAR(ch, B_CAP)) {
|
||
- pitch_shift++;
|
||
- synth_printf("%s", str_caps_start);
|
||
+ spk_pitch_shift++;
|
||
+ synth_printf("%s", spk_str_caps_start);
|
||
synth_printf("%s", cp);
|
||
- synth_printf("%s", str_caps_stop);
|
||
+ synth_printf("%s", spk_str_caps_stop);
|
||
} else {
|
||
if (*cp == '^') {
|
||
- synth_printf("%s", msg_get(MSG_CTRL));
|
||
+ synth_printf("%s", spk_msg_get(MSG_CTRL));
|
||
cp++;
|
||
}
|
||
synth_printf("%s", cp);
|
||
@@ -479,9 +479,9 @@ static void say_char(struct vc_data *vc)
|
||
spk_old_attr = spk_attr;
|
||
ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
|
||
if (spk_attr != spk_old_attr) {
|
||
- if (attrib_bleep & 1)
|
||
+ if (spk_attrib_bleep & 1)
|
||
bleep(spk_y);
|
||
- if (attrib_bleep & 2)
|
||
+ if (spk_attrib_bleep & 2)
|
||
say_attributes(vc);
|
||
}
|
||
speak_char(ch & 0xff);
|
||
@@ -497,7 +497,7 @@ static void say_phonetic_char(struct vc_data *vc)
|
||
synth_printf("%s\n", phonetic[--ch]);
|
||
} else {
|
||
if (IS_CHAR(ch, B_NUM))
|
||
- synth_printf("%s ", msg_get(MSG_NUMBER));
|
||
+ synth_printf("%s ", spk_msg_get(MSG_NUMBER));
|
||
speak_char(ch);
|
||
}
|
||
}
|
||
@@ -527,8 +527,8 @@ static void say_next_char(struct vc_data *vc)
|
||
}
|
||
|
||
/* get_word - will first check to see if the character under the
|
||
- * reading cursor is a space and if say_word_ctl is true it will
|
||
- * return the word space. If say_word_ctl is not set it will check to
|
||
+ * reading cursor is a space and if spk_say_word_ctl is true it will
|
||
+ * return the word space. If spk_say_word_ctl is not set it will check to
|
||
* see if there is a word starting on the next position to the right
|
||
* and return that word if it exists. If it does not exist it will
|
||
* move left to the beginning of any previous word on the line or the
|
||
@@ -544,9 +544,9 @@ static u_long get_word(struct vc_data *vc)
|
||
ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
|
||
|
||
/* decided to take out the sayword if on a space (mis-information */
|
||
- if (say_word_ctl && ch == SPACE) {
|
||
+ if (spk_say_word_ctl && ch == SPACE) {
|
||
*buf = '\0';
|
||
- synth_printf("%s\n", msg_get(MSG_SPACE));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_SPACE));
|
||
return 0;
|
||
} else if ((tmpx < vc->vc_cols - 2)
|
||
&& (ch == SPACE || ch == 0 || IS_WDLM(ch))
|
||
@@ -582,13 +582,13 @@ static u_long get_word(struct vc_data *vc)
|
||
static void say_word(struct vc_data *vc)
|
||
{
|
||
u_long cnt = get_word(vc);
|
||
- u_short saved_punc_mask = punc_mask;
|
||
+ u_short saved_punc_mask = spk_punc_mask;
|
||
if (cnt == 0)
|
||
return;
|
||
- punc_mask = PUNC;
|
||
+ spk_punc_mask = PUNC;
|
||
buf[cnt++] = SPACE;
|
||
spkup_write(buf, cnt);
|
||
- punc_mask = saved_punc_mask;
|
||
+ spk_punc_mask = saved_punc_mask;
|
||
}
|
||
|
||
static void say_prev_word(struct vc_data *vc)
|
||
@@ -686,22 +686,22 @@ static void say_next_word(struct vc_data *vc)
|
||
static void spell_word(struct vc_data *vc)
|
||
{
|
||
static char *delay_str[] = { "", ",", ".", ". .", ". . ." };
|
||
- char *cp = buf, *str_cap = str_caps_stop;
|
||
- char *cp1, *last_cap = str_caps_stop;
|
||
+ char *cp = buf, *str_cap = spk_str_caps_stop;
|
||
+ char *cp1, *last_cap = spk_str_caps_stop;
|
||
u_char ch;
|
||
if (!get_word(vc))
|
||
return;
|
||
while ((ch = (u_char) *cp)) {
|
||
if (cp != buf)
|
||
- synth_printf(" %s ", delay_str[spell_delay]);
|
||
+ synth_printf(" %s ", delay_str[spk_spell_delay]);
|
||
if (IS_CHAR(ch, B_CAP)) {
|
||
- str_cap = str_caps_start;
|
||
- if (*str_caps_stop)
|
||
- pitch_shift++;
|
||
+ str_cap = spk_str_caps_start;
|
||
+ if (*spk_str_caps_stop)
|
||
+ spk_pitch_shift++;
|
||
else /* synth has no pitch */
|
||
- last_cap = str_caps_stop;
|
||
+ last_cap = spk_str_caps_stop;
|
||
} else
|
||
- str_cap = str_caps_stop;
|
||
+ str_cap = spk_str_caps_stop;
|
||
if (str_cap != last_cap) {
|
||
synth_printf("%s", str_cap);
|
||
last_cap = str_cap;
|
||
@@ -711,17 +711,17 @@ static void spell_word(struct vc_data *vc)
|
||
ch &= 31;
|
||
cp1 = phonetic[--ch];
|
||
} else {
|
||
- cp1 = characters[ch];
|
||
+ cp1 = spk_characters[ch];
|
||
if (*cp1 == '^') {
|
||
- synth_printf("%s", msg_get(MSG_CTRL));
|
||
+ synth_printf("%s", spk_msg_get(MSG_CTRL));
|
||
cp1++;
|
||
}
|
||
}
|
||
synth_printf("%s", cp1);
|
||
cp++;
|
||
}
|
||
- if (str_cap != str_caps_stop)
|
||
- synth_printf("%s", str_caps_stop);
|
||
+ if (str_cap != spk_str_caps_stop)
|
||
+ synth_printf("%s", spk_str_caps_stop);
|
||
}
|
||
|
||
static int get_line(struct vc_data *vc)
|
||
@@ -746,9 +746,9 @@ static void say_line(struct vc_data *vc)
|
||
{
|
||
int i = get_line(vc);
|
||
char *cp;
|
||
- u_short saved_punc_mask = punc_mask;
|
||
+ u_short saved_punc_mask = spk_punc_mask;
|
||
if (i == 0) {
|
||
- synth_printf("%s\n", msg_get(MSG_BLANK));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_BLANK));
|
||
return;
|
||
}
|
||
buf[i++] = '\n';
|
||
@@ -758,9 +758,9 @@ static void say_line(struct vc_data *vc)
|
||
cp++;
|
||
synth_printf("%d, ", (cp - buf) + 1);
|
||
}
|
||
- punc_mask = punc_masks[reading_punc];
|
||
+ spk_punc_mask = spk_punc_masks[spk_reading_punc];
|
||
spkup_write(buf, i);
|
||
- punc_mask = saved_punc_mask;
|
||
+ spk_punc_mask = saved_punc_mask;
|
||
}
|
||
|
||
static void say_prev_line(struct vc_data *vc)
|
||
@@ -792,7 +792,7 @@ static int say_from_to(struct vc_data *vc, u_long from, u_long to,
|
||
{
|
||
int i = 0;
|
||
u_char tmp;
|
||
- u_short saved_punc_mask = punc_mask;
|
||
+ u_short saved_punc_mask = spk_punc_mask;
|
||
spk_old_attr = spk_attr;
|
||
spk_attr = get_attributes((u_short *) from);
|
||
while (from < to) {
|
||
@@ -809,10 +809,10 @@ static int say_from_to(struct vc_data *vc, u_long from, u_long to,
|
||
if (i < 1)
|
||
return i;
|
||
if (read_punc)
|
||
- punc_mask = punc_info[reading_punc].mask;
|
||
+ spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
|
||
spkup_write(buf, i);
|
||
if (read_punc)
|
||
- punc_mask = saved_punc_mask;
|
||
+ spk_punc_mask = saved_punc_mask;
|
||
return i - 1;
|
||
}
|
||
|
||
@@ -824,7 +824,7 @@ static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
|
||
start += from * 2;
|
||
if (say_from_to(vc, start, end, read_punc) <= 0)
|
||
if (cursor_track != read_all_mode)
|
||
- synth_printf("%s\n", msg_get(MSG_BLANK));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_BLANK));
|
||
}
|
||
|
||
/* Sentence Reading Commands */
|
||
@@ -924,7 +924,7 @@ static void speakup_win_say(struct vc_data *vc)
|
||
{
|
||
u_long start, end, from, to;
|
||
if (win_start < 2) {
|
||
- synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
|
||
return;
|
||
}
|
||
start = vc->vc_origin + (win_top * vc->vc_size_row);
|
||
@@ -975,7 +975,7 @@ static void say_first_char(struct vc_data *vc)
|
||
u_char ch;
|
||
spk_parked |= 0x01;
|
||
if (len == 0) {
|
||
- synth_printf("%s\n", msg_get(MSG_BLANK));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_BLANK));
|
||
return;
|
||
}
|
||
for (i = 0; i < len; i++)
|
||
@@ -994,7 +994,7 @@ static void say_last_char(struct vc_data *vc)
|
||
u_char ch;
|
||
spk_parked |= 0x01;
|
||
if (len == 0) {
|
||
- synth_printf("%s\n", msg_get(MSG_BLANK));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_BLANK));
|
||
return;
|
||
}
|
||
ch = buf[--len];
|
||
@@ -1006,7 +1006,7 @@ static void say_last_char(struct vc_data *vc)
|
||
|
||
static void say_position(struct vc_data *vc)
|
||
{
|
||
- synth_printf(msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
|
||
+ synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
|
||
vc->vc_num + 1);
|
||
synth_printf("\n");
|
||
}
|
||
@@ -1017,7 +1017,7 @@ static void say_char_num(struct vc_data *vc)
|
||
u_char tmp;
|
||
u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
|
||
ch &= 0xff;
|
||
- synth_printf(msg_get(MSG_CHAR_INFO), ch, ch);
|
||
+ synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
|
||
}
|
||
|
||
/* these are stub functions to keep keyboard.c happy. */
|
||
@@ -1066,7 +1066,7 @@ static void spkup_write(const char *in_buf, int count)
|
||
} else {
|
||
if ((last_type & CH_RPT) && rep_count > 2) {
|
||
synth_printf(" ");
|
||
- synth_printf(msg_get(MSG_REPEAT_DESC),
|
||
+ synth_printf(spk_msg_get(MSG_REPEAT_DESC),
|
||
++rep_count);
|
||
synth_printf(" ");
|
||
}
|
||
@@ -1074,7 +1074,7 @@ static void spkup_write(const char *in_buf, int count)
|
||
}
|
||
if (ch == spk_lastkey) {
|
||
rep_count = 0;
|
||
- if (key_echo == 1 && ch >= MINECHOCHAR)
|
||
+ if (spk_key_echo == 1 && ch >= MINECHOCHAR)
|
||
speak_char(ch);
|
||
} else if (char_type & B_ALPHA) {
|
||
if ((synth_flags & SF_DEC) && (last_type & PUNC))
|
||
@@ -1083,7 +1083,7 @@ static void spkup_write(const char *in_buf, int count)
|
||
} else if (char_type & B_NUM) {
|
||
rep_count = 0;
|
||
synth_printf("%c", ch);
|
||
- } else if (char_type & punc_mask) {
|
||
+ } else if (char_type & spk_punc_mask) {
|
||
speak_char(ch);
|
||
char_type &= ~PUNC; /* for dec nospell processing */
|
||
} else if (char_type & SYNTH_OK) {
|
||
@@ -1111,7 +1111,7 @@ static void spkup_write(const char *in_buf, int count)
|
||
if (in_count > 2 && rep_count > 2) {
|
||
if (last_type & CH_RPT) {
|
||
synth_printf(" ");
|
||
- synth_printf(msg_get(MSG_REPEAT_DESC2), ++rep_count);
|
||
+ synth_printf(spk_msg_get(MSG_REPEAT_DESC2), ++rep_count);
|
||
synth_printf(" ");
|
||
}
|
||
rep_count = 0;
|
||
@@ -1135,22 +1135,22 @@ static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
|
||
case KVAL(K_SHIFT):
|
||
del_timer(&cursor_timer);
|
||
spk_shut_up &= 0xfe;
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
read_all_doc(vc);
|
||
break;
|
||
case KVAL(K_CTRL):
|
||
del_timer(&cursor_timer);
|
||
cursor_track = prev_cursor_track;
|
||
spk_shut_up &= 0xfe;
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
break;
|
||
}
|
||
} else {
|
||
spk_shut_up &= 0xfe;
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
}
|
||
- if (say_ctrl && value < NUM_CTL_LABELS)
|
||
- synth_printf("%s", msg_get(MSG_CTL_START + value));
|
||
+ if (spk_say_ctrl && value < NUM_CTL_LABELS)
|
||
+ synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
|
||
spk_unlock(flags);
|
||
}
|
||
|
||
@@ -1171,12 +1171,12 @@ static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
|
||
spk_lastkey = value;
|
||
spk_keydown++;
|
||
spk_parked &= 0xfe;
|
||
- if (key_echo == 2 && value >= MINECHOCHAR)
|
||
+ if (spk_key_echo == 2 && value >= MINECHOCHAR)
|
||
speak_char(value);
|
||
spk_unlock(flags);
|
||
}
|
||
|
||
-int set_key_info(const u_char *key_info, u_char *k_buffer)
|
||
+int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
|
||
{
|
||
int i = 0, states, key_data_len;
|
||
const u_char *cp = key_info;
|
||
@@ -1188,12 +1188,12 @@ int set_key_info(const u_char *key_info, u_char *k_buffer)
|
||
num_keys = *cp;
|
||
states = (int)cp[1];
|
||
key_data_len = (states + 1) * (num_keys + 1);
|
||
- if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(key_buf))
|
||
+ if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
|
||
return -2;
|
||
memset(k_buffer, 0, SHIFT_TBL_SIZE);
|
||
- memset(our_keys, 0, sizeof(our_keys));
|
||
- shift_table = k_buffer;
|
||
- our_keys[0] = shift_table;
|
||
+ memset(spk_our_keys, 0, sizeof(spk_our_keys));
|
||
+ spk_shift_table = k_buffer;
|
||
+ spk_our_keys[0] = spk_shift_table;
|
||
cp1 += SHIFT_TBL_SIZE;
|
||
memcpy(cp1, cp, key_data_len + 3);
|
||
/* get num_keys, states and data */
|
||
@@ -1202,13 +1202,13 @@ int set_key_info(const u_char *key_info, u_char *k_buffer)
|
||
ch = *cp1++;
|
||
if (ch >= SHIFT_TBL_SIZE)
|
||
return -3;
|
||
- shift_table[ch] = i;
|
||
+ spk_shift_table[ch] = i;
|
||
}
|
||
keymap_flags = *cp1++;
|
||
while ((ch = *cp1)) {
|
||
if (ch >= MAX_KEY)
|
||
return -4;
|
||
- our_keys[ch] = cp1;
|
||
+ spk_our_keys[ch] = cp1;
|
||
cp1 += states + 1;
|
||
}
|
||
return 0;
|
||
@@ -1237,24 +1237,24 @@ static void toggle_cursoring(struct vc_data *vc)
|
||
cursor_track = prev_cursor_track;
|
||
if (++cursor_track >= CT_Max)
|
||
cursor_track = 0;
|
||
- synth_printf("%s\n", msg_get(MSG_CURSOR_MSGS_START + cursor_track));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
|
||
}
|
||
|
||
-void reset_default_chars(void)
|
||
+void spk_reset_default_chars(void)
|
||
{
|
||
int i;
|
||
|
||
/* First, free any non-default */
|
||
for (i = 0; i < 256; i++) {
|
||
- if ((characters[i] != NULL)
|
||
- && (characters[i] != default_chars[i]))
|
||
- kfree(characters[i]);
|
||
+ if ((spk_characters[i] != NULL)
|
||
+ && (spk_characters[i] != spk_default_chars[i]))
|
||
+ kfree(spk_characters[i]);
|
||
}
|
||
|
||
- memcpy(characters, default_chars, sizeof(default_chars));
|
||
+ memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
|
||
}
|
||
|
||
-void reset_default_chartab(void)
|
||
+void spk_reset_default_chartab(void)
|
||
{
|
||
memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
|
||
}
|
||
@@ -1267,8 +1267,8 @@ static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
|
||
return -1;
|
||
if (ch == SPACE) {
|
||
- synth_printf("%s\n", msg_get(MSG_EDIT_DONE));
|
||
- special_handler = NULL;
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
|
||
+ spk_special_handler = NULL;
|
||
return 1;
|
||
}
|
||
if (mask < PUNC && !(ch_type & PUNC))
|
||
@@ -1276,8 +1276,8 @@ static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
spk_chartab[ch] ^= mask;
|
||
speak_char(ch);
|
||
synth_printf(" %s\n",
|
||
- (spk_chartab[ch] & mask) ? msg_get(MSG_ON) :
|
||
- msg_get(MSG_OFF));
|
||
+ (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
|
||
+ spk_msg_get(MSG_OFF));
|
||
return 1;
|
||
}
|
||
|
||
@@ -1346,7 +1346,7 @@ static void read_all_doc(struct vc_data *vc)
|
||
if (cursor_track != read_all_mode)
|
||
prev_cursor_track = cursor_track;
|
||
cursor_track = read_all_mode;
|
||
- reset_index_count(0);
|
||
+ spk_reset_index_count(0);
|
||
if (get_sentence_buf(vc, 0) == -1)
|
||
kbd_fakekey2(vc, RA_DOWN_ARROW);
|
||
else {
|
||
@@ -1361,7 +1361,7 @@ static void stop_read_all(struct vc_data *vc)
|
||
del_timer(&cursor_timer);
|
||
cursor_track = prev_cursor_track;
|
||
spk_shut_up &= 0xfe;
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
}
|
||
|
||
static void start_read_all_timer(struct vc_data *vc, int command)
|
||
@@ -1370,7 +1370,7 @@ static void start_read_all_timer(struct vc_data *vc, int command)
|
||
|
||
cursor_con = vc->vc_num;
|
||
read_all_key = command;
|
||
- cursor_timeout = get_var(CURSOR_TIME);
|
||
+ cursor_timeout = spk_get_var(CURSOR_TIME);
|
||
mod_timer(&cursor_timer,
|
||
jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
|
||
}
|
||
@@ -1382,9 +1382,9 @@ static void handle_cursor_read_all(struct vc_data *vc, int command)
|
||
switch (command) {
|
||
case RA_NEXT_SENT:
|
||
/* Get Current Sentence */
|
||
- get_index_count(&indcount, &sentcount);
|
||
+ spk_get_index_count(&indcount, &sentcount);
|
||
/*printk("%d %d ", indcount, sentcount); */
|
||
- reset_index_count(sentcount + 1);
|
||
+ spk_reset_index_count(sentcount + 1);
|
||
if (indcount == 1) {
|
||
if (!say_sentence_num(sentcount + 1, 0)) {
|
||
kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
|
||
@@ -1395,7 +1395,7 @@ static void handle_cursor_read_all(struct vc_data *vc, int command)
|
||
sn = 0;
|
||
if (!say_sentence_num(sentcount + 1, 1)) {
|
||
sn = 1;
|
||
- reset_index_count(sn);
|
||
+ spk_reset_index_count(sn);
|
||
} else
|
||
synth_insert_next_index(0);
|
||
if (!say_sentence_num(sn, 0)) {
|
||
@@ -1437,7 +1437,7 @@ static void handle_cursor_read_all(struct vc_data *vc, int command)
|
||
case RA_FIND_PREV_SENT:
|
||
break;
|
||
case RA_TIMER:
|
||
- get_index_count(&indcount, &sentcount);
|
||
+ spk_get_index_count(&indcount, &sentcount);
|
||
if (indcount < 2)
|
||
kbd_fakekey2(vc, RA_DOWN_ARROW);
|
||
else
|
||
@@ -1458,7 +1458,7 @@ static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
|
||
}
|
||
del_timer(&cursor_timer);
|
||
spk_shut_up &= 0xfe;
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
start_read_all_timer(vc, value + 1);
|
||
spk_unlock(flags);
|
||
return NOTIFY_STOP;
|
||
@@ -1479,8 +1479,8 @@ static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
|
||
return;
|
||
}
|
||
spk_shut_up &= 0xfe;
|
||
- if (no_intr)
|
||
- do_flush();
|
||
+ if (spk_no_intr)
|
||
+ spk_do_flush();
|
||
/* the key press flushes if !no_inter but we want to flush on cursor
|
||
* moves regardless of no_inter state */
|
||
is_cursor = value + 1;
|
||
@@ -1491,7 +1491,7 @@ static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
|
||
cursor_con = vc->vc_num;
|
||
if (cursor_track == CT_Highlight)
|
||
reset_highlight_buffers(vc);
|
||
- cursor_timeout = get_var(CURSOR_TIME);
|
||
+ cursor_timeout = spk_get_var(CURSOR_TIME);
|
||
mod_timer(&cursor_timer,
|
||
jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
|
||
spk_unlock(flags);
|
||
@@ -1603,7 +1603,7 @@ static int speak_highlight(struct vc_data *vc)
|
||
if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
|
||
return 0;
|
||
spk_parked |= 0x01;
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
|
||
speakup_console[vc_num]->ht.highsize[hc]);
|
||
spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
|
||
@@ -1685,7 +1685,7 @@ static void speakup_con_write(struct vc_data *vc, const char *str, int len)
|
||
if (!spk_trylock(flags))
|
||
/* Speakup output, discard */
|
||
return;
|
||
- if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1))
|
||
+ if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
|
||
bleep(3);
|
||
if ((is_cursor) || (cursor_track == read_all_mode)) {
|
||
if (cursor_track == CT_Highlight)
|
||
@@ -1726,19 +1726,19 @@ static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
|
||
return;
|
||
spk_lock(flags);
|
||
spk_shut_up &= 0xfe;
|
||
- if (no_intr)
|
||
- do_flush();
|
||
+ if (spk_no_intr)
|
||
+ spk_do_flush();
|
||
switch (value) {
|
||
case KVAL(K_CAPS):
|
||
- label = msg_get(MSG_KEYNAME_CAPSLOCK);
|
||
+ label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
|
||
on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
|
||
break;
|
||
case KVAL(K_NUM):
|
||
- label = msg_get(MSG_KEYNAME_NUMLOCK);
|
||
+ label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
|
||
on_off = vt_get_leds(fg_console, VC_NUMLOCK);
|
||
break;
|
||
case KVAL(K_HOLD):
|
||
- label = msg_get(MSG_KEYNAME_SCROLLLOCK);
|
||
+ label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
|
||
on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
|
||
if (speakup_console[vc->vc_num])
|
||
speakup_console[vc->vc_num]->tty_stopped = on_off;
|
||
@@ -1750,7 +1750,7 @@ static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
|
||
}
|
||
if (on_off < 2)
|
||
synth_printf("%s %s\n",
|
||
- label, msg_get(MSG_STATUS_START + on_off));
|
||
+ label, spk_msg_get(MSG_STATUS_START + on_off));
|
||
spk_unlock(flags);
|
||
}
|
||
|
||
@@ -1764,13 +1764,13 @@ static int inc_dec_var(u_char value)
|
||
int var_id = (int)value - VAR_START;
|
||
int how = (var_id & 1) ? E_INC : E_DEC;
|
||
var_id = var_id / 2 + FIRST_SET_VAR;
|
||
- p_header = get_var_header(var_id);
|
||
+ p_header = spk_get_var_header(var_id);
|
||
if (p_header == NULL)
|
||
return -1;
|
||
if (p_header->var_type != VAR_NUM)
|
||
return -1;
|
||
var_data = p_header->data;
|
||
- if (set_num_var(1, p_header, how) != 0)
|
||
+ if (spk_set_num_var(1, p_header, how) != 0)
|
||
return -1;
|
||
if (!spk_close_press) {
|
||
for (pn = p_header->name; *pn; pn++) {
|
||
@@ -1790,18 +1790,18 @@ static void speakup_win_set(struct vc_data *vc)
|
||
{
|
||
char info[40];
|
||
if (win_start > 1) {
|
||
- synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
|
||
return;
|
||
}
|
||
if (spk_x < win_left || spk_y < win_top) {
|
||
- synth_printf("%s\n", msg_get(MSG_END_BEFORE_START));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
|
||
return;
|
||
}
|
||
if (win_start && spk_x == win_left && spk_y == win_top) {
|
||
win_left = 0;
|
||
win_right = vc->vc_cols - 1;
|
||
win_bottom = spk_y;
|
||
- snprintf(info, sizeof(info), msg_get(MSG_WINDOW_LINE),
|
||
+ snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
|
||
(int)win_top + 1);
|
||
} else {
|
||
if (!win_start) {
|
||
@@ -1811,8 +1811,8 @@ static void speakup_win_set(struct vc_data *vc)
|
||
win_bottom = spk_y;
|
||
win_right = spk_x;
|
||
}
|
||
- snprintf(info, sizeof(info), msg_get(MSG_WINDOW_BOUNDARY),
|
||
- (win_start) ? msg_get(MSG_END) : msg_get(MSG_START),
|
||
+ snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
|
||
+ (win_start) ? spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
|
||
(int)spk_y + 1, (int)spk_x + 1);
|
||
}
|
||
synth_printf("%s\n", info);
|
||
@@ -1824,32 +1824,32 @@ static void speakup_win_clear(struct vc_data *vc)
|
||
win_top = win_bottom = 0;
|
||
win_left = win_right = 0;
|
||
win_start = 0;
|
||
- synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
|
||
}
|
||
|
||
static void speakup_win_enable(struct vc_data *vc)
|
||
{
|
||
if (win_start < 2) {
|
||
- synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
|
||
return;
|
||
}
|
||
win_enabled ^= 1;
|
||
if (win_enabled)
|
||
- synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
|
||
else
|
||
- synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED));
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
|
||
}
|
||
|
||
static void speakup_bits(struct vc_data *vc)
|
||
{
|
||
int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
|
||
- if (special_handler != NULL || val < 1 || val > 6) {
|
||
- synth_printf("%s\n", msg_get(MSG_ERROR));
|
||
+ if (spk_special_handler != NULL || val < 1 || val > 6) {
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_ERROR));
|
||
return;
|
||
}
|
||
- pb_edit = &punc_info[val];
|
||
- synth_printf(msg_get(MSG_EDIT_PROMPT), pb_edit->name);
|
||
- special_handler = edit_bits;
|
||
+ pb_edit = &spk_punc_info[val];
|
||
+ synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
|
||
+ spk_special_handler = edit_bits;
|
||
}
|
||
|
||
static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
@@ -1887,9 +1887,9 @@ static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
if (ch < 'x' || ch > 'y') {
|
||
oops:
|
||
if (!spk_killed)
|
||
- synth_printf(" %s\n", msg_get(MSG_GOTO_CANCELED));
|
||
+ synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
|
||
goto_buf[num = 0] = '\0';
|
||
- special_handler = NULL;
|
||
+ spk_special_handler = NULL;
|
||
return 1;
|
||
}
|
||
cp = speakup_s2i(goto_buf, &go_pos);
|
||
@@ -1917,7 +1917,7 @@ static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
}
|
||
goto_buf[num = 0] = '\0';
|
||
do_goto:
|
||
- special_handler = NULL;
|
||
+ spk_special_handler = NULL;
|
||
spk_parked |= 0x01;
|
||
if (goto_x) {
|
||
spk_pos -= spk_x * 2;
|
||
@@ -1934,18 +1934,18 @@ static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
|
||
|
||
static void speakup_goto(struct vc_data *vc)
|
||
{
|
||
- if (special_handler != NULL) {
|
||
- synth_printf("%s\n", msg_get(MSG_ERROR));
|
||
+ if (spk_special_handler != NULL) {
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_ERROR));
|
||
return;
|
||
}
|
||
- synth_printf("%s\n", msg_get(MSG_GOTO));
|
||
- special_handler = handle_goto;
|
||
+ synth_printf("%s\n", spk_msg_get(MSG_GOTO));
|
||
+ spk_special_handler = handle_goto;
|
||
return;
|
||
}
|
||
|
||
static void speakup_help(struct vc_data *vc)
|
||
{
|
||
- handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
|
||
+ spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
|
||
}
|
||
|
||
static void do_nothing(struct vc_data *vc)
|
||
@@ -1992,7 +1992,7 @@ static void do_spkup(struct vc_data *vc, u_char value)
|
||
spk_shut_up &= 0xfe;
|
||
this_speakup_key = value;
|
||
if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
(*spkup_handler[value]) (vc);
|
||
} else {
|
||
if (inc_dec_var(value) < 0)
|
||
@@ -2032,7 +2032,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
|
||
}
|
||
if (keycode >= MAX_KEY)
|
||
goto no_map;
|
||
- key_info = our_keys[keycode];
|
||
+ key_info = spk_our_keys[keycode];
|
||
if (key_info == 0)
|
||
goto no_map;
|
||
/* Check valid read all mode keys */
|
||
@@ -2051,7 +2051,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
|
||
}
|
||
}
|
||
shift_info = (shift_state & 0x0f) + key_speakup;
|
||
- offset = shift_table[shift_info];
|
||
+ offset = spk_shift_table[shift_info];
|
||
if (offset) {
|
||
new_key = key_info[offset];
|
||
if (new_key) {
|
||
@@ -2062,7 +2062,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
|
||
if (up_flag || spk_killed)
|
||
goto out;
|
||
spk_shut_up &= 0xfe;
|
||
- do_flush();
|
||
+ spk_do_flush();
|
||
goto out;
|
||
}
|
||
if (up_flag)
|
||
@@ -2070,7 +2070,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
|
||
if (last_keycode == keycode &&
|
||
last_spk_jiffy + MAX_DELAY > jiffies) {
|
||
spk_close_press = 1;
|
||
- offset = shift_table[shift_info + 32];
|
||
+ offset = spk_shift_table[shift_info + 32];
|
||
/* double press? */
|
||
if (offset && key_info[offset])
|
||
new_key = key_info[offset];
|
||
@@ -2082,7 +2082,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
|
||
}
|
||
}
|
||
no_map:
|
||
- if (type == KT_SPKUP && special_handler == NULL) {
|
||
+ if (type == KT_SPKUP && spk_special_handler == NULL) {
|
||
do_spkup(vc, new_key);
|
||
spk_close_press = 0;
|
||
ret = 1;
|
||
@@ -2096,9 +2096,9 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
|
||
|| (value == KVAL(K_LEFT))
|
||
|| (value == KVAL(K_RIGHT));
|
||
if ((cursor_track != read_all_mode) || !kh)
|
||
- if (!no_intr)
|
||
- do_flush();
|
||
- if (special_handler) {
|
||
+ if (!spk_no_intr)
|
||
+ spk_do_flush();
|
||
+ if (spk_special_handler) {
|
||
if (type == KT_SPEC && value == 1) {
|
||
value = '\n';
|
||
type = KT_LATIN;
|
||
@@ -2106,7 +2106,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
|
||
type = KT_LATIN;
|
||
else if (value == 0x7f)
|
||
value = 8; /* make del = backspace */
|
||
- ret = (*special_handler) (vc, type, value, keycode);
|
||
+ ret = (*spk_special_handler) (vc, type, value, keycode);
|
||
spk_close_press = 0;
|
||
if (ret < 0)
|
||
bleep(9);
|
||
@@ -2219,6 +2219,7 @@ static void __exit speakup_exit(void)
|
||
unregister_keyboard_notifier(&keyboard_notifier_block);
|
||
unregister_vt_notifier(&vt_notifier_block);
|
||
speakup_unregister_devsynth();
|
||
+ speakup_cancel_paste();
|
||
del_timer(&cursor_timer);
|
||
kthread_stop(speakup_task);
|
||
speakup_task = NULL;
|
||
@@ -2237,11 +2238,11 @@ static void __exit speakup_exit(void)
|
||
speakup_unregister_var(i);
|
||
|
||
for (i = 0; i < 256; i++) {
|
||
- if (characters[i] != default_chars[i])
|
||
- kfree(characters[i]);
|
||
+ if (spk_characters[i] != spk_default_chars[i])
|
||
+ kfree(spk_characters[i]);
|
||
}
|
||
|
||
- free_user_msgs();
|
||
+ spk_free_user_msgs();
|
||
}
|
||
|
||
/* call by: module_init() */
|
||
@@ -2254,20 +2255,20 @@ static int __init speakup_init(void)
|
||
struct var_t *var;
|
||
|
||
/* These first few initializations cannot fail. */
|
||
- initialize_msgs(); /* Initialize arrays for i18n. */
|
||
- reset_default_chars();
|
||
- reset_default_chartab();
|
||
- strlwr(synth_name);
|
||
+ spk_initialize_msgs(); /* Initialize arrays for i18n. */
|
||
+ spk_reset_default_chars();
|
||
+ spk_reset_default_chartab();
|
||
+ spk_strlwr(synth_name);
|
||
spk_vars[0].u.n.high = vc->vc_cols;
|
||
for (var = spk_vars; var->var_id != MAXVARS; var++)
|
||
speakup_register_var(var);
|
||
for (var = synth_time_vars;
|
||
(var->var_id >= 0) && (var->var_id < MAXVARS); var++)
|
||
speakup_register_var(var);
|
||
- for (i = 1; punc_info[i].mask != 0; i++)
|
||
- set_mask_bits(0, i, 2);
|
||
+ for (i = 1; spk_punc_info[i].mask != 0; i++)
|
||
+ spk_set_mask_bits(0, i, 2);
|
||
|
||
- set_key_info(key_defaults, key_buf);
|
||
+ spk_set_key_info(spk_key_defaults, spk_key_buf);
|
||
|
||
/* From here on out, initializations can fail. */
|
||
err = speakup_add_virtual_keyboard();
|
||
@@ -2290,7 +2291,7 @@ static int __init speakup_init(void)
|
||
goto error_kobjects;
|
||
}
|
||
|
||
- if (quiet_boot)
|
||
+ if (spk_quiet_boot)
|
||
spk_shut_up |= 0x01;
|
||
|
||
err = speakup_kobj_init();
|
||
@@ -2352,11 +2353,11 @@ static int __init speakup_init(void)
|
||
speakup_unregister_var(i);
|
||
|
||
for (i = 0; i < 256; i++) {
|
||
- if (characters[i] != default_chars[i])
|
||
- kfree(characters[i]);
|
||
+ if (spk_characters[i] != spk_default_chars[i])
|
||
+ kfree(spk_characters[i]);
|
||
}
|
||
|
||
- free_user_msgs();
|
||
+ spk_free_user_msgs();
|
||
|
||
out:
|
||
return err;
|
||
diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c
|
||
index fe1f405..7eb602c 100644
|
||
--- a/drivers/staging/speakup/selection.c
|
||
+++ b/drivers/staging/speakup/selection.c
|
||
@@ -3,6 +3,8 @@
|
||
#include <linux/interrupt.h>
|
||
#include <linux/sched.h>
|
||
#include <linux/selection.h>
|
||
+#include <linux/workqueue.h>
|
||
+#include <asm/cmpxchg.h>
|
||
|
||
#include "speakup.h"
|
||
|
||
@@ -10,7 +12,7 @@
|
||
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
|
||
#define ishardspace(c) ((c) == ' ')
|
||
|
||
-unsigned short xs, ys, xe, ye; /* our region points */
|
||
+unsigned short spk_xs, spk_ys, spk_xe, spk_ye; /* our region points */
|
||
|
||
/* Variables for selection control. */
|
||
/* must not be disallocated */
|
||
@@ -51,12 +53,12 @@ int speakup_set_selection(struct tty_struct *tty)
|
||
int i, ps, pe;
|
||
struct vc_data *vc = vc_cons[fg_console].d;
|
||
|
||
- xs = limit(xs, vc->vc_cols - 1);
|
||
- ys = limit(ys, vc->vc_rows - 1);
|
||
- xe = limit(xe, vc->vc_cols - 1);
|
||
- ye = limit(ye, vc->vc_rows - 1);
|
||
- ps = ys * vc->vc_size_row + (xs << 1);
|
||
- pe = ye * vc->vc_size_row + (xe << 1);
|
||
+ spk_xs = limit(spk_xs, vc->vc_cols - 1);
|
||
+ spk_ys = limit(spk_ys, vc->vc_rows - 1);
|
||
+ spk_xe = limit(spk_xe, vc->vc_cols - 1);
|
||
+ spk_ye = limit(spk_ye, vc->vc_rows - 1);
|
||
+ ps = spk_ys * vc->vc_size_row + (spk_xs << 1);
|
||
+ pe = spk_ye * vc->vc_size_row + (spk_xe << 1);
|
||
|
||
if (ps > pe) {
|
||
/* make sel_start <= sel_end */
|
||
@@ -121,20 +123,24 @@ int speakup_set_selection(struct tty_struct *tty)
|
||
return 0;
|
||
}
|
||
|
||
-/* TODO: move to some helper thread, probably. That'd fix having to check for
|
||
- * in_atomic(). */
|
||
-int speakup_paste_selection(struct tty_struct *tty)
|
||
+struct speakup_paste_work {
|
||
+ struct work_struct work;
|
||
+ struct tty_struct *tty;
|
||
+};
|
||
+
|
||
+static void __speakup_paste_selection(struct work_struct *work)
|
||
{
|
||
+ struct speakup_paste_work *spw =
|
||
+ container_of(work, struct speakup_paste_work, work);
|
||
+ struct tty_struct *tty = xchg(&spw->tty, NULL);
|
||
struct vc_data *vc = (struct vc_data *) tty->driver_data;
|
||
int pasted = 0, count;
|
||
DECLARE_WAITQUEUE(wait, current);
|
||
+
|
||
add_wait_queue(&vc->paste_wait, &wait);
|
||
while (sel_buffer && sel_buffer_lth > pasted) {
|
||
set_current_state(TASK_INTERRUPTIBLE);
|
||
if (test_bit(TTY_THROTTLED, &tty->flags)) {
|
||
- if (in_atomic())
|
||
- /* if we are in an interrupt handler, abort */
|
||
- break;
|
||
schedule();
|
||
continue;
|
||
}
|
||
@@ -146,6 +152,26 @@ int speakup_paste_selection(struct tty_struct *tty)
|
||
}
|
||
remove_wait_queue(&vc->paste_wait, &wait);
|
||
current->state = TASK_RUNNING;
|
||
+ tty_kref_put(tty);
|
||
+}
|
||
+
|
||
+static struct speakup_paste_work speakup_paste_work = {
|
||
+ .work = __WORK_INITIALIZER(speakup_paste_work.work,
|
||
+ __speakup_paste_selection)
|
||
+};
|
||
+
|
||
+int speakup_paste_selection(struct tty_struct *tty)
|
||
+{
|
||
+ if (cmpxchg(&speakup_paste_work.tty, NULL, tty) != NULL)
|
||
+ return -EBUSY;
|
||
+
|
||
+ tty_kref_get(tty);
|
||
+ schedule_work_on(WORK_CPU_UNBOUND, &speakup_paste_work.work);
|
||
return 0;
|
||
}
|
||
|
||
+void speakup_cancel_paste(void)
|
||
+{
|
||
+ cancel_work_sync(&speakup_paste_work.work);
|
||
+ tty_kref_put(speakup_paste_work.tty);
|
||
+}
|
||
diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c
|
||
index a97d3d5..e4d27aa 100644
|
||
--- a/drivers/staging/speakup/serialio.c
|
||
+++ b/drivers/staging/speakup/serialio.c
|
||
@@ -116,7 +116,7 @@ static void start_serial_interrupt(int irq)
|
||
outb(1, speakup_info.port_tts + UART_FCR); /* Turn FIFO On */
|
||
}
|
||
|
||
-void stop_serial_interrupt(void)
|
||
+void spk_stop_serial_interrupt(void)
|
||
{
|
||
if (speakup_info.port_tts == 0)
|
||
return;
|
||
@@ -130,7 +130,7 @@ void stop_serial_interrupt(void)
|
||
free_irq(serstate->irq, (void *) synth_readbuf_handler);
|
||
}
|
||
|
||
-int wait_for_xmitr(void)
|
||
+int spk_wait_for_xmitr(void)
|
||
{
|
||
int tmout = SPK_XMITR_TIMEOUT;
|
||
if ((synth->alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) {
|
||
@@ -195,7 +195,7 @@ EXPORT_SYMBOL_GPL(spk_serial_in_nowait);
|
||
|
||
int spk_serial_out(const char ch)
|
||
{
|
||
- if (synth->alive && wait_for_xmitr()) {
|
||
+ if (synth->alive && spk_wait_for_xmitr()) {
|
||
outb_p(ch, speakup_info.port_tts);
|
||
return 1;
|
||
}
|
||
diff --git a/drivers/staging/speakup/speakup.h b/drivers/staging/speakup/speakup.h
|
||
index e66579e..cfbd88c 100644
|
||
--- a/drivers/staging/speakup/speakup.h
|
||
+++ b/drivers/staging/speakup/speakup.h
|
||
@@ -50,75 +50,76 @@
|
||
#define E_UNDEF -1
|
||
|
||
extern int speakup_thread(void *data);
|
||
-extern void reset_default_chars(void);
|
||
-extern void reset_default_chartab(void);
|
||
+extern void spk_reset_default_chars(void);
|
||
+extern void spk_reset_default_chartab(void);
|
||
extern void synth_start(void);
|
||
void synth_insert_next_index(int sent_num);
|
||
-void reset_index_count(int sc);
|
||
-void get_index_count(int *linecount, int *sentcount);
|
||
-extern int set_key_info(const u_char *key_info, u_char *k_buffer);
|
||
-extern char *strlwr(char *s);
|
||
+void spk_reset_index_count(int sc);
|
||
+void spk_get_index_count(int *linecount, int *sentcount);
|
||
+extern int spk_set_key_info(const u_char *key_info, u_char *k_buffer);
|
||
+extern char *spk_strlwr(char *s);
|
||
extern char *speakup_s2i(char *start, int *dest);
|
||
-extern char *s2uchar(char *start, char *dest);
|
||
-extern char *xlate(char *s);
|
||
+extern char *spk_s2uchar(char *start, char *dest);
|
||
+extern char *spk_xlate(char *s);
|
||
extern int speakup_kobj_init(void);
|
||
extern void speakup_kobj_exit(void);
|
||
-extern int chartab_get_value(char *keyword);
|
||
+extern int spk_chartab_get_value(char *keyword);
|
||
extern void speakup_register_var(struct var_t *var);
|
||
extern void speakup_unregister_var(enum var_id_t var_id);
|
||
-extern struct st_var_header *get_var_header(enum var_id_t var_id);
|
||
-extern struct st_var_header *var_header_by_name(const char *name);
|
||
-extern struct punc_var_t *get_punc_var(enum var_id_t var_id);
|
||
-extern int set_num_var(int val, struct st_var_header *var, int how);
|
||
-extern int set_string_var(const char *page, struct st_var_header *var, int len);
|
||
-extern int set_mask_bits(const char *input, const int which, const int how);
|
||
-extern special_func special_handler;
|
||
-extern int handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key);
|
||
+extern struct st_var_header *spk_get_var_header(enum var_id_t var_id);
|
||
+extern struct st_var_header *spk_var_header_by_name(const char *name);
|
||
+extern struct punc_var_t *spk_get_punc_var(enum var_id_t var_id);
|
||
+extern int spk_set_num_var(int val, struct st_var_header *var, int how);
|
||
+extern int spk_set_string_var(const char *page, struct st_var_header *var, int len);
|
||
+extern int spk_set_mask_bits(const char *input, const int which, const int how);
|
||
+extern special_func spk_special_handler;
|
||
+extern int spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key);
|
||
extern int synth_init(char *name);
|
||
extern void synth_release(void);
|
||
|
||
-extern void do_flush(void);
|
||
+extern void spk_do_flush(void);
|
||
extern void speakup_start_ttys(void);
|
||
extern void synth_buffer_add(char ch);
|
||
extern void synth_buffer_clear(void);
|
||
extern void speakup_clear_selection(void);
|
||
extern int speakup_set_selection(struct tty_struct *tty);
|
||
extern int speakup_paste_selection(struct tty_struct *tty);
|
||
+extern void speakup_cancel_paste(void);
|
||
extern void speakup_register_devsynth(void);
|
||
extern void speakup_unregister_devsynth(void);
|
||
extern void synth_write(const char *buf, size_t count);
|
||
extern int synth_supports_indexing(void);
|
||
|
||
extern struct vc_data *spk_sel_cons;
|
||
-extern unsigned short xs, ys, xe, ye; /* our region points */
|
||
+extern unsigned short spk_xs, spk_ys, spk_xe, spk_ye; /* our region points */
|
||
|
||
extern wait_queue_head_t speakup_event;
|
||
extern struct kobject *speakup_kobj;
|
||
extern struct task_struct *speakup_task;
|
||
-extern const u_char key_defaults[];
|
||
+extern const u_char spk_key_defaults[];
|
||
|
||
/* Protect speakup synthesizer list */
|
||
extern struct mutex spk_mutex;
|
||
extern struct st_spk_t *speakup_console[];
|
||
extern struct spk_synth *synth;
|
||
-extern char pitch_buff[];
|
||
-extern u_char *our_keys[];
|
||
-extern short punc_masks[];
|
||
-extern char str_caps_start[], str_caps_stop[];
|
||
-extern const struct st_bits_data punc_info[];
|
||
-extern u_char key_buf[600];
|
||
-extern char *characters[];
|
||
-extern char *default_chars[];
|
||
+extern char spk_pitch_buff[];
|
||
+extern u_char *spk_our_keys[];
|
||
+extern short spk_punc_masks[];
|
||
+extern char spk_str_caps_start[], spk_str_caps_stop[];
|
||
+extern const struct st_bits_data spk_punc_info[];
|
||
+extern u_char spk_key_buf[600];
|
||
+extern char *spk_characters[];
|
||
+extern char *spk_default_chars[];
|
||
extern u_short spk_chartab[];
|
||
-extern int no_intr, say_ctrl, say_word_ctl, punc_level;
|
||
-extern int reading_punc, attrib_bleep, bleeps;
|
||
-extern int bleep_time, bell_pos;
|
||
-extern int spell_delay, key_echo;
|
||
-extern short punc_mask;
|
||
-extern short pitch_shift, synth_flags;
|
||
-extern bool quiet_boot;
|
||
+extern int spk_no_intr, spk_say_ctrl, spk_say_word_ctl, spk_punc_level;
|
||
+extern int spk_reading_punc, spk_attrib_bleep, spk_bleeps;
|
||
+extern int spk_bleep_time, spk_bell_pos;
|
||
+extern int spk_spell_delay, spk_key_echo;
|
||
+extern short spk_punc_mask;
|
||
+extern short spk_pitch_shift, synth_flags;
|
||
+extern bool spk_quiet_boot;
|
||
extern char *synth_name;
|
||
-extern struct bleep unprocessed_sound;
|
||
+extern struct bleep spk_unprocessed_sound;
|
||
|
||
/* Prototypes from fakekey.c. */
|
||
int speakup_add_virtual_keyboard(void);
|
||
diff --git a/drivers/staging/speakup/speakup_acntpc.c b/drivers/staging/speakup/speakup_acntpc.c
|
||
index bbe28b6..1c1f0d5 100644
|
||
--- a/drivers/staging/speakup/speakup_acntpc.c
|
||
+++ b/drivers/staging/speakup/speakup_acntpc.c
|
||
@@ -182,9 +182,9 @@ static void do_catch_up(struct spk_synth *synth)
|
||
struct var_t *full_time;
|
||
struct var_t *jiffy_delta;
|
||
|
||
- jiffy_delta = get_var(JIFFY);
|
||
- delay_time = get_var(DELAY);
|
||
- full_time = get_var(FULL);
|
||
+ jiffy_delta = spk_get_var(JIFFY);
|
||
+ delay_time = spk_get_var(DELAY);
|
||
+ full_time = spk_get_var(FULL);
|
||
|
||
spk_lock(flags);
|
||
jiffy_delta_val = jiffy_delta->u.n.value;
|
||
diff --git a/drivers/staging/speakup/speakup_acntsa.c b/drivers/staging/speakup/speakup_acntsa.c
|
||
index 590fa6b..22a8b72 100644
|
||
--- a/drivers/staging/speakup/speakup_acntsa.c
|
||
+++ b/drivers/staging/speakup/speakup_acntsa.c
|
||
@@ -128,7 +128,7 @@ static int synth_probe(struct spk_synth *synth)
|
||
{
|
||
int failed;
|
||
|
||
- failed = serial_synth_probe(synth);
|
||
+ failed = spk_serial_synth_probe(synth);
|
||
if (failed == 0) {
|
||
spk_synth_immediate(synth, "\033=R\r");
|
||
mdelay(100);
|
||
diff --git a/drivers/staging/speakup/speakup_apollo.c b/drivers/staging/speakup/speakup_apollo.c
|
||
index 00d5ced..3e450cc 100644
|
||
--- a/drivers/staging/speakup/speakup_apollo.c
|
||
+++ b/drivers/staging/speakup/speakup_apollo.c
|
||
@@ -112,7 +112,7 @@ static struct spk_synth synth_apollo = {
|
||
.startup = SYNTH_START,
|
||
.checkval = SYNTH_CHECK,
|
||
.vars = vars,
|
||
- .probe = serial_synth_probe,
|
||
+ .probe = spk_serial_synth_probe,
|
||
.release = spk_serial_release,
|
||
.synth_immediate = spk_synth_immediate,
|
||
.catch_up = do_catch_up,
|
||
@@ -145,9 +145,9 @@ static void do_catch_up(struct spk_synth *synth)
|
||
int delay_time_val = 0;
|
||
int jiffy_delta_val = 0;
|
||
|
||
- jiffy_delta = get_var(JIFFY);
|
||
- delay_time = get_var(DELAY);
|
||
- full_time = get_var(FULL);
|
||
+ jiffy_delta = spk_get_var(JIFFY);
|
||
+ delay_time = spk_get_var(DELAY);
|
||
+ full_time = spk_get_var(FULL);
|
||
spk_lock(flags);
|
||
jiffy_delta_val = jiffy_delta->u.n.value;
|
||
spk_unlock(flags);
|
||
diff --git a/drivers/staging/speakup/speakup_audptr.c b/drivers/staging/speakup/speakup_audptr.c
|
||
index 94e5099..3508aee 100644
|
||
--- a/drivers/staging/speakup/speakup_audptr.c
|
||
+++ b/drivers/staging/speakup/speakup_audptr.c
|
||
@@ -162,7 +162,7 @@ static int synth_probe(struct spk_synth *synth)
|
||
{
|
||
int failed = 0;
|
||
|
||
- failed = serial_synth_probe(synth);
|
||
+ failed = spk_serial_synth_probe(synth);
|
||
if (failed == 0)
|
||
synth_version(synth);
|
||
synth->alive = !failed;
|
||
diff --git a/drivers/staging/speakup/speakup_bns.c b/drivers/staging/speakup/speakup_bns.c
|
||
index 43e5b54..4bfe3d4 100644
|
||
--- a/drivers/staging/speakup/speakup_bns.c
|
||
+++ b/drivers/staging/speakup/speakup_bns.c
|
||
@@ -100,7 +100,7 @@ static struct spk_synth synth_bns = {
|
||
.startup = SYNTH_START,
|
||
.checkval = SYNTH_CHECK,
|
||
.vars = vars,
|
||
- .probe = serial_synth_probe,
|
||
+ .probe = spk_serial_synth_probe,
|
||
.release = spk_serial_release,
|
||
.synth_immediate = spk_synth_immediate,
|
||
.catch_up = spk_do_catch_up,
|
||
diff --git a/drivers/staging/speakup/speakup_decext.c b/drivers/staging/speakup/speakup_decext.c
|
||
index b4ef915..d39a0de 100644
|
||
--- a/drivers/staging/speakup/speakup_decext.c
|
||
+++ b/drivers/staging/speakup/speakup_decext.c
|
||
@@ -130,7 +130,7 @@ static struct spk_synth synth_decext = {
|
||
.startup = SYNTH_START,
|
||
.checkval = SYNTH_CHECK,
|
||
.vars = vars,
|
||
- .probe = serial_synth_probe,
|
||
+ .probe = spk_serial_synth_probe,
|
||
.release = spk_serial_release,
|
||
.synth_immediate = spk_synth_immediate,
|
||
.catch_up = do_catch_up,
|
||
@@ -162,8 +162,8 @@ static void do_catch_up(struct spk_synth *synth)
|
||
int jiffy_delta_val = 0;
|
||
int delay_time_val = 0;
|
||
|
||
- jiffy_delta = get_var(JIFFY);
|
||
- delay_time = get_var(DELAY);
|
||
+ jiffy_delta = spk_get_var(JIFFY);
|
||
+ delay_time = spk_get_var(DELAY);
|
||
|
||
spk_lock(flags);
|
||
jiffy_delta_val = jiffy_delta->u.n.value;
|
||
diff --git a/drivers/staging/speakup/speakup_decpc.c b/drivers/staging/speakup/speakup_decpc.c
|
||
index de25527..cda6b0f 100644
|
||
--- a/drivers/staging/speakup/speakup_decpc.c
|
||
+++ b/drivers/staging/speakup/speakup_decpc.c
|
||
@@ -375,8 +375,8 @@ static void do_catch_up(struct spk_synth *synth)
|
||
int jiffy_delta_val;
|
||
int delay_time_val;
|
||
|
||
- jiffy_delta = get_var(JIFFY);
|
||
- delay_time = get_var(DELAY);
|
||
+ jiffy_delta = spk_get_var(JIFFY);
|
||
+ delay_time = spk_get_var(DELAY);
|
||
spk_lock(flags);
|
||
jiffy_delta_val = jiffy_delta->u.n.value;
|
||
spk_unlock(flags);
|
||
diff --git a/drivers/staging/speakup/speakup_dectlk.c b/drivers/staging/speakup/speakup_dectlk.c
|
||
index daff3b9..0dd2eb9 100644
|
||
--- a/drivers/staging/speakup/speakup_dectlk.c
|
||
+++ b/drivers/staging/speakup/speakup_dectlk.c
|
||
@@ -134,7 +134,7 @@ static struct spk_synth synth_dectlk = {
|
||
.vars = vars,
|
||
.default_pitch = ap_defaults,
|
||
.default_vol = g5_defaults,
|
||
- .probe = serial_synth_probe,
|
||
+ .probe = spk_serial_synth_probe,
|
||
.release = spk_serial_release,
|
||
.synth_immediate = spk_synth_immediate,
|
||
.catch_up = do_catch_up,
|
||
@@ -214,8 +214,8 @@ static void do_catch_up(struct spk_synth *synth)
|
||
int jiffy_delta_val;
|
||
int delay_time_val;
|
||
|
||
- jiffy_delta = get_var(JIFFY);
|
||
- delay_time = get_var(DELAY);
|
||
+ jiffy_delta = spk_get_var(JIFFY);
|
||
+ delay_time = spk_get_var(DELAY);
|
||
spk_lock(flags);
|
||
jiffy_delta_val = jiffy_delta->u.n.value;
|
||
spk_unlock(flags);
|
||
diff --git a/drivers/staging/speakup/speakup_dtlk.c b/drivers/staging/speakup/speakup_dtlk.c
|
||
index 97bc476..a9cefbd 100644
|
||
--- a/drivers/staging/speakup/speakup_dtlk.c
|
||
+++ b/drivers/staging/speakup/speakup_dtlk.c
|
||
@@ -198,8 +198,8 @@ static void do_catch_up(struct spk_synth *synth)
|
||
int jiffy_delta_val;
|
||
int delay_time_val;
|
||
|
||
- jiffy_delta = get_var(JIFFY);
|
||
- delay_time = get_var(DELAY);
|
||
+ jiffy_delta = spk_get_var(JIFFY);
|
||
+ delay_time = spk_get_var(DELAY);
|
||
spk_lock(flags);
|
||
jiffy_delta_val = jiffy_delta->u.n.value;
|
||
spk_unlock(flags);
|
||
diff --git a/drivers/staging/speakup/speakup_dummy.c b/drivers/staging/speakup/speakup_dummy.c
|
||
index c20f411..4a24b9c 100644
|
||
--- a/drivers/staging/speakup/speakup_dummy.c
|
||
+++ b/drivers/staging/speakup/speakup_dummy.c
|
||
@@ -102,7 +102,7 @@ static struct spk_synth synth_dummy = {
|
||
.startup = SYNTH_START,
|
||
.checkval = SYNTH_CHECK,
|
||
.vars = vars,
|
||
- .probe = serial_synth_probe,
|
||
+ .probe = spk_serial_synth_probe,
|
||
.release = spk_serial_release,
|
||
.synth_immediate = spk_synth_immediate,
|
||
.catch_up = spk_do_catch_up,
|
||
diff --git a/drivers/staging/speakup/speakup_keypc.c b/drivers/staging/speakup/speakup_keypc.c
|
||
index 496e014..feb5f22 100644
|
||
--- a/drivers/staging/speakup/speakup_keypc.c
|
||
+++ b/drivers/staging/speakup/speakup_keypc.c
|
||
@@ -184,9 +184,9 @@ static void do_catch_up(struct spk_synth *synth)
|
||
int full_time_val;
|
||
int jiffy_delta_val;
|
||
|
||
- jiffy_delta = get_var(JIFFY);
|
||
- delay_time = get_var(DELAY);
|
||
- full_time = get_var(FULL);
|
||
+ jiffy_delta = spk_get_var(JIFFY);
|
||
+ delay_time = spk_get_var(DELAY);
|
||
+ full_time = spk_get_var(FULL);
|
||
spk_lock(flags);
|
||
jiffy_delta_val = jiffy_delta->u.n.value;
|
||
spk_unlock(flags);
|
||
diff --git a/drivers/staging/speakup/speakup_ltlk.c b/drivers/staging/speakup/speakup_ltlk.c
|
||
index 971de1a..326f94d 100644
|
||
--- a/drivers/staging/speakup/speakup_ltlk.c
|
||
+++ b/drivers/staging/speakup/speakup_ltlk.c
|
||
@@ -161,7 +161,7 @@ static int synth_probe(struct spk_synth *synth)
|
||
{
|
||
int failed = 0;
|
||
|
||
- failed = serial_synth_probe(synth);
|
||
+ failed = spk_serial_synth_probe(synth);
|
||
if (failed == 0)
|
||
synth_interrogate(synth);
|
||
synth->alive = !failed;
|
||
diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c
|
||
index b5130c8..e2f5c81 100644
|
||
--- a/drivers/staging/speakup/speakup_soft.c
|
||
+++ b/drivers/staging/speakup/speakup_soft.c
|
||
@@ -46,7 +46,7 @@ static int misc_registered;
|
||
static struct var_t vars[] = {
|
||
{ CAPS_START, .u.s = {"\x01+3p" } },
|
||
{ CAPS_STOP, .u.s = {"\x01-3p" } },
|
||
- { RATE, .u.n = {"\x01%ds", 5, 0, 9, 0, 0, NULL } },
|
||
+ { RATE, .u.n = {"\x01%ds", 2, 0, 9, 0, 0, NULL } },
|
||
{ PITCH, .u.n = {"\x01%dp", 5, 0, 9, 0, 0, NULL } },
|
||
{ VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
|
||
{ TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
|
||
diff --git a/drivers/staging/speakup/speakup_spkout.c b/drivers/staging/speakup/speakup_spkout.c
|
||
index 9a3a80d..e74f856 100644
|
||
--- a/drivers/staging/speakup/speakup_spkout.c
|
||
+++ b/drivers/staging/speakup/speakup_spkout.c
|
||
@@ -107,7 +107,7 @@ static struct spk_synth synth_spkout = {
|
||
.startup = SYNTH_START,
|
||
.checkval = SYNTH_CHECK,
|
||
.vars = vars,
|
||
- .probe = serial_synth_probe,
|
||
+ .probe = spk_serial_synth_probe,
|
||
.release = spk_serial_release,
|
||
.synth_immediate = spk_synth_immediate,
|
||
.catch_up = spk_do_catch_up,
|
||
diff --git a/drivers/staging/speakup/speakup_txprt.c b/drivers/staging/speakup/speakup_txprt.c
|
||
index 5d5bf7c..5a29b9f 100644
|
||
--- a/drivers/staging/speakup/speakup_txprt.c
|
||
+++ b/drivers/staging/speakup/speakup_txprt.c
|
||
@@ -100,7 +100,7 @@ static struct spk_synth synth_txprt = {
|
||
.startup = SYNTH_START,
|
||
.checkval = SYNTH_CHECK,
|
||
.vars = vars,
|
||
- .probe = serial_synth_probe,
|
||
+ .probe = spk_serial_synth_probe,
|
||
.release = spk_serial_release,
|
||
.synth_immediate = spk_synth_immediate,
|
||
.catch_up = spk_do_catch_up,
|
||
diff --git a/drivers/staging/speakup/spk_priv.h b/drivers/staging/speakup/spk_priv.h
|
||
index a47c5b7..303105b 100644
|
||
--- a/drivers/staging/speakup/spk_priv.h
|
||
+++ b/drivers/staging/speakup/spk_priv.h
|
||
@@ -45,8 +45,8 @@
|
||
#define KT_SPKUP 15
|
||
|
||
extern const struct old_serial_port *spk_serial_init(int index);
|
||
-extern void stop_serial_interrupt(void);
|
||
-extern int wait_for_xmitr(void);
|
||
+extern void spk_stop_serial_interrupt(void);
|
||
+extern int spk_wait_for_xmitr(void);
|
||
extern unsigned char spk_serial_in(void);
|
||
extern unsigned char spk_serial_in_nowait(void);
|
||
extern int spk_serial_out(const char ch);
|
||
@@ -55,13 +55,13 @@ extern void spk_serial_release(void);
|
||
extern char synth_buffer_getc(void);
|
||
extern char synth_buffer_peek(void);
|
||
extern int synth_buffer_empty(void);
|
||
-extern struct var_t *get_var(enum var_id_t var_id);
|
||
+extern struct var_t *spk_get_var(enum var_id_t var_id);
|
||
extern ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||
char *buf);
|
||
extern ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||
const char *buf, size_t count);
|
||
|
||
-extern int serial_synth_probe(struct spk_synth *synth);
|
||
+extern int spk_serial_synth_probe(struct spk_synth *synth);
|
||
extern const char *spk_synth_immediate(struct spk_synth *synth, const char *buff);
|
||
extern void spk_do_catch_up(struct spk_synth *synth);
|
||
extern void spk_synth_flush(struct spk_synth *synth);
|
||
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c
|
||
index 5710fc5..33efbd3 100644
|
||
--- a/drivers/staging/speakup/synth.c
|
||
+++ b/drivers/staging/speakup/synth.c
|
||
@@ -20,9 +20,9 @@
|
||
#define MAXSYNTHS 16 /* Max number of synths in array. */
|
||
static struct spk_synth *synths[MAXSYNTHS];
|
||
struct spk_synth *synth;
|
||
-char pitch_buff[32] = "";
|
||
+char spk_pitch_buff[32] = "";
|
||
static int module_status;
|
||
-bool quiet_boot;
|
||
+bool spk_quiet_boot;
|
||
|
||
struct speakup_info_t speakup_info = {
|
||
.spinlock = __SPIN_LOCK_UNLOCKED(speakup_info.spinlock),
|
||
@@ -32,7 +32,7 @@ EXPORT_SYMBOL_GPL(speakup_info);
|
||
|
||
static int do_synth_init(struct spk_synth *in_synth);
|
||
|
||
-int serial_synth_probe(struct spk_synth *synth)
|
||
+int spk_serial_synth_probe(struct spk_synth *synth)
|
||
{
|
||
const struct old_serial_port *ser;
|
||
int failed = 0;
|
||
@@ -59,7 +59,7 @@ int serial_synth_probe(struct spk_synth *synth)
|
||
synth->alive = 1;
|
||
return 0;
|
||
}
|
||
-EXPORT_SYMBOL_GPL(serial_synth_probe);
|
||
+EXPORT_SYMBOL_GPL(spk_serial_synth_probe);
|
||
|
||
/* Main loop of the progression thread: keep eating from the buffer
|
||
* and push to the serial port, waiting as needed
|
||
@@ -79,9 +79,9 @@ void spk_do_catch_up(struct spk_synth *synth)
|
||
int delay_time_val;
|
||
int full_time_val;
|
||
|
||
- jiffy_delta = get_var(JIFFY);
|
||
- full_time = get_var(FULL);
|
||
- delay_time = get_var(DELAY);
|
||
+ jiffy_delta = spk_get_var(JIFFY);
|
||
+ full_time = spk_get_var(FULL);
|
||
+ delay_time = spk_get_var(DELAY);
|
||
|
||
spk_lock(flags);
|
||
jiffy_delta_val = jiffy_delta->u.n.value;
|
||
@@ -139,7 +139,7 @@ const char *spk_synth_immediate(struct spk_synth *synth, const char *buff)
|
||
while ((ch = *buff)) {
|
||
if (ch == '\n')
|
||
ch = synth->procspeech;
|
||
- if (wait_for_xmitr())
|
||
+ if (spk_wait_for_xmitr())
|
||
outb(ch, speakup_info.port_tts);
|
||
else
|
||
return buff;
|
||
@@ -166,7 +166,7 @@ int spk_synth_is_alive_restart(struct spk_synth *synth)
|
||
{
|
||
if (synth->alive)
|
||
return 1;
|
||
- if (!synth->alive && wait_for_xmitr() > 0) {
|
||
+ if (!synth->alive && spk_wait_for_xmitr() > 0) {
|
||
/* restart */
|
||
synth->alive = 1;
|
||
synth_printf("%s", synth->init);
|
||
@@ -192,20 +192,20 @@ void synth_start(void)
|
||
synth_buffer_clear();
|
||
return;
|
||
}
|
||
- trigger_time = get_var(TRIGGER);
|
||
+ trigger_time = spk_get_var(TRIGGER);
|
||
if (!timer_pending(&thread_timer))
|
||
mod_timer(&thread_timer, jiffies +
|
||
msecs_to_jiffies(trigger_time->u.n.value));
|
||
}
|
||
|
||
-void do_flush(void)
|
||
+void spk_do_flush(void)
|
||
{
|
||
speakup_info.flushing = 1;
|
||
synth_buffer_clear();
|
||
if (synth->alive) {
|
||
- if (pitch_shift) {
|
||
- synth_printf("%s", pitch_buff);
|
||
- pitch_shift = 0;
|
||
+ if (spk_pitch_shift) {
|
||
+ synth_printf("%s", spk_pitch_buff);
|
||
+ spk_pitch_shift = 0;
|
||
}
|
||
}
|
||
wake_up_interruptible_all(&speakup_event);
|
||
@@ -241,7 +241,7 @@ EXPORT_SYMBOL_GPL(synth_printf);
|
||
static int index_count;
|
||
static int sentence_count;
|
||
|
||
-void reset_index_count(int sc)
|
||
+void spk_reset_index_count(int sc)
|
||
{
|
||
static int first = 1;
|
||
if (first)
|
||
@@ -277,7 +277,7 @@ void synth_insert_next_index(int sent_num)
|
||
}
|
||
}
|
||
|
||
-void get_index_count(int *linecount, int *sentcount)
|
||
+void spk_get_index_count(int *linecount, int *sentcount)
|
||
{
|
||
int ind = synth->get_index();
|
||
if (ind) {
|
||
@@ -384,7 +384,7 @@ static int do_synth_init(struct spk_synth *in_synth)
|
||
for (var = synth->vars;
|
||
(var->var_id >= 0) && (var->var_id < MAXVARS); var++)
|
||
speakup_register_var(var);
|
||
- if (!quiet_boot)
|
||
+ if (!spk_quiet_boot)
|
||
synth_printf("%s found\n", synth->long_name);
|
||
if (synth->attributes.name
|
||
&& sysfs_create_group(speakup_kobj, &(synth->attributes)) < 0)
|
||
@@ -412,7 +412,7 @@ void synth_release(void)
|
||
sysfs_remove_group(speakup_kobj, &(synth->attributes));
|
||
for (var = synth->vars; var->var_id != MAXVARS; var++)
|
||
speakup_unregister_var(var->var_id);
|
||
- stop_serial_interrupt();
|
||
+ spk_stop_serial_interrupt();
|
||
synth->release();
|
||
synth = NULL;
|
||
}
|
||
@@ -460,4 +460,4 @@ void synth_remove(struct spk_synth *in_synth)
|
||
}
|
||
EXPORT_SYMBOL_GPL(synth_remove);
|
||
|
||
-short punc_masks[] = { 0, SOME, MOST, PUNC, PUNC|B_SYM };
|
||
+short spk_punc_masks[] = { 0, SOME, MOST, PUNC, PUNC|B_SYM };
|
||
diff --git a/drivers/staging/speakup/thread.c b/drivers/staging/speakup/thread.c
|
||
index 103c5c8..42fa660 100644
|
||
--- a/drivers/staging/speakup/thread.c
|
||
+++ b/drivers/staging/speakup/thread.c
|
||
@@ -23,8 +23,8 @@ int speakup_thread(void *data)
|
||
DEFINE_WAIT(wait);
|
||
while (1) {
|
||
spk_lock(flags);
|
||
- our_sound = unprocessed_sound;
|
||
- unprocessed_sound.active = 0;
|
||
+ our_sound = spk_unprocessed_sound;
|
||
+ spk_unprocessed_sound.active = 0;
|
||
prepare_to_wait(&speakup_event, &wait,
|
||
TASK_INTERRUPTIBLE);
|
||
should_break = kthread_should_stop() ||
|
||
diff --git a/drivers/staging/speakup/varhandlers.c b/drivers/staging/speakup/varhandlers.c
|
||
index ab7de93..f8c1e45 100644
|
||
--- a/drivers/staging/speakup/varhandlers.c
|
||
+++ b/drivers/staging/speakup/varhandlers.c
|
||
@@ -16,24 +16,24 @@ static struct st_var_header var_headers[] = {
|
||
{ "ex_num", EXNUMBER, VAR_PROC, NULL, NULL },
|
||
{ "characters", CHARS, VAR_PROC, NULL, NULL },
|
||
{ "synth_direct", SYNTH_DIRECT, VAR_PROC, NULL, NULL },
|
||
- { "caps_start", CAPS_START, VAR_STRING, str_caps_start, NULL },
|
||
- { "caps_stop", CAPS_STOP, VAR_STRING, str_caps_stop, NULL },
|
||
+ { "caps_start", CAPS_START, VAR_STRING, spk_str_caps_start, NULL },
|
||
+ { "caps_stop", CAPS_STOP, VAR_STRING, spk_str_caps_stop, NULL },
|
||
{ "delay_time", DELAY, VAR_TIME, NULL, NULL },
|
||
{ "trigger_time", TRIGGER, VAR_TIME, NULL, NULL },
|
||
{ "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL },
|
||
{ "full_time", FULL, VAR_TIME, NULL, NULL },
|
||
- { "spell_delay", SPELL_DELAY, VAR_NUM, &spell_delay, NULL },
|
||
- { "bleeps", BLEEPS, VAR_NUM, &bleeps, NULL },
|
||
- { "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &attrib_bleep, NULL },
|
||
- { "bleep_time", BLEEP_TIME, VAR_TIME, &bleep_time, NULL },
|
||
+ { "spell_delay", SPELL_DELAY, VAR_NUM, &spk_spell_delay, NULL },
|
||
+ { "bleeps", BLEEPS, VAR_NUM, &spk_bleeps, NULL },
|
||
+ { "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &spk_attrib_bleep, NULL },
|
||
+ { "bleep_time", BLEEP_TIME, VAR_TIME, &spk_bleep_time, NULL },
|
||
{ "cursor_time", CURSOR_TIME, VAR_TIME, NULL, NULL },
|
||
- { "punc_level", PUNC_LEVEL, VAR_NUM, &punc_level, NULL },
|
||
- { "reading_punc", READING_PUNC, VAR_NUM, &reading_punc, NULL },
|
||
- { "say_control", SAY_CONTROL, VAR_NUM, &say_ctrl, NULL },
|
||
- { "say_word_ctl", SAY_WORD_CTL, VAR_NUM, &say_word_ctl, NULL },
|
||
- { "no_interrupt", NO_INTERRUPT, VAR_NUM, &no_intr, NULL },
|
||
- { "key_echo", KEY_ECHO, VAR_NUM, &key_echo, NULL },
|
||
- { "bell_pos", BELL_POS, VAR_NUM, &bell_pos, NULL },
|
||
+ { "punc_level", PUNC_LEVEL, VAR_NUM, &spk_punc_level, NULL },
|
||
+ { "reading_punc", READING_PUNC, VAR_NUM, &spk_reading_punc, NULL },
|
||
+ { "say_control", SAY_CONTROL, VAR_NUM, &spk_say_ctrl, NULL },
|
||
+ { "say_word_ctl", SAY_WORD_CTL, VAR_NUM, &spk_say_word_ctl, NULL },
|
||
+ { "no_interrupt", NO_INTERRUPT, VAR_NUM, &spk_no_intr, NULL },
|
||
+ { "key_echo", KEY_ECHO, VAR_NUM, &spk_key_echo, NULL },
|
||
+ { "bell_pos", BELL_POS, VAR_NUM, &spk_bell_pos, NULL },
|
||
{ "rate", RATE, VAR_NUM, NULL, NULL },
|
||
{ "pitch", PITCH, VAR_NUM, NULL, NULL },
|
||
{ "vol", VOL, VAR_NUM, NULL, NULL },
|
||
@@ -58,7 +58,7 @@ static struct punc_var_t punc_vars[] = {
|
||
{ -1, -1 },
|
||
};
|
||
|
||
-int chartab_get_value(char *keyword)
|
||
+int spk_chartab_get_value(char *keyword)
|
||
{
|
||
int value = 0;
|
||
|
||
@@ -103,11 +103,11 @@ void speakup_register_var(struct var_t *var)
|
||
p_header->data = var;
|
||
switch (p_header->var_type) {
|
||
case VAR_STRING:
|
||
- set_string_var(nothing, p_header, 0);
|
||
+ spk_set_string_var(nothing, p_header, 0);
|
||
break;
|
||
case VAR_NUM:
|
||
case VAR_TIME:
|
||
- set_num_var(0, p_header, E_DEFAULT);
|
||
+ spk_set_num_var(0, p_header, E_DEFAULT);
|
||
break;
|
||
default:
|
||
break;
|
||
@@ -123,7 +123,7 @@ void speakup_unregister_var(enum var_id_t var_id)
|
||
p_header->data = NULL;
|
||
}
|
||
|
||
-struct st_var_header *get_var_header(enum var_id_t var_id)
|
||
+struct st_var_header *spk_get_var_header(enum var_id_t var_id)
|
||
{
|
||
struct st_var_header *p_header;
|
||
if (var_id < 0 || var_id >= MAXVARS)
|
||
@@ -134,7 +134,7 @@ struct st_var_header *get_var_header(enum var_id_t var_id)
|
||
return p_header;
|
||
}
|
||
|
||
-struct st_var_header *var_header_by_name(const char *name)
|
||
+struct st_var_header *spk_var_header_by_name(const char *name)
|
||
{
|
||
int i;
|
||
struct st_var_header *where = NULL;
|
||
@@ -151,15 +151,15 @@ struct st_var_header *var_header_by_name(const char *name)
|
||
return where;
|
||
}
|
||
|
||
-struct var_t *get_var(enum var_id_t var_id)
|
||
+struct var_t *spk_get_var(enum var_id_t var_id)
|
||
{
|
||
BUG_ON(var_id < 0 || var_id >= MAXVARS);
|
||
BUG_ON(!var_ptrs[var_id]);
|
||
return var_ptrs[var_id]->data;
|
||
}
|
||
-EXPORT_SYMBOL_GPL(get_var);
|
||
+EXPORT_SYMBOL_GPL(spk_get_var);
|
||
|
||
-struct punc_var_t *get_punc_var(enum var_id_t var_id)
|
||
+struct punc_var_t *spk_get_punc_var(enum var_id_t var_id)
|
||
{
|
||
struct punc_var_t *rv = NULL;
|
||
struct punc_var_t *where;
|
||
@@ -175,7 +175,7 @@ struct punc_var_t *get_punc_var(enum var_id_t var_id)
|
||
}
|
||
|
||
/* handlers for setting vars */
|
||
-int set_num_var(int input, struct st_var_header *var, int how)
|
||
+int spk_set_num_var(int input, struct st_var_header *var, int how)
|
||
{
|
||
int val;
|
||
short ret = 0;
|
||
@@ -217,7 +217,7 @@ int set_num_var(int input, struct st_var_header *var, int how)
|
||
if (p_val != NULL)
|
||
*p_val = val;
|
||
if (var->var_id == PUNC_LEVEL) {
|
||
- punc_mask = punc_masks[val];
|
||
+ spk_punc_mask = spk_punc_masks[val];
|
||
return ret;
|
||
}
|
||
if (var_data->u.n.multiplier != 0)
|
||
@@ -232,7 +232,7 @@ int set_num_var(int input, struct st_var_header *var, int how)
|
||
if (!var_data->u.n.synth_fmt)
|
||
return ret;
|
||
if (var->var_id == PITCH)
|
||
- cp = pitch_buff;
|
||
+ cp = spk_pitch_buff;
|
||
else
|
||
cp = buf;
|
||
if (!var_data->u.n.out_str)
|
||
@@ -244,7 +244,7 @@ int set_num_var(int input, struct st_var_header *var, int how)
|
||
return ret;
|
||
}
|
||
|
||
-int set_string_var(const char *page, struct st_var_header *var, int len)
|
||
+int spk_set_string_var(const char *page, struct st_var_header *var, int len)
|
||
{
|
||
int ret = 0;
|
||
struct var_t *var_data = var->data;
|
||
@@ -267,21 +267,21 @@ int set_string_var(const char *page, struct st_var_header *var, int len)
|
||
return ret;
|
||
}
|
||
|
||
-/* set_mask_bits sets or clears the punc/delim/repeat bits,
|
||
+/* spk_set_mask_bits sets or clears the punc/delim/repeat bits,
|
||
* if input is null uses the defaults.
|
||
* values for how: 0 clears bits of chars supplied,
|
||
* 1 clears allk, 2 sets bits for chars */
|
||
-int set_mask_bits(const char *input, const int which, const int how)
|
||
+int spk_set_mask_bits(const char *input, const int which, const int how)
|
||
{
|
||
u_char *cp;
|
||
- short mask = punc_info[which].mask;
|
||
+ short mask = spk_punc_info[which].mask;
|
||
if (how&1) {
|
||
- for (cp = (u_char *)punc_info[3].value; *cp; cp++)
|
||
+ for (cp = (u_char *)spk_punc_info[3].value; *cp; cp++)
|
||
spk_chartab[*cp] &= ~mask;
|
||
}
|
||
cp = (u_char *)input;
|
||
if (cp == 0)
|
||
- cp = punc_info[which].value;
|
||
+ cp = spk_punc_info[which].value;
|
||
else {
|
||
for ( ; *cp; cp++) {
|
||
if (*cp < SPACE)
|
||
@@ -308,7 +308,7 @@ int set_mask_bits(const char *input, const int which, const int how)
|
||
return 0;
|
||
}
|
||
|
||
-char *strlwr(char *s)
|
||
+char *spk_strlwr(char *s)
|
||
{
|
||
char *p;
|
||
if (s == NULL)
|
||
@@ -341,7 +341,7 @@ char *speakup_s2i(char *start, int *dest)
|
||
return start;
|
||
}
|
||
|
||
-char *s2uchar(char *start, char *dest)
|
||
+char *spk_s2uchar(char *start, char *dest)
|
||
{
|
||
int val = 0;
|
||
while (*start && *start <= SPACE)
|
||
@@ -357,7 +357,7 @@ char *s2uchar(char *start, char *dest)
|
||
return start;
|
||
}
|
||
|
||
-char *xlate(char *s)
|
||
+char *spk_xlate(char *s)
|
||
{
|
||
static const char finds[] = "nrtvafe";
|
||
static const char subs[] = "\n\r\t\013\001\014\033";
|
||
diff --git a/drivers/staging/tidspbridge/Kconfig b/drivers/staging/tidspbridge/Kconfig
|
||
index 0dd479f..f67c78e 100644
|
||
--- a/drivers/staging/tidspbridge/Kconfig
|
||
+++ b/drivers/staging/tidspbridge/Kconfig
|
||
@@ -4,7 +4,7 @@
|
||
|
||
menuconfig TIDSPBRIDGE
|
||
tristate "DSP Bridge driver"
|
||
- depends on ARCH_OMAP3
|
||
+ depends on ARCH_OMAP3 && BROKEN
|
||
select OMAP_MBOX_FWK
|
||
help
|
||
DSP/BIOS Bridge is designed for platforms that contain a GPP and
|
||
diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c
|
||
index c7df34e..f825814 100644
|
||
--- a/drivers/staging/tidspbridge/core/dsp-clock.c
|
||
+++ b/drivers/staging/tidspbridge/core/dsp-clock.c
|
||
@@ -213,7 +213,7 @@ int dsp_clk_enable(enum dsp_clk_id clk_id)
|
||
case GPT_CLK:
|
||
status = omap_dm_timer_start(timer[clk_id - 1]);
|
||
break;
|
||
-#ifdef CONFIG_OMAP_MCBSP
|
||
+#ifdef CONFIG_SND_OMAP_SOC_MCBSP
|
||
case MCBSP_CLK:
|
||
omap_mcbsp_request(MCBSP_ID(clk_id));
|
||
omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PAD_SRC);
|
||
@@ -289,7 +289,7 @@ int dsp_clk_disable(enum dsp_clk_id clk_id)
|
||
case GPT_CLK:
|
||
status = omap_dm_timer_stop(timer[clk_id - 1]);
|
||
break;
|
||
-#ifdef CONFIG_OMAP_MCBSP
|
||
+#ifdef CONFIG_SND_OMAP_SOC_MCBSP
|
||
case MCBSP_CLK:
|
||
omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PRCM_SRC);
|
||
omap_mcbsp_free(MCBSP_ID(clk_id));
|
||
diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c
|
||
index 06f27f6..4034281 100644
|
||
--- a/drivers/staging/vt6656/baseband.c
|
||
+++ b/drivers/staging/vt6656/baseband.c
|
||
@@ -976,6 +976,7 @@ BOOL BBbVT3184Init(PSDevice pDevice)
|
||
PBYTE pbyAgc;
|
||
WORD wLengthAgc;
|
||
BYTE abyArray[256];
|
||
+ u8 data;
|
||
|
||
ntStatus = CONTROLnsRequestIn(pDevice,
|
||
MESSAGE_TYPE_READ,
|
||
@@ -1144,6 +1145,16 @@ else {
|
||
ControlvWriteByte(pDevice,MESSAGE_REQUEST_BBREG,0x0D,0x01);
|
||
|
||
RFbRFTableDownload(pDevice);
|
||
+
|
||
+ /* Fix for TX USB resets from vendors driver */
|
||
+ CONTROLnsRequestIn(pDevice, MESSAGE_TYPE_READ, USB_REG4,
|
||
+ MESSAGE_REQUEST_MEM, sizeof(data), &data);
|
||
+
|
||
+ data |= 0x2;
|
||
+
|
||
+ CONTROLnsRequestOut(pDevice, MESSAGE_TYPE_WRITE, USB_REG4,
|
||
+ MESSAGE_REQUEST_MEM, sizeof(data), &data);
|
||
+
|
||
return TRUE;//ntStatus;
|
||
}
|
||
|
||
@@ -1623,7 +1634,6 @@ BBvUpdatePreEDThreshold(
|
||
|
||
if( bScanning )
|
||
{ // need Max sensitivity //RSSI -69, -70,....
|
||
- if(pDevice->byBBPreEDIndex == 0) break;
|
||
pDevice->byBBPreEDIndex = 0;
|
||
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xC9, 0x00); //CR201(0xC9)
|
||
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xCE, 0x30); //CR206(0xCE)
|
||
@@ -1766,7 +1776,6 @@ BBvUpdatePreEDThreshold(
|
||
|
||
if( bScanning )
|
||
{ // need Max sensitivity //RSSI -69, -70, ...
|
||
- if(pDevice->byBBPreEDIndex == 0) break;
|
||
pDevice->byBBPreEDIndex = 0;
|
||
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xC9, 0x00); //CR201(0xC9)
|
||
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xCE, 0x24); //CR206(0xCE)
|
||
@@ -1918,7 +1927,6 @@ BBvUpdatePreEDThreshold(
|
||
case RF_VT3342A0: //RobertYu:20060627, testing table
|
||
if( bScanning )
|
||
{ // need Max sensitivity //RSSI -67, -68, ...
|
||
- if(pDevice->byBBPreEDIndex == 0) break;
|
||
pDevice->byBBPreEDIndex = 0;
|
||
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xC9, 0x00); //CR201(0xC9)
|
||
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xCE, 0x38); //CR206(0xCE)
|
||
diff --git a/drivers/staging/vt6656/rndis.h b/drivers/staging/vt6656/rndis.h
|
||
index fccf7e9..dcf7bf5 100644
|
||
--- a/drivers/staging/vt6656/rndis.h
|
||
+++ b/drivers/staging/vt6656/rndis.h
|
||
@@ -69,6 +69,7 @@
|
||
|
||
#define VIAUSB20_PACKET_HEADER 0x04
|
||
|
||
+#define USB_REG4 0x604
|
||
|
||
/*--------------------- Export Classes ----------------------------*/
|
||
|
||
diff --git a/drivers/staging/wlags49_h2/wl_priv.c b/drivers/staging/wlags49_h2/wl_priv.c
|
||
index f30e5ee..ff459b2 100644
|
||
--- a/drivers/staging/wlags49_h2/wl_priv.c
|
||
+++ b/drivers/staging/wlags49_h2/wl_priv.c
|
||
@@ -570,6 +570,7 @@ int wvlan_uil_put_info( struct uilreq *urq, struct wl_private *lp )
|
||
ltv_t *pLtv;
|
||
bool_t ltvAllocated = FALSE;
|
||
ENCSTRCT sEncryption;
|
||
+ size_t len;
|
||
|
||
#ifdef USE_WDS
|
||
hcf_16 hcfPort = HCF_PORT_0;
|
||
@@ -686,7 +687,8 @@ int wvlan_uil_put_info( struct uilreq *urq, struct wl_private *lp )
|
||
break;
|
||
case CFG_CNF_OWN_NAME:
|
||
memset( lp->StationName, 0, sizeof( lp->StationName ));
|
||
- memcpy( (void *)lp->StationName, (void *)&pLtv->u.u8[2], (size_t)pLtv->u.u16[0]);
|
||
+ len = min_t(size_t, pLtv->u.u16[0], sizeof(lp->StationName));
|
||
+ strlcpy(lp->StationName, &pLtv->u.u8[2], len);
|
||
pLtv->u.u16[0] = CNV_INT_TO_LITTLE( pLtv->u.u16[0] );
|
||
break;
|
||
case CFG_CNF_LOAD_BALANCING:
|
||
@@ -1800,6 +1802,7 @@ int wvlan_set_station_nickname(struct net_device *dev,
|
||
{
|
||
struct wl_private *lp = wl_priv(dev);
|
||
unsigned long flags;
|
||
+ size_t len;
|
||
int ret = 0;
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
@@ -1810,8 +1813,8 @@ int wvlan_set_station_nickname(struct net_device *dev,
|
||
wl_lock(lp, &flags);
|
||
|
||
memset( lp->StationName, 0, sizeof( lp->StationName ));
|
||
-
|
||
- memcpy( lp->StationName, extra, wrqu->data.length);
|
||
+ len = min_t(size_t, wrqu->data.length, sizeof(lp->StationName));
|
||
+ strlcpy(lp->StationName, extra, len);
|
||
|
||
/* Commit the adapter parameters */
|
||
wl_apply( lp );
|
||
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
|
||
index a493049..2e7e5a8 100644
|
||
--- a/drivers/target/iscsi/iscsi_target.c
|
||
+++ b/drivers/target/iscsi/iscsi_target.c
|
||
@@ -50,7 +50,7 @@
|
||
static LIST_HEAD(g_tiqn_list);
|
||
static LIST_HEAD(g_np_list);
|
||
static DEFINE_SPINLOCK(tiqn_lock);
|
||
-static DEFINE_SPINLOCK(np_lock);
|
||
+static DEFINE_MUTEX(np_lock);
|
||
|
||
static struct idr tiqn_idr;
|
||
struct idr sess_idr;
|
||
@@ -262,6 +262,9 @@ int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
|
||
return 0;
|
||
}
|
||
|
||
+/*
|
||
+ * Called with mutex np_lock held
|
||
+ */
|
||
static struct iscsi_np *iscsit_get_np(
|
||
struct __kernel_sockaddr_storage *sockaddr,
|
||
int network_transport)
|
||
@@ -272,11 +275,10 @@ static struct iscsi_np *iscsit_get_np(
|
||
int ip_match = 0;
|
||
u16 port;
|
||
|
||
- spin_lock_bh(&np_lock);
|
||
list_for_each_entry(np, &g_np_list, np_list) {
|
||
- spin_lock(&np->np_thread_lock);
|
||
+ spin_lock_bh(&np->np_thread_lock);
|
||
if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
|
||
- spin_unlock(&np->np_thread_lock);
|
||
+ spin_unlock_bh(&np->np_thread_lock);
|
||
continue;
|
||
}
|
||
|
||
@@ -309,13 +311,11 @@ static struct iscsi_np *iscsit_get_np(
|
||
* while iscsi_tpg_add_network_portal() is called.
|
||
*/
|
||
np->np_exports++;
|
||
- spin_unlock(&np->np_thread_lock);
|
||
- spin_unlock_bh(&np_lock);
|
||
+ spin_unlock_bh(&np->np_thread_lock);
|
||
return np;
|
||
}
|
||
- spin_unlock(&np->np_thread_lock);
|
||
+ spin_unlock_bh(&np->np_thread_lock);
|
||
}
|
||
- spin_unlock_bh(&np_lock);
|
||
|
||
return NULL;
|
||
}
|
||
@@ -329,16 +329,22 @@ struct iscsi_np *iscsit_add_np(
|
||
struct sockaddr_in6 *sock_in6;
|
||
struct iscsi_np *np;
|
||
int ret;
|
||
+
|
||
+ mutex_lock(&np_lock);
|
||
+
|
||
/*
|
||
* Locate the existing struct iscsi_np if already active..
|
||
*/
|
||
np = iscsit_get_np(sockaddr, network_transport);
|
||
- if (np)
|
||
+ if (np) {
|
||
+ mutex_unlock(&np_lock);
|
||
return np;
|
||
+ }
|
||
|
||
np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL);
|
||
if (!np) {
|
||
pr_err("Unable to allocate memory for struct iscsi_np\n");
|
||
+ mutex_unlock(&np_lock);
|
||
return ERR_PTR(-ENOMEM);
|
||
}
|
||
|
||
@@ -361,6 +367,7 @@ struct iscsi_np *iscsit_add_np(
|
||
ret = iscsi_target_setup_login_socket(np, sockaddr);
|
||
if (ret != 0) {
|
||
kfree(np);
|
||
+ mutex_unlock(&np_lock);
|
||
return ERR_PTR(ret);
|
||
}
|
||
|
||
@@ -369,6 +376,7 @@ struct iscsi_np *iscsit_add_np(
|
||
pr_err("Unable to create kthread: iscsi_np\n");
|
||
ret = PTR_ERR(np->np_thread);
|
||
kfree(np);
|
||
+ mutex_unlock(&np_lock);
|
||
return ERR_PTR(ret);
|
||
}
|
||
/*
|
||
@@ -379,10 +387,10 @@ struct iscsi_np *iscsit_add_np(
|
||
* point because iscsi_np has not been added to g_np_list yet.
|
||
*/
|
||
np->np_exports = 1;
|
||
+ np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
|
||
|
||
- spin_lock_bh(&np_lock);
|
||
list_add_tail(&np->np_list, &g_np_list);
|
||
- spin_unlock_bh(&np_lock);
|
||
+ mutex_unlock(&np_lock);
|
||
|
||
pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
|
||
np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
|
||
@@ -453,9 +461,9 @@ int iscsit_del_np(struct iscsi_np *np)
|
||
}
|
||
iscsit_del_np_comm(np);
|
||
|
||
- spin_lock_bh(&np_lock);
|
||
+ mutex_lock(&np_lock);
|
||
list_del(&np->np_list);
|
||
- spin_unlock_bh(&np_lock);
|
||
+ mutex_unlock(&np_lock);
|
||
|
||
pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
|
||
np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
|
||
@@ -2339,6 +2347,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)
|
||
{
|
||
struct iscsi_cmd *cmd;
|
||
struct iscsi_conn *conn_p;
|
||
+ bool found = false;
|
||
|
||
/*
|
||
* Only send a Asynchronous Message on connections whos network
|
||
@@ -2347,11 +2356,12 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)
|
||
list_for_each_entry(conn_p, &conn->sess->sess_conn_list, conn_list) {
|
||
if (conn_p->conn_state == TARG_CONN_STATE_LOGGED_IN) {
|
||
iscsit_inc_conn_usage_count(conn_p);
|
||
+ found = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
- if (!conn_p)
|
||
+ if (!found)
|
||
return;
|
||
|
||
cmd = iscsit_allocate_cmd(conn_p, GFP_ATOMIC);
|
||
@@ -4282,6 +4292,7 @@ static void iscsit_logout_post_handler_diffcid(
|
||
{
|
||
struct iscsi_conn *l_conn;
|
||
struct iscsi_session *sess = conn->sess;
|
||
+ bool conn_found = false;
|
||
|
||
if (!sess)
|
||
return;
|
||
@@ -4290,12 +4301,13 @@ static void iscsit_logout_post_handler_diffcid(
|
||
list_for_each_entry(l_conn, &sess->sess_conn_list, conn_list) {
|
||
if (l_conn->cid == cid) {
|
||
iscsit_inc_conn_usage_count(l_conn);
|
||
+ conn_found = true;
|
||
break;
|
||
}
|
||
}
|
||
spin_unlock_bh(&sess->conn_lock);
|
||
|
||
- if (!l_conn)
|
||
+ if (!conn_found)
|
||
return;
|
||
|
||
if (l_conn->sock)
|
||
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
|
||
index a0fc7b9..cbb04f3 100644
|
||
--- a/drivers/target/iscsi/iscsi_target_auth.c
|
||
+++ b/drivers/target/iscsi/iscsi_target_auth.c
|
||
@@ -174,6 +174,7 @@ static int chap_server_compute_md5(
|
||
unsigned char client_digest[MD5_SIGNATURE_SIZE];
|
||
unsigned char server_digest[MD5_SIGNATURE_SIZE];
|
||
unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
|
||
+ size_t compare_len;
|
||
struct iscsi_chap *chap = conn->auth_protocol;
|
||
struct crypto_hash *tfm;
|
||
struct hash_desc desc;
|
||
@@ -212,7 +213,9 @@ static int chap_server_compute_md5(
|
||
goto out;
|
||
}
|
||
|
||
- if (memcmp(chap_n, auth->userid, strlen(auth->userid)) != 0) {
|
||
+ /* Include the terminating NULL in the compare */
|
||
+ compare_len = strlen(auth->userid) + 1;
|
||
+ if (strncmp(chap_n, auth->userid, compare_len) != 0) {
|
||
pr_err("CHAP_N values do not match!\n");
|
||
goto out;
|
||
}
|
||
@@ -339,6 +342,16 @@ static int chap_server_compute_md5(
|
||
goto out;
|
||
}
|
||
/*
|
||
+ * During mutual authentication, the CHAP_C generated by the
|
||
+ * initiator must not match the original CHAP_C generated by
|
||
+ * the target.
|
||
+ */
|
||
+ if (!memcmp(challenge_binhex, chap->challenge, CHAP_CHALLENGE_LENGTH)) {
|
||
+ pr_err("initiator CHAP_C matches target CHAP_C, failing"
|
||
+ " login attempt\n");
|
||
+ goto out;
|
||
+ }
|
||
+ /*
|
||
* Generate CHAP_N and CHAP_R for mutual authentication.
|
||
*/
|
||
tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
|
||
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
|
||
index 3cb7a4f..bc7d08f 100644
|
||
--- a/drivers/target/iscsi/iscsi_target_login.c
|
||
+++ b/drivers/target/iscsi/iscsi_target_login.c
|
||
@@ -131,13 +131,13 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
|
||
|
||
initiatorname_param = iscsi_find_param_from_key(
|
||
INITIATORNAME, conn->param_list);
|
||
- if (!initiatorname_param)
|
||
- return -1;
|
||
-
|
||
sessiontype_param = iscsi_find_param_from_key(
|
||
SESSIONTYPE, conn->param_list);
|
||
- if (!sessiontype_param)
|
||
+ if (!initiatorname_param || !sessiontype_param) {
|
||
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
|
||
+ ISCSI_LOGIN_STATUS_MISSING_FIELDS);
|
||
return -1;
|
||
+ }
|
||
|
||
sessiontype = (strncmp(sessiontype_param->value, NORMAL, 6)) ? 1 : 0;
|
||
|
||
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
|
||
index 2dba448..89f8909 100644
|
||
--- a/drivers/target/iscsi/iscsi_target_nego.c
|
||
+++ b/drivers/target/iscsi/iscsi_target_nego.c
|
||
@@ -89,7 +89,7 @@ int extract_param(
|
||
if (len < 0)
|
||
return -1;
|
||
|
||
- if (len > max_length) {
|
||
+ if (len >= max_length) {
|
||
pr_err("Length of input: %d exceeds max_length:"
|
||
" %d\n", len, max_length);
|
||
return -1;
|
||
@@ -628,8 +628,11 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log
|
||
login->req_buf,
|
||
payload_length,
|
||
conn->param_list);
|
||
- if (ret < 0)
|
||
+ if (ret < 0) {
|
||
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
|
||
+ ISCSI_LOGIN_STATUS_INIT_ERR);
|
||
return -1;
|
||
+ }
|
||
|
||
if (login->first_request)
|
||
if (iscsi_target_check_first_request(conn, login) < 0)
|
||
@@ -644,8 +647,11 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log
|
||
login->rsp_buf,
|
||
&login->rsp_length,
|
||
conn->param_list);
|
||
- if (ret < 0)
|
||
+ if (ret < 0) {
|
||
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
|
||
+ ISCSI_LOGIN_STATUS_INIT_ERR);
|
||
return -1;
|
||
+ }
|
||
|
||
if (!login->auth_complete &&
|
||
ISCSI_TPG_ATTRIB(ISCSI_TPG_C(conn))->authentication) {
|
||
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
|
||
index 8a8ff23..ed4abad 100644
|
||
--- a/drivers/target/iscsi/iscsi_target_parameters.c
|
||
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
|
||
@@ -552,7 +552,7 @@ int iscsi_copy_param_list(
|
||
param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL);
|
||
if (!param_list) {
|
||
pr_err("Unable to allocate memory for struct iscsi_param_list.\n");
|
||
- goto err_out;
|
||
+ return -1;
|
||
}
|
||
INIT_LIST_HEAD(¶m_list->param_list);
|
||
INIT_LIST_HEAD(¶m_list->extra_response_list);
|
||
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
|
||
index aa3c106..b10f585 100644
|
||
--- a/drivers/target/target_core_alua.c
|
||
+++ b/drivers/target/target_core_alua.c
|
||
@@ -394,7 +394,7 @@ static inline int core_alua_state_standby(
|
||
case SEND_DIAGNOSTIC:
|
||
return 0;
|
||
case MAINTENANCE_IN:
|
||
- switch (cdb[1]) {
|
||
+ switch (cdb[1] & 0x1f) {
|
||
case MI_REPORT_TARGET_PGS:
|
||
return 0;
|
||
default:
|
||
@@ -437,7 +437,7 @@ static inline int core_alua_state_unavailable(
|
||
case REPORT_LUNS:
|
||
return 0;
|
||
case MAINTENANCE_IN:
|
||
- switch (cdb[1]) {
|
||
+ switch (cdb[1] & 0x1f) {
|
||
case MI_REPORT_TARGET_PGS:
|
||
return 0;
|
||
default:
|
||
@@ -478,7 +478,7 @@ static inline int core_alua_state_transition(
|
||
case REPORT_LUNS:
|
||
return 0;
|
||
case MAINTENANCE_IN:
|
||
- switch (cdb[1]) {
|
||
+ switch (cdb[1] & 0x1f) {
|
||
case MI_REPORT_TARGET_PGS:
|
||
return 0;
|
||
default:
|
||
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
|
||
index f286955..f44459a 100644
|
||
--- a/drivers/target/target_core_file.c
|
||
+++ b/drivers/target/target_core_file.c
|
||
@@ -133,21 +133,24 @@ static struct se_device *fd_create_virtdevice(
|
||
ret = PTR_ERR(dev_p);
|
||
goto fail;
|
||
}
|
||
-#if 0
|
||
- if (di->no_create_file)
|
||
- flags = O_RDWR | O_LARGEFILE;
|
||
- else
|
||
- flags = O_RDWR | O_CREAT | O_LARGEFILE;
|
||
-#else
|
||
- flags = O_RDWR | O_CREAT | O_LARGEFILE;
|
||
-#endif
|
||
-/* flags |= O_DIRECT; */
|
||
/*
|
||
- * If fd_buffered_io=1 has not been set explicitly (the default),
|
||
- * use O_SYNC to force FILEIO writes to disk.
|
||
+ * Use O_DSYNC by default instead of O_SYNC to forgo syncing
|
||
+ * of pure timestamp updates.
|
||
+ */
|
||
+ flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;
|
||
+ /*
|
||
+ * Optionally allow fd_buffered_io=1 to be enabled for people
|
||
+ * who want use the fs buffer cache as an WriteCache mechanism.
|
||
+ *
|
||
+ * This means that in event of a hard failure, there is a risk
|
||
+ * of silent data-loss if the SCSI client has *not* performed a
|
||
+ * forced unit access (FUA) write, or issued SYNCHRONIZE_CACHE
|
||
+ * to write-out the entire device cache.
|
||
*/
|
||
- if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO))
|
||
- flags |= O_SYNC;
|
||
+ if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
|
||
+ pr_debug("FILEIO: Disabling O_DSYNC, using buffered FILEIO\n");
|
||
+ flags &= ~O_DSYNC;
|
||
+ }
|
||
|
||
file = filp_open(dev_p, flags, 0600);
|
||
if (IS_ERR(file)) {
|
||
@@ -215,6 +218,12 @@ static struct se_device *fd_create_virtdevice(
|
||
if (!dev)
|
||
goto fail;
|
||
|
||
+ if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
|
||
+ pr_debug("FILEIO: Forcing setting of emulate_write_cache=1"
|
||
+ " with FDBD_HAS_BUFFERED_IO_WCE\n");
|
||
+ dev->se_sub_dev->se_dev_attrib.emulate_write_cache = 1;
|
||
+ }
|
||
+
|
||
fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
|
||
fd_dev->fd_queue_depth = dev->queue_depth;
|
||
|
||
@@ -290,7 +299,7 @@ static int fd_do_readv(struct se_task *task)
|
||
|
||
for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
|
||
iov[i].iov_len = sg->length;
|
||
- iov[i].iov_base = sg_virt(sg);
|
||
+ iov[i].iov_base = kmap(sg_page(sg)) + sg->offset;
|
||
}
|
||
|
||
old_fs = get_fs();
|
||
@@ -298,6 +307,8 @@ static int fd_do_readv(struct se_task *task)
|
||
ret = vfs_readv(fd, &iov[0], task->task_sg_nents, &pos);
|
||
set_fs(old_fs);
|
||
|
||
+ for_each_sg(task->task_sg, sg, task->task_sg_nents, i)
|
||
+ kunmap(sg_page(sg));
|
||
kfree(iov);
|
||
/*
|
||
* Return zeros and GOOD status even if the READ did not return
|
||
@@ -343,7 +354,7 @@ static int fd_do_writev(struct se_task *task)
|
||
|
||
for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
|
||
iov[i].iov_len = sg->length;
|
||
- iov[i].iov_base = sg_virt(sg);
|
||
+ iov[i].iov_base = kmap(sg_page(sg)) + sg->offset;
|
||
}
|
||
|
||
old_fs = get_fs();
|
||
@@ -351,6 +362,9 @@ static int fd_do_writev(struct se_task *task)
|
||
ret = vfs_writev(fd, &iov[0], task->task_sg_nents, &pos);
|
||
set_fs(old_fs);
|
||
|
||
+ for_each_sg(task->task_sg, sg, task->task_sg_nents, i)
|
||
+ kunmap(sg_page(sg));
|
||
+
|
||
kfree(iov);
|
||
|
||
if (ret < 0 || ret != task->task_size) {
|
||
@@ -399,26 +413,6 @@ static void fd_emulate_sync_cache(struct se_task *task)
|
||
transport_complete_sync_cache(cmd, ret == 0);
|
||
}
|
||
|
||
-/*
|
||
- * WRITE Force Unit Access (FUA) emulation on a per struct se_task
|
||
- * LBA range basis..
|
||
- */
|
||
-static void fd_emulate_write_fua(struct se_cmd *cmd, struct se_task *task)
|
||
-{
|
||
- struct se_device *dev = cmd->se_dev;
|
||
- struct fd_dev *fd_dev = dev->dev_ptr;
|
||
- loff_t start = task->task_lba * dev->se_sub_dev->se_dev_attrib.block_size;
|
||
- loff_t end = start + task->task_size;
|
||
- int ret;
|
||
-
|
||
- pr_debug("FILEIO: FUA WRITE LBA: %llu, bytes: %u\n",
|
||
- task->task_lba, task->task_size);
|
||
-
|
||
- ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
|
||
- if (ret != 0)
|
||
- pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret);
|
||
-}
|
||
-
|
||
static int fd_do_task(struct se_task *task)
|
||
{
|
||
struct se_cmd *cmd = task->task_se_cmd;
|
||
@@ -433,19 +427,21 @@ static int fd_do_task(struct se_task *task)
|
||
ret = fd_do_readv(task);
|
||
} else {
|
||
ret = fd_do_writev(task);
|
||
-
|
||
+ /*
|
||
+ * Perform implict vfs_fsync_range() for fd_do_writev() ops
|
||
+ * for SCSI WRITEs with Forced Unit Access (FUA) set.
|
||
+ * Allow this to happen independent of WCE=0 setting.
|
||
+ */
|
||
if (ret > 0 &&
|
||
- dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0 &&
|
||
dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
|
||
(cmd->se_cmd_flags & SCF_FUA)) {
|
||
- /*
|
||
- * We might need to be a bit smarter here
|
||
- * and return some sense data to let the initiator
|
||
- * know the FUA WRITE cache sync failed..?
|
||
- */
|
||
- fd_emulate_write_fua(cmd, task);
|
||
- }
|
||
+ struct fd_dev *fd_dev = dev->dev_ptr;
|
||
+ loff_t start = task->task_lba *
|
||
+ dev->se_sub_dev->se_dev_attrib.block_size;
|
||
+ loff_t end = start + task->task_size;
|
||
|
||
+ vfs_fsync_range(fd_dev->fd_file, start, end, 1);
|
||
+ }
|
||
}
|
||
|
||
if (ret < 0) {
|
||
@@ -544,7 +540,7 @@ static ssize_t fd_set_configfs_dev_params(
|
||
pr_debug("FILEIO: Using buffered I/O"
|
||
" operations for struct fd_dev\n");
|
||
|
||
- fd_dev->fbd_flags |= FDBD_USE_BUFFERED_IO;
|
||
+ fd_dev->fbd_flags |= FDBD_HAS_BUFFERED_IO_WCE;
|
||
break;
|
||
default:
|
||
break;
|
||
@@ -579,8 +575,8 @@ static ssize_t fd_show_configfs_dev_params(
|
||
bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
|
||
bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s\n",
|
||
fd_dev->fd_dev_name, fd_dev->fd_dev_size,
|
||
- (fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO) ?
|
||
- "Buffered" : "Synchronous");
|
||
+ (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) ?
|
||
+ "Buffered-WCE" : "O_DSYNC");
|
||
return bl;
|
||
}
|
||
|
||
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
|
||
index 59e6e73..6b1b6a9 100644
|
||
--- a/drivers/target/target_core_file.h
|
||
+++ b/drivers/target/target_core_file.h
|
||
@@ -18,7 +18,7 @@ struct fd_request {
|
||
|
||
#define FBDF_HAS_PATH 0x01
|
||
#define FBDF_HAS_SIZE 0x02
|
||
-#define FDBD_USE_BUFFERED_IO 0x04
|
||
+#define FDBD_HAS_BUFFERED_IO_WCE 0x04
|
||
|
||
struct fd_dev {
|
||
u32 fbd_flags;
|
||
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
|
||
index d084ba3..d34577d 100644
|
||
--- a/drivers/target/target_core_pscsi.c
|
||
+++ b/drivers/target/target_core_pscsi.c
|
||
@@ -128,10 +128,10 @@ static int pscsi_pmode_enable_hba(struct se_hba *hba, unsigned long mode_flag)
|
||
* pSCSI Host ID and enable for phba mode
|
||
*/
|
||
sh = scsi_host_lookup(phv->phv_host_id);
|
||
- if (IS_ERR(sh)) {
|
||
+ if (!sh) {
|
||
pr_err("pSCSI: Unable to locate SCSI Host for"
|
||
" phv_host_id: %d\n", phv->phv_host_id);
|
||
- return PTR_ERR(sh);
|
||
+ return -EINVAL;
|
||
}
|
||
|
||
phv->phv_lld_host = sh;
|
||
@@ -562,10 +562,10 @@ static struct se_device *pscsi_create_virtdevice(
|
||
sh = phv->phv_lld_host;
|
||
} else {
|
||
sh = scsi_host_lookup(pdv->pdv_host_id);
|
||
- if (IS_ERR(sh)) {
|
||
+ if (!sh) {
|
||
pr_err("pSCSI: Unable to locate"
|
||
" pdv_host_id: %d\n", pdv->pdv_host_id);
|
||
- return ERR_CAST(sh);
|
||
+ return ERR_PTR(-EINVAL);
|
||
}
|
||
}
|
||
} else {
|
||
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
|
||
index 8b68f7b..fa4e21b 100644
|
||
--- a/drivers/target/target_core_rd.c
|
||
+++ b/drivers/target/target_core_rd.c
|
||
@@ -177,7 +177,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev)
|
||
- 1;
|
||
|
||
for (j = 0; j < sg_per_table; j++) {
|
||
- pg = alloc_pages(GFP_KERNEL, 0);
|
||
+ pg = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
|
||
if (!pg) {
|
||
pr_err("Unable to allocate scatterlist"
|
||
" pages for struct rd_dev_sg_table\n");
|
||
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
|
||
index 5362428..712999c 100644
|
||
--- a/drivers/target/target_core_transport.c
|
||
+++ b/drivers/target/target_core_transport.c
|
||
@@ -1458,6 +1458,7 @@ static inline void transport_generic_prepare_cdb(
|
||
case VERIFY_16: /* SBC - VRProtect */
|
||
case WRITE_VERIFY: /* SBC - VRProtect */
|
||
case WRITE_VERIFY_12: /* SBC - VRProtect */
|
||
+ case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
|
||
break;
|
||
default:
|
||
cdb[1] &= 0x1f; /* clear logical unit number */
|
||
@@ -2815,7 +2816,7 @@ static int transport_generic_cmd_sequencer(
|
||
/*
|
||
* Check for emulated MI_REPORT_TARGET_PGS.
|
||
*/
|
||
- if (cdb[1] == MI_REPORT_TARGET_PGS &&
|
||
+ if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS &&
|
||
su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
|
||
cmd->execute_task =
|
||
target_emulate_report_target_port_groups;
|
||
@@ -4706,7 +4707,7 @@ int transport_send_check_condition_and_sense(
|
||
/* ILLEGAL REQUEST */
|
||
buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||
/* LOGICAL UNIT COMMUNICATION FAILURE */
|
||
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x80;
|
||
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x08;
|
||
break;
|
||
}
|
||
/*
|
||
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
|
||
index 9249998..5ac8d56 100644
|
||
--- a/drivers/target/tcm_fc/tfc_sess.c
|
||
+++ b/drivers/target/tcm_fc/tfc_sess.c
|
||
@@ -69,6 +69,7 @@ static struct ft_tport *ft_tport_create(struct fc_lport *lport)
|
||
|
||
if (tport) {
|
||
tport->tpg = tpg;
|
||
+ tpg->tport = tport;
|
||
return tport;
|
||
}
|
||
|
||
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
|
||
index 8880adf..1da617f 100644
|
||
--- a/drivers/tty/hvc/hvc_console.c
|
||
+++ b/drivers/tty/hvc/hvc_console.c
|
||
@@ -31,6 +31,7 @@
|
||
#include <linux/list.h>
|
||
#include <linux/module.h>
|
||
#include <linux/major.h>
|
||
+#include <linux/atomic.h>
|
||
#include <linux/sysrq.h>
|
||
#include <linux/tty.h>
|
||
#include <linux/tty_flip.h>
|
||
@@ -70,6 +71,9 @@ static struct task_struct *hvc_task;
|
||
/* Picks up late kicks after list walk but before schedule() */
|
||
static int hvc_kicked;
|
||
|
||
+/* hvc_init is triggered from hvc_alloc, i.e. only when actually used */
|
||
+static atomic_t hvc_needs_init __read_mostly = ATOMIC_INIT(-1);
|
||
+
|
||
static int hvc_init(void);
|
||
|
||
#ifdef CONFIG_MAGIC_SYSRQ
|
||
@@ -186,7 +190,7 @@ static struct tty_driver *hvc_console_device(struct console *c, int *index)
|
||
return hvc_driver;
|
||
}
|
||
|
||
-static int __init hvc_console_setup(struct console *co, char *options)
|
||
+static int hvc_console_setup(struct console *co, char *options)
|
||
{
|
||
if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
|
||
return -ENODEV;
|
||
@@ -825,7 +829,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
|
||
int i;
|
||
|
||
/* We wait until a driver actually comes along */
|
||
- if (!hvc_driver) {
|
||
+ if (atomic_inc_not_zero(&hvc_needs_init)) {
|
||
int err = hvc_init();
|
||
if (err)
|
||
return ERR_PTR(err);
|
||
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
|
||
index 4a418e4..53ff37b 100644
|
||
--- a/drivers/tty/n_gsm.c
|
||
+++ b/drivers/tty/n_gsm.c
|
||
@@ -108,7 +108,7 @@ struct gsm_mux_net {
|
||
*/
|
||
|
||
struct gsm_msg {
|
||
- struct gsm_msg *next;
|
||
+ struct list_head list;
|
||
u8 addr; /* DLCI address + flags */
|
||
u8 ctrl; /* Control byte + flags */
|
||
unsigned int len; /* Length of data block (can be zero) */
|
||
@@ -245,8 +245,7 @@ struct gsm_mux {
|
||
unsigned int tx_bytes; /* TX data outstanding */
|
||
#define TX_THRESH_HI 8192
|
||
#define TX_THRESH_LO 2048
|
||
- struct gsm_msg *tx_head; /* Pending data packets */
|
||
- struct gsm_msg *tx_tail;
|
||
+ struct list_head tx_list; /* Pending data packets */
|
||
|
||
/* Control messages */
|
||
struct timer_list t2_timer; /* Retransmit timer for commands */
|
||
@@ -663,7 +662,7 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
|
||
m->len = len;
|
||
m->addr = addr;
|
||
m->ctrl = ctrl;
|
||
- m->next = NULL;
|
||
+ INIT_LIST_HEAD(&m->list);
|
||
return m;
|
||
}
|
||
|
||
@@ -673,22 +672,21 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
|
||
*
|
||
* The tty device has called us to indicate that room has appeared in
|
||
* the transmit queue. Ram more data into the pipe if we have any
|
||
+ * If we have been flow-stopped by a CMD_FCOFF, then we can only
|
||
+ * send messages on DLCI0 until CMD_FCON
|
||
*
|
||
* FIXME: lock against link layer control transmissions
|
||
*/
|
||
|
||
static void gsm_data_kick(struct gsm_mux *gsm)
|
||
{
|
||
- struct gsm_msg *msg = gsm->tx_head;
|
||
+ struct gsm_msg *msg, *nmsg;
|
||
int len;
|
||
int skip_sof = 0;
|
||
|
||
- /* FIXME: We need to apply this solely to data messages */
|
||
- if (gsm->constipated)
|
||
- return;
|
||
-
|
||
- while (gsm->tx_head != NULL) {
|
||
- msg = gsm->tx_head;
|
||
+ list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) {
|
||
+ if (gsm->constipated && msg->addr)
|
||
+ continue;
|
||
if (gsm->encoding != 0) {
|
||
gsm->txframe[0] = GSM1_SOF;
|
||
len = gsm_stuff_frame(msg->data,
|
||
@@ -711,14 +709,13 @@ static void gsm_data_kick(struct gsm_mux *gsm)
|
||
len - skip_sof) < 0)
|
||
break;
|
||
/* FIXME: Can eliminate one SOF in many more cases */
|
||
- gsm->tx_head = msg->next;
|
||
- if (gsm->tx_head == NULL)
|
||
- gsm->tx_tail = NULL;
|
||
gsm->tx_bytes -= msg->len;
|
||
- kfree(msg);
|
||
/* For a burst of frames skip the extra SOF within the
|
||
burst */
|
||
skip_sof = 1;
|
||
+
|
||
+ list_del(&msg->list);
|
||
+ kfree(msg);
|
||
}
|
||
}
|
||
|
||
@@ -768,11 +765,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
|
||
msg->data = dp;
|
||
|
||
/* Add to the actual output queue */
|
||
- if (gsm->tx_tail)
|
||
- gsm->tx_tail->next = msg;
|
||
- else
|
||
- gsm->tx_head = msg;
|
||
- gsm->tx_tail = msg;
|
||
+ list_add_tail(&msg->list, &gsm->tx_list);
|
||
gsm->tx_bytes += msg->len;
|
||
gsm_data_kick(gsm);
|
||
}
|
||
@@ -886,7 +879,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
|
||
if (len > gsm->mtu) {
|
||
if (dlci->adaption == 3) {
|
||
/* Over long frame, bin it */
|
||
- kfree_skb(dlci->skb);
|
||
+ dev_kfree_skb_any(dlci->skb);
|
||
dlci->skb = NULL;
|
||
return 0;
|
||
}
|
||
@@ -915,7 +908,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
|
||
skb_pull(dlci->skb, len);
|
||
__gsm_data_queue(dlci, msg);
|
||
if (last) {
|
||
- kfree_skb(dlci->skb);
|
||
+ dev_kfree_skb_any(dlci->skb);
|
||
dlci->skb = NULL;
|
||
}
|
||
return size;
|
||
@@ -976,6 +969,9 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
|
||
unsigned long flags;
|
||
int sweep;
|
||
|
||
+ if (dlci->constipated)
|
||
+ return;
|
||
+
|
||
spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
|
||
/* If we have nothing running then we need to fire up */
|
||
sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO);
|
||
@@ -1033,6 +1029,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
||
{
|
||
int mlines = 0;
|
||
u8 brk = 0;
|
||
+ int fc;
|
||
|
||
/* The modem status command can either contain one octet (v.24 signals)
|
||
or two octets (v.24 signals + break signals). The length field will
|
||
@@ -1044,19 +1041,21 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
||
else {
|
||
brk = modem & 0x7f;
|
||
modem = (modem >> 7) & 0x7f;
|
||
- };
|
||
+ }
|
||
|
||
/* Flow control/ready to communicate */
|
||
- if (modem & MDM_FC) {
|
||
+ fc = (modem & MDM_FC) || !(modem & MDM_RTR);
|
||
+ if (fc && !dlci->constipated) {
|
||
/* Need to throttle our output on this device */
|
||
dlci->constipated = 1;
|
||
- }
|
||
- if (modem & MDM_RTC) {
|
||
- mlines |= TIOCM_DSR | TIOCM_DTR;
|
||
+ } else if (!fc && dlci->constipated) {
|
||
dlci->constipated = 0;
|
||
gsm_dlci_data_kick(dlci);
|
||
}
|
||
+
|
||
/* Map modem bits */
|
||
+ if (modem & MDM_RTC)
|
||
+ mlines |= TIOCM_DSR | TIOCM_DTR;
|
||
if (modem & MDM_RTR)
|
||
mlines |= TIOCM_RTS | TIOCM_CTS;
|
||
if (modem & MDM_IC)
|
||
@@ -1091,6 +1090,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
|
||
{
|
||
unsigned int addr = 0;
|
||
unsigned int modem = 0;
|
||
+ unsigned int brk = 0;
|
||
struct gsm_dlci *dlci;
|
||
int len = clen;
|
||
u8 *dp = data;
|
||
@@ -1117,6 +1117,16 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
|
||
if (len == 0)
|
||
return;
|
||
}
|
||
+ len--;
|
||
+ if (len > 0) {
|
||
+ while (gsm_read_ea(&brk, *dp++) == 0) {
|
||
+ len--;
|
||
+ if (len == 0)
|
||
+ return;
|
||
+ }
|
||
+ modem <<= 7;
|
||
+ modem |= (brk & 0x7f);
|
||
+ }
|
||
tty = tty_port_tty_get(&dlci->port);
|
||
gsm_process_modem(tty, dlci, modem, clen);
|
||
if (tty) {
|
||
@@ -1214,19 +1224,19 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
|
||
gsm_control_reply(gsm, CMD_TEST, data, clen);
|
||
break;
|
||
case CMD_FCON:
|
||
- /* Modem wants us to STFU */
|
||
- gsm->constipated = 1;
|
||
- gsm_control_reply(gsm, CMD_FCON, NULL, 0);
|
||
- break;
|
||
- case CMD_FCOFF:
|
||
/* Modem can accept data again */
|
||
gsm->constipated = 0;
|
||
- gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
|
||
+ gsm_control_reply(gsm, CMD_FCON, NULL, 0);
|
||
/* Kick the link in case it is idling */
|
||
spin_lock_irqsave(&gsm->tx_lock, flags);
|
||
gsm_data_kick(gsm);
|
||
spin_unlock_irqrestore(&gsm->tx_lock, flags);
|
||
break;
|
||
+ case CMD_FCOFF:
|
||
+ /* Modem wants us to STFU */
|
||
+ gsm->constipated = 1;
|
||
+ gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
|
||
+ break;
|
||
case CMD_MSC:
|
||
/* Out of band modem line change indicator for a DLCI */
|
||
gsm_control_modem(gsm, data, clen);
|
||
@@ -1678,7 +1688,7 @@ static void gsm_dlci_free(struct kref *ref)
|
||
dlci->gsm->dlci[dlci->addr] = NULL;
|
||
kfifo_free(dlci->fifo);
|
||
while ((dlci->skb = skb_dequeue(&dlci->skb_list)))
|
||
- kfree_skb(dlci->skb);
|
||
+ dev_kfree_skb(dlci->skb);
|
||
kfree(dlci);
|
||
}
|
||
|
||
@@ -2029,7 +2039,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
|
||
{
|
||
int i;
|
||
struct gsm_dlci *dlci = gsm->dlci[0];
|
||
- struct gsm_msg *txq;
|
||
+ struct gsm_msg *txq, *ntxq;
|
||
struct gsm_control *gc;
|
||
|
||
gsm->dead = 1;
|
||
@@ -2064,11 +2074,9 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
|
||
if (gsm->dlci[i])
|
||
gsm_dlci_release(gsm->dlci[i]);
|
||
/* Now wipe the queues */
|
||
- for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
|
||
- gsm->tx_head = txq->next;
|
||
+ list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
|
||
kfree(txq);
|
||
- }
|
||
- gsm->tx_tail = NULL;
|
||
+ INIT_LIST_HEAD(&gsm->tx_list);
|
||
}
|
||
EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
|
||
|
||
@@ -2179,6 +2187,7 @@ struct gsm_mux *gsm_alloc_mux(void)
|
||
}
|
||
spin_lock_init(&gsm->lock);
|
||
kref_init(&gsm->ref);
|
||
+ INIT_LIST_HEAD(&gsm->tx_list);
|
||
|
||
gsm->t1 = T1;
|
||
gsm->t2 = T2;
|
||
@@ -2295,7 +2304,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||
gsm->error(gsm, *dp, flags);
|
||
break;
|
||
default:
|
||
- WARN_ONCE("%s: unknown flag %d\n",
|
||
+ WARN_ONCE(1, "%s: unknown flag %d\n",
|
||
tty_name(tty, buf), flags);
|
||
break;
|
||
}
|
||
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
|
||
index d537431..5fe2191 100644
|
||
--- a/drivers/tty/serial/8250/8250.c
|
||
+++ b/drivers/tty/serial/8250/8250.c
|
||
@@ -282,6 +282,33 @@ static const struct serial8250_config uart_config[] = {
|
||
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||
.flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
|
||
},
|
||
+ [PORT_BRCM_TRUMANAGE] = {
|
||
+ .name = "TruManage",
|
||
+ .fifo_size = 1,
|
||
+ .tx_loadsz = 1024,
|
||
+ .flags = UART_CAP_HFIFO,
|
||
+ },
|
||
+ [PORT_ALTR_16550_F32] = {
|
||
+ .name = "Altera 16550 FIFO32",
|
||
+ .fifo_size = 32,
|
||
+ .tx_loadsz = 32,
|
||
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||
+ .flags = UART_CAP_FIFO | UART_CAP_AFE,
|
||
+ },
|
||
+ [PORT_ALTR_16550_F64] = {
|
||
+ .name = "Altera 16550 FIFO64",
|
||
+ .fifo_size = 64,
|
||
+ .tx_loadsz = 64,
|
||
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||
+ .flags = UART_CAP_FIFO | UART_CAP_AFE,
|
||
+ },
|
||
+ [PORT_ALTR_16550_F128] = {
|
||
+ .name = "Altera 16550 FIFO128",
|
||
+ .fifo_size = 128,
|
||
+ .tx_loadsz = 128,
|
||
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||
+ .flags = UART_CAP_FIFO | UART_CAP_AFE,
|
||
+ },
|
||
};
|
||
|
||
#if defined(CONFIG_MIPS_ALCHEMY)
|
||
@@ -1470,6 +1497,11 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||
port->icount.tx++;
|
||
if (uart_circ_empty(xmit))
|
||
break;
|
||
+ if (up->capabilities & UART_CAP_HFIFO) {
|
||
+ if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) !=
|
||
+ BOTH_EMPTY)
|
||
+ break;
|
||
+ }
|
||
} while (--count > 0);
|
||
|
||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||
@@ -2641,7 +2673,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||
if (ser->irq >= nr_irqs || ser->irq < 0 ||
|
||
ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
|
||
ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
|
||
- ser->type == PORT_STARTECH)
|
||
+ ser->type == PORT_STARTECH || uart_config[ser->type].name == NULL)
|
||
return -EINVAL;
|
||
return 0;
|
||
}
|
||
@@ -2651,7 +2683,7 @@ serial8250_type(struct uart_port *port)
|
||
{
|
||
int type = port->type;
|
||
|
||
- if (type >= ARRAY_SIZE(uart_config))
|
||
+ if (type >= ARRAY_SIZE(uart_config) || uart_config[type].name == NULL)
|
||
type = 0;
|
||
return uart_config[type].name;
|
||
}
|
||
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
|
||
index 2868a1d..b37147c 100644
|
||
--- a/drivers/tty/serial/8250/8250.h
|
||
+++ b/drivers/tty/serial/8250/8250.h
|
||
@@ -69,6 +69,7 @@ struct serial8250_config {
|
||
#define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */
|
||
#define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */
|
||
#define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */
|
||
+#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */
|
||
|
||
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
|
||
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
|
||
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
|
||
index 40747fe..d53f396 100644
|
||
--- a/drivers/tty/serial/8250/8250_pci.c
|
||
+++ b/drivers/tty/serial/8250/8250_pci.c
|
||
@@ -1077,6 +1077,18 @@ pci_omegapci_setup(struct serial_private *priv,
|
||
return setup_port(priv, port, 2, idx * 8, 0);
|
||
}
|
||
|
||
+static int
|
||
+pci_brcm_trumanage_setup(struct serial_private *priv,
|
||
+ const struct pciserial_board *board,
|
||
+ struct uart_port *port, int idx)
|
||
+{
|
||
+ int ret = pci_default_setup(priv, board, port, idx);
|
||
+
|
||
+ port->type = PORT_BRCM_TRUMANAGE;
|
||
+ port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
|
||
+ return ret;
|
||
+}
|
||
+
|
||
static int skip_tx_en_setup(struct serial_private *priv,
|
||
const struct pciserial_board *board,
|
||
struct uart_port *port, int idx)
|
||
@@ -1142,6 +1154,7 @@ pci_xr17c154_setup(struct serial_private *priv,
|
||
#define PCI_DEVICE_ID_TITAN_800E 0xA014
|
||
#define PCI_DEVICE_ID_TITAN_200EI 0xA016
|
||
#define PCI_DEVICE_ID_TITAN_200EISI 0xA017
|
||
+#define PCI_DEVICE_ID_TITAN_200V3 0xA306
|
||
#define PCI_DEVICE_ID_TITAN_400V3 0xA310
|
||
#define PCI_DEVICE_ID_TITAN_410V3 0xA312
|
||
#define PCI_DEVICE_ID_TITAN_800V3 0xA314
|
||
@@ -1150,9 +1163,11 @@ pci_xr17c154_setup(struct serial_private *priv,
|
||
#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
|
||
#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
|
||
#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
|
||
+#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
|
||
|
||
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
|
||
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
|
||
+#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588
|
||
|
||
/*
|
||
* Master list of serial port init/setup/exit quirks.
|
||
@@ -1424,15 +1439,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||
},
|
||
{
|
||
.vendor = PCI_VENDOR_ID_PLX,
|
||
- .device = PCI_DEVICE_ID_PLX_9050,
|
||
- .subvendor = PCI_VENDOR_ID_PLX,
|
||
- .subdevice = PCI_SUBDEVICE_ID_UNKNOWN_0x1584,
|
||
- .init = pci_plx9050_init,
|
||
- .setup = pci_default_setup,
|
||
- .exit = __devexit_p(pci_plx9050_exit),
|
||
- },
|
||
- {
|
||
- .vendor = PCI_VENDOR_ID_PLX,
|
||
.device = PCI_DEVICE_ID_PLX_ROMULUS,
|
||
.subvendor = PCI_VENDOR_ID_PLX,
|
||
.subdevice = PCI_DEVICE_ID_PLX_ROMULUS,
|
||
@@ -1691,6 +1697,17 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||
.setup = pci_omegapci_setup,
|
||
},
|
||
/*
|
||
+ * Broadcom TruManage (NetXtreme)
|
||
+ */
|
||
+ {
|
||
+ .vendor = PCI_VENDOR_ID_BROADCOM,
|
||
+ .device = PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
|
||
+ .subvendor = PCI_ANY_ID,
|
||
+ .subdevice = PCI_ANY_ID,
|
||
+ .setup = pci_brcm_trumanage_setup,
|
||
+ },
|
||
+
|
||
+ /*
|
||
* Default "match everything" terminator entry
|
||
*/
|
||
{
|
||
@@ -1879,6 +1896,7 @@ enum pci_board_num_t {
|
||
pbn_ce4100_1_115200,
|
||
pbn_omegapci,
|
||
pbn_NETMOS9900_2s_115200,
|
||
+ pbn_brcm_trumanage,
|
||
};
|
||
|
||
/*
|
||
@@ -2585,6 +2603,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
|
||
.num_ports = 2,
|
||
.base_baud = 115200,
|
||
},
|
||
+ [pbn_brcm_trumanage] = {
|
||
+ .flags = FL_BASE0,
|
||
+ .num_ports = 1,
|
||
+ .reg_shift = 2,
|
||
+ .base_baud = 115200,
|
||
+ },
|
||
};
|
||
|
||
static const struct pci_device_id softmodem_blacklist[] = {
|
||
@@ -3108,7 +3132,12 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
|
||
PCI_VENDOR_ID_PLX,
|
||
PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0,
|
||
- pbn_b0_4_115200 },
|
||
+ pbn_b2_4_115200 },
|
||
+ /* Unknown card - subdevice 0x1588 */
|
||
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
|
||
+ PCI_VENDOR_ID_PLX,
|
||
+ PCI_SUBDEVICE_ID_UNKNOWN_0x1588, 0, 0,
|
||
+ pbn_b2_8_115200 },
|
||
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
|
||
PCI_SUBVENDOR_ID_KEYSPAN,
|
||
PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
|
||
@@ -3456,6 +3485,9 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
|
||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||
pbn_oxsemi_2_4000000 },
|
||
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3,
|
||
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||
+ pbn_b0_bt_2_921600 },
|
||
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3,
|
||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||
pbn_b0_4_921600 },
|
||
@@ -4139,6 +4171,13 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||
pbn_omegapci },
|
||
|
||
/*
|
||
+ * Broadcom TruManage
|
||
+ */
|
||
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
|
||
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||
+ pbn_brcm_trumanage },
|
||
+
|
||
+ /*
|
||
* These entries match devices with class COMMUNICATION_SERIAL,
|
||
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
|
||
*/
|
||
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
|
||
index ed7cd37..ff58d28 100644
|
||
--- a/drivers/tty/serial/atmel_serial.c
|
||
+++ b/drivers/tty/serial/atmel_serial.c
|
||
@@ -1022,12 +1022,24 @@ static int atmel_startup(struct uart_port *port)
|
||
static void atmel_shutdown(struct uart_port *port)
|
||
{
|
||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||
+
|
||
/*
|
||
- * Ensure everything is stopped.
|
||
+ * Clear out any scheduled tasklets before
|
||
+ * we destroy the buffers
|
||
+ */
|
||
+ tasklet_kill(&atmel_port->tasklet);
|
||
+
|
||
+ /*
|
||
+ * Ensure everything is stopped and
|
||
+ * disable all interrupts, port and break condition.
|
||
*/
|
||
atmel_stop_rx(port);
|
||
atmel_stop_tx(port);
|
||
|
||
+ UART_PUT_CR(port, ATMEL_US_RSTSTA);
|
||
+ UART_PUT_IDR(port, -1);
|
||
+
|
||
+
|
||
/*
|
||
* Shut-down the DMA.
|
||
*/
|
||
@@ -1054,12 +1066,6 @@ static void atmel_shutdown(struct uart_port *port)
|
||
}
|
||
|
||
/*
|
||
- * Disable all interrupts, port and break condition.
|
||
- */
|
||
- UART_PUT_CR(port, ATMEL_US_RSTSTA);
|
||
- UART_PUT_IDR(port, -1);
|
||
-
|
||
- /*
|
||
* Free the interrupt
|
||
*/
|
||
free_irq(port->irq, port);
|
||
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
|
||
index 0de7ed78..88620e1 100644
|
||
--- a/drivers/tty/serial/imx.c
|
||
+++ b/drivers/tty/serial/imx.c
|
||
@@ -131,6 +131,7 @@
|
||
#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
|
||
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
|
||
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
|
||
+#define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */
|
||
#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
|
||
#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7)
|
||
#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
|
||
@@ -666,22 +667,11 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
|
||
static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
|
||
{
|
||
unsigned int val;
|
||
- unsigned int ufcr_rfdiv;
|
||
-
|
||
- /* set receiver / transmitter trigger level.
|
||
- * RFDIV is set such way to satisfy requested uartclk value
|
||
- */
|
||
- val = TXTL << 10 | RXTL;
|
||
- ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2)
|
||
- / sport->port.uartclk;
|
||
-
|
||
- if(!ufcr_rfdiv)
|
||
- ufcr_rfdiv = 1;
|
||
-
|
||
- val |= UFCR_RFDIV_REG(ufcr_rfdiv);
|
||
|
||
+ /* set receiver / transmitter trigger level */
|
||
+ val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
|
||
+ val |= TXTL << UFCR_TXTL_SHF | RXTL;
|
||
writel(val, sport->port.membase + UFCR);
|
||
-
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
|
||
index e8c9cee..6563cad 100644
|
||
--- a/drivers/tty/serial/of_serial.c
|
||
+++ b/drivers/tty/serial/of_serial.c
|
||
@@ -182,6 +182,12 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
|
||
{ .compatible = "ns16750", .data = (void *)PORT_16750, },
|
||
{ .compatible = "ns16850", .data = (void *)PORT_16850, },
|
||
{ .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
|
||
+ { .compatible = "altr,16550-FIFO32",
|
||
+ .data = (void *)PORT_ALTR_16550_F32, },
|
||
+ { .compatible = "altr,16550-FIFO64",
|
||
+ .data = (void *)PORT_ALTR_16550_F64, },
|
||
+ { .compatible = "altr,16550-FIFO128",
|
||
+ .data = (void *)PORT_ALTR_16550_F128, },
|
||
#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
|
||
{ .compatible = "ibm,qpace-nwp-serial",
|
||
.data = (void *)PORT_NWPSERIAL, },
|
||
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
|
||
index 2e99f79..e78d2a6 100644
|
||
--- a/drivers/tty/serial/pch_uart.c
|
||
+++ b/drivers/tty/serial/pch_uart.c
|
||
@@ -646,11 +646,12 @@ static int dma_push_rx(struct eg20t_port *priv, int size)
|
||
dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
|
||
size - room);
|
||
if (!room)
|
||
- return room;
|
||
+ goto out;
|
||
|
||
tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
|
||
|
||
port->icount.rx += room;
|
||
+out:
|
||
tty_kref_put(tty);
|
||
|
||
return room;
|
||
@@ -1064,6 +1065,8 @@ static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)
|
||
if (tty == NULL) {
|
||
for (i = 0; error_msg[i] != NULL; i++)
|
||
dev_err(&priv->pdev->dev, error_msg[i]);
|
||
+ } else {
|
||
+ tty_kref_put(tty);
|
||
}
|
||
}
|
||
|
||
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
|
||
index 333c8d0..3f93c47 100644
|
||
--- a/drivers/tty/serial/pmac_zilog.c
|
||
+++ b/drivers/tty/serial/pmac_zilog.c
|
||
@@ -2051,6 +2051,9 @@ static int __init pmz_console_init(void)
|
||
/* Probe ports */
|
||
pmz_probe();
|
||
|
||
+ if (pmz_ports_count == 0)
|
||
+ return -ENODEV;
|
||
+
|
||
/* TODO: Autoprobe console based on OF */
|
||
/* pmz_console.index = i; */
|
||
register_console(&pmz_console);
|
||
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
|
||
index f0d93eb..c9549aa 100644
|
||
--- a/drivers/tty/serial/sunsab.c
|
||
+++ b/drivers/tty/serial/sunsab.c
|
||
@@ -157,6 +157,15 @@ receive_chars(struct uart_sunsab_port *up,
|
||
(up->port.line == up->port.cons->index))
|
||
saw_console_brk = 1;
|
||
|
||
+ if (count == 0) {
|
||
+ if (unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) {
|
||
+ stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR |
|
||
+ SAB82532_ISR0_FERR);
|
||
+ up->port.icount.brk++;
|
||
+ uart_handle_break(&up->port);
|
||
+ }
|
||
+ }
|
||
+
|
||
for (i = 0; i < count; i++) {
|
||
unsigned char ch = buf[i], flag;
|
||
|
||
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
|
||
index 24b18cb..57f8f53 100644
|
||
--- a/drivers/tty/tty_buffer.c
|
||
+++ b/drivers/tty/tty_buffer.c
|
||
@@ -114,11 +114,14 @@ static void __tty_buffer_flush(struct tty_struct *tty)
|
||
{
|
||
struct tty_buffer *thead;
|
||
|
||
- while ((thead = tty->buf.head) != NULL) {
|
||
- tty->buf.head = thead->next;
|
||
- tty_buffer_free(tty, thead);
|
||
+ if (tty->buf.head == NULL)
|
||
+ return;
|
||
+ while ((thead = tty->buf.head->next) != NULL) {
|
||
+ tty_buffer_free(tty, tty->buf.head);
|
||
+ tty->buf.head = thead;
|
||
}
|
||
- tty->buf.tail = NULL;
|
||
+ WARN_ON(tty->buf.head != tty->buf.tail);
|
||
+ tty->buf.head->read = tty->buf.head->commit;
|
||
}
|
||
|
||
/**
|
||
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
|
||
index e411f18..2f2540f 100644
|
||
--- a/drivers/usb/class/cdc-acm.c
|
||
+++ b/drivers/usb/class/cdc-acm.c
|
||
@@ -123,13 +123,23 @@ static void acm_release_minor(struct acm *acm)
|
||
static int acm_ctrl_msg(struct acm *acm, int request, int value,
|
||
void *buf, int len)
|
||
{
|
||
- int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
|
||
+ int retval;
|
||
+
|
||
+ retval = usb_autopm_get_interface(acm->control);
|
||
+ if (retval)
|
||
+ return retval;
|
||
+
|
||
+ retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
|
||
request, USB_RT_ACM, value,
|
||
acm->control->altsetting[0].desc.bInterfaceNumber,
|
||
buf, len, 5000);
|
||
+
|
||
dev_dbg(&acm->control->dev,
|
||
"%s - rq 0x%02x, val %#x, len %#x, result %d\n",
|
||
__func__, request, value, len, retval);
|
||
+
|
||
+ usb_autopm_put_interface(acm->control);
|
||
+
|
||
return retval < 0 ? retval : 0;
|
||
}
|
||
|
||
@@ -234,12 +244,9 @@ static int acm_write_start(struct acm *acm, int wbn)
|
||
acm->susp_count);
|
||
usb_autopm_get_interface_async(acm->control);
|
||
if (acm->susp_count) {
|
||
- if (!acm->delayed_wb)
|
||
- acm->delayed_wb = wb;
|
||
- else
|
||
- usb_autopm_put_interface_async(acm->control);
|
||
+ usb_anchor_urb(wb->urb, &acm->delayed);
|
||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||
- return 0; /* A white lie */
|
||
+ return 0;
|
||
}
|
||
usb_mark_last_busy(acm->dev);
|
||
|
||
@@ -535,6 +542,7 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||
{
|
||
struct acm *acm = container_of(port, struct acm, port);
|
||
int retval = -ENODEV;
|
||
+ int i;
|
||
|
||
dev_dbg(&acm->control->dev, "%s\n", __func__);
|
||
|
||
@@ -583,6 +591,8 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||
return 0;
|
||
|
||
error_submit_read_urbs:
|
||
+ for (i = 0; i < acm->rx_buflimit; i++)
|
||
+ usb_kill_urb(acm->read_urbs[i]);
|
||
acm->ctrlout = 0;
|
||
acm_set_control(acm, acm->ctrlout);
|
||
error_set_control:
|
||
@@ -610,21 +620,35 @@ static void acm_port_destruct(struct tty_port *port)
|
||
static void acm_port_shutdown(struct tty_port *port)
|
||
{
|
||
struct acm *acm = container_of(port, struct acm, port);
|
||
+ struct urb *urb;
|
||
+ struct acm_wb *wb;
|
||
int i;
|
||
+ int pm_err;
|
||
|
||
dev_dbg(&acm->control->dev, "%s\n", __func__);
|
||
|
||
mutex_lock(&acm->mutex);
|
||
if (!acm->disconnected) {
|
||
- usb_autopm_get_interface(acm->control);
|
||
+ pm_err = usb_autopm_get_interface(acm->control);
|
||
acm_set_control(acm, acm->ctrlout = 0);
|
||
+
|
||
+ for (;;) {
|
||
+ urb = usb_get_from_anchor(&acm->delayed);
|
||
+ if (!urb)
|
||
+ break;
|
||
+ wb = urb->context;
|
||
+ wb->use = 0;
|
||
+ usb_autopm_put_interface_async(acm->control);
|
||
+ }
|
||
+
|
||
usb_kill_urb(acm->ctrlurb);
|
||
for (i = 0; i < ACM_NW; i++)
|
||
usb_kill_urb(acm->wb[i].urb);
|
||
for (i = 0; i < acm->rx_buflimit; i++)
|
||
usb_kill_urb(acm->read_urbs[i]);
|
||
acm->control->needs_remote_wakeup = 0;
|
||
- usb_autopm_put_interface(acm->control);
|
||
+ if (!pm_err)
|
||
+ usb_autopm_put_interface(acm->control);
|
||
}
|
||
mutex_unlock(&acm->mutex);
|
||
}
|
||
@@ -1211,6 +1235,7 @@ static int acm_probe(struct usb_interface *intf,
|
||
acm->bInterval = epread->bInterval;
|
||
tty_port_init(&acm->port);
|
||
acm->port.ops = &acm_port_ops;
|
||
+ init_usb_anchor(&acm->delayed);
|
||
|
||
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
||
if (!buf) {
|
||
@@ -1441,18 +1466,15 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
|
||
struct acm *acm = usb_get_intfdata(intf);
|
||
int cnt;
|
||
|
||
+ spin_lock_irq(&acm->read_lock);
|
||
+ spin_lock(&acm->write_lock);
|
||
if (PMSG_IS_AUTO(message)) {
|
||
- int b;
|
||
-
|
||
- spin_lock_irq(&acm->write_lock);
|
||
- b = acm->transmitting;
|
||
- spin_unlock_irq(&acm->write_lock);
|
||
- if (b)
|
||
+ if (acm->transmitting) {
|
||
+ spin_unlock(&acm->write_lock);
|
||
+ spin_unlock_irq(&acm->read_lock);
|
||
return -EBUSY;
|
||
+ }
|
||
}
|
||
-
|
||
- spin_lock_irq(&acm->read_lock);
|
||
- spin_lock(&acm->write_lock);
|
||
cnt = acm->susp_count++;
|
||
spin_unlock(&acm->write_lock);
|
||
spin_unlock_irq(&acm->read_lock);
|
||
@@ -1460,8 +1482,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
|
||
if (cnt)
|
||
return 0;
|
||
|
||
- if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
|
||
- stop_data_traffic(acm);
|
||
+ stop_data_traffic(acm);
|
||
|
||
return 0;
|
||
}
|
||
@@ -1469,29 +1490,24 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
|
||
static int acm_resume(struct usb_interface *intf)
|
||
{
|
||
struct acm *acm = usb_get_intfdata(intf);
|
||
- struct acm_wb *wb;
|
||
+ struct urb *urb;
|
||
int rv = 0;
|
||
- int cnt;
|
||
|
||
spin_lock_irq(&acm->read_lock);
|
||
- acm->susp_count -= 1;
|
||
- cnt = acm->susp_count;
|
||
- spin_unlock_irq(&acm->read_lock);
|
||
+ spin_lock(&acm->write_lock);
|
||
|
||
- if (cnt)
|
||
- return 0;
|
||
+ if (--acm->susp_count)
|
||
+ goto out;
|
||
|
||
if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
|
||
- rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
|
||
-
|
||
- spin_lock_irq(&acm->write_lock);
|
||
- if (acm->delayed_wb) {
|
||
- wb = acm->delayed_wb;
|
||
- acm->delayed_wb = NULL;
|
||
- spin_unlock_irq(&acm->write_lock);
|
||
- acm_start_wb(acm, wb);
|
||
- } else {
|
||
- spin_unlock_irq(&acm->write_lock);
|
||
+ rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
|
||
+
|
||
+ for (;;) {
|
||
+ urb = usb_get_from_anchor(&acm->delayed);
|
||
+ if (!urb)
|
||
+ break;
|
||
+
|
||
+ acm_start_wb(acm, urb->context);
|
||
}
|
||
|
||
/*
|
||
@@ -1499,12 +1515,14 @@ static int acm_resume(struct usb_interface *intf)
|
||
* do the write path at all cost
|
||
*/
|
||
if (rv < 0)
|
||
- goto err_out;
|
||
+ goto out;
|
||
|
||
- rv = acm_submit_read_urbs(acm, GFP_NOIO);
|
||
+ rv = acm_submit_read_urbs(acm, GFP_ATOMIC);
|
||
}
|
||
+out:
|
||
+ spin_unlock(&acm->write_lock);
|
||
+ spin_unlock_irq(&acm->read_lock);
|
||
|
||
-err_out:
|
||
return rv;
|
||
}
|
||
|
||
@@ -1542,6 +1560,8 @@ static int acm_reset_resume(struct usb_interface *intf)
|
||
|
||
static const struct usb_device_id acm_ids[] = {
|
||
/* quirky and broken devices */
|
||
+ { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
|
||
+ .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
|
||
{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
|
||
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
|
||
},
|
||
@@ -1585,13 +1605,27 @@ static const struct usb_device_id acm_ids[] = {
|
||
},
|
||
/* Motorola H24 HSPA module: */
|
||
{ USB_DEVICE(0x22b8, 0x2d91) }, /* modem */
|
||
- { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */
|
||
- { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */
|
||
- { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */
|
||
- { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */
|
||
- { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */
|
||
- { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */
|
||
- { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */
|
||
+ { USB_DEVICE(0x22b8, 0x2d92), /* modem + diagnostics */
|
||
+ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
|
||
+ },
|
||
+ { USB_DEVICE(0x22b8, 0x2d93), /* modem + AT port */
|
||
+ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
|
||
+ },
|
||
+ { USB_DEVICE(0x22b8, 0x2d95), /* modem + AT port + diagnostics */
|
||
+ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
|
||
+ },
|
||
+ { USB_DEVICE(0x22b8, 0x2d96), /* modem + NMEA */
|
||
+ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
|
||
+ },
|
||
+ { USB_DEVICE(0x22b8, 0x2d97), /* modem + diagnostics + NMEA */
|
||
+ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
|
||
+ },
|
||
+ { USB_DEVICE(0x22b8, 0x2d99), /* modem + AT port + NMEA */
|
||
+ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
|
||
+ },
|
||
+ { USB_DEVICE(0x22b8, 0x2d9a), /* modem + AT port + diagnostics + NMEA */
|
||
+ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
|
||
+ },
|
||
|
||
{ USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
|
||
.driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
|
||
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
|
||
index 35ef887..9614780 100644
|
||
--- a/drivers/usb/class/cdc-acm.h
|
||
+++ b/drivers/usb/class/cdc-acm.h
|
||
@@ -117,7 +117,7 @@ struct acm {
|
||
unsigned int throttled:1; /* actually throttled */
|
||
unsigned int throttle_req:1; /* throttle requested */
|
||
u8 bInterval;
|
||
- struct acm_wb *delayed_wb; /* write queued for a device about to be woken */
|
||
+ struct usb_anchor delayed; /* writes queued for a device about to be woken */
|
||
};
|
||
|
||
#define CDC_DATA_INTERFACE_TYPE 0x0a
|
||
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
|
||
index 1434ee9..e5fa34e 100644
|
||
--- a/drivers/usb/class/cdc-wdm.c
|
||
+++ b/drivers/usb/class/cdc-wdm.c
|
||
@@ -822,13 +822,11 @@ static int wdm_manage_power(struct usb_interface *intf, int on)
|
||
{
|
||
/* need autopm_get/put here to ensure the usbcore sees the new value */
|
||
int rv = usb_autopm_get_interface(intf);
|
||
- if (rv < 0)
|
||
- goto err;
|
||
|
||
intf->needs_remote_wakeup = on;
|
||
- usb_autopm_put_interface(intf);
|
||
-err:
|
||
- return rv;
|
||
+ if (!rv)
|
||
+ usb_autopm_put_interface(intf);
|
||
+ return 0;
|
||
}
|
||
|
||
static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
|
||
index 78609d3..6ed7e7c 100644
|
||
--- a/drivers/usb/core/config.c
|
||
+++ b/drivers/usb/core/config.c
|
||
@@ -651,10 +651,6 @@ void usb_destroy_configuration(struct usb_device *dev)
|
||
*
|
||
* hub-only!! ... and only in reset path, or usb_new_device()
|
||
* (used by real hubs and virtual root hubs)
|
||
- *
|
||
- * NOTE: if this is a WUSB device and is not authorized, we skip the
|
||
- * whole thing. A non-authorized USB device has no
|
||
- * configurations.
|
||
*/
|
||
int usb_get_configuration(struct usb_device *dev)
|
||
{
|
||
@@ -666,8 +662,6 @@ int usb_get_configuration(struct usb_device *dev)
|
||
struct usb_config_descriptor *desc;
|
||
|
||
cfgno = 0;
|
||
- if (dev->authorized == 0) /* Not really an error */
|
||
- goto out_not_authorized;
|
||
result = -ENOMEM;
|
||
if (ncfg > USB_MAXCONFIG) {
|
||
dev_warn(ddev, "too many configurations: %d, "
|
||
@@ -749,7 +743,6 @@ int usb_get_configuration(struct usb_device *dev)
|
||
|
||
err:
|
||
kfree(desc);
|
||
-out_not_authorized:
|
||
dev->descriptor.bNumConfigurations = cfgno;
|
||
err2:
|
||
if (result == -ENOMEM)
|
||
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
|
||
index 2382640..71f6bd7 100644
|
||
--- a/drivers/usb/core/driver.c
|
||
+++ b/drivers/usb/core/driver.c
|
||
@@ -911,8 +911,7 @@ EXPORT_SYMBOL_GPL(usb_deregister);
|
||
* it doesn't support pre_reset/post_reset/reset_resume or
|
||
* because it doesn't support suspend/resume.
|
||
*
|
||
- * The caller must hold @intf's device's lock, but not its pm_mutex
|
||
- * and not @intf->dev.sem.
|
||
+ * The caller must hold @intf's device's lock, but not @intf's lock.
|
||
*/
|
||
void usb_forced_unbind_intf(struct usb_interface *intf)
|
||
{
|
||
@@ -925,16 +924,37 @@ void usb_forced_unbind_intf(struct usb_interface *intf)
|
||
intf->needs_binding = 1;
|
||
}
|
||
|
||
+/*
|
||
+ * Unbind drivers for @udev's marked interfaces. These interfaces have
|
||
+ * the needs_binding flag set, for example by usb_resume_interface().
|
||
+ *
|
||
+ * The caller must hold @udev's device lock.
|
||
+ */
|
||
+static void unbind_marked_interfaces(struct usb_device *udev)
|
||
+{
|
||
+ struct usb_host_config *config;
|
||
+ int i;
|
||
+ struct usb_interface *intf;
|
||
+
|
||
+ config = udev->actconfig;
|
||
+ if (config) {
|
||
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
|
||
+ intf = config->interface[i];
|
||
+ if (intf->dev.driver && intf->needs_binding)
|
||
+ usb_forced_unbind_intf(intf);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
/* Delayed forced unbinding of a USB interface driver and scan
|
||
* for rebinding.
|
||
*
|
||
- * The caller must hold @intf's device's lock, but not its pm_mutex
|
||
- * and not @intf->dev.sem.
|
||
+ * The caller must hold @intf's device's lock, but not @intf's lock.
|
||
*
|
||
* Note: Rebinds will be skipped if a system sleep transition is in
|
||
* progress and the PM "complete" callback hasn't occurred yet.
|
||
*/
|
||
-void usb_rebind_intf(struct usb_interface *intf)
|
||
+static void usb_rebind_intf(struct usb_interface *intf)
|
||
{
|
||
int rc;
|
||
|
||
@@ -951,68 +971,66 @@ void usb_rebind_intf(struct usb_interface *intf)
|
||
}
|
||
}
|
||
|
||
-#ifdef CONFIG_PM
|
||
-
|
||
-/* Unbind drivers for @udev's interfaces that don't support suspend/resume
|
||
- * There is no check for reset_resume here because it can be determined
|
||
- * only during resume whether reset_resume is needed.
|
||
+/*
|
||
+ * Rebind drivers to @udev's marked interfaces. These interfaces have
|
||
+ * the needs_binding flag set.
|
||
*
|
||
* The caller must hold @udev's device lock.
|
||
*/
|
||
-static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
|
||
+static void rebind_marked_interfaces(struct usb_device *udev)
|
||
{
|
||
struct usb_host_config *config;
|
||
int i;
|
||
struct usb_interface *intf;
|
||
- struct usb_driver *drv;
|
||
|
||
config = udev->actconfig;
|
||
if (config) {
|
||
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
|
||
intf = config->interface[i];
|
||
-
|
||
- if (intf->dev.driver) {
|
||
- drv = to_usb_driver(intf->dev.driver);
|
||
- if (!drv->suspend || !drv->resume)
|
||
- usb_forced_unbind_intf(intf);
|
||
- }
|
||
+ if (intf->needs_binding)
|
||
+ usb_rebind_intf(intf);
|
||
}
|
||
}
|
||
}
|
||
|
||
-/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
|
||
- * These interfaces have the needs_binding flag set by usb_resume_interface().
|
||
+/*
|
||
+ * Unbind all of @udev's marked interfaces and then rebind all of them.
|
||
+ * This ordering is necessary because some drivers claim several interfaces
|
||
+ * when they are first probed.
|
||
*
|
||
* The caller must hold @udev's device lock.
|
||
*/
|
||
-static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
|
||
+void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev)
|
||
{
|
||
- struct usb_host_config *config;
|
||
- int i;
|
||
- struct usb_interface *intf;
|
||
-
|
||
- config = udev->actconfig;
|
||
- if (config) {
|
||
- for (i = 0; i < config->desc.bNumInterfaces; ++i) {
|
||
- intf = config->interface[i];
|
||
- if (intf->dev.driver && intf->needs_binding)
|
||
- usb_forced_unbind_intf(intf);
|
||
- }
|
||
- }
|
||
+ unbind_marked_interfaces(udev);
|
||
+ rebind_marked_interfaces(udev);
|
||
}
|
||
|
||
-static void do_rebind_interfaces(struct usb_device *udev)
|
||
+#ifdef CONFIG_PM
|
||
+
|
||
+/* Unbind drivers for @udev's interfaces that don't support suspend/resume
|
||
+ * There is no check for reset_resume here because it can be determined
|
||
+ * only during resume whether reset_resume is needed.
|
||
+ *
|
||
+ * The caller must hold @udev's device lock.
|
||
+ */
|
||
+static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
|
||
{
|
||
struct usb_host_config *config;
|
||
int i;
|
||
struct usb_interface *intf;
|
||
+ struct usb_driver *drv;
|
||
|
||
config = udev->actconfig;
|
||
if (config) {
|
||
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
|
||
intf = config->interface[i];
|
||
- if (intf->needs_binding)
|
||
- usb_rebind_intf(intf);
|
||
+
|
||
+ if (intf->dev.driver) {
|
||
+ drv = to_usb_driver(intf->dev.driver);
|
||
+ if (!drv->suspend || !drv->resume)
|
||
+ usb_forced_unbind_intf(intf);
|
||
+ }
|
||
}
|
||
}
|
||
}
|
||
@@ -1390,7 +1408,7 @@ int usb_resume_complete(struct device *dev)
|
||
* whose needs_binding flag is set
|
||
*/
|
||
if (udev->state != USB_STATE_NOTATTACHED)
|
||
- do_rebind_interfaces(udev);
|
||
+ rebind_marked_interfaces(udev);
|
||
return 0;
|
||
}
|
||
|
||
@@ -1421,7 +1439,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
|
||
pm_runtime_disable(dev);
|
||
pm_runtime_set_active(dev);
|
||
pm_runtime_enable(dev);
|
||
- unbind_no_reset_resume_drivers_interfaces(udev);
|
||
+ unbind_marked_interfaces(udev);
|
||
}
|
||
|
||
/* Avoid PM error messages for devices disconnected while suspended
|
||
@@ -1756,10 +1774,13 @@ int usb_runtime_suspend(struct device *dev)
|
||
if (status == -EAGAIN || status == -EBUSY)
|
||
usb_mark_last_busy(udev);
|
||
|
||
- /* The PM core reacts badly unless the return code is 0,
|
||
- * -EAGAIN, or -EBUSY, so always return -EBUSY on an error.
|
||
+ /*
|
||
+ * The PM core reacts badly unless the return code is 0,
|
||
+ * -EAGAIN, or -EBUSY, so always return -EBUSY on an error
|
||
+ * (except for root hubs, because they don't suspend through
|
||
+ * an upstream port like other USB devices).
|
||
*/
|
||
- if (status != 0)
|
||
+ if (status != 0 && udev->parent)
|
||
return -EBUSY;
|
||
return status;
|
||
}
|
||
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
|
||
index 2b487d4..50ebe6c 100644
|
||
--- a/drivers/usb/core/hcd-pci.c
|
||
+++ b/drivers/usb/core/hcd-pci.c
|
||
@@ -71,7 +71,7 @@ static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
|
||
continue;
|
||
|
||
companion_hcd = pci_get_drvdata(companion);
|
||
- if (!companion_hcd)
|
||
+ if (!companion_hcd || !companion_hcd->self.root_hub)
|
||
continue;
|
||
|
||
/* For SET_HS_COMPANION, store a pointer to the EHCI bus in
|
||
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
||
index 950ce29..48aefff 100644
|
||
--- a/drivers/usb/core/hub.c
|
||
+++ b/drivers/usb/core/hub.c
|
||
@@ -953,6 +953,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
||
clear_port_feature(hub->hdev, port1,
|
||
USB_PORT_FEAT_C_ENABLE);
|
||
}
|
||
+ if (portchange & USB_PORT_STAT_C_RESET) {
|
||
+ need_debounce_delay = true;
|
||
+ clear_port_feature(hub->hdev, port1,
|
||
+ USB_PORT_FEAT_C_RESET);
|
||
+ }
|
||
if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
|
||
hub_is_superspeed(hub->hdev)) {
|
||
need_debounce_delay = true;
|
||
@@ -1373,6 +1378,7 @@ static int hub_configure(struct usb_hub *hub,
|
||
return 0;
|
||
|
||
fail:
|
||
+ hdev->maxchild = 0;
|
||
dev_err (hub_dev, "config failed, %s (err %d)\n",
|
||
message, ret);
|
||
/* hub_disconnect() frees urb and descriptor */
|
||
@@ -1433,8 +1439,19 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||
desc = intf->cur_altsetting;
|
||
hdev = interface_to_usbdev(intf);
|
||
|
||
- /* Hubs have proper suspend/resume support. */
|
||
- usb_enable_autosuspend(hdev);
|
||
+ /*
|
||
+ * Hubs have proper suspend/resume support, except for root hubs
|
||
+ * where the controller driver doesn't have bus_suspend and
|
||
+ * bus_resume methods.
|
||
+ */
|
||
+ if (hdev->parent) { /* normal device */
|
||
+ usb_enable_autosuspend(hdev);
|
||
+ } else { /* root hub */
|
||
+ const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver;
|
||
+
|
||
+ if (drv->bus_suspend && drv->bus_resume)
|
||
+ usb_enable_autosuspend(hdev);
|
||
+ }
|
||
|
||
if (hdev->level == MAX_TOPO_LEVEL) {
|
||
dev_err(&intf->dev,
|
||
@@ -2005,18 +2022,13 @@ static int usb_enumerate_device(struct usb_device *udev)
|
||
goto fail;
|
||
}
|
||
}
|
||
- if (udev->wusb == 1 && udev->authorized == 0) {
|
||
- udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
|
||
- udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
|
||
- udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
|
||
- }
|
||
- else {
|
||
- /* read the standard strings and cache them if present */
|
||
- udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
|
||
- udev->manufacturer = usb_cache_string(udev,
|
||
- udev->descriptor.iManufacturer);
|
||
- udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
|
||
- }
|
||
+
|
||
+ /* read the standard strings and cache them if present */
|
||
+ udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
|
||
+ udev->manufacturer = usb_cache_string(udev,
|
||
+ udev->descriptor.iManufacturer);
|
||
+ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
|
||
+
|
||
err = usb_enumerate_device_otg(udev);
|
||
fail:
|
||
return err;
|
||
@@ -2170,16 +2182,6 @@ int usb_deauthorize_device(struct usb_device *usb_dev)
|
||
usb_dev->authorized = 0;
|
||
usb_set_configuration(usb_dev, -1);
|
||
|
||
- kfree(usb_dev->product);
|
||
- usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
|
||
- kfree(usb_dev->manufacturer);
|
||
- usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
|
||
- kfree(usb_dev->serial);
|
||
- usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
|
||
-
|
||
- usb_destroy_configuration(usb_dev);
|
||
- usb_dev->descriptor.bNumConfigurations = 0;
|
||
-
|
||
out_unauthorized:
|
||
usb_unlock_device(usb_dev);
|
||
return 0;
|
||
@@ -2207,17 +2209,7 @@ int usb_authorize_device(struct usb_device *usb_dev)
|
||
goto error_device_descriptor;
|
||
}
|
||
|
||
- kfree(usb_dev->product);
|
||
- usb_dev->product = NULL;
|
||
- kfree(usb_dev->manufacturer);
|
||
- usb_dev->manufacturer = NULL;
|
||
- kfree(usb_dev->serial);
|
||
- usb_dev->serial = NULL;
|
||
-
|
||
usb_dev->authorized = 1;
|
||
- result = usb_enumerate_device(usb_dev);
|
||
- if (result < 0)
|
||
- goto error_enumerate;
|
||
/* Choose and set the configuration. This registers the interfaces
|
||
* with the driver core and lets interface drivers bind to them.
|
||
*/
|
||
@@ -2233,7 +2225,6 @@ int usb_authorize_device(struct usb_device *usb_dev)
|
||
}
|
||
dev_info(&usb_dev->dev, "authorized to connect\n");
|
||
|
||
-error_enumerate:
|
||
error_device_descriptor:
|
||
usb_autosuspend_device(usb_dev);
|
||
error_autoresume:
|
||
@@ -3889,9 +3880,10 @@ static void hub_events(void)
|
||
|
||
hub = list_entry(tmp, struct usb_hub, event_list);
|
||
kref_get(&hub->kref);
|
||
+ hdev = hub->hdev;
|
||
+ usb_get_dev(hdev);
|
||
spin_unlock_irq(&hub_event_lock);
|
||
|
||
- hdev = hub->hdev;
|
||
hub_dev = hub->intfdev;
|
||
intf = to_usb_interface(hub_dev);
|
||
dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
|
||
@@ -4210,8 +4202,9 @@ static void hub_events(void)
|
||
hub->hdev->children[i - 1];
|
||
|
||
dev_dbg(hub_dev, "warm reset port %d\n", i);
|
||
- if (!udev || !(portstatus &
|
||
- USB_PORT_STAT_CONNECTION)) {
|
||
+ if (!udev ||
|
||
+ !(portstatus & USB_PORT_STAT_CONNECTION) ||
|
||
+ udev->state == USB_STATE_NOTATTACHED) {
|
||
status = hub_port_reset(hub, i,
|
||
NULL, HUB_BH_RESET_TIME,
|
||
true);
|
||
@@ -4378,6 +4371,7 @@ static void hub_events(void)
|
||
usb_autopm_put_interface(intf);
|
||
loop_disconnected:
|
||
usb_unlock_device(hdev);
|
||
+ usb_put_dev(hdev);
|
||
kref_put(&hub->kref, hub_release);
|
||
|
||
} /* end while (1) */
|
||
@@ -4587,6 +4581,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
||
}
|
||
parent_hub = hdev_to_hub(parent_hdev);
|
||
|
||
+ /* Disable USB2 hardware LPM.
|
||
+ * It will be re-enabled by the enumeration process.
|
||
+ */
|
||
+ if (udev->usb2_hw_lpm_enabled == 1)
|
||
+ usb_set_usb2_hardware_lpm(udev, 0);
|
||
+
|
||
set_bit(port1, parent_hub->busy_bits);
|
||
for (i = 0; i < SET_CONFIG_TRIES; ++i) {
|
||
|
||
@@ -4750,10 +4750,11 @@ int usb_reset_device(struct usb_device *udev)
|
||
else if (cintf->condition ==
|
||
USB_INTERFACE_BOUND)
|
||
rebind = 1;
|
||
+ if (rebind)
|
||
+ cintf->needs_binding = 1;
|
||
}
|
||
- if (ret == 0 && rebind)
|
||
- usb_rebind_intf(cintf);
|
||
}
|
||
+ usb_unbind_and_rebind_marked_interfaces(udev);
|
||
}
|
||
|
||
usb_autosuspend_device(udev);
|
||
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
|
||
index 5e88cce..5e8e69d 100644
|
||
--- a/drivers/usb/core/quirks.c
|
||
+++ b/drivers/usb/core/quirks.c
|
||
@@ -38,6 +38,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||
/* Creative SB Audigy 2 NX */
|
||
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
|
||
|
||
+ /* Microsoft LifeCam-VX700 v2.0 */
|
||
+ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
|
||
+
|
||
/* Logitech Webcam C200 */
|
||
{ USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME },
|
||
|
||
@@ -119,6 +122,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||
/* Alcor Micro Corp. Hub */
|
||
{ USB_DEVICE(0x058f, 0x9254), .driver_info = USB_QUIRK_RESET_RESUME },
|
||
|
||
+ /* MicroTouch Systems touchscreen */
|
||
+ { USB_DEVICE(0x0596, 0x051e), .driver_info = USB_QUIRK_RESET_RESUME },
|
||
+
|
||
/* appletouch */
|
||
{ USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
|
||
|
||
@@ -152,6 +158,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||
/* Broadcom BCM92035DGROM BT dongle */
|
||
{ USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME },
|
||
|
||
+ /* MAYA44USB sound device */
|
||
+ { USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME },
|
||
+
|
||
/* Action Semiconductor flash disk */
|
||
{ USB_DEVICE(0x10d6, 0x2200), .driver_info =
|
||
USB_QUIRK_STRING_FETCH_255 },
|
||
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
|
||
index 4f40547..3ce064d 100644
|
||
--- a/drivers/usb/core/usb.h
|
||
+++ b/drivers/usb/core/usb.h
|
||
@@ -38,7 +38,7 @@ extern void usb_kick_khubd(struct usb_device *dev);
|
||
extern int usb_match_device(struct usb_device *dev,
|
||
const struct usb_device_id *id);
|
||
extern void usb_forced_unbind_intf(struct usb_interface *intf);
|
||
-extern void usb_rebind_intf(struct usb_interface *intf);
|
||
+extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev);
|
||
|
||
extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port,
|
||
void *owner);
|
||
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
|
||
index 2031096..e0d591f 100644
|
||
--- a/drivers/usb/dwc3/core.c
|
||
+++ b/drivers/usb/dwc3/core.c
|
||
@@ -739,8 +739,6 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
|
||
|
||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||
|
||
- pm_runtime_disable(&pdev->dev);
|
||
-
|
||
dwc3_debugfs_exit(dwc);
|
||
|
||
switch (dwc->mode) {
|
||
@@ -762,6 +760,9 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
|
||
|
||
dwc3_core_exit(dwc);
|
||
|
||
+ pm_runtime_put(&pdev->dev);
|
||
+ pm_runtime_disable(&pdev->dev);
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
|
||
index 402c0e2..1606376 100644
|
||
--- a/drivers/usb/dwc3/core.h
|
||
+++ b/drivers/usb/dwc3/core.h
|
||
@@ -895,15 +895,15 @@ struct dwc3_event_depevt {
|
||
* 12 - VndrDevTstRcved
|
||
* @reserved15_12: Reserved, not used
|
||
* @event_info: Information about this event
|
||
- * @reserved31_24: Reserved, not used
|
||
+ * @reserved31_25: Reserved, not used
|
||
*/
|
||
struct dwc3_event_devt {
|
||
u32 one_bit:1;
|
||
u32 device_event:7;
|
||
u32 type:4;
|
||
u32 reserved15_12:4;
|
||
- u32 event_info:8;
|
||
- u32 reserved31_24:8;
|
||
+ u32 event_info:9;
|
||
+ u32 reserved31_25:7;
|
||
} __packed;
|
||
|
||
/**
|
||
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
|
||
index a9ca9ad..4f31fcb 100644
|
||
--- a/drivers/usb/dwc3/dwc3-pci.c
|
||
+++ b/drivers/usb/dwc3/dwc3-pci.c
|
||
@@ -47,6 +47,8 @@
|
||
/* FIXME define these in <linux/pci_ids.h> */
|
||
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
|
||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
|
||
+#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
|
||
+#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
|
||
|
||
struct dwc3_pci {
|
||
struct device *dev;
|
||
@@ -155,6 +157,8 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
|
||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
|
||
},
|
||
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
|
||
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
|
||
{ } /* Terminating Entry */
|
||
};
|
||
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
|
||
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
|
||
index e05481a..a860254 100644
|
||
--- a/drivers/usb/dwc3/gadget.c
|
||
+++ b/drivers/usb/dwc3/gadget.c
|
||
@@ -692,6 +692,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
||
|
||
dwc3_remove_requests(dwc, dep);
|
||
|
||
+ /* make sure HW endpoint isn't stalled */
|
||
+ if (dep->flags & DWC3_EP_STALL)
|
||
+ __dwc3_gadget_ep_set_halt(dep, 0);
|
||
+
|
||
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
|
||
reg &= ~DWC3_DALEPENA_EP(dep->number);
|
||
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
|
||
@@ -2039,11 +2043,19 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
|
||
dep = dwc->eps[epnum];
|
||
if (!dep)
|
||
continue;
|
||
-
|
||
- dwc3_free_trb_pool(dep);
|
||
-
|
||
- if (epnum != 0 && epnum != 1)
|
||
+ /*
|
||
+ * Physical endpoints 0 and 1 are special; they form the
|
||
+ * bi-directional USB endpoint 0.
|
||
+ *
|
||
+ * For those two physical endpoints, we don't allocate a TRB
|
||
+ * pool nor do we add them the endpoints list. Due to that, we
|
||
+ * shouldn't do these two operations otherwise we would end up
|
||
+ * with all sorts of bugs when removing dwc3.ko.
|
||
+ */
|
||
+ if (epnum != 0 && epnum != 1) {
|
||
+ dwc3_free_trb_pool(dep);
|
||
list_del(&dep->endpoint.ep_list);
|
||
+ }
|
||
|
||
kfree(dep);
|
||
}
|
||
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
|
||
index be6952e..bf5671c 100644
|
||
--- a/drivers/usb/gadget/at91_udc.c
|
||
+++ b/drivers/usb/gadget/at91_udc.c
|
||
@@ -1741,16 +1741,6 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
||
return -ENODEV;
|
||
}
|
||
|
||
- if (pdev->num_resources != 2) {
|
||
- DBG("invalid num_resources\n");
|
||
- return -ENODEV;
|
||
- }
|
||
- if ((pdev->resource[0].flags != IORESOURCE_MEM)
|
||
- || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
|
||
- DBG("invalid resource type\n");
|
||
- return -ENODEV;
|
||
- }
|
||
-
|
||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||
if (!res)
|
||
return -ENXIO;
|
||
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
|
||
index 8283dbd..03fe354 100644
|
||
--- a/drivers/usb/gadget/composite.c
|
||
+++ b/drivers/usb/gadget/composite.c
|
||
@@ -593,6 +593,7 @@ static void reset_config(struct usb_composite_dev *cdev)
|
||
bitmap_zero(f->endpoints, 32);
|
||
}
|
||
cdev->config = NULL;
|
||
+ cdev->delayed_status = 0;
|
||
}
|
||
|
||
static int set_config(struct usb_composite_dev *cdev,
|
||
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
|
||
index 22a48a7..9913bb8 100644
|
||
--- a/drivers/usb/gadget/f_fs.c
|
||
+++ b/drivers/usb/gadget/f_fs.c
|
||
@@ -1426,11 +1426,13 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
|
||
ffs->ep0req->context = ffs;
|
||
|
||
lang = ffs->stringtabs;
|
||
- for (lang = ffs->stringtabs; *lang; ++lang) {
|
||
- struct usb_string *str = (*lang)->strings;
|
||
- int id = first_id;
|
||
- for (; str->s; ++id, ++str)
|
||
- str->id = id;
|
||
+ if (lang) {
|
||
+ for (; *lang; ++lang) {
|
||
+ struct usb_string *str = (*lang)->strings;
|
||
+ int id = first_id;
|
||
+ for (; str->s; ++id, ++str)
|
||
+ str->id = id;
|
||
+ }
|
||
}
|
||
|
||
ffs->gadget = cdev->gadget;
|
||
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
|
||
index ae13a10..0a7ca0d 100644
|
||
--- a/drivers/usb/gadget/inode.c
|
||
+++ b/drivers/usb/gadget/inode.c
|
||
@@ -1493,7 +1493,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||
}
|
||
break;
|
||
|
||
-#ifndef CONFIG_USB_GADGET_PXA25X
|
||
+#ifndef CONFIG_USB_PXA25X
|
||
/* PXA automagically handles this request too */
|
||
case USB_REQ_GET_CONFIGURATION:
|
||
if (ctrl->bRequestType != 0x80)
|
||
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
|
||
index 0909783..3302c27 100644
|
||
--- a/drivers/usb/host/ehci-pci.c
|
||
+++ b/drivers/usb/host/ehci-pci.c
|
||
@@ -549,7 +549,7 @@ static struct pci_driver ehci_pci_driver = {
|
||
.remove = usb_hcd_pci_remove,
|
||
.shutdown = usb_hcd_pci_shutdown,
|
||
|
||
-#ifdef CONFIG_PM_SLEEP
|
||
+#ifdef CONFIG_PM
|
||
.driver = {
|
||
.pm = &usb_hcd_pci_pm_ops
|
||
},
|
||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
|
||
index b029be2..2b9acd6 100644
|
||
--- a/drivers/usb/host/ehci-q.c
|
||
+++ b/drivers/usb/host/ehci-q.c
|
||
@@ -264,18 +264,14 @@ ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
|
||
__releases(ehci->lock)
|
||
__acquires(ehci->lock)
|
||
{
|
||
- if (likely (urb->hcpriv != NULL)) {
|
||
- struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
|
||
-
|
||
- /* S-mask in a QH means it's an interrupt urb */
|
||
- if ((qh->hw->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
|
||
-
|
||
- /* ... update hc-wide periodic stats (for usbfs) */
|
||
- ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
|
||
- }
|
||
- qh_put (qh);
|
||
+ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
|
||
+ /* ... update hc-wide periodic stats */
|
||
+ ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
|
||
}
|
||
|
||
+ if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS)
|
||
+ qh_put((struct ehci_qh *) urb->hcpriv);
|
||
+
|
||
if (unlikely(urb->unlinked)) {
|
||
COUNT(ehci->stats.unlink);
|
||
} else {
|
||
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
|
||
index a60679c..34655d0 100644
|
||
--- a/drivers/usb/host/ehci-sched.c
|
||
+++ b/drivers/usb/host/ehci-sched.c
|
||
@@ -1684,7 +1684,7 @@ itd_link_urb (
|
||
|
||
/* don't need that schedule data any more */
|
||
iso_sched_free (stream, iso_sched);
|
||
- urb->hcpriv = NULL;
|
||
+ urb->hcpriv = stream;
|
||
|
||
timer_action (ehci, TIMER_IO_WATCHDOG);
|
||
return enable_periodic(ehci);
|
||
@@ -2094,7 +2094,7 @@ sitd_link_urb (
|
||
|
||
/* don't need that schedule data any more */
|
||
iso_sched_free (stream, sched);
|
||
- urb->hcpriv = NULL;
|
||
+ urb->hcpriv = stream;
|
||
|
||
timer_action (ehci, TIMER_IO_WATCHDOG);
|
||
return enable_periodic(ehci);
|
||
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
|
||
index 1843bb6..6847b93 100644
|
||
--- a/drivers/usb/host/ohci-pci.c
|
||
+++ b/drivers/usb/host/ohci-pci.c
|
||
@@ -414,7 +414,7 @@ static struct pci_driver ohci_pci_driver = {
|
||
.remove = usb_hcd_pci_remove,
|
||
.shutdown = usb_hcd_pci_shutdown,
|
||
|
||
-#ifdef CONFIG_PM_SLEEP
|
||
+#ifdef CONFIG_PM
|
||
.driver = {
|
||
.pm = &usb_hcd_pci_pm_ops
|
||
},
|
||
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
|
||
index 7893351..90dcf54 100644
|
||
--- a/drivers/usb/host/pci-quirks.c
|
||
+++ b/drivers/usb/host/pci-quirks.c
|
||
@@ -555,6 +555,14 @@ static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = {
|
||
DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"),
|
||
},
|
||
},
|
||
+ {
|
||
+ /* HASEE E200 */
|
||
+ .matches = {
|
||
+ DMI_MATCH(DMI_BOARD_VENDOR, "HASEE"),
|
||
+ DMI_MATCH(DMI_BOARD_NAME, "E210"),
|
||
+ DMI_MATCH(DMI_BIOS_VERSION, "6.00"),
|
||
+ },
|
||
+ },
|
||
{ }
|
||
};
|
||
|
||
@@ -564,9 +572,14 @@ static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
|
||
{
|
||
int try_handoff = 1, tried_handoff = 0;
|
||
|
||
- /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying
|
||
- * the handoff on its unused controller. Skip it. */
|
||
- if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
|
||
+ /*
|
||
+ * The Pegatron Lucid tablet sporadically waits for 98 seconds trying
|
||
+ * the handoff on its unused controller. Skip it.
|
||
+ *
|
||
+ * The HASEE E200 hangs when the semaphore is set (bugzilla #77021).
|
||
+ */
|
||
+ if (pdev->vendor == 0x8086 && (pdev->device == 0x283a ||
|
||
+ pdev->device == 0x27cc)) {
|
||
if (dmi_check_system(ehci_dmi_nohandoff_table))
|
||
try_handoff = 0;
|
||
}
|
||
diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c
|
||
index c300bd2f7..0f228c4 100644
|
||
--- a/drivers/usb/host/uhci-pci.c
|
||
+++ b/drivers/usb/host/uhci-pci.c
|
||
@@ -293,7 +293,7 @@ static struct pci_driver uhci_pci_driver = {
|
||
.remove = usb_hcd_pci_remove,
|
||
.shutdown = uhci_shutdown,
|
||
|
||
-#ifdef CONFIG_PM_SLEEP
|
||
+#ifdef CONFIG_PM
|
||
.driver = {
|
||
.pm = &usb_hcd_pci_pm_ops
|
||
},
|
||
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
|
||
index 4d410b9..46b1af8 100644
|
||
--- a/drivers/usb/host/xhci-hub.c
|
||
+++ b/drivers/usb/host/xhci-hub.c
|
||
@@ -617,7 +617,8 @@ static int xhci_ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
|
||
}
|
||
|
||
/* Updates Link Status for super Speed port */
|
||
-static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
|
||
+static void xhci_hub_report_link_state(struct xhci_hcd *xhci,
|
||
+ u32 *status, u32 status_reg)
|
||
{
|
||
u32 pls = status_reg & PORT_PLS_MASK;
|
||
|
||
@@ -656,7 +657,8 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
|
||
* in which sometimes the port enters compliance mode
|
||
* caused by a delay on the host-device negotiation.
|
||
*/
|
||
- if (pls == USB_SS_PORT_LS_COMP_MOD)
|
||
+ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
|
||
+ (pls == USB_SS_PORT_LS_COMP_MOD))
|
||
pls |= USB_PORT_STAT_CONNECTION;
|
||
}
|
||
|
||
@@ -835,7 +837,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||
}
|
||
/* Update Port Link State for super speed ports*/
|
||
if (hcd->speed == HCD_USB3) {
|
||
- xhci_hub_report_link_state(&status, temp);
|
||
+ xhci_hub_report_link_state(xhci, &status, temp);
|
||
/*
|
||
* Verify if all USB3 Ports Have entered U0 already.
|
||
* Delete Compliance Mode Timer if so.
|
||
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
|
||
index 3347e9b..aa38b1f 100644
|
||
--- a/drivers/usb/host/xhci-mem.c
|
||
+++ b/drivers/usb/host/xhci-mem.c
|
||
@@ -1812,6 +1812,16 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||
kfree(cur_cd);
|
||
}
|
||
|
||
+ num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||
+ for (i = 0; i < num_ports && xhci->rh_bw; i++) {
|
||
+ struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table;
|
||
+ for (j = 0; j < XHCI_MAX_INTERVAL; j++) {
|
||
+ struct list_head *ep = &bwt->interval_bw[j].endpoints;
|
||
+ while (!list_empty(ep))
|
||
+ list_del_init(ep->next);
|
||
+ }
|
||
+ }
|
||
+
|
||
for (i = 1; i < MAX_HC_SLOTS; ++i)
|
||
xhci_free_virt_device(xhci, i);
|
||
|
||
@@ -1852,16 +1862,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||
if (!xhci->rh_bw)
|
||
goto no_bw;
|
||
|
||
- num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||
- for (i = 0; i < num_ports; i++) {
|
||
- struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table;
|
||
- for (j = 0; j < XHCI_MAX_INTERVAL; j++) {
|
||
- struct list_head *ep = &bwt->interval_bw[j].endpoints;
|
||
- while (!list_empty(ep))
|
||
- list_del_init(ep->next);
|
||
- }
|
||
- }
|
||
-
|
||
for (i = 0; i < num_ports; i++) {
|
||
struct xhci_tt_bw_info *tt, *n;
|
||
list_for_each_entry_safe(tt, n, &xhci->rh_bw[i].tts, tt_list) {
|
||
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
|
||
index 8b1c27f..0e1f1f0 100644
|
||
--- a/drivers/usb/host/xhci-pci.c
|
||
+++ b/drivers/usb/host/xhci-pci.c
|
||
@@ -87,6 +87,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||
/* AMD PLL quirk */
|
||
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
|
||
xhci->quirks |= XHCI_AMD_PLL_FIX;
|
||
+
|
||
+ if (pdev->vendor == PCI_VENDOR_ID_AMD)
|
||
+ xhci->quirks |= XHCI_TRUST_TX_LENGTH;
|
||
+
|
||
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
|
||
xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
|
||
@@ -109,6 +113,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||
xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
|
||
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
|
||
}
|
||
+ if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
|
||
+ pdev->device == 0x0015)
|
||
+ xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||
if (pdev->vendor == PCI_VENDOR_ID_VIA)
|
||
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||
}
|
||
@@ -330,7 +337,7 @@ static struct pci_driver xhci_pci_driver = {
|
||
/* suspend and resume implemented later */
|
||
|
||
.shutdown = usb_hcd_pci_shutdown,
|
||
-#ifdef CONFIG_PM_SLEEP
|
||
+#ifdef CONFIG_PM
|
||
.driver = {
|
||
.pm = &usb_hcd_pci_pm_ops
|
||
},
|
||
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
|
||
index 1e34a88..5cdb965 100644
|
||
--- a/drivers/usb/host/xhci-ring.c
|
||
+++ b/drivers/usb/host/xhci-ring.c
|
||
@@ -2534,7 +2534,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||
* last TRB of the previous TD. The command completion handle
|
||
* will take care the rest.
|
||
*/
|
||
- if (!event_seg && trb_comp_code == COMP_STOP_INVAL) {
|
||
+ if (!event_seg && (trb_comp_code == COMP_STOP ||
|
||
+ trb_comp_code == COMP_STOP_INVAL)) {
|
||
ret = 0;
|
||
goto cleanup;
|
||
}
|
||
@@ -3738,7 +3739,7 @@ static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
|
||
return 0;
|
||
|
||
max_burst = urb->ep->ss_ep_comp.bMaxBurst;
|
||
- return roundup(total_packet_count, max_burst + 1) - 1;
|
||
+ return DIV_ROUND_UP(total_packet_count, max_burst + 1) - 1;
|
||
}
|
||
|
||
/*
|
||
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
|
||
index 18d2573..1bef534 100644
|
||
--- a/drivers/usb/host/xhci.c
|
||
+++ b/drivers/usb/host/xhci.c
|
||
@@ -315,6 +315,9 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
|
||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||
|
||
+ if (xhci->quirks & XHCI_PLAT)
|
||
+ return;
|
||
+
|
||
xhci_free_irq(xhci);
|
||
|
||
if (xhci->msix_entries) {
|
||
@@ -958,7 +961,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
|
||
*/
|
||
int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
||
{
|
||
- u32 command, temp = 0;
|
||
+ u32 command, temp = 0, status;
|
||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||
struct usb_hcd *secondary_hcd;
|
||
int retval = 0;
|
||
@@ -1082,8 +1085,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
||
|
||
done:
|
||
if (retval == 0) {
|
||
- usb_hcd_resume_root_hub(hcd);
|
||
- usb_hcd_resume_root_hub(xhci->shared_hcd);
|
||
+ /* Resume root hubs only when have pending events. */
|
||
+ status = readl(&xhci->op_regs->status);
|
||
+ if (status & STS_EINT) {
|
||
+ usb_hcd_resume_root_hub(hcd);
|
||
+ usb_hcd_resume_root_hub(xhci->shared_hcd);
|
||
+ }
|
||
}
|
||
|
||
/*
|
||
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
|
||
index 284b854..14d9142 100644
|
||
--- a/drivers/usb/misc/adutux.c
|
||
+++ b/drivers/usb/misc/adutux.c
|
||
@@ -829,7 +829,7 @@ static int adu_probe(struct usb_interface *interface,
|
||
|
||
/* let the user know what node this device is now attached to */
|
||
dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n",
|
||
- udev->descriptor.idProduct, dev->serial_number,
|
||
+ le16_to_cpu(udev->descriptor.idProduct), dev->serial_number,
|
||
(dev->minor - ADU_MINOR_BASE));
|
||
exit:
|
||
dbg(2," %s : leave, return value %p (dev)", __func__, dev);
|
||
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
|
||
index 7af163d..f1bfd01 100644
|
||
--- a/drivers/usb/misc/sisusbvga/sisusb.c
|
||
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
|
||
@@ -3248,6 +3248,7 @@ static const struct usb_device_id sisusb_table[] = {
|
||
{ USB_DEVICE(0x0711, 0x0918) },
|
||
{ USB_DEVICE(0x0711, 0x0920) },
|
||
{ USB_DEVICE(0x0711, 0x0950) },
|
||
+ { USB_DEVICE(0x0711, 0x5200) },
|
||
{ USB_DEVICE(0x182d, 0x021c) },
|
||
{ USB_DEVICE(0x182d, 0x0269) },
|
||
{ }
|
||
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
|
||
index 055b84a..174be05 100644
|
||
--- a/drivers/usb/misc/usbtest.c
|
||
+++ b/drivers/usb/misc/usbtest.c
|
||
@@ -7,9 +7,10 @@
|
||
#include <linux/moduleparam.h>
|
||
#include <linux/scatterlist.h>
|
||
#include <linux/mutex.h>
|
||
-
|
||
+#include <linux/timer.h>
|
||
#include <linux/usb.h>
|
||
|
||
+#define SIMPLE_IO_TIMEOUT 10000 /* in milliseconds */
|
||
|
||
/*-------------------------------------------------------------------------*/
|
||
|
||
@@ -355,6 +356,7 @@ static int simple_io(
|
||
int max = urb->transfer_buffer_length;
|
||
struct completion completion;
|
||
int retval = 0;
|
||
+ unsigned long expire;
|
||
|
||
urb->context = &completion;
|
||
while (retval == 0 && iterations-- > 0) {
|
||
@@ -367,9 +369,15 @@ static int simple_io(
|
||
if (retval != 0)
|
||
break;
|
||
|
||
- /* NOTE: no timeouts; can't be broken out of by interrupt */
|
||
- wait_for_completion(&completion);
|
||
- retval = urb->status;
|
||
+ expire = msecs_to_jiffies(SIMPLE_IO_TIMEOUT);
|
||
+ if (!wait_for_completion_timeout(&completion, expire)) {
|
||
+ usb_kill_urb(urb);
|
||
+ retval = (urb->status == -ENOENT ?
|
||
+ -ETIMEDOUT : urb->status);
|
||
+ } else {
|
||
+ retval = urb->status;
|
||
+ }
|
||
+
|
||
urb->dev = udev;
|
||
if (retval == 0 && usb_pipein(urb->pipe))
|
||
retval = simple_check_buf(tdev, urb);
|
||
@@ -462,6 +470,14 @@ alloc_sglist(int nents, int max, int vary)
|
||
return sg;
|
||
}
|
||
|
||
+static void sg_timeout(unsigned long _req)
|
||
+{
|
||
+ struct usb_sg_request *req = (struct usb_sg_request *) _req;
|
||
+
|
||
+ req->status = -ETIMEDOUT;
|
||
+ usb_sg_cancel(req);
|
||
+}
|
||
+
|
||
static int perform_sglist(
|
||
struct usbtest_dev *tdev,
|
||
unsigned iterations,
|
||
@@ -473,6 +489,9 @@ static int perform_sglist(
|
||
{
|
||
struct usb_device *udev = testdev_to_usbdev(tdev);
|
||
int retval = 0;
|
||
+ struct timer_list sg_timer;
|
||
+
|
||
+ setup_timer_on_stack(&sg_timer, sg_timeout, (unsigned long) req);
|
||
|
||
while (retval == 0 && iterations-- > 0) {
|
||
retval = usb_sg_init(req, udev, pipe,
|
||
@@ -483,7 +502,10 @@ static int perform_sglist(
|
||
|
||
if (retval)
|
||
break;
|
||
+ mod_timer(&sg_timer, jiffies +
|
||
+ msecs_to_jiffies(SIMPLE_IO_TIMEOUT));
|
||
usb_sg_wait(req);
|
||
+ del_timer_sync(&sg_timer);
|
||
retval = req->status;
|
||
|
||
/* FIXME check resulting data pattern */
|
||
@@ -1135,6 +1157,11 @@ static int unlink1(struct usbtest_dev *dev, int pipe, int size, int async)
|
||
urb->context = &completion;
|
||
urb->complete = unlink1_callback;
|
||
|
||
+ if (usb_pipeout(urb->pipe)) {
|
||
+ simple_fill_buf(urb);
|
||
+ urb->transfer_flags |= URB_ZERO_PACKET;
|
||
+ }
|
||
+
|
||
/* keep the endpoint busy. there are lots of hc/hcd-internal
|
||
* states, and testing should get to all of them over time.
|
||
*
|
||
@@ -1265,6 +1292,11 @@ static int unlink_queued(struct usbtest_dev *dev, int pipe, unsigned num,
|
||
unlink_queued_callback, &ctx);
|
||
ctx.urbs[i]->transfer_dma = buf_dma;
|
||
ctx.urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
|
||
+
|
||
+ if (usb_pipeout(ctx.urbs[i]->pipe)) {
|
||
+ simple_fill_buf(ctx.urbs[i]);
|
||
+ ctx.urbs[i]->transfer_flags |= URB_ZERO_PACKET;
|
||
+ }
|
||
}
|
||
|
||
/* Submit all the URBs and then unlink URBs num - 4 and num - 2. */
|
||
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
|
||
index 95918da..49e3728 100644
|
||
--- a/drivers/usb/musb/musb_gadget.c
|
||
+++ b/drivers/usb/musb/musb_gadget.c
|
||
@@ -401,7 +401,19 @@ static void txstate(struct musb *musb, struct musb_request *req)
|
||
csr |= (MUSB_TXCSR_DMAENAB
|
||
| MUSB_TXCSR_DMAMODE
|
||
| MUSB_TXCSR_MODE);
|
||
- if (!musb_ep->hb_mult)
|
||
+ /*
|
||
+ * Enable Autoset according to table
|
||
+ * below
|
||
+ * bulk_split hb_mult Autoset_Enable
|
||
+ * 0 0 Yes(Normal)
|
||
+ * 0 >0 No(High BW ISO)
|
||
+ * 1 0 Yes(HS bulk)
|
||
+ * 1 >0 Yes(FS bulk)
|
||
+ */
|
||
+ if (!musb_ep->hb_mult ||
|
||
+ (musb_ep->hb_mult &&
|
||
+ can_bulk_split(musb,
|
||
+ musb_ep->type)))
|
||
csr |= MUSB_TXCSR_AUTOSET;
|
||
}
|
||
csr &= ~MUSB_TXCSR_P_UNDERRUN;
|
||
@@ -1100,11 +1112,15 @@ static int musb_gadget_enable(struct usb_ep *ep,
|
||
/* Set TXMAXP with the FIFO size of the endpoint
|
||
* to disable double buffering mode.
|
||
*/
|
||
- if (musb->double_buffer_not_ok)
|
||
+ if (musb->double_buffer_not_ok) {
|
||
musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
|
||
- else
|
||
+ } else {
|
||
+ if (can_bulk_split(musb, musb_ep->type))
|
||
+ musb_ep->hb_mult = (hw_ep->max_packet_sz_tx /
|
||
+ musb_ep->packet_sz) - 1;
|
||
musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz
|
||
| (musb_ep->hb_mult << 11));
|
||
+ }
|
||
|
||
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
|
||
if (musb_readw(regs, MUSB_TXCSR)
|
||
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
|
||
index 31bfe60..9282703 100644
|
||
--- a/drivers/usb/serial/ark3116.c
|
||
+++ b/drivers/usb/serial/ark3116.c
|
||
@@ -68,7 +68,6 @@ static int is_irda(struct usb_serial *serial)
|
||
}
|
||
|
||
struct ark3116_private {
|
||
- wait_queue_head_t delta_msr_wait;
|
||
struct async_icount icount;
|
||
int irda; /* 1 for irda device */
|
||
|
||
@@ -148,7 +147,6 @@ static int ark3116_attach(struct usb_serial *serial)
|
||
if (!priv)
|
||
return -ENOMEM;
|
||
|
||
- init_waitqueue_head(&priv->delta_msr_wait);
|
||
mutex_init(&priv->hw_lock);
|
||
spin_lock_init(&priv->status_lock);
|
||
|
||
@@ -460,10 +458,14 @@ static int ark3116_ioctl(struct tty_struct *tty,
|
||
case TIOCMIWAIT:
|
||
for (;;) {
|
||
struct async_icount prev = priv->icount;
|
||
- interruptible_sleep_on(&priv->delta_msr_wait);
|
||
+ interruptible_sleep_on(&port->delta_msr_wait);
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
+
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
if ((prev.rng == priv->icount.rng) &&
|
||
(prev.dsr == priv->icount.dsr) &&
|
||
(prev.dcd == priv->icount.dcd) &&
|
||
@@ -584,7 +586,7 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr)
|
||
priv->icount.dcd++;
|
||
if (msr & UART_MSR_TERI)
|
||
priv->icount.rng++;
|
||
- wake_up_interruptible(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
}
|
||
}
|
||
|
||
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
|
||
index aaab32d..a45594a 100644
|
||
--- a/drivers/usb/serial/ch341.c
|
||
+++ b/drivers/usb/serial/ch341.c
|
||
@@ -82,7 +82,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
|
||
|
||
struct ch341_private {
|
||
spinlock_t lock; /* access lock */
|
||
- wait_queue_head_t delta_msr_wait; /* wait queue for modem status */
|
||
unsigned baud_rate; /* set baud rate */
|
||
u8 line_control; /* set line control value RTS/DTR */
|
||
u8 line_status; /* active status of modem control inputs */
|
||
@@ -262,7 +261,6 @@ static int ch341_attach(struct usb_serial *serial)
|
||
return -ENOMEM;
|
||
|
||
spin_lock_init(&priv->lock);
|
||
- init_waitqueue_head(&priv->delta_msr_wait);
|
||
priv->baud_rate = DEFAULT_BAUD_RATE;
|
||
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
|
||
|
||
@@ -299,7 +297,7 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
|
||
priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
ch341_set_handshake(port->serial->dev, priv->line_control);
|
||
- wake_up_interruptible(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
}
|
||
|
||
static void ch341_close(struct usb_serial_port *port)
|
||
@@ -502,7 +500,7 @@ static void ch341_read_int_callback(struct urb *urb)
|
||
tty_kref_put(tty);
|
||
}
|
||
|
||
- wake_up_interruptible(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
}
|
||
|
||
exit:
|
||
@@ -528,11 +526,14 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
||
while (!multi_change) {
|
||
- interruptible_sleep_on(&priv->delta_msr_wait);
|
||
+ interruptible_sleep_on(&port->delta_msr_wait);
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
spin_lock_irqsave(&priv->lock, flags);
|
||
status = priv->line_status;
|
||
multi_change = priv->multi_status_change;
|
||
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
|
||
index b53065b..ac33957 100644
|
||
--- a/drivers/usb/serial/cp210x.c
|
||
+++ b/drivers/usb/serial/cp210x.c
|
||
@@ -110,6 +110,7 @@ static const struct usb_device_id id_table[] = {
|
||
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
|
||
{ USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
|
||
{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */
|
||
+ { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */
|
||
{ USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */
|
||
{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
|
||
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
|
||
@@ -158,6 +159,7 @@ static const struct usb_device_id id_table[] = {
|
||
{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
|
||
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
|
||
{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
|
||
+ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
|
||
{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
|
||
{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
|
||
{ USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */
|
||
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
|
||
index 270bda8..b1b8467 100644
|
||
--- a/drivers/usb/serial/cypress_m8.c
|
||
+++ b/drivers/usb/serial/cypress_m8.c
|
||
@@ -125,7 +125,6 @@ struct cypress_private {
|
||
int baud_rate; /* stores current baud rate in
|
||
integer form */
|
||
int isthrottled; /* if throttled, discard reads */
|
||
- wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */
|
||
char prev_status, diff_status; /* used for TIOCMIWAIT */
|
||
/* we pass a pointer to this as the argument sent to
|
||
cypress_set_termios old_termios */
|
||
@@ -475,7 +474,6 @@ static int generic_startup(struct usb_serial *serial)
|
||
kfree(priv);
|
||
return -ENOMEM;
|
||
}
|
||
- init_waitqueue_head(&priv->delta_msr_wait);
|
||
|
||
/* Skip reset for FRWD device. It is a workaound:
|
||
device hangs if it receives SET_CONFIGURE in Configured
|
||
@@ -919,12 +917,16 @@ static int cypress_ioctl(struct tty_struct *tty,
|
||
switch (cmd) {
|
||
/* This code comes from drivers/char/serial.c and ftdi_sio.c */
|
||
case TIOCMIWAIT:
|
||
- while (priv != NULL) {
|
||
- interruptible_sleep_on(&priv->delta_msr_wait);
|
||
+ for (;;) {
|
||
+ interruptible_sleep_on(&port->delta_msr_wait);
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
- else {
|
||
+
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
+ {
|
||
char diff = priv->diff_status;
|
||
if (diff == 0)
|
||
return -EIO; /* no change => error */
|
||
@@ -1250,7 +1252,7 @@ static void cypress_read_int_callback(struct urb *urb)
|
||
if (priv->current_status != priv->prev_status) {
|
||
priv->diff_status |= priv->current_status ^
|
||
priv->prev_status;
|
||
- wake_up_interruptible(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
priv->prev_status = priv->current_status;
|
||
}
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h
|
||
index b461311..ce13e61 100644
|
||
--- a/drivers/usb/serial/cypress_m8.h
|
||
+++ b/drivers/usb/serial/cypress_m8.h
|
||
@@ -63,7 +63,7 @@
|
||
#define UART_DSR 0x20 /* data set ready - flow control - device to host */
|
||
#define CONTROL_RTS 0x10 /* request to send - flow control - host to device */
|
||
#define UART_CTS 0x10 /* clear to send - flow control - device to host */
|
||
-#define UART_RI 0x10 /* ring indicator - modem - device to host */
|
||
+#define UART_RI 0x80 /* ring indicator - modem - device to host */
|
||
#define UART_CD 0x40 /* carrier detect - modem - device to host */
|
||
#define CYP_ERROR 0x08 /* received from input report - device to host */
|
||
/* Note - the below has nothing to do with the "feature report" reset */
|
||
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
|
||
index 3e4c27d..8425e9e 100644
|
||
--- a/drivers/usb/serial/ftdi_sio.c
|
||
+++ b/drivers/usb/serial/ftdi_sio.c
|
||
@@ -74,9 +74,7 @@ struct ftdi_private {
|
||
int flags; /* some ASYNC_xxxx flags are supported */
|
||
unsigned long last_dtr_rts; /* saved modem control outputs */
|
||
struct async_icount icount;
|
||
- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
|
||
char prev_status; /* Used for TIOCMIWAIT */
|
||
- bool dev_gone; /* Used to abort TIOCMIWAIT */
|
||
char transmit_empty; /* If transmitter is empty or not */
|
||
struct usb_serial_port *port;
|
||
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
|
||
@@ -164,7 +162,9 @@ static struct usb_device_id id_table_combined [] = {
|
||
{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
|
||
+ { USB_DEVICE(FTDI_VID, FTDI_BM_ATOM_NANO_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
|
||
+ { USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
|
||
@@ -204,6 +204,8 @@ static struct usb_device_id id_table_combined [] = {
|
||
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
|
||
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
|
||
+ { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_LP101_PID) },
|
||
+ { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_P200X_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
|
||
@@ -590,6 +592,8 @@ static struct usb_device_id id_table_combined [] = {
|
||
{ USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID),
|
||
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
||
+ { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID),
|
||
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
||
/*
|
||
* ELV devices:
|
||
*/
|
||
@@ -728,7 +732,8 @@ static struct usb_device_id id_table_combined [] = {
|
||
{ USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
|
||
- { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
|
||
+ { USB_DEVICE(TESTO_VID, TESTO_1_PID) },
|
||
+ { USB_DEVICE(TESTO_VID, TESTO_3_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
|
||
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
|
||
@@ -745,6 +750,7 @@ static struct usb_device_id id_table_combined [] = {
|
||
{ USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
|
||
.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
|
||
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
|
||
+ { USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) },
|
||
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
|
||
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
|
||
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
|
||
@@ -916,6 +922,46 @@ static struct usb_device_id id_table_combined [] = {
|
||
{ USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
|
||
/* Crucible Devices */
|
||
{ USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
|
||
+ { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) },
|
||
+ /* Cressi Devices */
|
||
+ { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) },
|
||
+ /* Brainboxes Devices */
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_001_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_012_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_023_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_034_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_101_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_1_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_2_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_3_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_4_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_5_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_6_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_7_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_8_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_257_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_1_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_2_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_3_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_4_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_313_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_324_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_1_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_2_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_357_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_1_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_2_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_3_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_1_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_2_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_1_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_2_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_3_PID) },
|
||
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_4_PID) },
|
||
+ /* ekey Devices */
|
||
+ { USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) },
|
||
+ /* GE Healthcare devices */
|
||
+ { USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) },
|
||
{ }, /* Optional parameter entry */
|
||
{ } /* Terminating entry */
|
||
};
|
||
@@ -1554,14 +1600,17 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
|
||
struct usb_device *udev = serial->dev;
|
||
|
||
struct usb_interface *interface = serial->interface;
|
||
- struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
|
||
+ struct usb_endpoint_descriptor *ep_desc;
|
||
|
||
unsigned num_endpoints;
|
||
- int i;
|
||
+ unsigned i;
|
||
|
||
num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
|
||
dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
|
||
|
||
+ if (!num_endpoints)
|
||
+ return;
|
||
+
|
||
/* NOTE: some customers have programmed FT232R/FT245R devices
|
||
* with an endpoint size of 0 - not good. In this case, we
|
||
* want to override the endpoint descriptor setting and use a
|
||
@@ -1740,10 +1789,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
|
||
kref_init(&priv->kref);
|
||
mutex_init(&priv->cfg_lock);
|
||
memset(&priv->icount, 0x00, sizeof(priv->icount));
|
||
- init_waitqueue_head(&priv->delta_msr_wait);
|
||
|
||
priv->flags = ASYNC_LOW_LATENCY;
|
||
- priv->dev_gone = false;
|
||
|
||
if (quirk && quirk->port_probe)
|
||
quirk->port_probe(priv);
|
||
@@ -1853,8 +1900,11 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
|
||
}
|
||
|
||
/*
|
||
- * First and second port on STMCLiteadaptors is reserved for JTAG interface
|
||
- * and the forth port for pio
|
||
+ * First two ports on JTAG adaptors using an FT4232 such as STMicroelectronics's
|
||
+ * ST Micro Connect Lite are reserved for JTAG or other non-UART interfaces and
|
||
+ * can be accessed from userspace.
|
||
+ * The next two ports are enabled as UARTs by default, where port 2 is
|
||
+ * a conventional RS-232 UART.
|
||
*/
|
||
static int ftdi_stmclite_probe(struct usb_serial *serial)
|
||
{
|
||
@@ -1863,12 +1913,13 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
|
||
|
||
dbg("%s", __func__);
|
||
|
||
- if (interface == udev->actconfig->interface[2])
|
||
- return 0;
|
||
-
|
||
- dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
|
||
+ if (interface == udev->actconfig->interface[0] ||
|
||
+ interface == udev->actconfig->interface[1]) {
|
||
+ dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
|
||
+ return -ENODEV;
|
||
+ }
|
||
|
||
- return -ENODEV;
|
||
+ return 0;
|
||
}
|
||
|
||
/*
|
||
@@ -1902,8 +1953,7 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
|
||
|
||
dbg("%s", __func__);
|
||
|
||
- priv->dev_gone = true;
|
||
- wake_up_interruptible_all(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
|
||
remove_sysfs_attrs(port);
|
||
|
||
@@ -2058,7 +2108,7 @@ static int ftdi_process_packet(struct tty_struct *tty,
|
||
if (diff_status & FTDI_RS0_RLSD)
|
||
priv->icount.dcd++;
|
||
|
||
- wake_up_interruptible_all(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
priv->prev_status = status;
|
||
}
|
||
|
||
@@ -2196,6 +2246,20 @@ static void ftdi_set_termios(struct tty_struct *tty,
|
||
termios->c_cflag |= CRTSCTS;
|
||
}
|
||
|
||
+ /*
|
||
+ * All FTDI UART chips are limited to CS7/8. We won't pretend to
|
||
+ * support CS5/6 and revert the CSIZE setting instead.
|
||
+ */
|
||
+ if ((C_CSIZE(tty) != CS8) && (C_CSIZE(tty) != CS7)) {
|
||
+ dev_warn(&port->dev, "requested CSIZE setting not supported\n");
|
||
+
|
||
+ termios->c_cflag &= ~CSIZE;
|
||
+ if (old_termios)
|
||
+ termios->c_cflag |= old_termios->c_cflag & CSIZE;
|
||
+ else
|
||
+ termios->c_cflag |= CS8;
|
||
+ }
|
||
+
|
||
cflag = termios->c_cflag;
|
||
|
||
if (!old_termios)
|
||
@@ -2232,13 +2296,16 @@ static void ftdi_set_termios(struct tty_struct *tty,
|
||
} else {
|
||
urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE;
|
||
}
|
||
- if (cflag & CSIZE) {
|
||
- switch (cflag & CSIZE) {
|
||
- case CS7: urb_value |= 7; dbg("Setting CS7"); break;
|
||
- case CS8: urb_value |= 8; dbg("Setting CS8"); break;
|
||
- default:
|
||
- dev_err(&port->dev, "CSIZE was set but not CS7-CS8\n");
|
||
- }
|
||
+ switch (cflag & CSIZE) {
|
||
+ case CS7:
|
||
+ urb_value |= 7;
|
||
+ dev_dbg(&port->dev, "Setting CS7\n");
|
||
+ break;
|
||
+ default:
|
||
+ case CS8:
|
||
+ urb_value |= 8;
|
||
+ dev_dbg(&port->dev, "Setting CS8\n");
|
||
+ break;
|
||
}
|
||
|
||
/* This is needed by the break command since it uses the same command
|
||
@@ -2461,11 +2528,15 @@ static int ftdi_ioctl(struct tty_struct *tty,
|
||
*/
|
||
case TIOCMIWAIT:
|
||
cprev = priv->icount;
|
||
- while (!priv->dev_gone) {
|
||
- interruptible_sleep_on(&priv->delta_msr_wait);
|
||
+ for (;;) {
|
||
+ interruptible_sleep_on(&port->delta_msr_wait);
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
+
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
cnow = priv->icount;
|
||
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
|
||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
|
||
@@ -2475,8 +2546,6 @@ static int ftdi_ioctl(struct tty_struct *tty,
|
||
}
|
||
cprev = cnow;
|
||
}
|
||
- return -EIO;
|
||
- break;
|
||
case TIOCSERGETLSR:
|
||
return get_lsr_info(port, (struct serial_struct __user *)arg);
|
||
break;
|
||
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
|
||
index 1b8af46..7628b91 100644
|
||
--- a/drivers/usb/serial/ftdi_sio_ids.h
|
||
+++ b/drivers/usb/serial/ftdi_sio_ids.h
|
||
@@ -42,6 +42,8 @@
|
||
/* www.candapter.com Ewert Energy Systems CANdapter device */
|
||
#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
|
||
|
||
+#define FTDI_BM_ATOM_NANO_PID 0xa559 /* Basic Micro ATOM Nano USB2Serial */
|
||
+
|
||
/*
|
||
* Texas Instruments XDS100v2 JTAG / BeagleBone A3
|
||
* http://processors.wiki.ti.com/index.php/XDS100
|
||
@@ -50,6 +52,7 @@
|
||
#define TI_XDS100V2_PID 0xa6d0
|
||
|
||
#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */
|
||
+#define FTDI_EV3CON_PID 0xABB9 /* Mindstorms EV3 Console Adapter */
|
||
|
||
/* US Interface Navigator (http://www.usinterface.com/) */
|
||
#define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */
|
||
@@ -363,6 +366,12 @@
|
||
/* Sprog II (Andrew Crosland's SprogII DCC interface) */
|
||
#define FTDI_SPROG_II 0xF0C8
|
||
|
||
+/*
|
||
+ * Two of the Tagsys RFID Readers
|
||
+ */
|
||
+#define FTDI_TAGSYS_LP101_PID 0xF0E9 /* Tagsys L-P101 RFID*/
|
||
+#define FTDI_TAGSYS_P200X_PID 0xF0EE /* Tagsys Medio P200x RFID*/
|
||
+
|
||
/* an infrared receiver for user access control with IR tags */
|
||
#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */
|
||
|
||
@@ -531,6 +540,11 @@
|
||
*/
|
||
#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */
|
||
|
||
+/*
|
||
+ * NovaTech product ids (FTDI_VID)
|
||
+ */
|
||
+#define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */
|
||
+
|
||
|
||
/********************************/
|
||
/** third-party VID/PID combos **/
|
||
@@ -786,7 +800,8 @@
|
||
* Submitted by Colin Leroy
|
||
*/
|
||
#define TESTO_VID 0x128D
|
||
-#define TESTO_USB_INTERFACE_PID 0x0001
|
||
+#define TESTO_1_PID 0x0001
|
||
+#define TESTO_3_PID 0x0003
|
||
|
||
/*
|
||
* Mobility Electronics products.
|
||
@@ -813,6 +828,12 @@
|
||
#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */
|
||
|
||
/*
|
||
+ * NOVITUS printers
|
||
+ */
|
||
+#define NOVITUS_VID 0x1a28
|
||
+#define NOVITUS_BONO_E_PID 0x6010
|
||
+
|
||
+/*
|
||
* RT Systems programming cables for various ham radios
|
||
*/
|
||
#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
|
||
@@ -1307,3 +1328,63 @@
|
||
* Manufacturer: Crucible Technologies
|
||
*/
|
||
#define FTDI_CT_COMET_PID 0x8e08
|
||
+
|
||
+/*
|
||
+ * Product: Z3X Box
|
||
+ * Manufacturer: Smart GSM Team
|
||
+ */
|
||
+#define FTDI_Z3X_PID 0x0011
|
||
+
|
||
+/*
|
||
+ * Product: Cressi PC Interface
|
||
+ * Manufacturer: Cressi
|
||
+ */
|
||
+#define FTDI_CRESSI_PID 0x87d0
|
||
+
|
||
+/*
|
||
+ * Brainboxes devices
|
||
+ */
|
||
+#define BRAINBOXES_VID 0x05d1
|
||
+#define BRAINBOXES_VX_001_PID 0x1001 /* VX-001 ExpressCard 1 Port RS232 */
|
||
+#define BRAINBOXES_VX_012_PID 0x1002 /* VX-012 ExpressCard 2 Port RS232 */
|
||
+#define BRAINBOXES_VX_023_PID 0x1003 /* VX-023 ExpressCard 1 Port RS422/485 */
|
||
+#define BRAINBOXES_VX_034_PID 0x1004 /* VX-034 ExpressCard 2 Port RS422/485 */
|
||
+#define BRAINBOXES_US_101_PID 0x1011 /* US-101 1xRS232 */
|
||
+#define BRAINBOXES_US_324_PID 0x1013 /* US-324 1xRS422/485 1Mbaud */
|
||
+#define BRAINBOXES_US_606_1_PID 0x2001 /* US-606 6 Port RS232 Serial Port 1 and 2 */
|
||
+#define BRAINBOXES_US_606_2_PID 0x2002 /* US-606 6 Port RS232 Serial Port 3 and 4 */
|
||
+#define BRAINBOXES_US_606_3_PID 0x2003 /* US-606 6 Port RS232 Serial Port 4 and 6 */
|
||
+#define BRAINBOXES_US_701_1_PID 0x2011 /* US-701 4xRS232 1Mbaud Port 1 and 2 */
|
||
+#define BRAINBOXES_US_701_2_PID 0x2012 /* US-701 4xRS422 1Mbaud Port 3 and 4 */
|
||
+#define BRAINBOXES_US_279_1_PID 0x2021 /* US-279 8xRS422 1Mbaud Port 1 and 2 */
|
||
+#define BRAINBOXES_US_279_2_PID 0x2022 /* US-279 8xRS422 1Mbaud Port 3 and 4 */
|
||
+#define BRAINBOXES_US_279_3_PID 0x2023 /* US-279 8xRS422 1Mbaud Port 5 and 6 */
|
||
+#define BRAINBOXES_US_279_4_PID 0x2024 /* US-279 8xRS422 1Mbaud Port 7 and 8 */
|
||
+#define BRAINBOXES_US_346_1_PID 0x3011 /* US-346 4xRS422/485 1Mbaud Port 1 and 2 */
|
||
+#define BRAINBOXES_US_346_2_PID 0x3012 /* US-346 4xRS422/485 1Mbaud Port 3 and 4 */
|
||
+#define BRAINBOXES_US_257_PID 0x5001 /* US-257 2xRS232 1Mbaud */
|
||
+#define BRAINBOXES_US_313_PID 0x6001 /* US-313 2xRS422/485 1Mbaud */
|
||
+#define BRAINBOXES_US_357_PID 0x7001 /* US_357 1xRS232/422/485 */
|
||
+#define BRAINBOXES_US_842_1_PID 0x8001 /* US-842 8xRS422/485 1Mbaud Port 1 and 2 */
|
||
+#define BRAINBOXES_US_842_2_PID 0x8002 /* US-842 8xRS422/485 1Mbaud Port 3 and 4 */
|
||
+#define BRAINBOXES_US_842_3_PID 0x8003 /* US-842 8xRS422/485 1Mbaud Port 5 and 6 */
|
||
+#define BRAINBOXES_US_842_4_PID 0x8004 /* US-842 8xRS422/485 1Mbaud Port 7 and 8 */
|
||
+#define BRAINBOXES_US_160_1_PID 0x9001 /* US-160 16xRS232 1Mbaud Port 1 and 2 */
|
||
+#define BRAINBOXES_US_160_2_PID 0x9002 /* US-160 16xRS232 1Mbaud Port 3 and 4 */
|
||
+#define BRAINBOXES_US_160_3_PID 0x9003 /* US-160 16xRS232 1Mbaud Port 5 and 6 */
|
||
+#define BRAINBOXES_US_160_4_PID 0x9004 /* US-160 16xRS232 1Mbaud Port 7 and 8 */
|
||
+#define BRAINBOXES_US_160_5_PID 0x9005 /* US-160 16xRS232 1Mbaud Port 9 and 10 */
|
||
+#define BRAINBOXES_US_160_6_PID 0x9006 /* US-160 16xRS232 1Mbaud Port 11 and 12 */
|
||
+#define BRAINBOXES_US_160_7_PID 0x9007 /* US-160 16xRS232 1Mbaud Port 13 and 14 */
|
||
+#define BRAINBOXES_US_160_8_PID 0x9008 /* US-160 16xRS232 1Mbaud Port 15 and 16 */
|
||
+
|
||
+/*
|
||
+ * ekey biometric systems GmbH (http://ekey.net/)
|
||
+ */
|
||
+#define FTDI_EKEY_CONV_USB_PID 0xCB08 /* Converter USB */
|
||
+
|
||
+/*
|
||
+ * GE Healthcare devices
|
||
+ */
|
||
+#define GE_HEALTHCARE_VID 0x1901
|
||
+#define GE_HEALTHCARE_NEMO_TRACKER_PID 0x0015
|
||
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
|
||
index 664deb6..546177f 100644
|
||
--- a/drivers/usb/serial/generic.c
|
||
+++ b/drivers/usb/serial/generic.c
|
||
@@ -223,14 +223,7 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port)
|
||
return result;
|
||
}
|
||
|
||
- /* Try sending off another urb, unless in irq context (in which case
|
||
- * there will be no free urb). */
|
||
- if (!in_irq())
|
||
- goto retry;
|
||
-
|
||
- clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
|
||
-
|
||
- return 0;
|
||
+ goto retry; /* try sending off another urb */
|
||
}
|
||
|
||
/**
|
||
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
|
||
index 323e872..32099d7 100644
|
||
--- a/drivers/usb/serial/io_edgeport.c
|
||
+++ b/drivers/usb/serial/io_edgeport.c
|
||
@@ -114,7 +114,6 @@ struct edgeport_port {
|
||
wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
|
||
wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */
|
||
wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */
|
||
- wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
|
||
|
||
struct async_icount icount;
|
||
struct usb_serial_port *port; /* loop back to the owner of this object */
|
||
@@ -884,7 +883,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
/* initialize our wait queues */
|
||
init_waitqueue_head(&edge_port->wait_open);
|
||
init_waitqueue_head(&edge_port->wait_chase);
|
||
- init_waitqueue_head(&edge_port->delta_msr_wait);
|
||
init_waitqueue_head(&edge_port->wait_command);
|
||
|
||
/* initialize our icount structure */
|
||
@@ -1701,13 +1699,17 @@ static int edge_ioctl(struct tty_struct *tty,
|
||
dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
|
||
cprev = edge_port->icount;
|
||
while (1) {
|
||
- prepare_to_wait(&edge_port->delta_msr_wait,
|
||
+ prepare_to_wait(&port->delta_msr_wait,
|
||
&wait, TASK_INTERRUPTIBLE);
|
||
schedule();
|
||
- finish_wait(&edge_port->delta_msr_wait, &wait);
|
||
+ finish_wait(&port->delta_msr_wait, &wait);
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
+
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
cnow = edge_port->icount;
|
||
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
|
||
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
|
||
@@ -2088,7 +2090,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
|
||
icount->dcd++;
|
||
if (newMsr & EDGEPORT_MSR_DELTA_RI)
|
||
icount->rng++;
|
||
- wake_up_interruptible(&edge_port->delta_msr_wait);
|
||
+ wake_up_interruptible(&edge_port->port->delta_msr_wait);
|
||
}
|
||
|
||
/* Save the new modem status */
|
||
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
|
||
index b68efdc..5175182 100644
|
||
--- a/drivers/usb/serial/io_ti.c
|
||
+++ b/drivers/usb/serial/io_ti.c
|
||
@@ -29,6 +29,7 @@
|
||
#include <linux/spinlock.h>
|
||
#include <linux/mutex.h>
|
||
#include <linux/serial.h>
|
||
+#include <linux/swab.h>
|
||
#include <linux/kfifo.h>
|
||
#include <linux/ioctl.h>
|
||
#include <linux/firmware.h>
|
||
@@ -91,9 +92,6 @@ struct edgeport_port {
|
||
int close_pending;
|
||
int lsr_event;
|
||
struct async_icount icount;
|
||
- wait_queue_head_t delta_msr_wait; /* for handling sleeping while
|
||
- waiting for msr change to
|
||
- happen */
|
||
struct edgeport_serial *edge_serial;
|
||
struct usb_serial_port *port;
|
||
__u8 bUartMode; /* Port type, 0: RS232, etc. */
|
||
@@ -301,7 +299,7 @@ static int read_download_mem(struct usb_device *dev, int start_address,
|
||
{
|
||
int status = 0;
|
||
__u8 read_length;
|
||
- __be16 be_start_address;
|
||
+ u16 be_start_address;
|
||
|
||
dbg("%s - @ %x for %d", __func__, start_address, length);
|
||
|
||
@@ -318,10 +316,14 @@ static int read_download_mem(struct usb_device *dev, int start_address,
|
||
dbg("%s - @ %x for %d", __func__,
|
||
start_address, read_length);
|
||
}
|
||
- be_start_address = cpu_to_be16(start_address);
|
||
+ /*
|
||
+ * NOTE: Must use swab as wIndex is sent in little-endian
|
||
+ * byte order regardless of host byte order.
|
||
+ */
|
||
+ be_start_address = swab16((u16)start_address);
|
||
status = ti_vread_sync(dev, UMPC_MEMORY_READ,
|
||
(__u16)address_type,
|
||
- (__force __u16)be_start_address,
|
||
+ be_start_address,
|
||
buffer, read_length);
|
||
|
||
if (status) {
|
||
@@ -421,7 +423,7 @@ static int write_i2c_mem(struct edgeport_serial *serial,
|
||
{
|
||
int status = 0;
|
||
int write_length;
|
||
- __be16 be_start_address;
|
||
+ u16 be_start_address;
|
||
|
||
/* We can only send a maximum of 1 aligned byte page at a time */
|
||
|
||
@@ -437,11 +439,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,
|
||
usb_serial_debug_data(debug, &serial->serial->dev->dev,
|
||
__func__, write_length, buffer);
|
||
|
||
- /* Write first page */
|
||
- be_start_address = cpu_to_be16(start_address);
|
||
+ /*
|
||
+ * Write first page.
|
||
+ *
|
||
+ * NOTE: Must use swab as wIndex is sent in little-endian byte order
|
||
+ * regardless of host byte order.
|
||
+ */
|
||
+ be_start_address = swab16((u16)start_address);
|
||
status = ti_vsend_sync(serial->serial->dev,
|
||
UMPC_MEMORY_WRITE, (__u16)address_type,
|
||
- (__force __u16)be_start_address,
|
||
+ be_start_address,
|
||
buffer, write_length);
|
||
if (status) {
|
||
dbg("%s - ERROR %d", __func__, status);
|
||
@@ -465,11 +472,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,
|
||
usb_serial_debug_data(debug, &serial->serial->dev->dev,
|
||
__func__, write_length, buffer);
|
||
|
||
- /* Write next page */
|
||
- be_start_address = cpu_to_be16(start_address);
|
||
+ /*
|
||
+ * Write next page.
|
||
+ *
|
||
+ * NOTE: Must use swab as wIndex is sent in little-endian byte
|
||
+ * order regardless of host byte order.
|
||
+ */
|
||
+ be_start_address = swab16((u16)start_address);
|
||
status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE,
|
||
(__u16)address_type,
|
||
- (__force __u16)be_start_address,
|
||
+ be_start_address,
|
||
buffer, write_length);
|
||
if (status) {
|
||
dev_err(&serial->serial->dev->dev, "%s - ERROR %d\n",
|
||
@@ -676,8 +688,8 @@ static int get_descriptor_addr(struct edgeport_serial *serial,
|
||
if (rom_desc->Type == desc_type)
|
||
return start_address;
|
||
|
||
- start_address = start_address + sizeof(struct ti_i2c_desc)
|
||
- + rom_desc->Size;
|
||
+ start_address = start_address + sizeof(struct ti_i2c_desc) +
|
||
+ le16_to_cpu(rom_desc->Size);
|
||
|
||
} while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type);
|
||
|
||
@@ -690,7 +702,7 @@ static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer)
|
||
__u16 i;
|
||
__u8 cs = 0;
|
||
|
||
- for (i = 0; i < rom_desc->Size; i++)
|
||
+ for (i = 0; i < le16_to_cpu(rom_desc->Size); i++)
|
||
cs = (__u8)(cs + buffer[i]);
|
||
|
||
if (cs != rom_desc->CheckSum) {
|
||
@@ -744,7 +756,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
|
||
break;
|
||
|
||
if ((start_address + sizeof(struct ti_i2c_desc) +
|
||
- rom_desc->Size) > TI_MAX_I2C_SIZE) {
|
||
+ le16_to_cpu(rom_desc->Size)) > TI_MAX_I2C_SIZE) {
|
||
status = -ENODEV;
|
||
dbg("%s - structure too big, erroring out.", __func__);
|
||
break;
|
||
@@ -759,7 +771,8 @@ static int check_i2c_image(struct edgeport_serial *serial)
|
||
/* Read the descriptor data */
|
||
status = read_rom(serial, start_address +
|
||
sizeof(struct ti_i2c_desc),
|
||
- rom_desc->Size, buffer);
|
||
+ le16_to_cpu(rom_desc->Size),
|
||
+ buffer);
|
||
if (status)
|
||
break;
|
||
|
||
@@ -768,7 +781,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
|
||
break;
|
||
}
|
||
start_address = start_address + sizeof(struct ti_i2c_desc) +
|
||
- rom_desc->Size;
|
||
+ le16_to_cpu(rom_desc->Size);
|
||
|
||
} while ((rom_desc->Type != I2C_DESC_TYPE_ION) &&
|
||
(start_address < TI_MAX_I2C_SIZE));
|
||
@@ -807,7 +820,7 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer)
|
||
|
||
/* Read the descriptor data */
|
||
status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc),
|
||
- rom_desc->Size, buffer);
|
||
+ le16_to_cpu(rom_desc->Size), buffer);
|
||
if (status)
|
||
goto exit;
|
||
|
||
@@ -902,7 +915,7 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev)
|
||
firmware_rec = (struct ti_i2c_firmware_rec*)i2c_header->Data;
|
||
|
||
i2c_header->Type = I2C_DESC_TYPE_FIRMWARE_BLANK;
|
||
- i2c_header->Size = (__u16)buffer_size;
|
||
+ i2c_header->Size = cpu_to_le16(buffer_size);
|
||
i2c_header->CheckSum = cs;
|
||
firmware_rec->Ver_Major = OperationalMajorVersion;
|
||
firmware_rec->Ver_Minor = OperationalMinorVersion;
|
||
@@ -1549,7 +1562,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
|
||
icount->dcd++;
|
||
if (msr & EDGEPORT_MSR_DELTA_RI)
|
||
icount->rng++;
|
||
- wake_up_interruptible(&edge_port->delta_msr_wait);
|
||
+ wake_up_interruptible(&edge_port->port->delta_msr_wait);
|
||
}
|
||
|
||
/* Save the new modem status */
|
||
@@ -1867,7 +1880,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
dev = port->serial->dev;
|
||
|
||
memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
|
||
- init_waitqueue_head(&edge_port->delta_msr_wait);
|
||
|
||
/* turn off loopback */
|
||
status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0);
|
||
@@ -2553,10 +2565,14 @@ static int edge_ioctl(struct tty_struct *tty,
|
||
dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
|
||
cprev = edge_port->icount;
|
||
while (1) {
|
||
- interruptible_sleep_on(&edge_port->delta_msr_wait);
|
||
+ interruptible_sleep_on(&port->delta_msr_wait);
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
+
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
cnow = edge_port->icount;
|
||
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
|
||
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
|
||
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
|
||
index 51f83fb..6f6a856 100644
|
||
--- a/drivers/usb/serial/io_usbvend.h
|
||
+++ b/drivers/usb/serial/io_usbvend.h
|
||
@@ -594,7 +594,7 @@ struct edge_boot_descriptor {
|
||
|
||
struct ti_i2c_desc {
|
||
__u8 Type; // Type of descriptor
|
||
- __u16 Size; // Size of data only not including header
|
||
+ __le16 Size; // Size of data only not including header
|
||
__u8 CheckSum; // Checksum (8 bit sum of data only)
|
||
__u8 Data[0]; // Data starts here
|
||
} __attribute__((packed));
|
||
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
|
||
index 253bff6..66d806e 100644
|
||
--- a/drivers/usb/serial/keyspan.c
|
||
+++ b/drivers/usb/serial/keyspan.c
|
||
@@ -2486,7 +2486,7 @@ static int keyspan_startup(struct usb_serial *serial)
|
||
if (d_details == NULL) {
|
||
dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
|
||
__func__, le16_to_cpu(serial->dev->descriptor.idProduct));
|
||
- return 1;
|
||
+ return -ENODEV;
|
||
}
|
||
|
||
/* Setup private data for serial driver */
|
||
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
|
||
index 933dd07..954fb86 100644
|
||
--- a/drivers/usb/serial/mct_u232.c
|
||
+++ b/drivers/usb/serial/mct_u232.c
|
||
@@ -126,8 +126,6 @@ struct mct_u232_private {
|
||
unsigned char last_msr; /* Modem Status Register */
|
||
unsigned int rx_flags; /* Throttling flags */
|
||
struct async_icount icount;
|
||
- wait_queue_head_t msr_wait; /* for handling sleeping while waiting
|
||
- for msr change to happen */
|
||
};
|
||
|
||
#define THROTTLED 0x01
|
||
@@ -407,7 +405,6 @@ static int mct_u232_startup(struct usb_serial *serial)
|
||
if (!priv)
|
||
return -ENOMEM;
|
||
spin_lock_init(&priv->lock);
|
||
- init_waitqueue_head(&priv->msr_wait);
|
||
usb_set_serial_port_data(serial->port[0], priv);
|
||
|
||
init_waitqueue_head(&serial->port[0]->write_wait);
|
||
@@ -631,7 +628,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
|
||
tty_kref_put(tty);
|
||
}
|
||
#endif
|
||
- wake_up_interruptible(&priv->msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
exit:
|
||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||
@@ -852,13 +849,17 @@ static int mct_u232_ioctl(struct tty_struct *tty,
|
||
cprev = mct_u232_port->icount;
|
||
spin_unlock_irqrestore(&mct_u232_port->lock, flags);
|
||
for ( ; ; ) {
|
||
- prepare_to_wait(&mct_u232_port->msr_wait,
|
||
+ prepare_to_wait(&port->delta_msr_wait,
|
||
&wait, TASK_INTERRUPTIBLE);
|
||
schedule();
|
||
- finish_wait(&mct_u232_port->msr_wait, &wait);
|
||
+ finish_wait(&port->delta_msr_wait, &wait);
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
+
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
spin_lock_irqsave(&mct_u232_port->lock, flags);
|
||
cnow = mct_u232_port->icount;
|
||
spin_unlock_irqrestore(&mct_u232_port->lock, flags);
|
||
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
|
||
index c854235..947b866 100644
|
||
--- a/drivers/usb/serial/mos7840.c
|
||
+++ b/drivers/usb/serial/mos7840.c
|
||
@@ -185,6 +185,10 @@
|
||
#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
|
||
|
||
|
||
+enum mos7840_flag {
|
||
+ MOS7840_FLAG_CTRL_BUSY,
|
||
+};
|
||
+
|
||
static const struct usb_device_id moschip_port_id_table[] = {
|
||
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
|
||
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
|
||
@@ -240,7 +244,6 @@ struct moschip_port {
|
||
char open;
|
||
char open_ports;
|
||
wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
|
||
- wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
|
||
int delta_msr_cond;
|
||
struct async_icount icount;
|
||
struct usb_serial_port *port; /* loop back to the owner of this object */
|
||
@@ -259,6 +262,8 @@ struct moschip_port {
|
||
struct urb *write_urb_pool[NUM_URBS];
|
||
char busy[NUM_URBS];
|
||
bool read_urb_busy;
|
||
+
|
||
+ unsigned long flags;
|
||
};
|
||
|
||
|
||
@@ -453,6 +458,9 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
|
||
icount->rng++;
|
||
smp_wmb();
|
||
}
|
||
+
|
||
+ mos7840_port->delta_msr_cond = 1;
|
||
+ wake_up_interruptible(&port->port->delta_msr_wait);
|
||
}
|
||
}
|
||
|
||
@@ -517,11 +525,11 @@ static void mos7840_control_callback(struct urb *urb)
|
||
/* this urb is terminated, clean up */
|
||
dbg("%s - urb shutting down with status: %d", __func__,
|
||
status);
|
||
- return;
|
||
+ goto out;
|
||
default:
|
||
dbg("%s - nonzero urb status received: %d", __func__,
|
||
status);
|
||
- return;
|
||
+ goto out;
|
||
}
|
||
|
||
dbg("%s urb buffer size is %d", __func__, urb->actual_length);
|
||
@@ -534,6 +542,8 @@ static void mos7840_control_callback(struct urb *urb)
|
||
mos7840_handle_new_msr(mos7840_port, regval);
|
||
else if (mos7840_port->MsrLsr == 1)
|
||
mos7840_handle_new_lsr(mos7840_port, regval);
|
||
+out:
|
||
+ clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags);
|
||
}
|
||
|
||
static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
|
||
@@ -544,6 +554,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
|
||
unsigned char *buffer = mcs->ctrl_buf;
|
||
int ret;
|
||
|
||
+ if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags))
|
||
+ return -EBUSY;
|
||
+
|
||
dr->bRequestType = MCS_RD_RTYPE;
|
||
dr->bRequest = MCS_RDREQ;
|
||
dr->wValue = cpu_to_le16(Wval); /* 0 */
|
||
@@ -555,6 +568,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
|
||
mos7840_control_callback, mcs);
|
||
mcs->control_urb->transfer_buffer_length = 2;
|
||
ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
|
||
+ if (ret)
|
||
+ clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags);
|
||
+
|
||
return ret;
|
||
}
|
||
|
||
@@ -921,20 +937,20 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
|
||
if (status < 0) {
|
||
dbg("Reading Spreg failed");
|
||
- return -1;
|
||
+ goto err;
|
||
}
|
||
Data |= 0x80;
|
||
status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
|
||
if (status < 0) {
|
||
dbg("writing Spreg failed");
|
||
- return -1;
|
||
+ goto err;
|
||
}
|
||
|
||
Data &= ~0x80;
|
||
status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
|
||
if (status < 0) {
|
||
dbg("writing Spreg failed");
|
||
- return -1;
|
||
+ goto err;
|
||
}
|
||
/* End of block to be checked */
|
||
|
||
@@ -943,7 +959,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
&Data);
|
||
if (status < 0) {
|
||
dbg("Reading Controlreg failed");
|
||
- return -1;
|
||
+ goto err;
|
||
}
|
||
Data |= 0x08; /* Driver done bit */
|
||
Data |= 0x20; /* rx_disable */
|
||
@@ -951,7 +967,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
mos7840_port->ControlRegOffset, Data);
|
||
if (status < 0) {
|
||
dbg("writing Controlreg failed");
|
||
- return -1;
|
||
+ goto err;
|
||
}
|
||
/* do register settings here */
|
||
/* Set all regs to the device default values. */
|
||
@@ -962,21 +978,21 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
|
||
if (status < 0) {
|
||
dbg("disabling interrupts failed");
|
||
- return -1;
|
||
+ goto err;
|
||
}
|
||
/* Set FIFO_CONTROL_REGISTER to the default value */
|
||
Data = 0x00;
|
||
status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
|
||
if (status < 0) {
|
||
dbg("Writing FIFO_CONTROL_REGISTER failed");
|
||
- return -1;
|
||
+ goto err;
|
||
}
|
||
|
||
Data = 0xcf;
|
||
status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
|
||
if (status < 0) {
|
||
dbg("Writing FIFO_CONTROL_REGISTER failed");
|
||
- return -1;
|
||
+ goto err;
|
||
}
|
||
|
||
Data = 0x03;
|
||
@@ -1113,7 +1129,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
||
/* initialize our wait queues */
|
||
init_waitqueue_head(&mos7840_port->wait_chase);
|
||
- init_waitqueue_head(&mos7840_port->delta_msr_wait);
|
||
|
||
/* initialize our icount structure */
|
||
memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
|
||
@@ -1133,7 +1148,15 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
dbg ("%s leave", __func__);
|
||
|
||
return 0;
|
||
-
|
||
+err:
|
||
+ for (j = 0; j < NUM_URBS; ++j) {
|
||
+ urb = mos7840_port->write_urb_pool[j];
|
||
+ if (!urb)
|
||
+ continue;
|
||
+ kfree(urb->transfer_buffer);
|
||
+ usb_free_urb(urb);
|
||
+ }
|
||
+ return status;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
@@ -1664,7 +1687,11 @@ static int mos7840_tiocmget(struct tty_struct *tty)
|
||
return -ENODEV;
|
||
|
||
status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
|
||
+ if (status != 1)
|
||
+ return -EIO;
|
||
status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
|
||
+ if (status != 1)
|
||
+ return -EIO;
|
||
result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
|
||
| ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
|
||
| ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
|
||
@@ -1958,25 +1985,25 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
|
||
iflag = tty->termios->c_iflag;
|
||
|
||
/* Change the number of bits */
|
||
- if (cflag & CSIZE) {
|
||
- switch (cflag & CSIZE) {
|
||
- case CS5:
|
||
- lData = LCR_BITS_5;
|
||
- break;
|
||
+ switch (cflag & CSIZE) {
|
||
+ case CS5:
|
||
+ lData = LCR_BITS_5;
|
||
+ break;
|
||
|
||
- case CS6:
|
||
- lData = LCR_BITS_6;
|
||
- break;
|
||
+ case CS6:
|
||
+ lData = LCR_BITS_6;
|
||
+ break;
|
||
|
||
- case CS7:
|
||
- lData = LCR_BITS_7;
|
||
- break;
|
||
- default:
|
||
- case CS8:
|
||
- lData = LCR_BITS_8;
|
||
- break;
|
||
- }
|
||
+ case CS7:
|
||
+ lData = LCR_BITS_7;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ case CS8:
|
||
+ lData = LCR_BITS_8;
|
||
+ break;
|
||
}
|
||
+
|
||
/* Change the Parity bit */
|
||
if (cflag & PARENB) {
|
||
if (cflag & PARODD) {
|
||
@@ -2070,8 +2097,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
|
||
mos7840_port->read_urb_busy = false;
|
||
}
|
||
}
|
||
- wake_up(&mos7840_port->delta_msr_wait);
|
||
- mos7840_port->delta_msr_cond = 1;
|
||
dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x",
|
||
mos7840_port->shadowLCR);
|
||
}
|
||
@@ -2280,13 +2305,18 @@ static int mos7840_ioctl(struct tty_struct *tty,
|
||
while (1) {
|
||
/* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */
|
||
mos7840_port->delta_msr_cond = 0;
|
||
- wait_event_interruptible(mos7840_port->delta_msr_wait,
|
||
- (mos7840_port->
|
||
+ wait_event_interruptible(port->delta_msr_wait,
|
||
+ (port->serial->disconnected ||
|
||
+ mos7840_port->
|
||
delta_msr_cond == 1));
|
||
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
+
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
cnow = mos7840_port->icount;
|
||
smp_rmb();
|
||
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
|
||
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
|
||
index 9def72f..703ebe7 100644
|
||
--- a/drivers/usb/serial/option.c
|
||
+++ b/drivers/usb/serial/option.c
|
||
@@ -85,6 +85,7 @@ static void option_instat_callback(struct urb *urb);
|
||
#define HUAWEI_PRODUCT_K4505 0x1464
|
||
#define HUAWEI_PRODUCT_K3765 0x1465
|
||
#define HUAWEI_PRODUCT_K4605 0x14C6
|
||
+#define HUAWEI_PRODUCT_E173S6 0x1C07
|
||
|
||
#define QUANTA_VENDOR_ID 0x0408
|
||
#define QUANTA_PRODUCT_Q101 0xEA02
|
||
@@ -160,6 +161,7 @@ static void option_instat_callback(struct urb *urb);
|
||
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000
|
||
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001
|
||
#define NOVATELWIRELESS_PRODUCT_E362 0x9010
|
||
+#define NOVATELWIRELESS_PRODUCT_E371 0x9011
|
||
#define NOVATELWIRELESS_PRODUCT_G2 0xA010
|
||
#define NOVATELWIRELESS_PRODUCT_MC551 0xB001
|
||
|
||
@@ -233,8 +235,31 @@ static void option_instat_callback(struct urb *urb);
|
||
#define QUALCOMM_VENDOR_ID 0x05C6
|
||
|
||
#define CMOTECH_VENDOR_ID 0x16d8
|
||
-#define CMOTECH_PRODUCT_6008 0x6008
|
||
-#define CMOTECH_PRODUCT_6280 0x6280
|
||
+#define CMOTECH_PRODUCT_6001 0x6001
|
||
+#define CMOTECH_PRODUCT_CMU_300 0x6002
|
||
+#define CMOTECH_PRODUCT_6003 0x6003
|
||
+#define CMOTECH_PRODUCT_6004 0x6004
|
||
+#define CMOTECH_PRODUCT_6005 0x6005
|
||
+#define CMOTECH_PRODUCT_CGU_628A 0x6006
|
||
+#define CMOTECH_PRODUCT_CHE_628S 0x6007
|
||
+#define CMOTECH_PRODUCT_CMU_301 0x6008
|
||
+#define CMOTECH_PRODUCT_CHU_628 0x6280
|
||
+#define CMOTECH_PRODUCT_CHU_628S 0x6281
|
||
+#define CMOTECH_PRODUCT_CDU_680 0x6803
|
||
+#define CMOTECH_PRODUCT_CDU_685A 0x6804
|
||
+#define CMOTECH_PRODUCT_CHU_720S 0x7001
|
||
+#define CMOTECH_PRODUCT_7002 0x7002
|
||
+#define CMOTECH_PRODUCT_CHU_629K 0x7003
|
||
+#define CMOTECH_PRODUCT_7004 0x7004
|
||
+#define CMOTECH_PRODUCT_7005 0x7005
|
||
+#define CMOTECH_PRODUCT_CGU_629 0x7006
|
||
+#define CMOTECH_PRODUCT_CHU_629S 0x700a
|
||
+#define CMOTECH_PRODUCT_CHU_720I 0x7211
|
||
+#define CMOTECH_PRODUCT_7212 0x7212
|
||
+#define CMOTECH_PRODUCT_7213 0x7213
|
||
+#define CMOTECH_PRODUCT_7251 0x7251
|
||
+#define CMOTECH_PRODUCT_7252 0x7252
|
||
+#define CMOTECH_PRODUCT_7253 0x7253
|
||
|
||
#define TELIT_VENDOR_ID 0x1bc7
|
||
#define TELIT_PRODUCT_UC864E 0x1003
|
||
@@ -242,6 +267,7 @@ static void option_instat_callback(struct urb *urb);
|
||
#define TELIT_PRODUCT_CC864_DUAL 0x1005
|
||
#define TELIT_PRODUCT_CC864_SINGLE 0x1006
|
||
#define TELIT_PRODUCT_DE910_DUAL 0x1010
|
||
+#define TELIT_PRODUCT_UE910_V2 0x1012
|
||
#define TELIT_PRODUCT_LE920 0x1200
|
||
|
||
/* ZTE PRODUCTS */
|
||
@@ -290,6 +316,7 @@ static void option_instat_callback(struct urb *urb);
|
||
#define ALCATEL_PRODUCT_X060S_X200 0x0000
|
||
#define ALCATEL_PRODUCT_X220_X500D 0x0017
|
||
#define ALCATEL_PRODUCT_L100V 0x011e
|
||
+#define ALCATEL_PRODUCT_L800MA 0x0203
|
||
|
||
#define PIRELLI_VENDOR_ID 0x1266
|
||
#define PIRELLI_PRODUCT_C100_1 0x1002
|
||
@@ -324,9 +351,15 @@ static void option_instat_callback(struct urb *urb);
|
||
* It seems to contain a Qualcomm QSC6240/6290 chipset */
|
||
#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
|
||
|
||
+/* iBall 3.5G connect wireless modem */
|
||
+#define IBALL_3_5G_CONNECT 0x9605
|
||
+
|
||
/* Zoom */
|
||
#define ZOOM_PRODUCT_4597 0x9607
|
||
|
||
+/* SpeedUp SU9800 usb 3g modem */
|
||
+#define SPEEDUP_PRODUCT_SU9800 0x9800
|
||
+
|
||
/* Haier products */
|
||
#define HAIER_VENDOR_ID 0x201e
|
||
#define HAIER_PRODUCT_CE100 0x2009
|
||
@@ -347,8 +380,13 @@ static void option_instat_callback(struct urb *urb);
|
||
/* Olivetti products */
|
||
#define OLIVETTI_VENDOR_ID 0x0b3c
|
||
#define OLIVETTI_PRODUCT_OLICARD100 0xc000
|
||
+#define OLIVETTI_PRODUCT_OLICARD120 0xc001
|
||
+#define OLIVETTI_PRODUCT_OLICARD140 0xc002
|
||
#define OLIVETTI_PRODUCT_OLICARD145 0xc003
|
||
+#define OLIVETTI_PRODUCT_OLICARD155 0xc004
|
||
#define OLIVETTI_PRODUCT_OLICARD200 0xc005
|
||
+#define OLIVETTI_PRODUCT_OLICARD160 0xc00a
|
||
+#define OLIVETTI_PRODUCT_OLICARD500 0xc00b
|
||
|
||
/* Celot products */
|
||
#define CELOT_VENDOR_ID 0x211f
|
||
@@ -457,6 +495,14 @@ static void option_instat_callback(struct urb *urb);
|
||
#define CHANGHONG_VENDOR_ID 0x2077
|
||
#define CHANGHONG_PRODUCT_CH690 0x7001
|
||
|
||
+/* Inovia */
|
||
+#define INOVIA_VENDOR_ID 0x20a6
|
||
+#define INOVIA_SEW858 0x1105
|
||
+
|
||
+/* VIA Telecom */
|
||
+#define VIATELECOM_VENDOR_ID 0x15eb
|
||
+#define VIATELECOM_PRODUCT_CDS7 0x0001
|
||
+
|
||
/* some devices interfaces need special handling due to a number of reasons */
|
||
enum option_blacklist_reason {
|
||
OPTION_BLACKLIST_NONE = 0,
|
||
@@ -506,6 +552,10 @@ static const struct option_blacklist_info huawei_cdc12_blacklist = {
|
||
.reserved = BIT(1) | BIT(2),
|
||
};
|
||
|
||
+static const struct option_blacklist_info net_intf0_blacklist = {
|
||
+ .reserved = BIT(0),
|
||
+};
|
||
+
|
||
static const struct option_blacklist_info net_intf1_blacklist = {
|
||
.reserved = BIT(1),
|
||
};
|
||
@@ -582,6 +632,8 @@ static const struct usb_device_id option_ids[] = {
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff),
|
||
.driver_info = (kernel_ulong_t) &net_intf1_blacklist },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S6, 0xff, 0xff, 0xff),
|
||
+ .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff),
|
||
.driver_info = (kernel_ulong_t) &net_intf2_blacklist },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) },
|
||
@@ -644,6 +696,10 @@ static const struct usb_device_id option_ids[] = {
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x72) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x73) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x74) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x75) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) },
|
||
@@ -698,11 +754,247 @@ static const struct usb_device_id option_ids[] = {
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x72) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x73) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x74) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x75) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) },
|
||
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x01) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x02) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x03) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x04) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x05) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x06) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x10) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x12) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x13) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x14) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x15) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x17) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x18) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x19) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x31) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x32) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x33) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x34) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x35) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x36) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x48) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x49) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x61) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x62) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x63) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x64) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x65) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x66) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x72) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x73) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x74) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x75) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x01) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x02) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x03) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x04) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x05) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x06) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x10) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x12) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x13) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x14) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x15) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x17) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x18) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x19) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x31) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x32) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x33) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x34) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x35) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x36) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x48) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x49) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x61) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x62) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x63) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x64) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x65) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x66) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x72) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x73) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x74) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x75) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x01) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x02) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x03) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x04) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x05) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x06) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x10) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x12) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x13) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x14) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x15) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x17) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x18) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x19) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x31) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x32) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x33) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x34) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x35) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x36) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x48) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x49) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x61) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x62) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x63) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x64) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x65) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x66) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x72) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x73) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x74) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x75) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x01) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x02) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x03) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x04) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x05) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x06) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x10) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x12) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x13) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x14) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x15) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x17) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x18) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x19) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x31) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x32) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x33) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x34) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x35) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x36) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x48) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x49) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4C) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x61) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x62) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x63) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x64) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x65) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x66) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x72) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x73) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x74) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x75) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) },
|
||
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) },
|
||
|
||
|
||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
|
||
@@ -745,6 +1037,7 @@ static const struct usb_device_id option_ids[] = {
|
||
/* Novatel Ovation MC551 a.k.a. Verizon USB551L */
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E371, 0xff, 0xff, 0xff) },
|
||
|
||
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },
|
||
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) },
|
||
@@ -798,13 +1091,53 @@ static const struct usb_device_id option_ids[] = {
|
||
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
|
||
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
|
||
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
|
||
- { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */
|
||
- { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6004) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6005) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_628A) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHE_628S),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_301),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628S) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_680) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_685A) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720S),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7002),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629K),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7004),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7005) },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_629),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629S),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720I),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7212),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7213),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7251),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7252),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
|
||
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7253),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
|
||
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
|
||
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
|
||
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },
|
||
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
|
||
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
|
||
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
|
||
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
|
||
.driver_info = (kernel_ulong_t)&telit_le920_blacklist },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
|
||
@@ -1126,7 +1459,8 @@ static const struct usb_device_id option_ids[] = {
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) },
|
||
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) },
|
||
@@ -1171,6 +1505,25 @@ static const struct usb_device_id option_ids[] = {
|
||
.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff), /* ZTE MF91 */
|
||
.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G v2 */
|
||
+ .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1545, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1546, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1547, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1565, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1566, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1567, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1589, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1590, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1591, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1592, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1594, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1596, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1598, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1600, 0xff, 0xff, 0xff) },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,
|
||
0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
|
||
@@ -1197,6 +1550,17 @@ static const struct usb_device_id option_ids[] = {
|
||
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff),
|
||
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8b, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8c, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8d, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8e, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8f, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff90, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff91, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff92, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) },
|
||
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
|
||
@@ -1239,12 +1603,16 @@ static const struct usb_device_id option_ids[] = {
|
||
.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
|
||
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V),
|
||
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||
+ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L800MA),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
|
||
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
|
||
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
|
||
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
|
||
.driver_info = (kernel_ulong_t)&four_g_w14_blacklist
|
||
},
|
||
+ { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
|
||
{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
|
||
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
|
||
{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
|
||
/* Pirelli */
|
||
{ USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1)},
|
||
@@ -1266,7 +1634,8 @@ static const struct usb_device_id option_ids[] = {
|
||
/* Cinterion */
|
||
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
|
||
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
|
||
- { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) },
|
||
+ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },
|
||
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
|
||
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||
@@ -1276,10 +1645,21 @@ static const struct usb_device_id option_ids[] = {
|
||
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },
|
||
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */
|
||
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
|
||
-
|
||
- { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
|
||
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD140),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
|
||
- { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200) },
|
||
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD155),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
|
||
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
|
||
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD160),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
|
||
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD500),
|
||
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
|
||
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
|
||
@@ -1367,6 +1747,8 @@ static const struct usb_device_id option_ids[] = {
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
|
||
+ { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
|
||
+ { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) },
|
||
{ } /* Terminating entry */
|
||
};
|
||
MODULE_DEVICE_TABLE(usb, option_ids);
|
||
@@ -1569,6 +1951,7 @@ static int option_send_setup(struct usb_serial_port *port)
|
||
struct usb_wwan_port_private *portdata;
|
||
int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
|
||
int val = 0;
|
||
+ int res;
|
||
dbg("%s", __func__);
|
||
|
||
if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
|
||
@@ -1584,9 +1967,17 @@ static int option_send_setup(struct usb_serial_port *port)
|
||
if (portdata->rts_state)
|
||
val |= 0x02;
|
||
|
||
- return usb_control_msg(serial->dev,
|
||
- usb_rcvctrlpipe(serial->dev, 0),
|
||
- 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||
+ res = usb_autopm_get_interface(serial->interface);
|
||
+ if (res)
|
||
+ return res;
|
||
+
|
||
+ res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
|
||
+ 0x22, 0x21, val, ifNum, NULL,
|
||
+ 0, USB_CTRL_SET_TIMEOUT);
|
||
+
|
||
+ usb_autopm_put_interface(serial->interface);
|
||
+
|
||
+ return res;
|
||
}
|
||
|
||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
|
||
index 5fdc33c..bddc9f1 100644
|
||
--- a/drivers/usb/serial/oti6858.c
|
||
+++ b/drivers/usb/serial/oti6858.c
|
||
@@ -198,7 +198,6 @@ struct oti6858_private {
|
||
u8 setup_done;
|
||
struct delayed_work delayed_setup_work;
|
||
|
||
- wait_queue_head_t intr_wait;
|
||
struct usb_serial_port *port; /* USB port with which associated */
|
||
};
|
||
|
||
@@ -356,7 +355,6 @@ static int oti6858_startup(struct usb_serial *serial)
|
||
break;
|
||
|
||
spin_lock_init(&priv->lock);
|
||
- init_waitqueue_head(&priv->intr_wait);
|
||
/* INIT_WORK(&priv->setup_work, setup_line, serial->port[i]); */
|
||
/* INIT_WORK(&priv->write_work, send_data, serial->port[i]); */
|
||
priv->port = port;
|
||
@@ -703,11 +701,15 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
||
while (1) {
|
||
- wait_event_interruptible(priv->intr_wait,
|
||
+ wait_event_interruptible(port->delta_msr_wait,
|
||
+ port->serial->disconnected ||
|
||
priv->status.pin_state != prev);
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
spin_lock_irqsave(&priv->lock, flags);
|
||
status = priv->status.pin_state & PIN_MASK;
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
@@ -819,7 +821,7 @@ static void oti6858_read_int_callback(struct urb *urb)
|
||
|
||
if (!priv->transient) {
|
||
if (xs->pin_state != priv->status.pin_state)
|
||
- wake_up_interruptible(&priv->intr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE);
|
||
}
|
||
|
||
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
|
||
index a1a9062..3e450b4 100644
|
||
--- a/drivers/usb/serial/pl2303.c
|
||
+++ b/drivers/usb/serial/pl2303.c
|
||
@@ -51,6 +51,7 @@ static const struct usb_device_id id_table[] = {
|
||
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
|
||
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
|
||
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
|
||
+ { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) },
|
||
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
|
||
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
|
||
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
|
||
@@ -86,6 +87,9 @@ static const struct usb_device_id id_table[] = {
|
||
{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
|
||
{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
|
||
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
|
||
+ { USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) },
|
||
+ { USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) },
|
||
+ { USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) },
|
||
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
|
||
{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
|
||
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
|
||
@@ -149,7 +153,6 @@ enum pl2303_type {
|
||
|
||
struct pl2303_private {
|
||
spinlock_t lock;
|
||
- wait_queue_head_t delta_msr_wait;
|
||
u8 line_control;
|
||
u8 line_status;
|
||
enum pl2303_type type;
|
||
@@ -203,7 +206,6 @@ static int pl2303_startup(struct usb_serial *serial)
|
||
if (!priv)
|
||
goto cleanup;
|
||
spin_lock_init(&priv->lock);
|
||
- init_waitqueue_head(&priv->delta_msr_wait);
|
||
priv->type = type;
|
||
usb_set_serial_port_data(serial->port[i], priv);
|
||
}
|
||
@@ -271,7 +273,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
||
serial settings even to the same values as before. Thus
|
||
we actually need to filter in this specific case */
|
||
|
||
- if (!tty_termios_hw_change(tty->termios, old_termios))
|
||
+ if (old_termios && !tty_termios_hw_change(tty->termios, old_termios))
|
||
return;
|
||
|
||
cflag = tty->termios->c_cflag;
|
||
@@ -280,7 +282,8 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
||
if (!buf) {
|
||
dev_err(&port->dev, "%s - out of memory.\n", __func__);
|
||
/* Report back no change occurred */
|
||
- *tty->termios = *old_termios;
|
||
+ if (old_termios)
|
||
+ *tty->termios = *old_termios;
|
||
return;
|
||
}
|
||
|
||
@@ -290,24 +293,22 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
||
dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
|
||
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
|
||
|
||
- if (cflag & CSIZE) {
|
||
- switch (cflag & CSIZE) {
|
||
- case CS5:
|
||
- buf[6] = 5;
|
||
- break;
|
||
- case CS6:
|
||
- buf[6] = 6;
|
||
- break;
|
||
- case CS7:
|
||
- buf[6] = 7;
|
||
- break;
|
||
- default:
|
||
- case CS8:
|
||
- buf[6] = 8;
|
||
- break;
|
||
- }
|
||
- dbg("%s - data bits = %d", __func__, buf[6]);
|
||
+ switch (cflag & CSIZE) {
|
||
+ case CS5:
|
||
+ buf[6] = 5;
|
||
+ break;
|
||
+ case CS6:
|
||
+ buf[6] = 6;
|
||
+ break;
|
||
+ case CS7:
|
||
+ buf[6] = 7;
|
||
+ break;
|
||
+ default:
|
||
+ case CS8:
|
||
+ buf[6] = 8;
|
||
+ break;
|
||
}
|
||
+ dbg("%s - data bits = %d", __func__, buf[6]);
|
||
|
||
/* For reference buf[0]:buf[3] baud rate value */
|
||
/* NOTE: Only the values defined in baud_sup are supported !
|
||
@@ -420,7 +421,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
||
control = priv->line_control;
|
||
if ((cflag & CBAUD) == B0)
|
||
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
|
||
- else if ((old_termios->c_cflag & CBAUD) == B0)
|
||
+ else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
|
||
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
|
||
if (control != priv->line_control) {
|
||
control = priv->line_control;
|
||
@@ -481,7 +482,6 @@ static void pl2303_close(struct usb_serial_port *port)
|
||
|
||
static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
{
|
||
- struct ktermios tmp_termios;
|
||
struct usb_serial *serial = port->serial;
|
||
struct pl2303_private *priv = usb_get_serial_port_data(port);
|
||
int result;
|
||
@@ -499,7 +499,7 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
||
/* Setup termios */
|
||
if (tty)
|
||
- pl2303_set_termios(tty, port, &tmp_termios);
|
||
+ pl2303_set_termios(tty, port, NULL);
|
||
|
||
dbg("%s - submitting interrupt urb", __func__);
|
||
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||
@@ -597,11 +597,14 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
||
while (1) {
|
||
- interruptible_sleep_on(&priv->delta_msr_wait);
|
||
+ interruptible_sleep_on(&port->delta_msr_wait);
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
spin_lock_irqsave(&priv->lock, flags);
|
||
status = priv->line_status;
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
@@ -723,7 +726,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
if (priv->line_status & UART_BREAK_ERROR)
|
||
usb_serial_handle_break(port);
|
||
- wake_up_interruptible(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
|
||
tty = tty_port_tty_get(&port->port);
|
||
if (!tty)
|
||
@@ -790,7 +793,7 @@ static void pl2303_process_read_urb(struct urb *urb)
|
||
line_status = priv->line_status;
|
||
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
- wake_up_interruptible(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
|
||
if (!urb->actual_length)
|
||
return;
|
||
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
|
||
index c38b8c0..71fd9da 100644
|
||
--- a/drivers/usb/serial/pl2303.h
|
||
+++ b/drivers/usb/serial/pl2303.h
|
||
@@ -22,6 +22,7 @@
|
||
#define PL2303_PRODUCT_ID_GPRS 0x0609
|
||
#define PL2303_PRODUCT_ID_HCR331 0x331a
|
||
#define PL2303_PRODUCT_ID_MOTOROLA 0x0307
|
||
+#define PL2303_PRODUCT_ID_ZTEK 0xe1f1
|
||
|
||
#define ATEN_VENDOR_ID 0x0557
|
||
#define ATEN_VENDOR_ID2 0x0547
|
||
@@ -121,8 +122,11 @@
|
||
#define SUPERIAL_VENDOR_ID 0x5372
|
||
#define SUPERIAL_PRODUCT_ID 0x2303
|
||
|
||
-/* Hewlett-Packard LD220-HP POS Pole Display */
|
||
+/* Hewlett-Packard POS Pole Displays */
|
||
#define HP_VENDOR_ID 0x03f0
|
||
+#define HP_LD960_PRODUCT_ID 0x0b39
|
||
+#define HP_LCM220_PRODUCT_ID 0x3139
|
||
+#define HP_LCM960_PRODUCT_ID 0x3239
|
||
#define HP_LD220_PRODUCT_ID 0x3524
|
||
|
||
/* Cressi Edy (diving computer) PC interface */
|
||
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
|
||
index 8ec15c2..e3ddec0 100644
|
||
--- a/drivers/usb/serial/sierra.c
|
||
+++ b/drivers/usb/serial/sierra.c
|
||
@@ -59,6 +59,7 @@ struct sierra_intf_private {
|
||
spinlock_t susp_lock;
|
||
unsigned int suspended:1;
|
||
int in_flight;
|
||
+ unsigned int open_ports;
|
||
};
|
||
|
||
static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
|
||
@@ -295,17 +296,21 @@ static const struct usb_device_id id_table[] = {
|
||
{ USB_DEVICE(0x1199, 0x68A2), /* Sierra Wireless MC77xx in QMI mode */
|
||
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
|
||
},
|
||
- { USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */
|
||
+ /* Sierra Wireless Direct IP modems */
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68A3, 0xFF, 0xFF, 0xFF),
|
||
+ .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
|
||
+ },
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68AA, 0xFF, 0xFF, 0xFF),
|
||
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
|
||
},
|
||
/* AT&T Direct IP LTE modems */
|
||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF),
|
||
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
|
||
},
|
||
- { USB_DEVICE(0x0f3d, 0x68A3), /* Airprime/Sierra Wireless Direct IP modems */
|
||
+ /* Airprime/Sierra Wireless Direct IP modems */
|
||
+ { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68A3, 0xFF, 0xFF, 0xFF),
|
||
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
|
||
},
|
||
- { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */
|
||
|
||
{ }
|
||
};
|
||
@@ -802,6 +807,7 @@ static void sierra_close(struct usb_serial_port *port)
|
||
struct usb_serial *serial = port->serial;
|
||
struct sierra_port_private *portdata;
|
||
struct sierra_intf_private *intfdata = port->serial->private;
|
||
+ struct urb *urb;
|
||
|
||
|
||
dev_dbg(&port->dev, "%s\n", __func__);
|
||
@@ -813,7 +819,6 @@ static void sierra_close(struct usb_serial_port *port)
|
||
if (serial->dev) {
|
||
mutex_lock(&serial->disc_mutex);
|
||
if (!serial->disconnected) {
|
||
- serial->interface->needs_remote_wakeup = 0;
|
||
/* odd error handling due to pm counters */
|
||
if (!usb_autopm_get_interface(serial->interface))
|
||
sierra_send_setup(port);
|
||
@@ -824,8 +829,21 @@ static void sierra_close(struct usb_serial_port *port)
|
||
mutex_unlock(&serial->disc_mutex);
|
||
spin_lock_irq(&intfdata->susp_lock);
|
||
portdata->opened = 0;
|
||
+ if (--intfdata->open_ports == 0)
|
||
+ serial->interface->needs_remote_wakeup = 0;
|
||
spin_unlock_irq(&intfdata->susp_lock);
|
||
|
||
+ for (;;) {
|
||
+ urb = usb_get_from_anchor(&portdata->delayed);
|
||
+ if (!urb)
|
||
+ break;
|
||
+ kfree(urb->transfer_buffer);
|
||
+ usb_free_urb(urb);
|
||
+ usb_autopm_put_interface_async(serial->interface);
|
||
+ spin_lock(&portdata->lock);
|
||
+ portdata->outstanding_urbs--;
|
||
+ spin_unlock(&portdata->lock);
|
||
+ }
|
||
|
||
/* Stop reading urbs */
|
||
sierra_stop_rx_urbs(port);
|
||
@@ -868,23 +886,29 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN);
|
||
|
||
err = sierra_submit_rx_urbs(port, GFP_KERNEL);
|
||
- if (err) {
|
||
- /* get rid of everything as in close */
|
||
- sierra_close(port);
|
||
- /* restore balance for autopm */
|
||
- if (!serial->disconnected)
|
||
- usb_autopm_put_interface(serial->interface);
|
||
- return err;
|
||
- }
|
||
+ if (err)
|
||
+ goto err_submit;
|
||
+
|
||
sierra_send_setup(port);
|
||
|
||
- serial->interface->needs_remote_wakeup = 1;
|
||
spin_lock_irq(&intfdata->susp_lock);
|
||
portdata->opened = 1;
|
||
+ if (++intfdata->open_ports == 1)
|
||
+ serial->interface->needs_remote_wakeup = 1;
|
||
spin_unlock_irq(&intfdata->susp_lock);
|
||
usb_autopm_put_interface(serial->interface);
|
||
|
||
return 0;
|
||
+
|
||
+err_submit:
|
||
+ sierra_stop_rx_urbs(port);
|
||
+
|
||
+ for (i = 0; i < portdata->num_in_urbs; i++) {
|
||
+ sierra_release_urb(portdata->in_urbs[i]);
|
||
+ portdata->in_urbs[i] = NULL;
|
||
+ }
|
||
+
|
||
+ return err;
|
||
}
|
||
|
||
|
||
@@ -995,6 +1019,7 @@ static void sierra_release(struct usb_serial *serial)
|
||
portdata = usb_get_serial_port_data(port);
|
||
if (!portdata)
|
||
continue;
|
||
+ usb_set_serial_port_data(port, NULL);
|
||
kfree(portdata);
|
||
}
|
||
kfree(serial->private);
|
||
@@ -1011,6 +1036,8 @@ static void stop_read_write_urbs(struct usb_serial *serial)
|
||
for (i = 0; i < serial->num_ports; ++i) {
|
||
port = serial->port[i];
|
||
portdata = usb_get_serial_port_data(port);
|
||
+ if (!portdata)
|
||
+ continue;
|
||
sierra_stop_rx_urbs(port);
|
||
usb_kill_anchored_urbs(&portdata->active);
|
||
}
|
||
@@ -1053,6 +1080,9 @@ static int sierra_resume(struct usb_serial *serial)
|
||
port = serial->port[i];
|
||
portdata = usb_get_serial_port_data(port);
|
||
|
||
+ if (!portdata)
|
||
+ continue;
|
||
+
|
||
while ((urb = usb_get_from_anchor(&portdata->delayed))) {
|
||
usb_anchor_urb(urb, &portdata->active);
|
||
intfdata->in_flight++;
|
||
@@ -1060,8 +1090,12 @@ static int sierra_resume(struct usb_serial *serial)
|
||
if (err < 0) {
|
||
intfdata->in_flight--;
|
||
usb_unanchor_urb(urb);
|
||
- usb_scuttle_anchored_urbs(&portdata->delayed);
|
||
- break;
|
||
+ kfree(urb->transfer_buffer);
|
||
+ usb_free_urb(urb);
|
||
+ spin_lock(&portdata->lock);
|
||
+ portdata->outstanding_urbs--;
|
||
+ spin_unlock(&portdata->lock);
|
||
+ continue;
|
||
}
|
||
}
|
||
|
||
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
|
||
index f06c9a8..692da69 100644
|
||
--- a/drivers/usb/serial/spcp8x5.c
|
||
+++ b/drivers/usb/serial/spcp8x5.c
|
||
@@ -162,7 +162,6 @@ static struct usb_driver spcp8x5_driver = {
|
||
struct spcp8x5_private {
|
||
spinlock_t lock;
|
||
enum spcp8x5_type type;
|
||
- wait_queue_head_t delta_msr_wait;
|
||
u8 line_control;
|
||
u8 line_status;
|
||
};
|
||
@@ -196,7 +195,6 @@ static int spcp8x5_startup(struct usb_serial *serial)
|
||
goto cleanup;
|
||
|
||
spin_lock_init(&priv->lock);
|
||
- init_waitqueue_head(&priv->delta_msr_wait);
|
||
priv->type = type;
|
||
usb_set_serial_port_data(serial->port[i] , priv);
|
||
}
|
||
@@ -339,7 +337,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
|
||
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
|
||
unsigned long flags;
|
||
unsigned int cflag = tty->termios->c_cflag;
|
||
- unsigned int old_cflag = old_termios->c_cflag;
|
||
unsigned short uartdata;
|
||
unsigned char buf[2] = {0, 0};
|
||
int baud;
|
||
@@ -348,15 +345,15 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
|
||
|
||
|
||
/* check that they really want us to change something */
|
||
- if (!tty_termios_hw_change(tty->termios, old_termios))
|
||
+ if (old_termios && !tty_termios_hw_change(tty->termios, old_termios))
|
||
return;
|
||
|
||
/* set DTR/RTS active */
|
||
spin_lock_irqsave(&priv->lock, flags);
|
||
control = priv->line_control;
|
||
- if ((old_cflag & CBAUD) == B0) {
|
||
+ if (old_termios && (old_termios->c_cflag & CBAUD) == B0) {
|
||
priv->line_control |= MCR_DTR;
|
||
- if (!(old_cflag & CRTSCTS))
|
||
+ if (!(old_termios->c_cflag & CRTSCTS))
|
||
priv->line_control |= MCR_RTS;
|
||
}
|
||
if (control != priv->line_control) {
|
||
@@ -396,22 +393,20 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
|
||
}
|
||
|
||
/* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
|
||
- if (cflag & CSIZE) {
|
||
- switch (cflag & CSIZE) {
|
||
- case CS5:
|
||
- buf[1] |= SET_UART_FORMAT_SIZE_5;
|
||
- break;
|
||
- case CS6:
|
||
- buf[1] |= SET_UART_FORMAT_SIZE_6;
|
||
- break;
|
||
- case CS7:
|
||
- buf[1] |= SET_UART_FORMAT_SIZE_7;
|
||
- break;
|
||
- default:
|
||
- case CS8:
|
||
- buf[1] |= SET_UART_FORMAT_SIZE_8;
|
||
- break;
|
||
- }
|
||
+ switch (cflag & CSIZE) {
|
||
+ case CS5:
|
||
+ buf[1] |= SET_UART_FORMAT_SIZE_5;
|
||
+ break;
|
||
+ case CS6:
|
||
+ buf[1] |= SET_UART_FORMAT_SIZE_6;
|
||
+ break;
|
||
+ case CS7:
|
||
+ buf[1] |= SET_UART_FORMAT_SIZE_7;
|
||
+ break;
|
||
+ default:
|
||
+ case CS8:
|
||
+ buf[1] |= SET_UART_FORMAT_SIZE_8;
|
||
+ break;
|
||
}
|
||
|
||
/* Set Stop bit2 : 0:1bit 1:2bit */
|
||
@@ -446,7 +441,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
|
||
* status of the device. */
|
||
static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
{
|
||
- struct ktermios tmp_termios;
|
||
struct usb_serial *serial = port->serial;
|
||
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
|
||
int ret;
|
||
@@ -469,7 +463,7 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
||
/* Setup termios */
|
||
if (tty)
|
||
- spcp8x5_set_termios(tty, port, &tmp_termios);
|
||
+ spcp8x5_set_termios(tty, port, NULL);
|
||
|
||
spcp8x5_get_msr(serial->dev, &status, priv->type);
|
||
|
||
@@ -501,7 +495,7 @@ static void spcp8x5_process_read_urb(struct urb *urb)
|
||
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
/* wake up the wait for termios */
|
||
- wake_up_interruptible(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
|
||
if (!urb->actual_length)
|
||
return;
|
||
@@ -551,12 +545,15 @@ static int spcp8x5_wait_modem_info(struct usb_serial_port *port,
|
||
|
||
while (1) {
|
||
/* wake up in bulk read */
|
||
- interruptible_sleep_on(&priv->delta_msr_wait);
|
||
+ interruptible_sleep_on(&port->delta_msr_wait);
|
||
|
||
/* see if a signal did it */
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
spin_lock_irqsave(&priv->lock, flags);
|
||
status = priv->line_status;
|
||
spin_unlock_irqrestore(&priv->lock, flags);
|
||
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
|
||
index b8db69d..d19fa6a 100644
|
||
--- a/drivers/usb/serial/ssu100.c
|
||
+++ b/drivers/usb/serial/ssu100.c
|
||
@@ -77,7 +77,6 @@ struct ssu100_port_private {
|
||
spinlock_t status_lock;
|
||
u8 shadowLSR;
|
||
u8 shadowMSR;
|
||
- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
|
||
struct async_icount icount;
|
||
};
|
||
|
||
@@ -386,8 +385,9 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
|
||
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||
|
||
while (1) {
|
||
- wait_event_interruptible(priv->delta_msr_wait,
|
||
- ((priv->icount.rng != prev.rng) ||
|
||
+ wait_event_interruptible(port->delta_msr_wait,
|
||
+ (port->serial->disconnected ||
|
||
+ (priv->icount.rng != prev.rng) ||
|
||
(priv->icount.dsr != prev.dsr) ||
|
||
(priv->icount.dcd != prev.dcd) ||
|
||
(priv->icount.cts != prev.cts)));
|
||
@@ -395,6 +395,9 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
spin_lock_irqsave(&priv->status_lock, flags);
|
||
cur = priv->icount;
|
||
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||
@@ -477,7 +480,6 @@ static int ssu100_attach(struct usb_serial *serial)
|
||
}
|
||
|
||
spin_lock_init(&priv->status_lock);
|
||
- init_waitqueue_head(&priv->delta_msr_wait);
|
||
usb_set_serial_port_data(port, priv);
|
||
|
||
return ssu100_initdevice(serial->dev);
|
||
@@ -563,7 +565,7 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
|
||
priv->icount.dcd++;
|
||
if (msr & UART_MSR_TERI)
|
||
priv->icount.rng++;
|
||
- wake_up_interruptible(&priv->delta_msr_wait);
|
||
+ wake_up_interruptible(&port->delta_msr_wait);
|
||
}
|
||
}
|
||
|
||
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
|
||
index a7492ba..2575779 100644
|
||
--- a/drivers/usb/serial/ti_usb_3410_5052.c
|
||
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
|
||
@@ -75,7 +75,6 @@ struct ti_port {
|
||
int tp_flags;
|
||
int tp_closing_wait;/* in .01 secs */
|
||
struct async_icount tp_icount;
|
||
- wait_queue_head_t tp_msr_wait; /* wait for msr change */
|
||
wait_queue_head_t tp_write_wait;
|
||
struct ti_device *tp_tdev;
|
||
struct usb_serial_port *tp_port;
|
||
@@ -210,6 +209,7 @@ static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1]
|
||
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
|
||
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
|
||
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
|
||
+ { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
|
||
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
|
||
{ }
|
||
};
|
||
@@ -429,7 +429,6 @@ static int ti_startup(struct usb_serial *serial)
|
||
tport->tp_uart_base_addr = (i == 0 ?
|
||
TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR);
|
||
tport->tp_closing_wait = closing_wait;
|
||
- init_waitqueue_head(&tport->tp_msr_wait);
|
||
init_waitqueue_head(&tport->tp_write_wait);
|
||
if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE,
|
||
GFP_KERNEL)) {
|
||
@@ -826,9 +825,13 @@ static int ti_ioctl(struct tty_struct *tty,
|
||
dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
|
||
cprev = tport->tp_icount;
|
||
while (1) {
|
||
- interruptible_sleep_on(&tport->tp_msr_wait);
|
||
+ interruptible_sleep_on(&port->delta_msr_wait);
|
||
if (signal_pending(current))
|
||
return -ERESTARTSYS;
|
||
+
|
||
+ if (port->serial->disconnected)
|
||
+ return -EIO;
|
||
+
|
||
cnow = tport->tp_icount;
|
||
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
|
||
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
|
||
@@ -1457,7 +1460,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
|
||
icount->dcd++;
|
||
if (msr & TI_MSR_DELTA_RI)
|
||
icount->rng++;
|
||
- wake_up_interruptible(&tport->tp_msr_wait);
|
||
+ wake_up_interruptible(&tport->tp_port->delta_msr_wait);
|
||
spin_unlock_irqrestore(&tport->tp_lock, flags);
|
||
}
|
||
|
||
@@ -1684,12 +1687,13 @@ static int ti_download_firmware(struct ti_device *tdev)
|
||
|
||
dbg("%s\n", __func__);
|
||
/* try ID specific firmware first, then try generic firmware */
|
||
- sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor,
|
||
- dev->descriptor.idProduct);
|
||
+ sprintf(buf, "ti_usb-v%04x-p%04x.fw",
|
||
+ le16_to_cpu(dev->descriptor.idVendor),
|
||
+ le16_to_cpu(dev->descriptor.idProduct));
|
||
if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) {
|
||
buf[0] = '\0';
|
||
- if (dev->descriptor.idVendor == MTS_VENDOR_ID) {
|
||
- switch (dev->descriptor.idProduct) {
|
||
+ if (le16_to_cpu(dev->descriptor.idVendor) == MTS_VENDOR_ID) {
|
||
+ switch (le16_to_cpu(dev->descriptor.idProduct)) {
|
||
case MTS_CDMA_PRODUCT_ID:
|
||
strcpy(buf, "mts_cdma.fw");
|
||
break;
|
||
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
|
||
index 810695b..a08230e 100644
|
||
--- a/drivers/usb/serial/usb-serial.c
|
||
+++ b/drivers/usb/serial/usb-serial.c
|
||
@@ -794,29 +794,37 @@ int usb_serial_probe(struct usb_interface *interface,
|
||
if (usb_endpoint_is_bulk_in(endpoint)) {
|
||
/* we found a bulk in endpoint */
|
||
dbg("found bulk in on endpoint %d", i);
|
||
- bulk_in_endpoint[num_bulk_in] = endpoint;
|
||
- ++num_bulk_in;
|
||
+ if (num_bulk_in < MAX_NUM_PORTS) {
|
||
+ bulk_in_endpoint[num_bulk_in] = endpoint;
|
||
+ ++num_bulk_in;
|
||
+ }
|
||
}
|
||
|
||
if (usb_endpoint_is_bulk_out(endpoint)) {
|
||
/* we found a bulk out endpoint */
|
||
dbg("found bulk out on endpoint %d", i);
|
||
- bulk_out_endpoint[num_bulk_out] = endpoint;
|
||
- ++num_bulk_out;
|
||
+ if (num_bulk_out < MAX_NUM_PORTS) {
|
||
+ bulk_out_endpoint[num_bulk_out] = endpoint;
|
||
+ ++num_bulk_out;
|
||
+ }
|
||
}
|
||
|
||
if (usb_endpoint_is_int_in(endpoint)) {
|
||
/* we found a interrupt in endpoint */
|
||
dbg("found interrupt in on endpoint %d", i);
|
||
- interrupt_in_endpoint[num_interrupt_in] = endpoint;
|
||
- ++num_interrupt_in;
|
||
+ if (num_interrupt_in < MAX_NUM_PORTS) {
|
||
+ interrupt_in_endpoint[num_interrupt_in] = endpoint;
|
||
+ ++num_interrupt_in;
|
||
+ }
|
||
}
|
||
|
||
if (usb_endpoint_is_int_out(endpoint)) {
|
||
/* we found an interrupt out endpoint */
|
||
dbg("found interrupt out on endpoint %d", i);
|
||
- interrupt_out_endpoint[num_interrupt_out] = endpoint;
|
||
- ++num_interrupt_out;
|
||
+ if (num_interrupt_out < MAX_NUM_PORTS) {
|
||
+ interrupt_out_endpoint[num_interrupt_out] = endpoint;
|
||
+ ++num_interrupt_out;
|
||
+ }
|
||
}
|
||
}
|
||
|
||
@@ -839,8 +847,10 @@ int usb_serial_probe(struct usb_interface *interface,
|
||
if (usb_endpoint_is_int_in(endpoint)) {
|
||
/* we found a interrupt in endpoint */
|
||
dbg("found interrupt in for Prolific device on separate interface");
|
||
- interrupt_in_endpoint[num_interrupt_in] = endpoint;
|
||
- ++num_interrupt_in;
|
||
+ if (num_interrupt_in < MAX_NUM_PORTS) {
|
||
+ interrupt_in_endpoint[num_interrupt_in] = endpoint;
|
||
+ ++num_interrupt_in;
|
||
+ }
|
||
}
|
||
}
|
||
}
|
||
@@ -879,6 +889,11 @@ int usb_serial_probe(struct usb_interface *interface,
|
||
num_ports = type->num_ports;
|
||
}
|
||
|
||
+ if (num_ports > MAX_NUM_PORTS) {
|
||
+ dev_warn(&interface->dev, "too many ports requested: %d\n", num_ports);
|
||
+ num_ports = MAX_NUM_PORTS;
|
||
+ }
|
||
+
|
||
serial->num_ports = num_ports;
|
||
serial->num_bulk_in = num_bulk_in;
|
||
serial->num_bulk_out = num_bulk_out;
|
||
@@ -908,6 +923,7 @@ int usb_serial_probe(struct usb_interface *interface,
|
||
port->port.ops = &serial_port_ops;
|
||
port->serial = serial;
|
||
spin_lock_init(&port->lock);
|
||
+ init_waitqueue_head(&port->delta_msr_wait);
|
||
/* Keep this for private driver use for the moment but
|
||
should probably go away */
|
||
INIT_WORK(&port->work, usb_serial_port_work);
|
||
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
|
||
index 49f3a85..1f05022 100644
|
||
--- a/drivers/usb/serial/usb_wwan.c
|
||
+++ b/drivers/usb/serial/usb_wwan.c
|
||
@@ -236,8 +236,10 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
|
||
usb_pipeendpoint(this_urb->pipe), i);
|
||
|
||
err = usb_autopm_get_interface_async(port->serial->interface);
|
||
- if (err < 0)
|
||
+ if (err < 0) {
|
||
+ clear_bit(i, &portdata->out_busy);
|
||
break;
|
||
+ }
|
||
|
||
/* send the data */
|
||
memcpy(this_urb->transfer_buffer, buf, todo);
|
||
@@ -518,6 +520,14 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
|
||
dbg("%s", __func__);
|
||
|
||
+ if (port->interrupt_in_urb) {
|
||
+ err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||
+ if (err) {
|
||
+ dev_dbg(&port->dev, "%s: submit int urb failed: %d\n",
|
||
+ __func__, err);
|
||
+ }
|
||
+ }
|
||
+
|
||
/* Start reading from the IN endpoint */
|
||
for (i = 0; i < N_IN_URB; i++) {
|
||
urb = portdata->in_urbs[i];
|
||
@@ -546,12 +556,26 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
}
|
||
EXPORT_SYMBOL(usb_wwan_open);
|
||
|
||
+static void unbusy_queued_urb(struct urb *urb,
|
||
+ struct usb_wwan_port_private *portdata)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < N_OUT_URB; i++) {
|
||
+ if (urb == portdata->out_urbs[i]) {
|
||
+ clear_bit(i, &portdata->out_busy);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
void usb_wwan_close(struct usb_serial_port *port)
|
||
{
|
||
int i;
|
||
struct usb_serial *serial = port->serial;
|
||
struct usb_wwan_port_private *portdata;
|
||
struct usb_wwan_intf_private *intfdata = port->serial->private;
|
||
+ struct urb *urb;
|
||
|
||
dbg("%s", __func__);
|
||
portdata = usb_get_serial_port_data(port);
|
||
@@ -562,10 +586,19 @@ void usb_wwan_close(struct usb_serial_port *port)
|
||
portdata->opened = 0;
|
||
spin_unlock_irq(&intfdata->susp_lock);
|
||
|
||
+ for (;;) {
|
||
+ urb = usb_get_from_anchor(&portdata->delayed);
|
||
+ if (!urb)
|
||
+ break;
|
||
+ unbusy_queued_urb(urb, portdata);
|
||
+ usb_autopm_put_interface_async(serial->interface);
|
||
+ }
|
||
+
|
||
for (i = 0; i < N_IN_URB; i++)
|
||
usb_kill_urb(portdata->in_urbs[i]);
|
||
for (i = 0; i < N_OUT_URB; i++)
|
||
usb_kill_urb(portdata->out_urbs[i]);
|
||
+ usb_kill_urb(port->interrupt_in_urb);
|
||
/* balancing - important as an error cannot be handled*/
|
||
usb_autopm_get_interface_no_resume(serial->interface);
|
||
serial->interface->needs_remote_wakeup = 0;
|
||
@@ -641,7 +674,7 @@ static void usb_wwan_setup_urbs(struct usb_serial *serial)
|
||
|
||
int usb_wwan_startup(struct usb_serial *serial)
|
||
{
|
||
- int i, j, err;
|
||
+ int i, j;
|
||
struct usb_serial_port *port;
|
||
struct usb_wwan_port_private *portdata;
|
||
u8 *buffer;
|
||
@@ -678,12 +711,6 @@ int usb_wwan_startup(struct usb_serial *serial)
|
||
}
|
||
|
||
usb_set_serial_port_data(port, portdata);
|
||
-
|
||
- if (!port->interrupt_in_urb)
|
||
- continue;
|
||
- err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||
- if (err)
|
||
- dbg("%s: submit irq_in urb failed %d", __func__, err);
|
||
}
|
||
usb_wwan_setup_urbs(serial);
|
||
return 0;
|
||
@@ -791,18 +818,6 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
|
||
}
|
||
EXPORT_SYMBOL(usb_wwan_suspend);
|
||
|
||
-static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata)
|
||
-{
|
||
- int i;
|
||
-
|
||
- for (i = 0; i < N_OUT_URB; i++) {
|
||
- if (urb == portdata->out_urbs[i]) {
|
||
- clear_bit(i, &portdata->out_busy);
|
||
- break;
|
||
- }
|
||
- }
|
||
-}
|
||
-
|
||
static void play_delayed(struct usb_serial_port *port)
|
||
{
|
||
struct usb_wwan_intf_private *data;
|
||
@@ -839,21 +854,6 @@ int usb_wwan_resume(struct usb_serial *serial)
|
||
int err = 0;
|
||
|
||
dbg("%s entered", __func__);
|
||
- /* get the interrupt URBs resubmitted unconditionally */
|
||
- for (i = 0; i < serial->num_ports; i++) {
|
||
- port = serial->port[i];
|
||
- if (!port->interrupt_in_urb) {
|
||
- dbg("%s: No interrupt URB for port %d", __func__, i);
|
||
- continue;
|
||
- }
|
||
- err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
|
||
- dbg("Submitted interrupt URB for port %d (result %d)", i, err);
|
||
- if (err < 0) {
|
||
- err("%s: Error %d for interrupt URB of port%d",
|
||
- __func__, err, i);
|
||
- goto err_out;
|
||
- }
|
||
- }
|
||
|
||
spin_lock_irq(&intfdata->susp_lock);
|
||
intfdata->suspended = 0;
|
||
@@ -866,6 +866,16 @@ int usb_wwan_resume(struct usb_serial *serial)
|
||
if (!portdata->opened)
|
||
continue;
|
||
|
||
+ if (port->interrupt_in_urb) {
|
||
+ err = usb_submit_urb(port->interrupt_in_urb,
|
||
+ GFP_ATOMIC);
|
||
+ if (err) {
|
||
+ dev_err(&port->dev,
|
||
+ "%s: submit int urb failed: %d\n",
|
||
+ __func__, err);
|
||
+ }
|
||
+ }
|
||
+
|
||
for (j = 0; j < N_IN_URB; j++) {
|
||
urb = portdata->in_urbs[j];
|
||
|
||
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
|
||
index 0d06d7c..bf7014d 100644
|
||
--- a/drivers/usb/serial/whiteheat.c
|
||
+++ b/drivers/usb/serial/whiteheat.c
|
||
@@ -953,6 +953,10 @@ static void command_port_read_callback(struct urb *urb)
|
||
dbg("%s - command_info is NULL, exiting.", __func__);
|
||
return;
|
||
}
|
||
+ if (!urb->actual_length) {
|
||
+ dev_dbg(&urb->dev->dev, "%s - empty response, exiting.\n", __func__);
|
||
+ return;
|
||
+ }
|
||
if (status) {
|
||
dbg("%s - nonzero urb status: %d", __func__, status);
|
||
if (status != -ENOENT)
|
||
@@ -974,7 +978,8 @@ static void command_port_read_callback(struct urb *urb)
|
||
/* These are unsolicited reports from the firmware, hence no
|
||
waiting command to wakeup */
|
||
dbg("%s - event received", __func__);
|
||
- } else if (data[0] == WHITEHEAT_GET_DTR_RTS) {
|
||
+ } else if ((data[0] == WHITEHEAT_GET_DTR_RTS) &&
|
||
+ (urb->actual_length - 1 <= sizeof(command_info->result_buffer))) {
|
||
memcpy(command_info->result_buffer, &data[1],
|
||
urb->actual_length - 1);
|
||
command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
|
||
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
|
||
index 685edc8..144386b 100644
|
||
--- a/drivers/usb/storage/Kconfig
|
||
+++ b/drivers/usb/storage/Kconfig
|
||
@@ -19,7 +19,9 @@ config USB_STORAGE
|
||
|
||
This option depends on 'SCSI' support being enabled, but you
|
||
probably also need 'SCSI device support: SCSI disk support'
|
||
- (BLK_DEV_SD) for most USB storage devices.
|
||
+ (BLK_DEV_SD) for most USB storage devices. Some devices also
|
||
+ will require 'Probe all LUNs on each SCSI device'
|
||
+ (SCSI_MULTI_LUN).
|
||
|
||
To compile this driver as a module, choose M here: the
|
||
module will be called usb-storage.
|
||
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
|
||
index d496efa..a4f033b 100644
|
||
--- a/drivers/usb/storage/scsiglue.c
|
||
+++ b/drivers/usb/storage/scsiglue.c
|
||
@@ -78,6 +78,8 @@ static const char* host_info(struct Scsi_Host *host)
|
||
|
||
static int slave_alloc (struct scsi_device *sdev)
|
||
{
|
||
+ struct us_data *us = host_to_us(sdev->host);
|
||
+
|
||
/*
|
||
* Set the INQUIRY transfer length to 36. We don't use any of
|
||
* the extra data and many devices choke if asked for more or
|
||
@@ -102,6 +104,10 @@ static int slave_alloc (struct scsi_device *sdev)
|
||
*/
|
||
blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
|
||
|
||
+ /* Tell the SCSI layer if we know there is more than one LUN */
|
||
+ if (us->protocol == USB_PR_BULK && us->max_lun > 0)
|
||
+ sdev->sdev_bflags |= BLIST_FORCELUN;
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
|
||
index fa1ceeb..f3248fb 100644
|
||
--- a/drivers/usb/storage/shuttle_usbat.c
|
||
+++ b/drivers/usb/storage/shuttle_usbat.c
|
||
@@ -1846,7 +1846,7 @@ static int usbat_probe(struct usb_interface *intf,
|
||
us->transport_name = "Shuttle USBAT";
|
||
us->transport = usbat_flash_transport;
|
||
us->transport_reset = usb_stor_CB_reset;
|
||
- us->max_lun = 1;
|
||
+ us->max_lun = 0;
|
||
|
||
result = usb_stor_probe2(us);
|
||
return result;
|
||
diff --git a/drivers/usb/storage/unusual_cypress.h b/drivers/usb/storage/unusual_cypress.h
|
||
index 65a6a75..82e8ed0 100644
|
||
--- a/drivers/usb/storage/unusual_cypress.h
|
||
+++ b/drivers/usb/storage/unusual_cypress.h
|
||
@@ -31,7 +31,7 @@ UNUSUAL_DEV( 0x04b4, 0x6831, 0x0000, 0x9999,
|
||
"Cypress ISD-300LP",
|
||
USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
|
||
|
||
-UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x0219,
|
||
+UNUSUAL_DEV( 0x14cd, 0x6116, 0x0160, 0x0160,
|
||
"Super Top",
|
||
"USB 2.0 SATA BRIDGE",
|
||
USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
|
||
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
|
||
index cf442e0..a280945 100644
|
||
--- a/drivers/usb/storage/unusual_devs.h
|
||
+++ b/drivers/usb/storage/unusual_devs.h
|
||
@@ -93,6 +93,12 @@ UNUSUAL_DEV( 0x03f0, 0x4002, 0x0001, 0x0001,
|
||
"PhotoSmart R707",
|
||
USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY),
|
||
|
||
+UNUSUAL_DEV( 0x03f3, 0x0001, 0x0000, 0x9999,
|
||
+ "Adaptec",
|
||
+ "USBConnect 2000",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
|
||
+ US_FL_SCM_MULT_TARG ),
|
||
+
|
||
/* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net>
|
||
* and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product)
|
||
* for USB floppies that need the SINGLE_LUN enforcement.
|
||
@@ -226,6 +232,27 @@ UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370,
|
||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
US_FL_MAX_SECTORS_64 ),
|
||
|
||
+/* Reported by Daniele Forsi <dforsi@gmail.com> */
|
||
+UNUSUAL_DEV( 0x0421, 0x04b9, 0x0350, 0x0350,
|
||
+ "Nokia",
|
||
+ "5300",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
+ US_FL_MAX_SECTORS_64 ),
|
||
+
|
||
+/* Patch submitted by Victor A. Santos <victoraur.santos@gmail.com> */
|
||
+UNUSUAL_DEV( 0x0421, 0x05af, 0x0742, 0x0742,
|
||
+ "Nokia",
|
||
+ "305",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
+ US_FL_MAX_SECTORS_64),
|
||
+
|
||
+/* Patch submitted by Mikhail Zolotaryov <lebon@lebon.org.ua> */
|
||
+UNUSUAL_DEV( 0x0421, 0x06aa, 0x1110, 0x1110,
|
||
+ "Nokia",
|
||
+ "502",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
+ US_FL_MAX_SECTORS_64 ),
|
||
+
|
||
#ifdef NO_SDDR09
|
||
UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
|
||
"Microtech",
|
||
@@ -712,6 +739,12 @@ UNUSUAL_DEV( 0x059b, 0x0001, 0x0100, 0x0100,
|
||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
US_FL_SINGLE_LUN ),
|
||
|
||
+UNUSUAL_DEV( 0x059b, 0x0040, 0x0100, 0x0100,
|
||
+ "Iomega",
|
||
+ "Jaz USB Adapter",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
+ US_FL_SINGLE_LUN ),
|
||
+
|
||
/* Reported by <Hendryk.Pfeiffer@gmx.de> */
|
||
UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000,
|
||
"LaCie",
|
||
@@ -1084,6 +1117,18 @@ UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200,
|
||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
US_FL_NOT_LOCKABLE),
|
||
|
||
+UNUSUAL_DEV( 0x085a, 0x0026, 0x0100, 0x0133,
|
||
+ "Xircom",
|
||
+ "PortGear USB-SCSI (Mac USB Dock)",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
|
||
+ US_FL_SCM_MULT_TARG ),
|
||
+
|
||
+UNUSUAL_DEV( 0x085a, 0x0028, 0x0100, 0x0133,
|
||
+ "Xircom",
|
||
+ "PortGear USB to SCSI Converter",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
|
||
+ US_FL_SCM_MULT_TARG ),
|
||
+
|
||
/* Submitted by Jan De Luyck <lkml@kcore.org> */
|
||
UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000,
|
||
"CITIZEN",
|
||
@@ -1434,6 +1479,13 @@ UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100,
|
||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
US_FL_FIX_CAPACITY ),
|
||
|
||
+/* Reported by Moritz Moeller-Herrmann <moritz-kernel@moeller-herrmann.de> */
|
||
+UNUSUAL_DEV( 0x0fca, 0x8004, 0x0201, 0x0201,
|
||
+ "Research In Motion",
|
||
+ "BlackBerry Bold 9000",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
+ US_FL_MAX_SECTORS_64 ),
|
||
+
|
||
/* Reported by Michael Stattmann <michael@stattmann.com> */
|
||
UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000,
|
||
"Sony Ericsson",
|
||
@@ -1897,6 +1949,14 @@ UNUSUAL_DEV( 0x152d, 0x2329, 0x0100, 0x0100,
|
||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
|
||
|
||
+/* Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI)
|
||
+ * and Mac USB Dock USB-SCSI */
|
||
+UNUSUAL_DEV( 0x1645, 0x0007, 0x0100, 0x0133,
|
||
+ "Entrega Technologies",
|
||
+ "USB to SCSI Converter",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
|
||
+ US_FL_SCM_MULT_TARG ),
|
||
+
|
||
/* Reported by Robert Schedel <r.schedel@yahoo.de>
|
||
* Note: this is a 'super top' device like the above 14cd/6600 device */
|
||
UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201,
|
||
@@ -1912,6 +1972,12 @@ UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000,
|
||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||
US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
|
||
|
||
+UNUSUAL_DEV( 0x1822, 0x0001, 0x0000, 0x9999,
|
||
+ "Ariston Technologies",
|
||
+ "iConnect USB to SCSI adapter",
|
||
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
|
||
+ US_FL_SCM_MULT_TARG ),
|
||
+
|
||
/* Reported by Hans de Goede <hdegoede@redhat.com>
|
||
* These Appotech controllers are found in Picture Frames, they provide a
|
||
* (buggy) emulation of a cdrom drive which contains the windows software
|
||
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
|
||
index f0d546c..ca1031b 100644
|
||
--- a/drivers/usb/wusbcore/wa-rpipe.c
|
||
+++ b/drivers/usb/wusbcore/wa-rpipe.c
|
||
@@ -332,7 +332,10 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,
|
||
/* FIXME: compute so seg_size > ep->maxpktsize */
|
||
rpipe->descr.wBlocks = cpu_to_le16(16); /* given */
|
||
/* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */
|
||
- rpipe->descr.wMaxPacketSize = cpu_to_le16(ep->desc.wMaxPacketSize);
|
||
+ if (usb_endpoint_xfer_isoc(&ep->desc))
|
||
+ rpipe->descr.wMaxPacketSize = epcd->wOverTheAirPacketSize;
|
||
+ else
|
||
+ rpipe->descr.wMaxPacketSize = ep->desc.wMaxPacketSize;
|
||
rpipe->descr.bHSHubAddress = 0; /* reserved: zero */
|
||
rpipe->descr.bHSHubPort = wusb_port_no_to_idx(urb->dev->portnum);
|
||
/* FIXME: use maximum speed as supported or recommended by device */
|
||
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
|
||
index 57c01ab..5f6df6e 100644
|
||
--- a/drivers/usb/wusbcore/wa-xfer.c
|
||
+++ b/drivers/usb/wusbcore/wa-xfer.c
|
||
@@ -90,7 +90,8 @@
|
||
#include "wusbhc.h"
|
||
|
||
enum {
|
||
- WA_SEGS_MAX = 255,
|
||
+ /* [WUSB] section 8.3.3 allocates 7 bits for the segment index. */
|
||
+ WA_SEGS_MAX = 128,
|
||
};
|
||
|
||
enum wa_seg_status {
|
||
@@ -444,7 +445,7 @@ static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer,
|
||
xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize;
|
||
xfer->segs = (urb->transfer_buffer_length + xfer->seg_size - 1)
|
||
/ xfer->seg_size;
|
||
- if (xfer->segs >= WA_SEGS_MAX) {
|
||
+ if (xfer->segs > WA_SEGS_MAX) {
|
||
dev_err(dev, "BUG? ops, number of segments %d bigger than %d\n",
|
||
(int)(urb->transfer_buffer_length / xfer->seg_size),
|
||
WA_SEGS_MAX);
|
||
diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c
|
||
index 5241f1d..3c9e929 100644
|
||
--- a/drivers/uwb/lc-dev.c
|
||
+++ b/drivers/uwb/lc-dev.c
|
||
@@ -441,16 +441,19 @@ void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce)
|
||
uwb_dev->mac_addr = *bce->mac_addr;
|
||
uwb_dev->dev_addr = bce->dev_addr;
|
||
dev_set_name(&uwb_dev->dev, macbuf);
|
||
+
|
||
+ /* plug the beacon cache */
|
||
+ bce->uwb_dev = uwb_dev;
|
||
+ uwb_dev->bce = bce;
|
||
+ uwb_bce_get(bce); /* released in uwb_dev_sys_release() */
|
||
+
|
||
result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc);
|
||
if (result < 0) {
|
||
dev_err(dev, "new device %s: cannot instantiate device\n",
|
||
macbuf);
|
||
goto error_dev_add;
|
||
}
|
||
- /* plug the beacon cache */
|
||
- bce->uwb_dev = uwb_dev;
|
||
- uwb_dev->bce = bce;
|
||
- uwb_bce_get(bce); /* released in uwb_dev_sys_release() */
|
||
+
|
||
dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n",
|
||
macbuf, devbuf, rc->uwb_dev.dev.parent->bus->name,
|
||
dev_name(rc->uwb_dev.dev.parent));
|
||
@@ -458,6 +461,8 @@ void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce)
|
||
return;
|
||
|
||
error_dev_add:
|
||
+ bce->uwb_dev = NULL;
|
||
+ uwb_bce_put(bce);
|
||
kfree(uwb_dev);
|
||
return;
|
||
}
|
||
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
|
||
index 50a3cb5..3fd908c 100644
|
||
--- a/drivers/vhost/net.c
|
||
+++ b/drivers/vhost/net.c
|
||
@@ -324,9 +324,13 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
|
||
r = -ENOBUFS;
|
||
goto err;
|
||
}
|
||
- d = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
|
||
+ r = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
|
||
ARRAY_SIZE(vq->iov) - seg, &out,
|
||
&in, log, log_num);
|
||
+ if (unlikely(r < 0))
|
||
+ goto err;
|
||
+
|
||
+ d = r;
|
||
if (d == vq->num) {
|
||
r = 0;
|
||
goto err;
|
||
@@ -351,6 +355,12 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
|
||
*iovcount = seg;
|
||
if (unlikely(log))
|
||
*log_num = nlogs;
|
||
+
|
||
+ /* Detect overrun */
|
||
+ if (unlikely(datalen > 0)) {
|
||
+ r = UIO_MAXIOV + 1;
|
||
+ goto err;
|
||
+ }
|
||
return headcount;
|
||
err:
|
||
vhost_discard_vq_desc(vq, headcount);
|
||
@@ -405,6 +415,14 @@ static void handle_rx(struct vhost_net *net)
|
||
/* On error, stop handling until the next kick. */
|
||
if (unlikely(headcount < 0))
|
||
break;
|
||
+ /* On overrun, truncate and discard */
|
||
+ if (unlikely(headcount > UIO_MAXIOV)) {
|
||
+ msg.msg_iovlen = 1;
|
||
+ err = sock->ops->recvmsg(NULL, sock, &msg,
|
||
+ 1, MSG_DONTWAIT | MSG_TRUNC);
|
||
+ pr_debug("Discarded rx packet: len %zd\n", sock_len);
|
||
+ continue;
|
||
+ }
|
||
/* OK, now we need to know about added descriptors. */
|
||
if (!headcount) {
|
||
if (unlikely(vhost_enable_notify(&net->dev, vq))) {
|
||
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
|
||
index e45833c..182bd68 100644
|
||
--- a/drivers/video/aty/mach64_accel.c
|
||
+++ b/drivers/video/aty/mach64_accel.c
|
||
@@ -4,6 +4,7 @@
|
||
*/
|
||
|
||
#include <linux/delay.h>
|
||
+#include <asm/unaligned.h>
|
||
#include <linux/fb.h>
|
||
#include <video/mach64.h>
|
||
#include "atyfb.h"
|
||
@@ -419,7 +420,7 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
|
||
u32 *pbitmap, dwords = (src_bytes + 3) / 4;
|
||
for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) {
|
||
wait_for_fifo(1, par);
|
||
- aty_st_le32(HOST_DATA0, le32_to_cpup(pbitmap), par);
|
||
+ aty_st_le32(HOST_DATA0, get_unaligned_le32(pbitmap), par);
|
||
}
|
||
}
|
||
|
||
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
|
||
index 46f72ed..4b87318 100644
|
||
--- a/drivers/video/aty/mach64_cursor.c
|
||
+++ b/drivers/video/aty/mach64_cursor.c
|
||
@@ -5,6 +5,7 @@
|
||
#include <linux/fb.h>
|
||
#include <linux/init.h>
|
||
#include <linux/string.h>
|
||
+#include "../fb_draw.h"
|
||
|
||
#include <asm/io.h>
|
||
|
||
@@ -157,24 +158,33 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
|
||
|
||
for (i = 0; i < height; i++) {
|
||
for (j = 0; j < width; j++) {
|
||
+ u16 l = 0xaaaa;
|
||
b = *src++;
|
||
m = *msk++;
|
||
switch (cursor->rop) {
|
||
case ROP_XOR:
|
||
// Upper 4 bits of mask data
|
||
- fb_writeb(cursor_bits_lookup[(b ^ m) >> 4], dst++);
|
||
+ l = cursor_bits_lookup[(b ^ m) >> 4] |
|
||
// Lower 4 bits of mask
|
||
- fb_writeb(cursor_bits_lookup[(b ^ m) & 0x0f],
|
||
- dst++);
|
||
+ (cursor_bits_lookup[(b ^ m) & 0x0f] << 8);
|
||
break;
|
||
case ROP_COPY:
|
||
// Upper 4 bits of mask data
|
||
- fb_writeb(cursor_bits_lookup[(b & m) >> 4], dst++);
|
||
+ l = cursor_bits_lookup[(b & m) >> 4] |
|
||
// Lower 4 bits of mask
|
||
- fb_writeb(cursor_bits_lookup[(b & m) & 0x0f],
|
||
- dst++);
|
||
+ (cursor_bits_lookup[(b & m) & 0x0f] << 8);
|
||
break;
|
||
}
|
||
+ /*
|
||
+ * If cursor size is not a multiple of 8 characters
|
||
+ * we must pad it with transparent pattern (0xaaaa).
|
||
+ */
|
||
+ if ((j + 1) * 8 > cursor->image.width) {
|
||
+ l = comp(l, 0xaaaa,
|
||
+ (1 << ((cursor->image.width & 7) * 2)) - 1);
|
||
+ }
|
||
+ fb_writeb(l & 0xff, dst++);
|
||
+ fb_writeb(l >> 8, dst++);
|
||
}
|
||
dst += offset;
|
||
}
|
||
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c
|
||
index 0443a4f..dab3a0c 100644
|
||
--- a/drivers/video/backlight/atmel-pwm-bl.c
|
||
+++ b/drivers/video/backlight/atmel-pwm-bl.c
|
||
@@ -70,7 +70,7 @@ static int atmel_pwm_bl_set_intensity(struct backlight_device *bd)
|
||
static int atmel_pwm_bl_get_intensity(struct backlight_device *bd)
|
||
{
|
||
struct atmel_pwm_bl *pwmbl = bl_get_data(bd);
|
||
- u8 intensity;
|
||
+ u32 intensity;
|
||
|
||
if (pwmbl->pdata->pwm_active_low) {
|
||
intensity = pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY) -
|
||
@@ -80,7 +80,7 @@ static int atmel_pwm_bl_get_intensity(struct backlight_device *bd)
|
||
pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY);
|
||
}
|
||
|
||
- return intensity;
|
||
+ return intensity & 0xffff;
|
||
}
|
||
|
||
static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl)
|
||
@@ -211,7 +211,8 @@ static int __exit atmel_pwm_bl_remove(struct platform_device *pdev)
|
||
struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev);
|
||
|
||
if (pwmbl->gpio_on != -1) {
|
||
- gpio_set_value(pwmbl->gpio_on, 0);
|
||
+ gpio_set_value(pwmbl->gpio_on,
|
||
+ 0 ^ pwmbl->pdata->on_active_low);
|
||
gpio_free(pwmbl->gpio_on);
|
||
}
|
||
pwm_channel_disable(&pwmbl->pwmc);
|
||
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
|
||
index bb5a96b..bcb5723 100644
|
||
--- a/drivers/video/cfbcopyarea.c
|
||
+++ b/drivers/video/cfbcopyarea.c
|
||
@@ -43,13 +43,22 @@
|
||
*/
|
||
|
||
static void
|
||
-bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
- const unsigned long __iomem *src, int src_idx, int bits,
|
||
+bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
|
||
+ const unsigned long __iomem *src, unsigned src_idx, int bits,
|
||
unsigned n, u32 bswapmask)
|
||
{
|
||
unsigned long first, last;
|
||
int const shift = dst_idx-src_idx;
|
||
- int left, right;
|
||
+
|
||
+#if 0
|
||
+ /*
|
||
+ * If you suspect bug in this function, compare it with this simple
|
||
+ * memmove implementation.
|
||
+ */
|
||
+ fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
|
||
+ (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
|
||
+ return;
|
||
+#endif
|
||
|
||
first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
|
||
last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
|
||
@@ -98,9 +107,8 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
unsigned long d0, d1;
|
||
int m;
|
||
|
||
- right = shift & (bits - 1);
|
||
- left = -shift & (bits - 1);
|
||
- bswapmask &= shift;
|
||
+ int const left = shift & (bits - 1);
|
||
+ int const right = -shift & (bits - 1);
|
||
|
||
if (dst_idx+n <= bits) {
|
||
// Single destination word
|
||
@@ -110,15 +118,15 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
d0 = fb_rev_pixels_in_long(d0, bswapmask);
|
||
if (shift > 0) {
|
||
// Single source word
|
||
- d0 >>= right;
|
||
+ d0 <<= left;
|
||
} else if (src_idx+n <= bits) {
|
||
// Single source word
|
||
- d0 <<= left;
|
||
+ d0 >>= right;
|
||
} else {
|
||
// 2 source words
|
||
d1 = FB_READL(src + 1);
|
||
d1 = fb_rev_pixels_in_long(d1, bswapmask);
|
||
- d0 = d0<<left | d1>>right;
|
||
+ d0 = d0 >> right | d1 << left;
|
||
}
|
||
d0 = fb_rev_pixels_in_long(d0, bswapmask);
|
||
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
|
||
@@ -135,60 +143,59 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
if (shift > 0) {
|
||
// Single source word
|
||
d1 = d0;
|
||
- d0 >>= right;
|
||
- dst++;
|
||
+ d0 <<= left;
|
||
n -= bits - dst_idx;
|
||
} else {
|
||
// 2 source words
|
||
d1 = FB_READL(src++);
|
||
d1 = fb_rev_pixels_in_long(d1, bswapmask);
|
||
|
||
- d0 = d0<<left | d1>>right;
|
||
- dst++;
|
||
+ d0 = d0 >> right | d1 << left;
|
||
n -= bits - dst_idx;
|
||
}
|
||
d0 = fb_rev_pixels_in_long(d0, bswapmask);
|
||
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
|
||
d0 = d1;
|
||
+ dst++;
|
||
|
||
// Main chunk
|
||
m = n % bits;
|
||
n /= bits;
|
||
while ((n >= 4) && !bswapmask) {
|
||
d1 = FB_READL(src++);
|
||
- FB_WRITEL(d0 << left | d1 >> right, dst++);
|
||
+ FB_WRITEL(d0 >> right | d1 << left, dst++);
|
||
d0 = d1;
|
||
d1 = FB_READL(src++);
|
||
- FB_WRITEL(d0 << left | d1 >> right, dst++);
|
||
+ FB_WRITEL(d0 >> right | d1 << left, dst++);
|
||
d0 = d1;
|
||
d1 = FB_READL(src++);
|
||
- FB_WRITEL(d0 << left | d1 >> right, dst++);
|
||
+ FB_WRITEL(d0 >> right | d1 << left, dst++);
|
||
d0 = d1;
|
||
d1 = FB_READL(src++);
|
||
- FB_WRITEL(d0 << left | d1 >> right, dst++);
|
||
+ FB_WRITEL(d0 >> right | d1 << left, dst++);
|
||
d0 = d1;
|
||
n -= 4;
|
||
}
|
||
while (n--) {
|
||
d1 = FB_READL(src++);
|
||
d1 = fb_rev_pixels_in_long(d1, bswapmask);
|
||
- d0 = d0 << left | d1 >> right;
|
||
+ d0 = d0 >> right | d1 << left;
|
||
d0 = fb_rev_pixels_in_long(d0, bswapmask);
|
||
FB_WRITEL(d0, dst++);
|
||
d0 = d1;
|
||
}
|
||
|
||
// Trailing bits
|
||
- if (last) {
|
||
- if (m <= right) {
|
||
+ if (m) {
|
||
+ if (m <= bits - right) {
|
||
// Single source word
|
||
- d0 <<= left;
|
||
+ d0 >>= right;
|
||
} else {
|
||
// 2 source words
|
||
d1 = FB_READL(src);
|
||
d1 = fb_rev_pixels_in_long(d1,
|
||
bswapmask);
|
||
- d0 = d0<<left | d1>>right;
|
||
+ d0 = d0 >> right | d1 << left;
|
||
}
|
||
d0 = fb_rev_pixels_in_long(d0, bswapmask);
|
||
FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
|
||
@@ -202,43 +209,46 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
*/
|
||
|
||
static void
|
||
-bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
- const unsigned long __iomem *src, int src_idx, int bits,
|
||
+bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
|
||
+ const unsigned long __iomem *src, unsigned src_idx, int bits,
|
||
unsigned n, u32 bswapmask)
|
||
{
|
||
unsigned long first, last;
|
||
int shift;
|
||
|
||
- dst += (n-1)/bits;
|
||
- src += (n-1)/bits;
|
||
- if ((n-1) % bits) {
|
||
- dst_idx += (n-1) % bits;
|
||
- dst += dst_idx >> (ffs(bits) - 1);
|
||
- dst_idx &= bits - 1;
|
||
- src_idx += (n-1) % bits;
|
||
- src += src_idx >> (ffs(bits) - 1);
|
||
- src_idx &= bits - 1;
|
||
- }
|
||
+#if 0
|
||
+ /*
|
||
+ * If you suspect bug in this function, compare it with this simple
|
||
+ * memmove implementation.
|
||
+ */
|
||
+ fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
|
||
+ (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
|
||
+ return;
|
||
+#endif
|
||
+
|
||
+ dst += (dst_idx + n - 1) / bits;
|
||
+ src += (src_idx + n - 1) / bits;
|
||
+ dst_idx = (dst_idx + n - 1) % bits;
|
||
+ src_idx = (src_idx + n - 1) % bits;
|
||
|
||
shift = dst_idx-src_idx;
|
||
|
||
- first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
|
||
- last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
|
||
- bswapmask);
|
||
+ first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask);
|
||
+ last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask);
|
||
|
||
if (!shift) {
|
||
// Same alignment for source and dest
|
||
|
||
if ((unsigned long)dst_idx+1 >= n) {
|
||
// Single word
|
||
- if (last)
|
||
- first &= last;
|
||
- FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
|
||
+ if (first)
|
||
+ last &= first;
|
||
+ FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
|
||
} else {
|
||
// Multiple destination words
|
||
|
||
// Leading bits
|
||
- if (first != ~0UL) {
|
||
+ if (first) {
|
||
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
|
||
dst--;
|
||
src--;
|
||
@@ -262,7 +272,7 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
FB_WRITEL(FB_READL(src--), dst--);
|
||
|
||
// Trailing bits
|
||
- if (last)
|
||
+ if (last != -1UL)
|
||
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
|
||
}
|
||
} else {
|
||
@@ -270,29 +280,28 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
unsigned long d0, d1;
|
||
int m;
|
||
|
||
- int const left = -shift & (bits-1);
|
||
- int const right = shift & (bits-1);
|
||
- bswapmask &= shift;
|
||
+ int const left = shift & (bits-1);
|
||
+ int const right = -shift & (bits-1);
|
||
|
||
if ((unsigned long)dst_idx+1 >= n) {
|
||
// Single destination word
|
||
- if (last)
|
||
- first &= last;
|
||
+ if (first)
|
||
+ last &= first;
|
||
d0 = FB_READL(src);
|
||
if (shift < 0) {
|
||
// Single source word
|
||
- d0 <<= left;
|
||
+ d0 >>= right;
|
||
} else if (1+(unsigned long)src_idx >= n) {
|
||
// Single source word
|
||
- d0 >>= right;
|
||
+ d0 <<= left;
|
||
} else {
|
||
// 2 source words
|
||
d1 = FB_READL(src - 1);
|
||
d1 = fb_rev_pixels_in_long(d1, bswapmask);
|
||
- d0 = d0>>right | d1<<left;
|
||
+ d0 = d0 << left | d1 >> right;
|
||
}
|
||
d0 = fb_rev_pixels_in_long(d0, bswapmask);
|
||
- FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
|
||
+ FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
|
||
} else {
|
||
// Multiple destination words
|
||
/** We must always remember the last value read, because in case
|
||
@@ -307,12 +316,12 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
if (shift < 0) {
|
||
// Single source word
|
||
d1 = d0;
|
||
- d0 <<= left;
|
||
+ d0 >>= right;
|
||
} else {
|
||
// 2 source words
|
||
d1 = FB_READL(src--);
|
||
d1 = fb_rev_pixels_in_long(d1, bswapmask);
|
||
- d0 = d0>>right | d1<<left;
|
||
+ d0 = d0 << left | d1 >> right;
|
||
}
|
||
d0 = fb_rev_pixels_in_long(d0, bswapmask);
|
||
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
|
||
@@ -325,39 +334,39 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
|
||
n /= bits;
|
||
while ((n >= 4) && !bswapmask) {
|
||
d1 = FB_READL(src--);
|
||
- FB_WRITEL(d0 >> right | d1 << left, dst--);
|
||
+ FB_WRITEL(d0 << left | d1 >> right, dst--);
|
||
d0 = d1;
|
||
d1 = FB_READL(src--);
|
||
- FB_WRITEL(d0 >> right | d1 << left, dst--);
|
||
+ FB_WRITEL(d0 << left | d1 >> right, dst--);
|
||
d0 = d1;
|
||
d1 = FB_READL(src--);
|
||
- FB_WRITEL(d0 >> right | d1 << left, dst--);
|
||
+ FB_WRITEL(d0 << left | d1 >> right, dst--);
|
||
d0 = d1;
|
||
d1 = FB_READL(src--);
|
||
- FB_WRITEL(d0 >> right | d1 << left, dst--);
|
||
+ FB_WRITEL(d0 << left | d1 >> right, dst--);
|
||
d0 = d1;
|
||
n -= 4;
|
||
}
|
||
while (n--) {
|
||
d1 = FB_READL(src--);
|
||
d1 = fb_rev_pixels_in_long(d1, bswapmask);
|
||
- d0 = d0 >> right | d1 << left;
|
||
+ d0 = d0 << left | d1 >> right;
|
||
d0 = fb_rev_pixels_in_long(d0, bswapmask);
|
||
FB_WRITEL(d0, dst--);
|
||
d0 = d1;
|
||
}
|
||
|
||
// Trailing bits
|
||
- if (last) {
|
||
- if (m <= left) {
|
||
+ if (m) {
|
||
+ if (m <= bits - left) {
|
||
// Single source word
|
||
- d0 >>= right;
|
||
+ d0 <<= left;
|
||
} else {
|
||
// 2 source words
|
||
d1 = FB_READL(src);
|
||
d1 = fb_rev_pixels_in_long(d1,
|
||
bswapmask);
|
||
- d0 = d0>>right | d1<<left;
|
||
+ d0 = d0 << left | d1 >> right;
|
||
}
|
||
d0 = fb_rev_pixels_in_long(d0, bswapmask);
|
||
FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
|
||
@@ -371,9 +380,9 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
|
||
u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
|
||
u32 height = area->height, width = area->width;
|
||
unsigned long const bits_per_line = p->fix.line_length*8u;
|
||
- unsigned long __iomem *dst = NULL, *src = NULL;
|
||
+ unsigned long __iomem *base = NULL;
|
||
int bits = BITS_PER_LONG, bytes = bits >> 3;
|
||
- int dst_idx = 0, src_idx = 0, rev_copy = 0;
|
||
+ unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
|
||
u32 bswapmask = fb_compute_bswapmask(p);
|
||
|
||
if (p->state != FBINFO_STATE_RUNNING)
|
||
@@ -389,7 +398,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
|
||
|
||
// split the base of the framebuffer into a long-aligned address and the
|
||
// index of the first bit
|
||
- dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
|
||
+ base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
|
||
dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
|
||
// add offset of source and target area
|
||
dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
|
||
@@ -402,20 +411,14 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
|
||
while (height--) {
|
||
dst_idx -= bits_per_line;
|
||
src_idx -= bits_per_line;
|
||
- dst += dst_idx >> (ffs(bits) - 1);
|
||
- dst_idx &= (bytes - 1);
|
||
- src += src_idx >> (ffs(bits) - 1);
|
||
- src_idx &= (bytes - 1);
|
||
- bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
|
||
+ bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
|
||
+ base + (src_idx / bits), src_idx % bits, bits,
|
||
width*p->var.bits_per_pixel, bswapmask);
|
||
}
|
||
} else {
|
||
while (height--) {
|
||
- dst += dst_idx >> (ffs(bits) - 1);
|
||
- dst_idx &= (bytes - 1);
|
||
- src += src_idx >> (ffs(bits) - 1);
|
||
- src_idx &= (bytes - 1);
|
||
- bitcpy(p, dst, dst_idx, src, src_idx, bits,
|
||
+ bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
|
||
+ base + (src_idx / bits), src_idx % bits, bits,
|
||
width*p->var.bits_per_pixel, bswapmask);
|
||
dst_idx += bits_per_line;
|
||
src_idx += bits_per_line;
|
||
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
|
||
index 5855d17..9d8feac 100644
|
||
--- a/drivers/video/console/vgacon.c
|
||
+++ b/drivers/video/console/vgacon.c
|
||
@@ -42,6 +42,7 @@
|
||
#include <linux/kd.h>
|
||
#include <linux/slab.h>
|
||
#include <linux/vt_kern.h>
|
||
+#include <linux/sched.h>
|
||
#include <linux/selection.h>
|
||
#include <linux/spinlock.h>
|
||
#include <linux/ioport.h>
|
||
@@ -1124,11 +1125,15 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
|
||
|
||
if (arg) {
|
||
if (set)
|
||
- for (i = 0; i < cmapsz; i++)
|
||
+ for (i = 0; i < cmapsz; i++) {
|
||
vga_writeb(arg[i], charmap + i);
|
||
+ cond_resched();
|
||
+ }
|
||
else
|
||
- for (i = 0; i < cmapsz; i++)
|
||
+ for (i = 0; i < cmapsz; i++) {
|
||
arg[i] = vga_readb(charmap + i);
|
||
+ cond_resched();
|
||
+ }
|
||
|
||
/*
|
||
* In 512-character mode, the character map is not contiguous if
|
||
@@ -1139,11 +1144,15 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
|
||
charmap += 2 * cmapsz;
|
||
arg += cmapsz;
|
||
if (set)
|
||
- for (i = 0; i < cmapsz; i++)
|
||
+ for (i = 0; i < cmapsz; i++) {
|
||
vga_writeb(arg[i], charmap + i);
|
||
+ cond_resched();
|
||
+ }
|
||
else
|
||
- for (i = 0; i < cmapsz; i++)
|
||
+ for (i = 0; i < cmapsz; i++) {
|
||
arg[i] = vga_readb(charmap + i);
|
||
+ cond_resched();
|
||
+ }
|
||
}
|
||
}
|
||
|
||
diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c
|
||
index acb9370..7aa8668 100644
|
||
--- a/drivers/video/kyro/fbdev.c
|
||
+++ b/drivers/video/kyro/fbdev.c
|
||
@@ -625,15 +625,15 @@ static int kyrofb_ioctl(struct fb_info *info,
|
||
}
|
||
break;
|
||
case KYRO_IOCTL_UVSTRIDE:
|
||
- if (copy_to_user(argp, &deviceInfo.ulOverlayUVStride, sizeof(unsigned long)))
|
||
+ if (copy_to_user(argp, &deviceInfo.ulOverlayUVStride, sizeof(deviceInfo.ulOverlayUVStride)))
|
||
return -EFAULT;
|
||
break;
|
||
case KYRO_IOCTL_STRIDE:
|
||
- if (copy_to_user(argp, &deviceInfo.ulOverlayStride, sizeof(unsigned long)))
|
||
+ if (copy_to_user(argp, &deviceInfo.ulOverlayStride, sizeof(deviceInfo.ulOverlayStride)))
|
||
return -EFAULT;
|
||
break;
|
||
case KYRO_IOCTL_OVERLAY_OFFSET:
|
||
- if (copy_to_user(argp, &deviceInfo.ulOverlayOffset, sizeof(unsigned long)))
|
||
+ if (copy_to_user(argp, &deviceInfo.ulOverlayOffset, sizeof(deviceInfo.ulOverlayOffset)))
|
||
return -EFAULT;
|
||
break;
|
||
}
|
||
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
|
||
index 8335a6f..0d5cb85 100644
|
||
--- a/drivers/video/matrox/matroxfb_accel.c
|
||
+++ b/drivers/video/matrox/matroxfb_accel.c
|
||
@@ -192,10 +192,18 @@ void matrox_cfbX_init(struct matrox_fb_info *minfo)
|
||
minfo->accel.m_dwg_rect = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
|
||
if (isMilleniumII(minfo)) minfo->accel.m_dwg_rect |= M_DWG_TRANSC;
|
||
minfo->accel.m_opmode = mopmode;
|
||
+ minfo->accel.m_access = maccess;
|
||
+ minfo->accel.m_pitch = mpitch;
|
||
}
|
||
|
||
EXPORT_SYMBOL(matrox_cfbX_init);
|
||
|
||
+static void matrox_accel_restore_maccess(struct matrox_fb_info *minfo)
|
||
+{
|
||
+ mga_outl(M_MACCESS, minfo->accel.m_access);
|
||
+ mga_outl(M_PITCH, minfo->accel.m_pitch);
|
||
+}
|
||
+
|
||
static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy,
|
||
int sx, int dy, int dx, int height, int width)
|
||
{
|
||
@@ -207,7 +215,8 @@ static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy,
|
||
CRITBEGIN
|
||
|
||
if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
|
||
- mga_fifo(2);
|
||
+ mga_fifo(4);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
|
||
M_DWG_BFCOL | M_DWG_REPLACE);
|
||
mga_outl(M_AR5, vxres);
|
||
@@ -215,7 +224,8 @@ static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy,
|
||
start = sy*vxres+sx+curr_ydstorg(minfo);
|
||
end = start+width;
|
||
} else {
|
||
- mga_fifo(3);
|
||
+ mga_fifo(5);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
|
||
mga_outl(M_SGN, 5);
|
||
mga_outl(M_AR5, -vxres);
|
||
@@ -224,7 +234,8 @@ static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy,
|
||
start = end+width;
|
||
dy += height-1;
|
||
}
|
||
- mga_fifo(4);
|
||
+ mga_fifo(6);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
mga_outl(M_AR0, end);
|
||
mga_outl(M_AR3, start);
|
||
mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
|
||
@@ -246,7 +257,8 @@ static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres,
|
||
CRITBEGIN
|
||
|
||
if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
|
||
- mga_fifo(2);
|
||
+ mga_fifo(4);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
|
||
M_DWG_BFCOL | M_DWG_REPLACE);
|
||
mga_outl(M_AR5, vxres);
|
||
@@ -254,7 +266,8 @@ static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres,
|
||
start = sy*vxres+sx+curr_ydstorg(minfo);
|
||
end = start+width;
|
||
} else {
|
||
- mga_fifo(3);
|
||
+ mga_fifo(5);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
|
||
mga_outl(M_SGN, 5);
|
||
mga_outl(M_AR5, -vxres);
|
||
@@ -263,7 +276,8 @@ static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres,
|
||
start = end+width;
|
||
dy += height-1;
|
||
}
|
||
- mga_fifo(5);
|
||
+ mga_fifo(7);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
mga_outl(M_AR0, end);
|
||
mga_outl(M_AR3, start);
|
||
mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
|
||
@@ -298,7 +312,8 @@ static void matroxfb_accel_clear(struct matrox_fb_info *minfo, u_int32_t color,
|
||
|
||
CRITBEGIN
|
||
|
||
- mga_fifo(5);
|
||
+ mga_fifo(7);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE);
|
||
mga_outl(M_FCOL, color);
|
||
mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
|
||
@@ -341,7 +356,8 @@ static void matroxfb_cfb4_clear(struct matrox_fb_info *minfo, u_int32_t bgx,
|
||
width >>= 1;
|
||
sx >>= 1;
|
||
if (width) {
|
||
- mga_fifo(5);
|
||
+ mga_fifo(7);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE2);
|
||
mga_outl(M_FCOL, bgx);
|
||
mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
|
||
@@ -415,7 +431,8 @@ static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx,
|
||
|
||
CRITBEGIN
|
||
|
||
- mga_fifo(3);
|
||
+ mga_fifo(5);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
if (easy)
|
||
mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
|
||
else
|
||
@@ -425,7 +442,8 @@ static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx,
|
||
fxbndry = ((xx + width - 1) << 16) | xx;
|
||
mmio = minfo->mmio.vbase;
|
||
|
||
- mga_fifo(6);
|
||
+ mga_fifo(8);
|
||
+ matrox_accel_restore_maccess(minfo);
|
||
mga_writel(mmio, M_FXBNDRY, fxbndry);
|
||
mga_writel(mmio, M_AR0, ar0);
|
||
mga_writel(mmio, M_AR3, 0);
|
||
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
|
||
index 11ed57b..89a8a89a 100644
|
||
--- a/drivers/video/matrox/matroxfb_base.h
|
||
+++ b/drivers/video/matrox/matroxfb_base.h
|
||
@@ -307,6 +307,8 @@ struct matrox_accel_data {
|
||
#endif
|
||
u_int32_t m_dwg_rect;
|
||
u_int32_t m_opmode;
|
||
+ u_int32_t m_access;
|
||
+ u_int32_t m_pitch;
|
||
};
|
||
|
||
struct v4l2_queryctrl;
|
||
@@ -696,7 +698,7 @@ void matroxfb_unregister_driver(struct matroxfb_driver* drv);
|
||
|
||
#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
|
||
|
||
-#define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000)
|
||
+#define WaitTillIdle() do { mga_inl(M_STATUS); do {} while (mga_inl(M_STATUS) & 0x10000); } while (0)
|
||
|
||
/* code speedup */
|
||
#ifdef CONFIG_FB_MATROX_MILLENIUM
|
||
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
|
||
index b00db40..3e005fa9 100644
|
||
--- a/drivers/video/omap2/omapfb/omapfb-main.c
|
||
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
|
||
@@ -1187,7 +1187,7 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
|
||
break;
|
||
|
||
if (regno < 16) {
|
||
- u16 pal;
|
||
+ u32 pal;
|
||
pal = ((red >> (16 - var->red.length)) <<
|
||
var->red.offset) |
|
||
((green >> (16 - var->green.length)) <<
|
||
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
|
||
index aba7686..3b15bca 100644
|
||
--- a/drivers/video/tgafb.c
|
||
+++ b/drivers/video/tgafb.c
|
||
@@ -192,6 +192,8 @@ tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
||
|
||
if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
|
||
return -EINVAL;
|
||
+ if (var->xres * var->yres * (var->bits_per_pixel >> 3) > info->fix.smem_len)
|
||
+ return -EINVAL;
|
||
if (var->nonstd)
|
||
return -EINVAL;
|
||
if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ)
|
||
@@ -272,6 +274,7 @@ tgafb_set_par(struct fb_info *info)
|
||
par->yres = info->var.yres;
|
||
par->pll_freq = pll_freq = 1000000000 / info->var.pixclock;
|
||
par->bits_per_pixel = info->var.bits_per_pixel;
|
||
+ info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
|
||
|
||
tga_type = par->tga_type;
|
||
|
||
@@ -1146,222 +1149,57 @@ copyarea_line_32bpp(struct fb_info *info, u32 dy, u32 sy,
|
||
__raw_writel(TGA_MODE_SBM_24BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
|
||
}
|
||
|
||
-/* The general case of forward copy in 8bpp mode. */
|
||
+/* The (almost) general case of backward copy in 8bpp mode. */
|
||
static inline void
|
||
-copyarea_foreward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
|
||
- u32 height, u32 width, u32 line_length)
|
||
+copyarea_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
|
||
+ u32 height, u32 width, u32 line_length,
|
||
+ const struct fb_copyarea *area)
|
||
{
|
||
struct tga_par *par = (struct tga_par *) info->par;
|
||
- unsigned long i, copied, left;
|
||
- unsigned long dpos, spos, dalign, salign, yincr;
|
||
- u32 smask_first, dmask_first, dmask_last;
|
||
- int pixel_shift, need_prime, need_second;
|
||
- unsigned long n64, n32, xincr_first;
|
||
+ unsigned i, yincr;
|
||
+ int depos, sepos, backward, last_step, step;
|
||
+ u32 mask_last;
|
||
+ unsigned n32;
|
||
void __iomem *tga_regs;
|
||
void __iomem *tga_fb;
|
||
|
||
- yincr = line_length;
|
||
- if (dy > sy) {
|
||
- dy += height - 1;
|
||
- sy += height - 1;
|
||
- yincr = -yincr;
|
||
- }
|
||
-
|
||
- /* Compute the offsets and alignments in the frame buffer.
|
||
- More than anything else, these control how we do copies. */
|
||
- dpos = dy * line_length + dx;
|
||
- spos = sy * line_length + sx;
|
||
- dalign = dpos & 7;
|
||
- salign = spos & 7;
|
||
- dpos &= -8;
|
||
- spos &= -8;
|
||
-
|
||
- /* Compute the value for the PIXELSHIFT register. This controls
|
||
- both non-co-aligned source and destination and copy direction. */
|
||
- if (dalign >= salign)
|
||
- pixel_shift = dalign - salign;
|
||
- else
|
||
- pixel_shift = 8 - (salign - dalign);
|
||
-
|
||
- /* Figure out if we need an additional priming step for the
|
||
- residue register. */
|
||
- need_prime = (salign > dalign);
|
||
- if (need_prime)
|
||
- dpos -= 8;
|
||
-
|
||
- /* Begin by copying the leading unaligned destination. Copy enough
|
||
- to make the next destination address 32-byte aligned. */
|
||
- copied = 32 - (dalign + (dpos & 31));
|
||
- if (copied == 32)
|
||
- copied = 0;
|
||
- xincr_first = (copied + 7) & -8;
|
||
- smask_first = dmask_first = (1ul << copied) - 1;
|
||
- smask_first <<= salign;
|
||
- dmask_first <<= dalign + need_prime*8;
|
||
- if (need_prime && copied > 24)
|
||
- copied -= 8;
|
||
- left = width - copied;
|
||
-
|
||
- /* Care for small copies. */
|
||
- if (copied > width) {
|
||
- u32 t;
|
||
- t = (1ul << width) - 1;
|
||
- t <<= dalign + need_prime*8;
|
||
- dmask_first &= t;
|
||
- left = 0;
|
||
- }
|
||
-
|
||
- /* Attempt to use 64-byte copies. This is only possible if the
|
||
- source and destination are co-aligned at 64 bytes. */
|
||
- n64 = need_second = 0;
|
||
- if ((dpos & 63) == (spos & 63)
|
||
- && (height == 1 || line_length % 64 == 0)) {
|
||
- /* We may need a 32-byte copy to ensure 64 byte alignment. */
|
||
- need_second = (dpos + xincr_first) & 63;
|
||
- if ((need_second & 32) != need_second)
|
||
- printk(KERN_ERR "tgafb: need_second wrong\n");
|
||
- if (left >= need_second + 64) {
|
||
- left -= need_second;
|
||
- n64 = left / 64;
|
||
- left %= 64;
|
||
- } else
|
||
- need_second = 0;
|
||
- }
|
||
-
|
||
- /* Copy trailing full 32-byte sections. This will be the main
|
||
- loop if the 64 byte loop can't be used. */
|
||
- n32 = left / 32;
|
||
- left %= 32;
|
||
-
|
||
- /* Copy the trailing unaligned destination. */
|
||
- dmask_last = (1ul << left) - 1;
|
||
-
|
||
- tga_regs = par->tga_regs_base;
|
||
- tga_fb = par->tga_fb_base;
|
||
-
|
||
- /* Set up the MODE and PIXELSHIFT registers. */
|
||
- __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
|
||
- __raw_writel(pixel_shift, tga_regs+TGA_PIXELSHIFT_REG);
|
||
- wmb();
|
||
-
|
||
- for (i = 0; i < height; ++i) {
|
||
- unsigned long j;
|
||
- void __iomem *sfb;
|
||
- void __iomem *dfb;
|
||
-
|
||
- sfb = tga_fb + spos;
|
||
- dfb = tga_fb + dpos;
|
||
- if (dmask_first) {
|
||
- __raw_writel(smask_first, sfb);
|
||
- wmb();
|
||
- __raw_writel(dmask_first, dfb);
|
||
- wmb();
|
||
- sfb += xincr_first;
|
||
- dfb += xincr_first;
|
||
- }
|
||
-
|
||
- if (need_second) {
|
||
- __raw_writel(0xffffffff, sfb);
|
||
- wmb();
|
||
- __raw_writel(0xffffffff, dfb);
|
||
- wmb();
|
||
- sfb += 32;
|
||
- dfb += 32;
|
||
- }
|
||
-
|
||
- if (n64 && (((unsigned long)sfb | (unsigned long)dfb) & 63))
|
||
- printk(KERN_ERR
|
||
- "tgafb: misaligned copy64 (s:%p, d:%p)\n",
|
||
- sfb, dfb);
|
||
-
|
||
- for (j = 0; j < n64; ++j) {
|
||
- __raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC);
|
||
- wmb();
|
||
- __raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST);
|
||
- wmb();
|
||
- sfb += 64;
|
||
- dfb += 64;
|
||
- }
|
||
-
|
||
- for (j = 0; j < n32; ++j) {
|
||
- __raw_writel(0xffffffff, sfb);
|
||
- wmb();
|
||
- __raw_writel(0xffffffff, dfb);
|
||
- wmb();
|
||
- sfb += 32;
|
||
- dfb += 32;
|
||
- }
|
||
-
|
||
- if (dmask_last) {
|
||
- __raw_writel(0xffffffff, sfb);
|
||
- wmb();
|
||
- __raw_writel(dmask_last, dfb);
|
||
- wmb();
|
||
- }
|
||
-
|
||
- spos += yincr;
|
||
- dpos += yincr;
|
||
+ /* Do acceleration only if we are aligned on 8 pixels */
|
||
+ if ((dx | sx | width) & 7) {
|
||
+ cfb_copyarea(info, area);
|
||
+ return;
|
||
}
|
||
|
||
- /* Reset the MODE register to normal. */
|
||
- __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
|
||
-}
|
||
-
|
||
-/* The (almost) general case of backward copy in 8bpp mode. */
|
||
-static inline void
|
||
-copyarea_backward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
|
||
- u32 height, u32 width, u32 line_length,
|
||
- const struct fb_copyarea *area)
|
||
-{
|
||
- struct tga_par *par = (struct tga_par *) info->par;
|
||
- unsigned long i, left, yincr;
|
||
- unsigned long depos, sepos, dealign, sealign;
|
||
- u32 mask_first, mask_last;
|
||
- unsigned long n32;
|
||
- void __iomem *tga_regs;
|
||
- void __iomem *tga_fb;
|
||
-
|
||
yincr = line_length;
|
||
if (dy > sy) {
|
||
dy += height - 1;
|
||
sy += height - 1;
|
||
yincr = -yincr;
|
||
}
|
||
+ backward = dy == sy && dx > sx && dx < sx + width;
|
||
|
||
/* Compute the offsets and alignments in the frame buffer.
|
||
More than anything else, these control how we do copies. */
|
||
- depos = dy * line_length + dx + width;
|
||
- sepos = sy * line_length + sx + width;
|
||
- dealign = depos & 7;
|
||
- sealign = sepos & 7;
|
||
-
|
||
- /* ??? The documentation appears to be incorrect (or very
|
||
- misleading) wrt how pixel shifting works in backward copy
|
||
- mode, i.e. when PIXELSHIFT is negative. I give up for now.
|
||
- Do handle the common case of co-aligned backward copies,
|
||
- but frob everything else back on generic code. */
|
||
- if (dealign != sealign) {
|
||
- cfb_copyarea(info, area);
|
||
- return;
|
||
- }
|
||
-
|
||
- /* We begin the copy with the trailing pixels of the
|
||
- unaligned destination. */
|
||
- mask_first = (1ul << dealign) - 1;
|
||
- left = width - dealign;
|
||
-
|
||
- /* Care for small copies. */
|
||
- if (dealign > width) {
|
||
- mask_first ^= (1ul << (dealign - width)) - 1;
|
||
- left = 0;
|
||
- }
|
||
+ depos = dy * line_length + dx;
|
||
+ sepos = sy * line_length + sx;
|
||
+ if (backward)
|
||
+ depos += width, sepos += width;
|
||
|
||
/* Next copy full words at a time. */
|
||
- n32 = left / 32;
|
||
- left %= 32;
|
||
+ n32 = width / 32;
|
||
+ last_step = width % 32;
|
||
|
||
/* Finally copy the unaligned head of the span. */
|
||
- mask_last = -1 << (32 - left);
|
||
+ mask_last = (1ul << last_step) - 1;
|
||
+
|
||
+ if (!backward) {
|
||
+ step = 32;
|
||
+ last_step = 32;
|
||
+ } else {
|
||
+ step = -32;
|
||
+ last_step = -last_step;
|
||
+ sepos -= 32;
|
||
+ depos -= 32;
|
||
+ }
|
||
|
||
tga_regs = par->tga_regs_base;
|
||
tga_fb = par->tga_fb_base;
|
||
@@ -1378,25 +1216,33 @@ copyarea_backward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
|
||
|
||
sfb = tga_fb + sepos;
|
||
dfb = tga_fb + depos;
|
||
- if (mask_first) {
|
||
- __raw_writel(mask_first, sfb);
|
||
- wmb();
|
||
- __raw_writel(mask_first, dfb);
|
||
- wmb();
|
||
- }
|
||
|
||
- for (j = 0; j < n32; ++j) {
|
||
- sfb -= 32;
|
||
- dfb -= 32;
|
||
+ for (j = 0; j < n32; j++) {
|
||
+ if (j < 2 && j + 1 < n32 && !backward &&
|
||
+ !(((unsigned long)sfb | (unsigned long)dfb) & 63)) {
|
||
+ do {
|
||
+ __raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC);
|
||
+ wmb();
|
||
+ __raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST);
|
||
+ wmb();
|
||
+ sfb += 64;
|
||
+ dfb += 64;
|
||
+ j += 2;
|
||
+ } while (j + 1 < n32);
|
||
+ j--;
|
||
+ continue;
|
||
+ }
|
||
__raw_writel(0xffffffff, sfb);
|
||
wmb();
|
||
__raw_writel(0xffffffff, dfb);
|
||
wmb();
|
||
+ sfb += step;
|
||
+ dfb += step;
|
||
}
|
||
|
||
if (mask_last) {
|
||
- sfb -= 32;
|
||
- dfb -= 32;
|
||
+ sfb += last_step - step;
|
||
+ dfb += last_step - step;
|
||
__raw_writel(mask_last, sfb);
|
||
wmb();
|
||
__raw_writel(mask_last, dfb);
|
||
@@ -1457,14 +1303,9 @@ tgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
|
||
else if (bpp == 32)
|
||
cfb_copyarea(info, area);
|
||
|
||
- /* Detect overlapping source and destination that requires
|
||
- a backward copy. */
|
||
- else if (dy == sy && dx > sx && dx < sx + width)
|
||
- copyarea_backward_8bpp(info, dx, dy, sx, sy, height,
|
||
- width, line_length, area);
|
||
else
|
||
- copyarea_foreward_8bpp(info, dx, dy, sx, sy, height,
|
||
- width, line_length);
|
||
+ copyarea_8bpp(info, dx, dy, sx, sy, height,
|
||
+ width, line_length, area);
|
||
}
|
||
|
||
|
||
@@ -1480,6 +1321,7 @@ tgafb_init_fix(struct fb_info *info)
|
||
int tga_bus_tc = TGA_BUS_TC(par->dev);
|
||
u8 tga_type = par->tga_type;
|
||
const char *tga_type_name = NULL;
|
||
+ unsigned memory_size;
|
||
|
||
switch (tga_type) {
|
||
case TGA_TYPE_8PLANE:
|
||
@@ -1487,21 +1329,25 @@ tgafb_init_fix(struct fb_info *info)
|
||
tga_type_name = "Digital ZLXp-E1";
|
||
if (tga_bus_tc)
|
||
tga_type_name = "Digital ZLX-E1";
|
||
+ memory_size = 2097152;
|
||
break;
|
||
case TGA_TYPE_24PLANE:
|
||
if (tga_bus_pci)
|
||
tga_type_name = "Digital ZLXp-E2";
|
||
if (tga_bus_tc)
|
||
tga_type_name = "Digital ZLX-E2";
|
||
+ memory_size = 8388608;
|
||
break;
|
||
case TGA_TYPE_24PLUSZ:
|
||
if (tga_bus_pci)
|
||
tga_type_name = "Digital ZLXp-E3";
|
||
if (tga_bus_tc)
|
||
tga_type_name = "Digital ZLX-E3";
|
||
+ memory_size = 16777216;
|
||
break;
|
||
default:
|
||
tga_type_name = "Unknown";
|
||
+ memory_size = 16777216;
|
||
break;
|
||
}
|
||
|
||
@@ -1513,9 +1359,8 @@ tgafb_init_fix(struct fb_info *info)
|
||
? FB_VISUAL_PSEUDOCOLOR
|
||
: FB_VISUAL_DIRECTCOLOR);
|
||
|
||
- info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
|
||
info->fix.smem_start = (size_t) par->tga_fb_base;
|
||
- info->fix.smem_len = info->fix.line_length * par->yres;
|
||
+ info->fix.smem_len = memory_size;
|
||
info->fix.mmio_start = (size_t) par->tga_regs_base;
|
||
info->fix.mmio_len = 512;
|
||
|
||
@@ -1640,6 +1485,9 @@ tgafb_register(struct device *dev)
|
||
modedb_tga = &modedb_tc;
|
||
modedbsize_tga = 1;
|
||
}
|
||
+
|
||
+ tgafb_init_fix(info);
|
||
+
|
||
ret = fb_find_mode(&info->var, info,
|
||
mode_option ? mode_option : mode_option_tga,
|
||
modedb_tga, modedbsize_tga, NULL,
|
||
@@ -1657,7 +1505,6 @@ tgafb_register(struct device *dev)
|
||
}
|
||
|
||
tgafb_set_par(info);
|
||
- tgafb_init_fix(info);
|
||
|
||
if (register_framebuffer(info) < 0) {
|
||
printk(KERN_ERR "tgafb: Could not register framebuffer\n");
|
||
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
|
||
index 8807fe5..4366254 100644
|
||
--- a/drivers/virtio/virtio_balloon.c
|
||
+++ b/drivers/virtio/virtio_balloon.c
|
||
@@ -305,6 +305,12 @@ static int balloon(void *_vballoon)
|
||
else if (diff < 0)
|
||
leak_balloon(vb, -diff);
|
||
update_balloon_size(vb);
|
||
+
|
||
+ /*
|
||
+ * For large balloon changes, we could spend a lot of time
|
||
+ * and always have work to do. Be nice if preempt disabled.
|
||
+ */
|
||
+ cond_resched();
|
||
}
|
||
return 0;
|
||
}
|
||
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
|
||
index 40788c9..73705af 100644
|
||
--- a/drivers/w1/w1_netlink.c
|
||
+++ b/drivers/w1/w1_netlink.c
|
||
@@ -54,28 +54,29 @@ static void w1_send_slave(struct w1_master *dev, u64 rn)
|
||
struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1);
|
||
struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
|
||
int avail;
|
||
+ u64 *data;
|
||
|
||
/* update kernel slave list */
|
||
w1_slave_found(dev, rn);
|
||
|
||
avail = dev->priv_size - cmd->len;
|
||
|
||
- if (avail > 8) {
|
||
- u64 *data = (void *)(cmd + 1) + cmd->len;
|
||
+ if (avail < 8) {
|
||
+ msg->ack++;
|
||
+ cn_netlink_send(msg, 0, GFP_KERNEL);
|
||
|
||
- *data = rn;
|
||
- cmd->len += 8;
|
||
- hdr->len += 8;
|
||
- msg->len += 8;
|
||
- return;
|
||
+ msg->len = sizeof(struct w1_netlink_msg) +
|
||
+ sizeof(struct w1_netlink_cmd);
|
||
+ hdr->len = sizeof(struct w1_netlink_cmd);
|
||
+ cmd->len = 0;
|
||
}
|
||
|
||
- msg->ack++;
|
||
- cn_netlink_send(msg, 0, GFP_KERNEL);
|
||
+ data = (void *)(cmd + 1) + cmd->len;
|
||
|
||
- msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd);
|
||
- hdr->len = sizeof(struct w1_netlink_cmd);
|
||
- cmd->len = 0;
|
||
+ *data = rn;
|
||
+ cmd->len += 8;
|
||
+ hdr->len += 8;
|
||
+ msg->len += 8;
|
||
}
|
||
|
||
static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg,
|
||
diff --git a/drivers/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c
|
||
index 3fb83b0..ab6d3f5 100644
|
||
--- a/drivers/watchdog/sc1200wdt.c
|
||
+++ b/drivers/watchdog/sc1200wdt.c
|
||
@@ -409,8 +409,9 @@ static int __init sc1200wdt_init(void)
|
||
#if defined CONFIG_PNP
|
||
/* now that the user has specified an IO port and we haven't detected
|
||
* any devices, disable pnp support */
|
||
+ if (isapnp)
|
||
+ pnp_unregister_driver(&scl200wdt_pnp_driver);
|
||
isapnp = 0;
|
||
- pnp_unregister_driver(&scl200wdt_pnp_driver);
|
||
#endif
|
||
|
||
if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
|
||
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
|
||
index bbb170e..a3b97e0 100644
|
||
--- a/drivers/watchdog/sp805_wdt.c
|
||
+++ b/drivers/watchdog/sp805_wdt.c
|
||
@@ -62,7 +62,6 @@
|
||
* @adev: amba device structure of wdt
|
||
* @status: current status of wdt
|
||
* @load_val: load value to be set for current timeout
|
||
- * @timeout: current programmed timeout
|
||
*/
|
||
struct sp805_wdt {
|
||
spinlock_t lock;
|
||
@@ -73,7 +72,6 @@ struct sp805_wdt {
|
||
#define WDT_BUSY 0
|
||
#define WDT_CAN_BE_CLOSED 1
|
||
unsigned int load_val;
|
||
- unsigned int timeout;
|
||
};
|
||
|
||
/* local variables */
|
||
@@ -101,7 +99,7 @@ static void wdt_setload(unsigned int timeout)
|
||
spin_lock(&wdt->lock);
|
||
wdt->load_val = load;
|
||
/* roundup timeout to closest positive integer value */
|
||
- wdt->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
|
||
+ wdd->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
|
||
spin_unlock(&wdt->lock);
|
||
}
|
||
|
||
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
|
||
index 33dcad6..9161f06 100644
|
||
--- a/drivers/xen/events.c
|
||
+++ b/drivers/xen/events.c
|
||
@@ -1422,8 +1422,10 @@ void rebind_evtchn_irq(int evtchn, int irq)
|
||
/* Rebind an evtchn so that it gets delivered to a specific cpu */
|
||
static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
|
||
{
|
||
+ struct shared_info *s = HYPERVISOR_shared_info;
|
||
struct evtchn_bind_vcpu bind_vcpu;
|
||
int evtchn = evtchn_from_irq(irq);
|
||
+ int masked;
|
||
|
||
if (!VALID_EVTCHN(evtchn))
|
||
return -1;
|
||
@@ -1440,6 +1442,12 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
|
||
bind_vcpu.vcpu = tcpu;
|
||
|
||
/*
|
||
+ * Mask the event while changing the VCPU binding to prevent
|
||
+ * it being delivered on an unexpected VCPU.
|
||
+ */
|
||
+ masked = sync_test_and_set_bit(evtchn, s->evtchn_mask);
|
||
+
|
||
+ /*
|
||
* If this fails, it usually just indicates that we're dealing with a
|
||
* virq or IPI channel, which don't actually need to be rebound. Ignore
|
||
* it, but don't do the xenlinux-level rebind in that case.
|
||
@@ -1447,6 +1455,9 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
|
||
if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
|
||
bind_evtchn_to_cpu(evtchn, tcpu);
|
||
|
||
+ if (!masked)
|
||
+ unmask_evtchn(evtchn);
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
|
||
index 412b96c..8da1ed1 100644
|
||
--- a/drivers/xen/manage.c
|
||
+++ b/drivers/xen/manage.c
|
||
@@ -109,16 +109,11 @@ static void do_suspend(void)
|
||
|
||
shutting_down = SHUTDOWN_SUSPEND;
|
||
|
||
-#ifdef CONFIG_PREEMPT
|
||
- /* If the kernel is preemptible, we need to freeze all the processes
|
||
- to prevent them from being in the middle of a pagetable update
|
||
- during suspend. */
|
||
err = freeze_processes();
|
||
if (err) {
|
||
printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
|
||
goto out;
|
||
}
|
||
-#endif
|
||
|
||
err = dpm_suspend_start(PMSG_FREEZE);
|
||
if (err) {
|
||
@@ -170,10 +165,8 @@ static void do_suspend(void)
|
||
clock_was_set();
|
||
|
||
out_thaw:
|
||
-#ifdef CONFIG_PREEMPT
|
||
thaw_processes();
|
||
out:
|
||
-#endif
|
||
shutting_down = SHUTDOWN_INVALID;
|
||
}
|
||
#endif /* CONFIG_HIBERNATE_CALLBACKS */
|
||
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
|
||
index bcec067..9a6b24a 100644
|
||
--- a/fs/btrfs/backref.c
|
||
+++ b/fs/btrfs/backref.c
|
||
@@ -1033,7 +1033,7 @@ static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,
|
||
*out_eiref = (struct btrfs_extent_inline_ref *)(ei + 1);
|
||
}
|
||
*ptr = (unsigned long)*out_eiref;
|
||
- if ((void *)*ptr >= (void *)ei + item_size)
|
||
+ if ((unsigned long)(*ptr) >= (unsigned long)ei + item_size)
|
||
return -ENOENT;
|
||
}
|
||
|
||
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
|
||
index 86eff48..503a6bd 100644
|
||
--- a/fs/btrfs/compression.c
|
||
+++ b/fs/btrfs/compression.c
|
||
@@ -995,6 +995,8 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
|
||
bytes = min(bytes, working_bytes);
|
||
kaddr = kmap_atomic(page_out);
|
||
memcpy(kaddr + *pg_offset, buf + buf_offset, bytes);
|
||
+ if (*pg_index == (vcnt - 1) && *pg_offset == 0)
|
||
+ memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
|
||
kunmap_atomic(kaddr);
|
||
flush_dcache_page(page_out);
|
||
|
||
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
|
||
index c4f0a99..224ce21 100644
|
||
--- a/fs/btrfs/extent-tree.c
|
||
+++ b/fs/btrfs/extent-tree.c
|
||
@@ -7033,7 +7033,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
||
*/
|
||
if (root_dropped == false)
|
||
btrfs_add_dead_root(root);
|
||
- if (err)
|
||
+ if (err && err != -EAGAIN)
|
||
btrfs_std_error(root->fs_info, err);
|
||
return err;
|
||
}
|
||
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
|
||
index d64fda5..24b58c7 100644
|
||
--- a/fs/btrfs/extent_io.c
|
||
+++ b/fs/btrfs/extent_io.c
|
||
@@ -1551,6 +1551,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode,
|
||
* shortening the size of the delalloc range we're searching
|
||
*/
|
||
free_extent_state(cached_state);
|
||
+ cached_state = NULL;
|
||
if (!loops) {
|
||
unsigned long offset = (*start) & (PAGE_CACHE_SIZE - 1);
|
||
max_bytes = PAGE_CACHE_SIZE - offset;
|
||
@@ -2244,7 +2245,7 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
|
||
{
|
||
int uptodate = (err == 0);
|
||
struct extent_io_tree *tree;
|
||
- int ret;
|
||
+ int ret = 0;
|
||
|
||
tree = &BTRFS_I(page->mapping->host)->io_tree;
|
||
|
||
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
|
||
index 06744f1..d5dc63c 100644
|
||
--- a/fs/btrfs/volumes.c
|
||
+++ b/fs/btrfs/volumes.c
|
||
@@ -1446,11 +1446,12 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
|
||
struct btrfs_fs_devices *fs_devices;
|
||
fs_devices = root->fs_info->fs_devices;
|
||
while (fs_devices) {
|
||
- if (fs_devices->seed == cur_devices)
|
||
+ if (fs_devices->seed == cur_devices) {
|
||
+ fs_devices->seed = cur_devices->seed;
|
||
break;
|
||
+ }
|
||
fs_devices = fs_devices->seed;
|
||
}
|
||
- fs_devices->seed = cur_devices->seed;
|
||
cur_devices->seed = NULL;
|
||
lock_chunks(root);
|
||
__btrfs_close_devices(cur_devices);
|
||
diff --git a/fs/buffer.c b/fs/buffer.c
|
||
index 2d866fa..4279f0f 100644
|
||
--- a/fs/buffer.c
|
||
+++ b/fs/buffer.c
|
||
@@ -613,14 +613,16 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode);
|
||
static void __set_page_dirty(struct page *page,
|
||
struct address_space *mapping, int warn)
|
||
{
|
||
- spin_lock_irq(&mapping->tree_lock);
|
||
+ unsigned long flags;
|
||
+
|
||
+ spin_lock_irqsave(&mapping->tree_lock, flags);
|
||
if (page->mapping) { /* Race with truncate? */
|
||
WARN_ON_ONCE(warn && !PageUptodate(page));
|
||
account_page_dirtied(page, mapping);
|
||
radix_tree_tag_set(&mapping->page_tree,
|
||
page_index(page), PAGECACHE_TAG_DIRTY);
|
||
}
|
||
- spin_unlock_irq(&mapping->tree_lock);
|
||
+ spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||
__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
|
||
}
|
||
|
||
@@ -969,7 +971,8 @@ grow_dev_page(struct block_device *bdev, sector_t block,
|
||
bh = page_buffers(page);
|
||
if (bh->b_size == size) {
|
||
end_block = init_page_buffers(page, bdev,
|
||
- index << sizebits, size);
|
||
+ (sector_t)index << sizebits,
|
||
+ size);
|
||
goto done;
|
||
}
|
||
if (!try_to_free_buffers(page))
|
||
@@ -990,7 +993,8 @@ grow_dev_page(struct block_device *bdev, sector_t block,
|
||
*/
|
||
spin_lock(&inode->i_mapping->private_lock);
|
||
link_dev_buffers(page, bh);
|
||
- end_block = init_page_buffers(page, bdev, index << sizebits, size);
|
||
+ end_block = init_page_buffers(page, bdev, (sector_t)index << sizebits,
|
||
+ size);
|
||
spin_unlock(&inode->i_mapping->private_lock);
|
||
done:
|
||
ret = (block < end_block) ? 1 : -ENXIO;
|
||
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c
|
||
index 0e3c092..b4d2438 100644
|
||
--- a/fs/cachefiles/rdwr.c
|
||
+++ b/fs/cachefiles/rdwr.c
|
||
@@ -918,7 +918,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
|
||
* own time */
|
||
dget(object->backer);
|
||
mntget(cache->mnt);
|
||
- file = dentry_open(object->backer, cache->mnt, O_RDWR,
|
||
+ file = dentry_open(object->backer, cache->mnt, O_RDWR | O_LARGEFILE,
|
||
cache->cache_cred);
|
||
if (IS_ERR(file)) {
|
||
ret = PTR_ERR(file);
|
||
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
|
||
index bb01881..9fdc051 100644
|
||
--- a/fs/ceph/addr.c
|
||
+++ b/fs/ceph/addr.c
|
||
@@ -213,9 +213,13 @@ static int readpage_nounlock(struct file *filp, struct page *page)
|
||
if (err < 0) {
|
||
SetPageError(page);
|
||
goto out;
|
||
- } else if (err < PAGE_CACHE_SIZE) {
|
||
+ } else {
|
||
+ if (err < PAGE_CACHE_SIZE) {
|
||
/* zero fill remainder of page */
|
||
- zero_user_segment(page, err, PAGE_CACHE_SIZE);
|
||
+ zero_user_segment(page, err, PAGE_CACHE_SIZE);
|
||
+ } else {
|
||
+ flush_dcache_page(page);
|
||
+ }
|
||
}
|
||
SetPageUptodate(page);
|
||
|
||
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
|
||
index cf1b9e0..ae3ca03 100644
|
||
--- a/fs/ceph/mds_client.c
|
||
+++ b/fs/ceph/mds_client.c
|
||
@@ -609,6 +609,8 @@ static void __unregister_request(struct ceph_mds_client *mdsc,
|
||
req->r_unsafe_dir = NULL;
|
||
}
|
||
|
||
+ complete_all(&req->r_safe_completion);
|
||
+
|
||
ceph_mdsc_put_request(req);
|
||
}
|
||
|
||
@@ -1815,8 +1817,11 @@ static int __do_request(struct ceph_mds_client *mdsc,
|
||
int mds = -1;
|
||
int err = -EAGAIN;
|
||
|
||
- if (req->r_err || req->r_got_result)
|
||
+ if (req->r_err || req->r_got_result) {
|
||
+ if (req->r_aborted)
|
||
+ __unregister_request(mdsc, req);
|
||
goto out;
|
||
+ }
|
||
|
||
if (req->r_timeout &&
|
||
time_after_eq(jiffies, req->r_started + req->r_timeout)) {
|
||
@@ -2129,7 +2134,6 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
|
||
if (head->safe) {
|
||
req->r_got_safe = true;
|
||
__unregister_request(mdsc, req);
|
||
- complete_all(&req->r_safe_completion);
|
||
|
||
if (req->r_got_unsafe) {
|
||
/*
|
||
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
|
||
index f04c096..e5206fc 100644
|
||
--- a/fs/ceph/snap.c
|
||
+++ b/fs/ceph/snap.c
|
||
@@ -331,7 +331,7 @@ static int build_snap_context(struct ceph_snap_realm *realm)
|
||
|
||
/* alloc new snap context */
|
||
err = -ENOMEM;
|
||
- if (num > (ULONG_MAX - sizeof(*snapc)) / sizeof(u64))
|
||
+ if (num > (SIZE_MAX - sizeof(*snapc)) / sizeof(u64))
|
||
goto fail;
|
||
snapc = kzalloc(sizeof(*snapc) + num*sizeof(u64), GFP_NOFS);
|
||
if (!snapc)
|
||
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
|
||
index 6a8568c..f2da2bd 100644
|
||
--- a/fs/cifs/cifs_unicode.c
|
||
+++ b/fs/cifs/cifs_unicode.c
|
||
@@ -290,7 +290,8 @@ int
|
||
cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||
const struct nls_table *cp, int mapChars)
|
||
{
|
||
- int i, j, charlen;
|
||
+ int i, charlen;
|
||
+ int j = 0;
|
||
char src_char;
|
||
__le16 dst_char;
|
||
wchar_t tmp;
|
||
@@ -298,12 +299,11 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||
if (!mapChars)
|
||
return cifs_strtoUTF16(target, source, PATH_MAX, cp);
|
||
|
||
- for (i = 0, j = 0; i < srclen; j++) {
|
||
+ for (i = 0; i < srclen; j++) {
|
||
src_char = source[i];
|
||
charlen = 1;
|
||
switch (src_char) {
|
||
case 0:
|
||
- put_unaligned(0, &target[j]);
|
||
goto ctoUTF16_out;
|
||
case ':':
|
||
dst_char = cpu_to_le16(UNI_COLON);
|
||
@@ -350,6 +350,7 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||
}
|
||
|
||
ctoUTF16_out:
|
||
+ put_unaligned(0, &target[j]); /* Null terminate target unicode string */
|
||
return j;
|
||
}
|
||
|
||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
|
||
index d7561e0..c0f65e8 100644
|
||
--- a/fs/cifs/cifsfs.c
|
||
+++ b/fs/cifs/cifsfs.c
|
||
@@ -87,6 +87,30 @@ extern mempool_t *cifs_mid_poolp;
|
||
|
||
struct workqueue_struct *cifsiod_wq;
|
||
|
||
+/*
|
||
+ * Bumps refcount for cifs super block.
|
||
+ * Note that it should be only called if a referece to VFS super block is
|
||
+ * already held, e.g. in open-type syscalls context. Otherwise it can race with
|
||
+ * atomic_dec_and_test in deactivate_locked_super.
|
||
+ */
|
||
+void
|
||
+cifs_sb_active(struct super_block *sb)
|
||
+{
|
||
+ struct cifs_sb_info *server = CIFS_SB(sb);
|
||
+
|
||
+ if (atomic_inc_return(&server->active) == 1)
|
||
+ atomic_inc(&sb->s_active);
|
||
+}
|
||
+
|
||
+void
|
||
+cifs_sb_deactive(struct super_block *sb)
|
||
+{
|
||
+ struct cifs_sb_info *server = CIFS_SB(sb);
|
||
+
|
||
+ if (atomic_dec_and_test(&server->active))
|
||
+ deactivate_super(sb);
|
||
+}
|
||
+
|
||
static int
|
||
cifs_read_super(struct super_block *sb)
|
||
{
|
||
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
|
||
index 6536535..f711765 100644
|
||
--- a/fs/cifs/cifsfs.h
|
||
+++ b/fs/cifs/cifsfs.h
|
||
@@ -41,6 +41,10 @@ extern struct file_system_type cifs_fs_type;
|
||
extern const struct address_space_operations cifs_addr_ops;
|
||
extern const struct address_space_operations cifs_addr_ops_smallbuf;
|
||
|
||
+/* Functions related to super block operations */
|
||
+extern void cifs_sb_active(struct super_block *sb);
|
||
+extern void cifs_sb_deactive(struct super_block *sb);
|
||
+
|
||
/* Functions related to inodes */
|
||
extern const struct inode_operations cifs_dir_inode_ops;
|
||
extern struct inode *cifs_root_iget(struct super_block *);
|
||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
|
||
index 3a75ee5..6e60981 100644
|
||
--- a/fs/cifs/cifssmb.c
|
||
+++ b/fs/cifs/cifssmb.c
|
||
@@ -3454,11 +3454,13 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
|
||
return 0;
|
||
}
|
||
cifs_acl->version = cpu_to_le16(1);
|
||
- if (acl_type == ACL_TYPE_ACCESS)
|
||
+ if (acl_type == ACL_TYPE_ACCESS) {
|
||
cifs_acl->access_entry_count = cpu_to_le16(count);
|
||
- else if (acl_type == ACL_TYPE_DEFAULT)
|
||
+ cifs_acl->default_entry_count = __constant_cpu_to_le16(0xFFFF);
|
||
+ } else if (acl_type == ACL_TYPE_DEFAULT) {
|
||
cifs_acl->default_entry_count = cpu_to_le16(count);
|
||
- else {
|
||
+ cifs_acl->access_entry_count = __constant_cpu_to_le16(0xFFFF);
|
||
+ } else {
|
||
cFYI(1, "unknown ACL type %d", acl_type);
|
||
return 0;
|
||
}
|
||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
|
||
index e7ebb5a..0898d99 100644
|
||
--- a/fs/cifs/file.c
|
||
+++ b/fs/cifs/file.c
|
||
@@ -265,6 +265,8 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
|
||
mutex_init(&pCifsFile->fh_mutex);
|
||
INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
|
||
|
||
+ cifs_sb_active(inode->i_sb);
|
||
+
|
||
spin_lock(&cifs_file_list_lock);
|
||
list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
|
||
/* if readable file instance put first in list*/
|
||
@@ -293,7 +295,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
||
struct inode *inode = cifs_file->dentry->d_inode;
|
||
struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
|
||
struct cifsInodeInfo *cifsi = CIFS_I(inode);
|
||
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||
+ struct super_block *sb = inode->i_sb;
|
||
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||
struct cifsLockInfo *li, *tmp;
|
||
|
||
spin_lock(&cifs_file_list_lock);
|
||
@@ -345,6 +348,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
||
|
||
cifs_put_tlink(cifs_file->tlink);
|
||
dput(cifs_file->dentry);
|
||
+ cifs_sb_deactive(sb);
|
||
kfree(cifs_file);
|
||
}
|
||
|
||
@@ -882,7 +886,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
||
if (!buf) {
|
||
mutex_unlock(&cinode->lock_mutex);
|
||
FreeXid(xid);
|
||
- return rc;
|
||
+ return -ENOMEM;
|
||
}
|
||
|
||
for (i = 0; i < 2; i++) {
|
||
@@ -2185,7 +2189,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
|
||
unsigned long nr_segs, loff_t *poffset)
|
||
{
|
||
unsigned long nr_pages, i;
|
||
- size_t copied, len, cur_len;
|
||
+ size_t bytes, copied, len, cur_len;
|
||
ssize_t total_written = 0;
|
||
loff_t offset;
|
||
struct iov_iter it;
|
||
@@ -2236,14 +2240,45 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
|
||
|
||
save_len = cur_len;
|
||
for (i = 0; i < nr_pages; i++) {
|
||
- copied = min_t(const size_t, cur_len, PAGE_SIZE);
|
||
+ bytes = min_t(const size_t, cur_len, PAGE_SIZE);
|
||
copied = iov_iter_copy_from_user(wdata->pages[i], &it,
|
||
- 0, copied);
|
||
+ 0, bytes);
|
||
cur_len -= copied;
|
||
iov_iter_advance(&it, copied);
|
||
+ /*
|
||
+ * If we didn't copy as much as we expected, then that
|
||
+ * may mean we trod into an unmapped area. Stop copying
|
||
+ * at that point. On the next pass through the big
|
||
+ * loop, we'll likely end up getting a zero-length
|
||
+ * write and bailing out of it.
|
||
+ */
|
||
+ if (copied < bytes)
|
||
+ break;
|
||
}
|
||
cur_len = save_len - cur_len;
|
||
|
||
+ /*
|
||
+ * If we have no data to send, then that probably means that
|
||
+ * the copy above failed altogether. That's most likely because
|
||
+ * the address in the iovec was bogus. Set the rc to -EFAULT,
|
||
+ * free anything we allocated and bail out.
|
||
+ */
|
||
+ if (!cur_len) {
|
||
+ for (i = 0; i < nr_pages; i++)
|
||
+ put_page(wdata->pages[i]);
|
||
+ kfree(wdata);
|
||
+ rc = -EFAULT;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * i + 1 now represents the number of pages we actually used in
|
||
+ * the copy phase above. Bring nr_pages down to that, and free
|
||
+ * any pages that we didn't use.
|
||
+ */
|
||
+ for ( ; nr_pages > i + 1; nr_pages--)
|
||
+ put_page(wdata->pages[nr_pages - 1]);
|
||
+
|
||
wdata->sync_mode = WB_SYNC_ALL;
|
||
wdata->nr_pages = nr_pages;
|
||
wdata->offset = (__u64)offset;
|
||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
|
||
index 43944c6..8d6ac6b 100644
|
||
--- a/fs/cifs/inode.c
|
||
+++ b/fs/cifs/inode.c
|
||
@@ -1653,6 +1653,12 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
|
||
target_dentry, toName);
|
||
}
|
||
|
||
+ /* force revalidate to go get info when needed */
|
||
+ CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
|
||
+
|
||
+ source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime =
|
||
+ target_dir->i_mtime = current_fs_time(source_dir->i_sb);
|
||
+
|
||
cifs_rename_exit:
|
||
kfree(info_buf_source);
|
||
kfree(fromName);
|
||
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
|
||
index a4217f0..6406ac9 100644
|
||
--- a/fs/cifs/readdir.c
|
||
+++ b/fs/cifs/readdir.c
|
||
@@ -96,6 +96,14 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
|
||
dput(dentry);
|
||
}
|
||
|
||
+ /*
|
||
+ * If we know that the inode will need to be revalidated immediately,
|
||
+ * then don't create a new dentry for it. We'll end up doing an on
|
||
+ * the wire call either way and this spares us an invalidation.
|
||
+ */
|
||
+ if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
|
||
+ return NULL;
|
||
+
|
||
dentry = d_alloc(parent, name);
|
||
if (dentry == NULL)
|
||
return NULL;
|
||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
|
||
index b17a433..955b9c2 100644
|
||
--- a/fs/cifs/transport.c
|
||
+++ b/fs/cifs/transport.c
|
||
@@ -511,6 +511,13 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
|
||
mutex_unlock(&server->srv_mutex);
|
||
return rc;
|
||
}
|
||
+
|
||
+ /*
|
||
+ * The response to this call was already factored into the sequence
|
||
+ * number when the call went out, so we must adjust it back downward
|
||
+ * after signing here.
|
||
+ */
|
||
+ --server->sequence_number;
|
||
rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
|
||
mutex_unlock(&server->srv_mutex);
|
||
|
||
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
|
||
index 7e6c52d..c91f6d1 100644
|
||
--- a/fs/configfs/dir.c
|
||
+++ b/fs/configfs/dir.c
|
||
@@ -56,10 +56,19 @@ static void configfs_d_iput(struct dentry * dentry,
|
||
struct configfs_dirent *sd = dentry->d_fsdata;
|
||
|
||
if (sd) {
|
||
- BUG_ON(sd->s_dentry != dentry);
|
||
/* Coordinate with configfs_readdir */
|
||
spin_lock(&configfs_dirent_lock);
|
||
- sd->s_dentry = NULL;
|
||
+ /* Coordinate with configfs_attach_attr where will increase
|
||
+ * sd->s_count and update sd->s_dentry to new allocated one.
|
||
+ * Only set sd->dentry to null when this dentry is the only
|
||
+ * sd owner.
|
||
+ * If not do so, configfs_d_iput may run just after
|
||
+ * configfs_attach_attr and set sd->s_dentry to null
|
||
+ * even it's still in use.
|
||
+ */
|
||
+ if (atomic_read(&sd->s_count) <= 2)
|
||
+ sd->s_dentry = NULL;
|
||
+
|
||
spin_unlock(&configfs_dirent_lock);
|
||
configfs_put(sd);
|
||
}
|
||
@@ -426,8 +435,11 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
|
||
struct configfs_attribute * attr = sd->s_element;
|
||
int error;
|
||
|
||
+ spin_lock(&configfs_dirent_lock);
|
||
dentry->d_fsdata = configfs_get(sd);
|
||
sd->s_dentry = dentry;
|
||
+ spin_unlock(&configfs_dirent_lock);
|
||
+
|
||
error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG,
|
||
configfs_init_file);
|
||
if (error) {
|
||
diff --git a/fs/dcache.c b/fs/dcache.c
|
||
index 9d39de4..09e2eda 100644
|
||
--- a/fs/dcache.c
|
||
+++ b/fs/dcache.c
|
||
@@ -2513,7 +2513,6 @@ static int prepend_path(const struct path *path,
|
||
bool slash = false;
|
||
int error = 0;
|
||
|
||
- br_read_lock(vfsmount_lock);
|
||
while (dentry != root->dentry || vfsmnt != root->mnt) {
|
||
struct dentry * parent;
|
||
|
||
@@ -2543,8 +2542,6 @@ static int prepend_path(const struct path *path,
|
||
if (!error && !slash)
|
||
error = prepend(buffer, buflen, "/", 1);
|
||
|
||
-out:
|
||
- br_read_unlock(vfsmount_lock);
|
||
return error;
|
||
|
||
global_root:
|
||
@@ -2561,7 +2558,7 @@ static int prepend_path(const struct path *path,
|
||
error = prepend(buffer, buflen, "/", 1);
|
||
if (!error)
|
||
error = real_mount(vfsmnt)->mnt_ns ? 1 : 2;
|
||
- goto out;
|
||
+ return error;
|
||
}
|
||
|
||
/**
|
||
@@ -2588,9 +2585,11 @@ char *__d_path(const struct path *path,
|
||
int error;
|
||
|
||
prepend(&res, &buflen, "\0", 1);
|
||
+ br_read_lock(vfsmount_lock);
|
||
write_seqlock(&rename_lock);
|
||
error = prepend_path(path, root, &res, &buflen);
|
||
write_sequnlock(&rename_lock);
|
||
+ br_read_unlock(vfsmount_lock);
|
||
|
||
if (error < 0)
|
||
return ERR_PTR(error);
|
||
@@ -2607,9 +2606,11 @@ char *d_absolute_path(const struct path *path,
|
||
int error;
|
||
|
||
prepend(&res, &buflen, "\0", 1);
|
||
+ br_read_lock(vfsmount_lock);
|
||
write_seqlock(&rename_lock);
|
||
error = prepend_path(path, &root, &res, &buflen);
|
||
write_sequnlock(&rename_lock);
|
||
+ br_read_unlock(vfsmount_lock);
|
||
|
||
if (error > 1)
|
||
error = -EINVAL;
|
||
@@ -2673,11 +2674,13 @@ char *d_path(const struct path *path, char *buf, int buflen)
|
||
return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
|
||
|
||
get_fs_root(current->fs, &root);
|
||
+ br_read_lock(vfsmount_lock);
|
||
write_seqlock(&rename_lock);
|
||
error = path_with_deleted(path, &root, &res, &buflen);
|
||
+ write_sequnlock(&rename_lock);
|
||
+ br_read_unlock(vfsmount_lock);
|
||
if (error < 0)
|
||
res = ERR_PTR(error);
|
||
- write_sequnlock(&rename_lock);
|
||
path_put(&root);
|
||
return res;
|
||
}
|
||
@@ -2832,6 +2835,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
|
||
get_fs_root_and_pwd(current->fs, &root, &pwd);
|
||
|
||
error = -ENOENT;
|
||
+ br_read_lock(vfsmount_lock);
|
||
write_seqlock(&rename_lock);
|
||
if (!d_unlinked(pwd.dentry)) {
|
||
unsigned long len;
|
||
@@ -2841,6 +2845,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
|
||
prepend(&cwd, &buflen, "\0", 1);
|
||
error = prepend_path(&pwd, &root, &cwd, &buflen);
|
||
write_sequnlock(&rename_lock);
|
||
+ br_read_unlock(vfsmount_lock);
|
||
|
||
if (error < 0)
|
||
goto out;
|
||
@@ -2861,6 +2866,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
|
||
}
|
||
} else {
|
||
write_sequnlock(&rename_lock);
|
||
+ br_read_unlock(vfsmount_lock);
|
||
}
|
||
|
||
out:
|
||
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
|
||
index 10f5e0b..901c3d7 100644
|
||
--- a/fs/devpts/inode.c
|
||
+++ b/fs/devpts/inode.c
|
||
@@ -475,6 +475,7 @@ static void devpts_kill_sb(struct super_block *sb)
|
||
{
|
||
struct pts_fs_info *fsi = DEVPTS_SB(sb);
|
||
|
||
+ ida_destroy(&fsi->allocated_ptys);
|
||
kfree(fsi);
|
||
kill_litter_super(sb);
|
||
}
|
||
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
|
||
index 2333203..d28fc34 100644
|
||
--- a/fs/ecryptfs/keystore.c
|
||
+++ b/fs/ecryptfs/keystore.c
|
||
@@ -1149,7 +1149,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
|
||
struct ecryptfs_msg_ctx *msg_ctx;
|
||
struct ecryptfs_message *msg = NULL;
|
||
char *auth_tok_sig;
|
||
- char *payload;
|
||
+ char *payload = NULL;
|
||
size_t payload_len;
|
||
int rc;
|
||
|
||
@@ -1204,6 +1204,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
|
||
out:
|
||
if (msg)
|
||
kfree(msg);
|
||
+ kfree(payload);
|
||
return rc;
|
||
}
|
||
|
||
diff --git a/fs/exec.c b/fs/exec.c
|
||
index c1c7993..a4d05ce 100644
|
||
--- a/fs/exec.c
|
||
+++ b/fs/exec.c
|
||
@@ -909,11 +909,13 @@ static int de_thread(struct task_struct *tsk)
|
||
|
||
sig->notify_count = -1; /* for exit_notify() */
|
||
for (;;) {
|
||
+ threadgroup_change_begin(tsk);
|
||
write_lock_irq(&tasklist_lock);
|
||
if (likely(leader->exit_state))
|
||
break;
|
||
__set_current_state(TASK_UNINTERRUPTIBLE);
|
||
write_unlock_irq(&tasklist_lock);
|
||
+ threadgroup_change_end(tsk);
|
||
schedule();
|
||
}
|
||
|
||
@@ -969,6 +971,7 @@ static int de_thread(struct task_struct *tsk)
|
||
if (unlikely(leader->ptrace))
|
||
__wake_up_parent(leader, leader->parent);
|
||
write_unlock_irq(&tasklist_lock);
|
||
+ threadgroup_change_end(tsk);
|
||
|
||
release_task(leader);
|
||
}
|
||
@@ -2049,6 +2052,12 @@ static int __get_dumpable(unsigned long mm_flags)
|
||
return (ret >= 2) ? 2 : ret;
|
||
}
|
||
|
||
+/*
|
||
+ * This returns the actual value of the suid_dumpable flag. For things
|
||
+ * that are using this for checking for privilege transitions, it must
|
||
+ * test against SUID_DUMP_USER rather than treating it as a boolean
|
||
+ * value.
|
||
+ */
|
||
int get_dumpable(struct mm_struct *mm)
|
||
{
|
||
return __get_dumpable(mm->flags);
|
||
diff --git a/fs/exofs/ore.c b/fs/exofs/ore.c
|
||
index 1585db1a..a73bc26 100644
|
||
--- a/fs/exofs/ore.c
|
||
+++ b/fs/exofs/ore.c
|
||
@@ -103,7 +103,7 @@ int ore_verify_layout(unsigned total_comps, struct ore_layout *layout)
|
||
|
||
layout->max_io_length =
|
||
(BIO_MAX_PAGES_KMALLOC * PAGE_SIZE - layout->stripe_unit) *
|
||
- layout->group_width;
|
||
+ (layout->group_width - layout->parity);
|
||
if (layout->parity) {
|
||
unsigned stripe_length =
|
||
(layout->group_width - layout->parity) *
|
||
@@ -286,7 +286,8 @@ int ore_get_rw_state(struct ore_layout *layout, struct ore_components *oc,
|
||
if (length) {
|
||
ore_calc_stripe_info(layout, offset, length, &ios->si);
|
||
ios->length = ios->si.length;
|
||
- ios->nr_pages = (ios->length + PAGE_SIZE - 1) / PAGE_SIZE;
|
||
+ ios->nr_pages = ((ios->offset & (PAGE_SIZE - 1)) +
|
||
+ ios->length + PAGE_SIZE - 1) / PAGE_SIZE;
|
||
if (layout->parity)
|
||
_ore_post_alloc_raid_stuff(ios);
|
||
}
|
||
@@ -536,6 +537,7 @@ void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset,
|
||
u64 H = LmodS - G * T;
|
||
|
||
u32 N = div_u64(H, U);
|
||
+ u32 Nlast;
|
||
|
||
/* "H - (N * U)" is just "H % U" so it's bound to u32 */
|
||
u32 C = (u32)(H - (N * U)) / stripe_unit + G * group_width;
|
||
@@ -568,6 +570,10 @@ void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset,
|
||
si->length = T - H;
|
||
if (si->length > length)
|
||
si->length = length;
|
||
+
|
||
+ Nlast = div_u64(H + si->length + U - 1, U);
|
||
+ si->maxdevUnits = Nlast - N;
|
||
+
|
||
si->M = M;
|
||
}
|
||
EXPORT_SYMBOL(ore_calc_stripe_info);
|
||
@@ -583,13 +589,16 @@ int _ore_add_stripe_unit(struct ore_io_state *ios, unsigned *cur_pg,
|
||
int ret;
|
||
|
||
if (per_dev->bio == NULL) {
|
||
- unsigned pages_in_stripe = ios->layout->group_width *
|
||
- (ios->layout->stripe_unit / PAGE_SIZE);
|
||
- unsigned nr_pages = ios->nr_pages * ios->layout->group_width /
|
||
- (ios->layout->group_width -
|
||
- ios->layout->parity);
|
||
- unsigned bio_size = (nr_pages + pages_in_stripe) /
|
||
- ios->layout->group_width;
|
||
+ unsigned bio_size;
|
||
+
|
||
+ if (!ios->reading) {
|
||
+ bio_size = ios->si.maxdevUnits;
|
||
+ } else {
|
||
+ bio_size = (ios->si.maxdevUnits + 1) *
|
||
+ (ios->layout->group_width - ios->layout->parity) /
|
||
+ ios->layout->group_width;
|
||
+ }
|
||
+ bio_size *= (ios->layout->stripe_unit / PAGE_SIZE);
|
||
|
||
per_dev->bio = bio_kmalloc(GFP_KERNEL, bio_size);
|
||
if (unlikely(!per_dev->bio)) {
|
||
@@ -609,8 +618,12 @@ int _ore_add_stripe_unit(struct ore_io_state *ios, unsigned *cur_pg,
|
||
added_len = bio_add_pc_page(q, per_dev->bio, pages[pg],
|
||
pglen, pgbase);
|
||
if (unlikely(pglen != added_len)) {
|
||
- ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=%u\n",
|
||
- per_dev->bio->bi_vcnt);
|
||
+ /* If bi_vcnt == bi_max then this is a SW BUG */
|
||
+ ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=0x%x "
|
||
+ "bi_max=0x%x BIO_MAX=0x%x cur_len=0x%x\n",
|
||
+ per_dev->bio->bi_vcnt,
|
||
+ per_dev->bio->bi_max_vecs,
|
||
+ BIO_MAX_PAGES_KMALLOC, cur_len);
|
||
ret = -ENOMEM;
|
||
goto out;
|
||
}
|
||
@@ -1099,7 +1112,7 @@ int ore_truncate(struct ore_layout *layout, struct ore_components *oc,
|
||
size_attr->attr = g_attr_logical_length;
|
||
size_attr->attr.val_ptr = &size_attr->newsize;
|
||
|
||
- ORE_DBGMSG("trunc(0x%llx) obj_offset=0x%llx dev=%d\n",
|
||
+ ORE_DBGMSG2("trunc(0x%llx) obj_offset=0x%llx dev=%d\n",
|
||
_LLU(oc->comps->obj.id), _LLU(obj_size), i);
|
||
ret = _truncate_mirrors(ios, i * ios->layout->mirrors_p1,
|
||
&size_attr->attr);
|
||
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
|
||
index 740cad8..6a7c483 100644
|
||
--- a/fs/ext2/inode.c
|
||
+++ b/fs/ext2/inode.c
|
||
@@ -614,6 +614,8 @@ static int ext2_get_blocks(struct inode *inode,
|
||
int count = 0;
|
||
ext2_fsblk_t first_block = 0;
|
||
|
||
+ BUG_ON(maxblocks == 0);
|
||
+
|
||
depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary);
|
||
|
||
if (depth == 0)
|
||
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
|
||
index 1c33128..e98171a 100644
|
||
--- a/fs/ext2/xip.c
|
||
+++ b/fs/ext2/xip.c
|
||
@@ -35,6 +35,7 @@ __ext2_get_block(struct inode *inode, pgoff_t pgoff, int create,
|
||
int rc;
|
||
|
||
memset(&tmp, 0, sizeof(struct buffer_head));
|
||
+ tmp.b_size = 1 << inode->i_blkbits;
|
||
rc = ext2_get_block(inode, pgoff, &tmp, create);
|
||
*result = tmp.b_blocknr;
|
||
|
||
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
|
||
index cc761ad..92490e9 100644
|
||
--- a/fs/ext3/dir.c
|
||
+++ b/fs/ext3/dir.c
|
||
@@ -21,30 +21,15 @@
|
||
*
|
||
*/
|
||
|
||
+#include <linux/compat.h>
|
||
#include "ext3.h"
|
||
|
||
static unsigned char ext3_filetype_table[] = {
|
||
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
|
||
};
|
||
|
||
-static int ext3_readdir(struct file *, void *, filldir_t);
|
||
static int ext3_dx_readdir(struct file * filp,
|
||
void * dirent, filldir_t filldir);
|
||
-static int ext3_release_dir (struct inode * inode,
|
||
- struct file * filp);
|
||
-
|
||
-const struct file_operations ext3_dir_operations = {
|
||
- .llseek = generic_file_llseek,
|
||
- .read = generic_read_dir,
|
||
- .readdir = ext3_readdir, /* we take BKL. needed?*/
|
||
- .unlocked_ioctl = ext3_ioctl,
|
||
-#ifdef CONFIG_COMPAT
|
||
- .compat_ioctl = ext3_compat_ioctl,
|
||
-#endif
|
||
- .fsync = ext3_sync_file, /* BKL held */
|
||
- .release = ext3_release_dir,
|
||
-};
|
||
-
|
||
|
||
static unsigned char get_dtype(struct super_block *sb, int filetype)
|
||
{
|
||
@@ -55,6 +40,25 @@ static unsigned char get_dtype(struct super_block *sb, int filetype)
|
||
return (ext3_filetype_table[filetype]);
|
||
}
|
||
|
||
+/**
|
||
+ * Check if the given dir-inode refers to an htree-indexed directory
|
||
+ * (or a directory which chould potentially get coverted to use htree
|
||
+ * indexing).
|
||
+ *
|
||
+ * Return 1 if it is a dx dir, 0 if not
|
||
+ */
|
||
+static int is_dx_dir(struct inode *inode)
|
||
+{
|
||
+ struct super_block *sb = inode->i_sb;
|
||
+
|
||
+ if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
|
||
+ EXT3_FEATURE_COMPAT_DIR_INDEX) &&
|
||
+ ((EXT3_I(inode)->i_flags & EXT3_INDEX_FL) ||
|
||
+ ((inode->i_size >> sb->s_blocksize_bits) == 1)))
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
|
||
int ext3_check_dir_entry (const char * function, struct inode * dir,
|
||
struct ext3_dir_entry_2 * de,
|
||
@@ -94,18 +98,13 @@ static int ext3_readdir(struct file * filp,
|
||
unsigned long offset;
|
||
int i, stored;
|
||
struct ext3_dir_entry_2 *de;
|
||
- struct super_block *sb;
|
||
int err;
|
||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||
+ struct super_block *sb = inode->i_sb;
|
||
int ret = 0;
|
||
int dir_has_error = 0;
|
||
|
||
- sb = inode->i_sb;
|
||
-
|
||
- if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
|
||
- EXT3_FEATURE_COMPAT_DIR_INDEX) &&
|
||
- ((EXT3_I(inode)->i_flags & EXT3_INDEX_FL) ||
|
||
- ((inode->i_size >> sb->s_blocksize_bits) == 1))) {
|
||
+ if (is_dx_dir(inode)) {
|
||
err = ext3_dx_readdir(filp, dirent, filldir);
|
||
if (err != ERR_BAD_DX_DIR) {
|
||
ret = err;
|
||
@@ -227,22 +226,87 @@ static int ext3_readdir(struct file * filp,
|
||
return ret;
|
||
}
|
||
|
||
+static inline int is_32bit_api(void)
|
||
+{
|
||
+#ifdef CONFIG_COMPAT
|
||
+ return is_compat_task();
|
||
+#else
|
||
+ return (BITS_PER_LONG == 32);
|
||
+#endif
|
||
+}
|
||
+
|
||
/*
|
||
* These functions convert from the major/minor hash to an f_pos
|
||
- * value.
|
||
+ * value for dx directories
|
||
*
|
||
- * Currently we only use major hash numer. This is unfortunate, but
|
||
- * on 32-bit machines, the same VFS interface is used for lseek and
|
||
- * llseek, so if we use the 64 bit offset, then the 32-bit versions of
|
||
- * lseek/telldir/seekdir will blow out spectacularly, and from within
|
||
- * the ext2 low-level routine, we don't know if we're being called by
|
||
- * a 64-bit version of the system call or the 32-bit version of the
|
||
- * system call. Worse yet, NFSv2 only allows for a 32-bit readdir
|
||
- * cookie. Sigh.
|
||
+ * Upper layer (for example NFS) should specify FMODE_32BITHASH or
|
||
+ * FMODE_64BITHASH explicitly. On the other hand, we allow ext3 to be mounted
|
||
+ * directly on both 32-bit and 64-bit nodes, under such case, neither
|
||
+ * FMODE_32BITHASH nor FMODE_64BITHASH is specified.
|
||
*/
|
||
-#define hash2pos(major, minor) (major >> 1)
|
||
-#define pos2maj_hash(pos) ((pos << 1) & 0xffffffff)
|
||
-#define pos2min_hash(pos) (0)
|
||
+static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
|
||
+{
|
||
+ if ((filp->f_mode & FMODE_32BITHASH) ||
|
||
+ (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
|
||
+ return major >> 1;
|
||
+ else
|
||
+ return ((__u64)(major >> 1) << 32) | (__u64)minor;
|
||
+}
|
||
+
|
||
+static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
|
||
+{
|
||
+ if ((filp->f_mode & FMODE_32BITHASH) ||
|
||
+ (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
|
||
+ return (pos << 1) & 0xffffffff;
|
||
+ else
|
||
+ return ((pos >> 32) << 1) & 0xffffffff;
|
||
+}
|
||
+
|
||
+static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
|
||
+{
|
||
+ if ((filp->f_mode & FMODE_32BITHASH) ||
|
||
+ (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
|
||
+ return 0;
|
||
+ else
|
||
+ return pos & 0xffffffff;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Return 32- or 64-bit end-of-file for dx directories
|
||
+ */
|
||
+static inline loff_t ext3_get_htree_eof(struct file *filp)
|
||
+{
|
||
+ if ((filp->f_mode & FMODE_32BITHASH) ||
|
||
+ (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
|
||
+ return EXT3_HTREE_EOF_32BIT;
|
||
+ else
|
||
+ return EXT3_HTREE_EOF_64BIT;
|
||
+}
|
||
+
|
||
+
|
||
+/*
|
||
+ * ext3_dir_llseek() calls generic_file_llseek[_size]() to handle both
|
||
+ * non-htree and htree directories, where the "offset" is in terms
|
||
+ * of the filename hash value instead of the byte offset.
|
||
+ *
|
||
+ * Because we may return a 64-bit hash that is well beyond s_maxbytes,
|
||
+ * we need to pass the max hash as the maximum allowable offset in
|
||
+ * the htree directory case.
|
||
+ *
|
||
+ * NOTE: offsets obtained *before* ext3_set_inode_flag(dir, EXT3_INODE_INDEX)
|
||
+ * will be invalid once the directory was converted into a dx directory
|
||
+ */
|
||
+loff_t ext3_dir_llseek(struct file *file, loff_t offset, int origin)
|
||
+{
|
||
+ struct inode *inode = file->f_mapping->host;
|
||
+ int dx_dir = is_dx_dir(inode);
|
||
+
|
||
+ if (likely(dx_dir))
|
||
+ return generic_file_llseek_size(file, offset, origin,
|
||
+ ext3_get_htree_eof(file));
|
||
+ else
|
||
+ return generic_file_llseek(file, offset, origin);
|
||
+}
|
||
|
||
/*
|
||
* This structure holds the nodes of the red-black tree used to store
|
||
@@ -303,15 +367,16 @@ static void free_rb_tree_fname(struct rb_root *root)
|
||
}
|
||
|
||
|
||
-static struct dir_private_info *ext3_htree_create_dir_info(loff_t pos)
|
||
+static struct dir_private_info *ext3_htree_create_dir_info(struct file *filp,
|
||
+ loff_t pos)
|
||
{
|
||
struct dir_private_info *p;
|
||
|
||
p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL);
|
||
if (!p)
|
||
return NULL;
|
||
- p->curr_hash = pos2maj_hash(pos);
|
||
- p->curr_minor_hash = pos2min_hash(pos);
|
||
+ p->curr_hash = pos2maj_hash(filp, pos);
|
||
+ p->curr_minor_hash = pos2min_hash(filp, pos);
|
||
return p;
|
||
}
|
||
|
||
@@ -401,7 +466,7 @@ static int call_filldir(struct file * filp, void * dirent,
|
||
printk("call_filldir: called with null fname?!?\n");
|
||
return 0;
|
||
}
|
||
- curr_pos = hash2pos(fname->hash, fname->minor_hash);
|
||
+ curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
|
||
while (fname) {
|
||
error = filldir(dirent, fname->name,
|
||
fname->name_len, curr_pos,
|
||
@@ -426,13 +491,13 @@ static int ext3_dx_readdir(struct file * filp,
|
||
int ret;
|
||
|
||
if (!info) {
|
||
- info = ext3_htree_create_dir_info(filp->f_pos);
|
||
+ info = ext3_htree_create_dir_info(filp, filp->f_pos);
|
||
if (!info)
|
||
return -ENOMEM;
|
||
filp->private_data = info;
|
||
}
|
||
|
||
- if (filp->f_pos == EXT3_HTREE_EOF)
|
||
+ if (filp->f_pos == ext3_get_htree_eof(filp))
|
||
return 0; /* EOF */
|
||
|
||
/* Some one has messed with f_pos; reset the world */
|
||
@@ -440,8 +505,8 @@ static int ext3_dx_readdir(struct file * filp,
|
||
free_rb_tree_fname(&info->root);
|
||
info->curr_node = NULL;
|
||
info->extra_fname = NULL;
|
||
- info->curr_hash = pos2maj_hash(filp->f_pos);
|
||
- info->curr_minor_hash = pos2min_hash(filp->f_pos);
|
||
+ info->curr_hash = pos2maj_hash(filp, filp->f_pos);
|
||
+ info->curr_minor_hash = pos2min_hash(filp, filp->f_pos);
|
||
}
|
||
|
||
/*
|
||
@@ -473,7 +538,7 @@ static int ext3_dx_readdir(struct file * filp,
|
||
if (ret < 0)
|
||
return ret;
|
||
if (ret == 0) {
|
||
- filp->f_pos = EXT3_HTREE_EOF;
|
||
+ filp->f_pos = ext3_get_htree_eof(filp);
|
||
break;
|
||
}
|
||
info->curr_node = rb_first(&info->root);
|
||
@@ -493,7 +558,7 @@ static int ext3_dx_readdir(struct file * filp,
|
||
info->curr_minor_hash = fname->minor_hash;
|
||
} else {
|
||
if (info->next_hash == ~0) {
|
||
- filp->f_pos = EXT3_HTREE_EOF;
|
||
+ filp->f_pos = ext3_get_htree_eof(filp);
|
||
break;
|
||
}
|
||
info->curr_hash = info->next_hash;
|
||
@@ -512,3 +577,15 @@ static int ext3_release_dir (struct inode * inode, struct file * filp)
|
||
|
||
return 0;
|
||
}
|
||
+
|
||
+const struct file_operations ext3_dir_operations = {
|
||
+ .llseek = ext3_dir_llseek,
|
||
+ .read = generic_read_dir,
|
||
+ .readdir = ext3_readdir,
|
||
+ .unlocked_ioctl = ext3_ioctl,
|
||
+#ifdef CONFIG_COMPAT
|
||
+ .compat_ioctl = ext3_compat_ioctl,
|
||
+#endif
|
||
+ .fsync = ext3_sync_file,
|
||
+ .release = ext3_release_dir,
|
||
+};
|
||
diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h
|
||
index b6515fd..fe5bef7 100644
|
||
--- a/fs/ext3/ext3.h
|
||
+++ b/fs/ext3/ext3.h
|
||
@@ -920,7 +920,11 @@ struct dx_hash_info
|
||
u32 *seed;
|
||
};
|
||
|
||
-#define EXT3_HTREE_EOF 0x7fffffff
|
||
+
|
||
+/* 32 and 64 bit signed EOF for dx directories */
|
||
+#define EXT3_HTREE_EOF_32BIT ((1UL << (32 - 1)) - 1)
|
||
+#define EXT3_HTREE_EOF_64BIT ((1ULL << (64 - 1)) - 1)
|
||
+
|
||
|
||
/*
|
||
* Control parameters used by ext3_htree_next_block
|
||
diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c
|
||
index d10231d..ede315c 100644
|
||
--- a/fs/ext3/hash.c
|
||
+++ b/fs/ext3/hash.c
|
||
@@ -198,8 +198,8 @@ int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo)
|
||
return -1;
|
||
}
|
||
hash = hash & ~1;
|
||
- if (hash == (EXT3_HTREE_EOF << 1))
|
||
- hash = (EXT3_HTREE_EOF-1) << 1;
|
||
+ if (hash == (EXT3_HTREE_EOF_32BIT << 1))
|
||
+ hash = (EXT3_HTREE_EOF_32BIT - 1) << 1;
|
||
hinfo->hash = hash;
|
||
hinfo->minor_hash = minor_hash;
|
||
return 0;
|
||
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
|
||
index 0f2a2fe..f1551f0 100644
|
||
--- a/fs/ext4/ext4.h
|
||
+++ b/fs/ext4/ext4.h
|
||
@@ -751,6 +751,8 @@ do { \
|
||
if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \
|
||
(einode)->xtime.tv_sec = \
|
||
(signed)le32_to_cpu((raw_inode)->xtime); \
|
||
+ else \
|
||
+ (einode)->xtime.tv_sec = 0; \
|
||
if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \
|
||
ext4_decode_extra_time(&(einode)->xtime, \
|
||
raw_inode->xtime ## _extra); \
|
||
@@ -1678,7 +1680,7 @@ ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no)
|
||
/*
|
||
* Special error return code only used by dx_probe() and its callers.
|
||
*/
|
||
-#define ERR_BAD_DX_DIR -75000
|
||
+#define ERR_BAD_DX_DIR (-(MAX_ERRNO - 1))
|
||
|
||
void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
|
||
ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp);
|
||
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
|
||
index b0ae1f3..5b95e18 100644
|
||
--- a/fs/ext4/extents.c
|
||
+++ b/fs/ext4/extents.c
|
||
@@ -317,8 +317,10 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
|
||
{
|
||
ext4_fsblk_t block = ext4_ext_pblock(ext);
|
||
int len = ext4_ext_get_actual_len(ext);
|
||
+ ext4_lblk_t lblock = le32_to_cpu(ext->ee_block);
|
||
+ ext4_lblk_t last = lblock + len - 1;
|
||
|
||
- if (len == 0)
|
||
+ if (lblock > last)
|
||
return 0;
|
||
return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
|
||
}
|
||
@@ -344,11 +346,26 @@ static int ext4_valid_extent_entries(struct inode *inode,
|
||
if (depth == 0) {
|
||
/* leaf entries */
|
||
struct ext4_extent *ext = EXT_FIRST_EXTENT(eh);
|
||
+ struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
|
||
+ ext4_fsblk_t pblock = 0;
|
||
+ ext4_lblk_t lblock = 0;
|
||
+ ext4_lblk_t prev = 0;
|
||
+ int len = 0;
|
||
while (entries) {
|
||
if (!ext4_valid_extent(inode, ext))
|
||
return 0;
|
||
+
|
||
+ /* Check for overlapping extents */
|
||
+ lblock = le32_to_cpu(ext->ee_block);
|
||
+ len = ext4_ext_get_actual_len(ext);
|
||
+ if ((lblock <= prev) && prev) {
|
||
+ pblock = ext4_ext_pblock(ext);
|
||
+ es->s_last_error_block = cpu_to_le64(pblock);
|
||
+ return 0;
|
||
+ }
|
||
ext++;
|
||
entries--;
|
||
+ prev = lblock + len - 1;
|
||
}
|
||
} else {
|
||
struct ext4_extent_idx *ext_idx = EXT_FIRST_INDEX(eh);
|
||
@@ -653,6 +670,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
|
||
struct ext4_extent_header *eh;
|
||
struct buffer_head *bh;
|
||
short int depth, i, ppos = 0, alloc = 0;
|
||
+ int ret;
|
||
|
||
eh = ext_inode_hdr(inode);
|
||
depth = ext_depth(inode);
|
||
@@ -682,12 +700,15 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
|
||
path[ppos].p_ext = NULL;
|
||
|
||
bh = sb_getblk(inode->i_sb, path[ppos].p_block);
|
||
- if (unlikely(!bh))
|
||
+ if (unlikely(!bh)) {
|
||
+ ret = -ENOMEM;
|
||
goto err;
|
||
+ }
|
||
if (!bh_uptodate_or_lock(bh)) {
|
||
trace_ext4_ext_load_extent(inode, block,
|
||
path[ppos].p_block);
|
||
- if (bh_submit_read(bh) < 0) {
|
||
+ ret = bh_submit_read(bh);
|
||
+ if (ret < 0) {
|
||
put_bh(bh);
|
||
goto err;
|
||
}
|
||
@@ -700,13 +721,15 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
|
||
put_bh(bh);
|
||
EXT4_ERROR_INODE(inode,
|
||
"ppos %d > depth %d", ppos, depth);
|
||
+ ret = -EIO;
|
||
goto err;
|
||
}
|
||
path[ppos].p_bh = bh;
|
||
path[ppos].p_hdr = eh;
|
||
i--;
|
||
|
||
- if (need_to_validate && ext4_ext_check(inode, eh, i))
|
||
+ ret = need_to_validate ? ext4_ext_check(inode, eh, i) : 0;
|
||
+ if (ret < 0)
|
||
goto err;
|
||
}
|
||
|
||
@@ -728,7 +751,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
|
||
ext4_ext_drop_refs(path);
|
||
if (alloc)
|
||
kfree(path);
|
||
- return ERR_PTR(-EIO);
|
||
+ return ERR_PTR(ret);
|
||
}
|
||
|
||
/*
|
||
@@ -883,7 +906,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
||
}
|
||
bh = sb_getblk(inode->i_sb, newblock);
|
||
if (!bh) {
|
||
- err = -EIO;
|
||
+ err = -ENOMEM;
|
||
goto cleanup;
|
||
}
|
||
lock_buffer(bh);
|
||
@@ -955,7 +978,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
||
newblock = ablocks[--a];
|
||
bh = sb_getblk(inode->i_sb, newblock);
|
||
if (!bh) {
|
||
- err = -EIO;
|
||
+ err = -ENOMEM;
|
||
goto cleanup;
|
||
}
|
||
lock_buffer(bh);
|
||
@@ -1066,11 +1089,8 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
|
||
return err;
|
||
|
||
bh = sb_getblk(inode->i_sb, newblock);
|
||
- if (!bh) {
|
||
- err = -EIO;
|
||
- ext4_std_error(inode->i_sb, err);
|
||
- return err;
|
||
- }
|
||
+ if (!bh)
|
||
+ return -ENOMEM;
|
||
lock_buffer(bh);
|
||
|
||
err = ext4_journal_get_create_access(handle, bh);
|
||
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
|
||
index cb70f18..6199922 100644
|
||
--- a/fs/ext4/file.c
|
||
+++ b/fs/ext4/file.c
|
||
@@ -80,7 +80,7 @@ ext4_unaligned_aio(struct inode *inode, const struct iovec *iov,
|
||
size_t count = iov_length(iov, nr_segs);
|
||
loff_t final_size = pos + count;
|
||
|
||
- if (pos >= inode->i_size)
|
||
+ if (pos >= i_size_read(inode))
|
||
return 0;
|
||
|
||
if ((pos & blockmask) || (final_size & blockmask))
|
||
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
|
||
index bb6c7d8..a8d03a4 100644
|
||
--- a/fs/ext4/fsync.c
|
||
+++ b/fs/ext4/fsync.c
|
||
@@ -260,8 +260,7 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
||
if (journal->j_flags & JBD2_BARRIER &&
|
||
!jbd2_trans_will_send_data_barrier(journal, commit_tid))
|
||
needs_barrier = true;
|
||
- jbd2_log_start_commit(journal, commit_tid);
|
||
- ret = jbd2_log_wait_commit(journal, commit_tid);
|
||
+ ret = jbd2_complete_transaction(journal, commit_tid);
|
||
if (needs_barrier)
|
||
blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
|
||
out:
|
||
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
|
||
index 830e1b2..6dc6153 100644
|
||
--- a/fs/ext4/indirect.c
|
||
+++ b/fs/ext4/indirect.c
|
||
@@ -145,6 +145,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
|
||
struct super_block *sb = inode->i_sb;
|
||
Indirect *p = chain;
|
||
struct buffer_head *bh;
|
||
+ int ret = -EIO;
|
||
|
||
*err = 0;
|
||
/* i_data is not going away, no lock needed */
|
||
@@ -153,8 +154,10 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
|
||
goto no_block;
|
||
while (--depth) {
|
||
bh = sb_getblk(sb, le32_to_cpu(p->key));
|
||
- if (unlikely(!bh))
|
||
+ if (unlikely(!bh)) {
|
||
+ ret = -ENOMEM;
|
||
goto failure;
|
||
+ }
|
||
|
||
if (!bh_uptodate_or_lock(bh)) {
|
||
if (bh_submit_read(bh) < 0) {
|
||
@@ -176,7 +179,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
|
||
return NULL;
|
||
|
||
failure:
|
||
- *err = -EIO;
|
||
+ *err = ret;
|
||
no_block:
|
||
return p;
|
||
}
|
||
@@ -470,7 +473,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
|
||
*/
|
||
bh = sb_getblk(inode->i_sb, new_blocks[n-1]);
|
||
if (unlikely(!bh)) {
|
||
- err = -EIO;
|
||
+ err = -ENOMEM;
|
||
goto failed;
|
||
}
|
||
|
||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
|
||
index 755950c..bb5fd6b 100644
|
||
--- a/fs/ext4/inode.c
|
||
+++ b/fs/ext4/inode.c
|
||
@@ -37,6 +37,7 @@
|
||
#include <linux/printk.h>
|
||
#include <linux/slab.h>
|
||
#include <linux/ratelimit.h>
|
||
+#include <linux/bitops.h>
|
||
|
||
#include "ext4_jbd2.h"
|
||
#include "xattr.h"
|
||
@@ -149,8 +150,7 @@ void ext4_evict_inode(struct inode *inode)
|
||
journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
|
||
tid_t commit_tid = EXT4_I(inode)->i_datasync_tid;
|
||
|
||
- jbd2_log_start_commit(journal, commit_tid);
|
||
- jbd2_log_wait_commit(journal, commit_tid);
|
||
+ jbd2_complete_transaction(journal, commit_tid);
|
||
filemap_write_and_wait(&inode->i_data);
|
||
}
|
||
truncate_inode_pages(&inode->i_data, 0);
|
||
@@ -664,7 +664,7 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
|
||
|
||
bh = sb_getblk(inode->i_sb, map.m_pblk);
|
||
if (!bh) {
|
||
- *errp = -EIO;
|
||
+ *errp = -ENOMEM;
|
||
return NULL;
|
||
}
|
||
if (map.m_flags & EXT4_MAP_NEW) {
|
||
@@ -2801,9 +2801,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
|
||
if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
|
||
ext4_free_io_end(io_end);
|
||
out:
|
||
+ inode_dio_done(inode);
|
||
if (is_async)
|
||
aio_complete(iocb, ret, 0);
|
||
- inode_dio_done(inode);
|
||
return;
|
||
}
|
||
|
||
@@ -3462,11 +3462,8 @@ static int __ext4_get_inode_loc(struct inode *inode,
|
||
iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb);
|
||
|
||
bh = sb_getblk(sb, block);
|
||
- if (!bh) {
|
||
- EXT4_ERROR_INODE_BLOCK(inode, block,
|
||
- "unable to read itable block");
|
||
- return -EIO;
|
||
- }
|
||
+ if (!bh)
|
||
+ return -ENOMEM;
|
||
if (!buffer_uptodate(bh)) {
|
||
lock_buffer(bh);
|
||
|
||
@@ -3584,18 +3581,20 @@ int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc)
|
||
void ext4_set_inode_flags(struct inode *inode)
|
||
{
|
||
unsigned int flags = EXT4_I(inode)->i_flags;
|
||
+ unsigned int new_fl = 0;
|
||
|
||
- inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
|
||
if (flags & EXT4_SYNC_FL)
|
||
- inode->i_flags |= S_SYNC;
|
||
+ new_fl |= S_SYNC;
|
||
if (flags & EXT4_APPEND_FL)
|
||
- inode->i_flags |= S_APPEND;
|
||
+ new_fl |= S_APPEND;
|
||
if (flags & EXT4_IMMUTABLE_FL)
|
||
- inode->i_flags |= S_IMMUTABLE;
|
||
+ new_fl |= S_IMMUTABLE;
|
||
if (flags & EXT4_NOATIME_FL)
|
||
- inode->i_flags |= S_NOATIME;
|
||
+ new_fl |= S_NOATIME;
|
||
if (flags & EXT4_DIRSYNC_FL)
|
||
- inode->i_flags |= S_DIRSYNC;
|
||
+ new_fl |= S_DIRSYNC;
|
||
+ set_mask_bits(&inode->i_flags,
|
||
+ S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl);
|
||
}
|
||
|
||
/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
|
||
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
|
||
index a986d3e..fd73b2d 100644
|
||
--- a/fs/ext4/mballoc.c
|
||
+++ b/fs/ext4/mballoc.c
|
||
@@ -3016,7 +3016,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
|
||
}
|
||
BUG_ON(start + size <= ac->ac_o_ex.fe_logical &&
|
||
start > ac->ac_o_ex.fe_logical);
|
||
- BUG_ON(size <= 0 || size > EXT4_CLUSTERS_PER_GROUP(ac->ac_sb));
|
||
+ BUG_ON(size <= 0 || size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb));
|
||
|
||
/* now prepare goal request */
|
||
|
||
@@ -3327,6 +3327,9 @@ static void ext4_mb_pa_callback(struct rcu_head *head)
|
||
{
|
||
struct ext4_prealloc_space *pa;
|
||
pa = container_of(head, struct ext4_prealloc_space, u.pa_rcu);
|
||
+
|
||
+ BUG_ON(atomic_read(&pa->pa_count));
|
||
+ BUG_ON(pa->pa_deleted == 0);
|
||
kmem_cache_free(ext4_pspace_cachep, pa);
|
||
}
|
||
|
||
@@ -3340,11 +3343,13 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
|
||
ext4_group_t grp;
|
||
ext4_fsblk_t grp_blk;
|
||
|
||
- if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0)
|
||
- return;
|
||
-
|
||
/* in this short window concurrent discard can set pa_deleted */
|
||
spin_lock(&pa->pa_lock);
|
||
+ if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0) {
|
||
+ spin_unlock(&pa->pa_lock);
|
||
+ return;
|
||
+ }
|
||
+
|
||
if (pa->pa_deleted == 1) {
|
||
spin_unlock(&pa->pa_lock);
|
||
return;
|
||
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c
|
||
index ed6548d..444b701 100644
|
||
--- a/fs/ext4/mmp.c
|
||
+++ b/fs/ext4/mmp.c
|
||
@@ -41,6 +41,8 @@ static int read_mmp_block(struct super_block *sb, struct buffer_head **bh,
|
||
* is not blocked in the elevator. */
|
||
if (!*bh)
|
||
*bh = sb_getblk(sb, mmp_block);
|
||
+ if (!*bh)
|
||
+ return -ENOMEM;
|
||
if (*bh) {
|
||
get_bh(*bh);
|
||
lock_buffer(*bh);
|
||
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
|
||
index b8a5e9e..1a3f19a 100644
|
||
--- a/fs/ext4/namei.c
|
||
+++ b/fs/ext4/namei.c
|
||
@@ -861,7 +861,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
|
||
buffer */
|
||
int num = 0;
|
||
ext4_lblk_t nblocks;
|
||
- int i, err;
|
||
+ int i, err = 0;
|
||
int namelen;
|
||
|
||
*res_dir = NULL;
|
||
@@ -886,7 +886,11 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
|
||
* return. Otherwise, fall back to doing a search the
|
||
* old fashioned way.
|
||
*/
|
||
- if (bh || (err != ERR_BAD_DX_DIR))
|
||
+ if (err == -ENOENT)
|
||
+ return NULL;
|
||
+ if (err && err != ERR_BAD_DX_DIR)
|
||
+ return ERR_PTR(err);
|
||
+ if (bh)
|
||
return bh;
|
||
dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, "
|
||
"falling back\n"));
|
||
@@ -917,6 +921,11 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
|
||
}
|
||
num++;
|
||
bh = ext4_getblk(NULL, dir, b++, 0, &err);
|
||
+ if (unlikely(err)) {
|
||
+ if (ra_max == 0)
|
||
+ return ERR_PTR(err);
|
||
+ break;
|
||
+ }
|
||
bh_use[ra_max] = bh;
|
||
if (bh)
|
||
ll_rw_block(READ | REQ_META | REQ_PRIO,
|
||
@@ -1026,6 +1035,8 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru
|
||
return ERR_PTR(-ENAMETOOLONG);
|
||
|
||
bh = ext4_find_entry(dir, &dentry->d_name, &de);
|
||
+ if (IS_ERR(bh))
|
||
+ return (struct dentry *) bh;
|
||
inode = NULL;
|
||
if (bh) {
|
||
__u32 ino = le32_to_cpu(de->inode);
|
||
@@ -1063,6 +1074,8 @@ struct dentry *ext4_get_parent(struct dentry *child)
|
||
struct buffer_head *bh;
|
||
|
||
bh = ext4_find_entry(child->d_inode, &dotdot, &de);
|
||
+ if (IS_ERR(bh))
|
||
+ return (struct dentry *) bh;
|
||
if (!bh)
|
||
return ERR_PTR(-ENOENT);
|
||
ino = le32_to_cpu(de->inode);
|
||
@@ -2143,6 +2156,8 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
|
||
|
||
retval = -ENOENT;
|
||
bh = ext4_find_entry(dir, &dentry->d_name, &de);
|
||
+ if (IS_ERR(bh))
|
||
+ return PTR_ERR(bh);
|
||
if (!bh)
|
||
goto end_rmdir;
|
||
|
||
@@ -2208,6 +2223,8 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
|
||
|
||
retval = -ENOENT;
|
||
bh = ext4_find_entry(dir, &dentry->d_name, &de);
|
||
+ if (IS_ERR(bh))
|
||
+ return PTR_ERR(bh);
|
||
if (!bh)
|
||
goto end_unlink;
|
||
|
||
@@ -2424,6 +2441,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||
ext4_handle_sync(handle);
|
||
|
||
old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de);
|
||
+ if (IS_ERR(old_bh))
|
||
+ return PTR_ERR(old_bh);
|
||
/*
|
||
* Check for inode number is _not_ due to possible IO errors.
|
||
* We might rmdir the source, keep it as pwd of some process
|
||
@@ -2437,6 +2456,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||
|
||
new_inode = new_dentry->d_inode;
|
||
new_bh = ext4_find_entry(new_dir, &new_dentry->d_name, &new_de);
|
||
+ if (IS_ERR(new_bh)) {
|
||
+ retval = PTR_ERR(new_bh);
|
||
+ new_bh = NULL;
|
||
+ goto end_rename;
|
||
+ }
|
||
if (new_bh) {
|
||
if (!new_inode) {
|
||
brelse(new_bh);
|
||
@@ -2515,7 +2539,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||
struct ext4_dir_entry_2 *old_de2;
|
||
|
||
old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de2);
|
||
- if (old_bh2) {
|
||
+ if (IS_ERR(old_bh2)) {
|
||
+ retval = PTR_ERR(old_bh2);
|
||
+ } else if (old_bh2) {
|
||
retval = ext4_delete_entry(handle, old_dir,
|
||
old_de2, old_bh2);
|
||
brelse(old_bh2);
|
||
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
|
||
index dcdeef1..6822ad7 100644
|
||
--- a/fs/ext4/page-io.c
|
||
+++ b/fs/ext4/page-io.c
|
||
@@ -107,14 +107,13 @@ int ext4_end_io_nolock(ext4_io_end_t *io)
|
||
inode->i_ino, offset, size, ret);
|
||
}
|
||
|
||
- if (io->iocb)
|
||
- aio_complete(io->iocb, io->result, 0);
|
||
-
|
||
- if (io->flag & EXT4_IO_END_DIRECT)
|
||
- inode_dio_done(inode);
|
||
/* Wake up anyone waiting on unwritten extent conversion */
|
||
if (atomic_dec_and_test(&EXT4_I(inode)->i_aiodio_unwritten))
|
||
wake_up_all(ext4_ioend_wq(io->inode));
|
||
+ if (io->flag & EXT4_IO_END_DIRECT)
|
||
+ inode_dio_done(inode);
|
||
+ if (io->iocb)
|
||
+ aio_complete(io->iocb, io->result, 0);
|
||
return ret;
|
||
}
|
||
|
||
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
|
||
index c299dde..28cc353 100644
|
||
--- a/fs/ext4/resize.c
|
||
+++ b/fs/ext4/resize.c
|
||
@@ -315,7 +315,7 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
|
||
|
||
bh = sb_getblk(sb, blk);
|
||
if (!bh)
|
||
- return ERR_PTR(-EIO);
|
||
+ return ERR_PTR(-ENOMEM);
|
||
if ((err = ext4_journal_get_write_access(handle, bh))) {
|
||
brelse(bh);
|
||
bh = ERR_PTR(err);
|
||
@@ -377,7 +377,7 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
|
||
start = ext4_group_first_block_no(sb, group);
|
||
group -= flex_gd->groups[0].group;
|
||
|
||
- count2 = sb->s_blocksize * 8 - (block - start);
|
||
+ count2 = EXT4_BLOCKS_PER_GROUP(sb) - (block - start);
|
||
if (count2 > count)
|
||
count2 = count;
|
||
|
||
@@ -392,7 +392,7 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
|
||
|
||
bh = sb_getblk(sb, flex_gd->groups[group].block_bitmap);
|
||
if (!bh)
|
||
- return -EIO;
|
||
+ return -ENOMEM;
|
||
|
||
err = ext4_journal_get_write_access(handle, bh);
|
||
if (err)
|
||
@@ -470,7 +470,7 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
|
||
|
||
gdb = sb_getblk(sb, block);
|
||
if (!gdb) {
|
||
- err = -EIO;
|
||
+ err = -ENOMEM;
|
||
goto out;
|
||
}
|
||
|
||
@@ -528,6 +528,7 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
|
||
bh = bclean(handle, sb, block);
|
||
if (IS_ERR(bh)) {
|
||
err = PTR_ERR(bh);
|
||
+ bh = NULL;
|
||
goto out;
|
||
}
|
||
if (ext4_bg_has_super(sb, group)) {
|
||
@@ -556,6 +557,7 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
|
||
bh = bclean(handle, sb, block);
|
||
if (IS_ERR(bh)) {
|
||
err = PTR_ERR(bh);
|
||
+ bh = NULL;
|
||
goto out;
|
||
}
|
||
|
||
@@ -991,7 +993,7 @@ static void update_backups(struct super_block *sb,
|
||
|
||
bh = sb_getblk(sb, group * bpg + blk_off);
|
||
if (!bh) {
|
||
- err = -EIO;
|
||
+ err = -ENOMEM;
|
||
break;
|
||
}
|
||
ext4_debug("update metadata backup %#04lx\n",
|
||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
|
||
index a3c9fa4..230204c 100644
|
||
--- a/fs/ext4/super.c
|
||
+++ b/fs/ext4/super.c
|
||
@@ -2632,10 +2632,11 @@ static void print_daily_error_info(unsigned long arg)
|
||
es = sbi->s_es;
|
||
|
||
if (es->s_error_count)
|
||
- ext4_msg(sb, KERN_NOTICE, "error count: %u",
|
||
+ /* fsck newer than v1.41.13 is needed to clean this condition. */
|
||
+ ext4_msg(sb, KERN_NOTICE, "error count since last fsck: %u",
|
||
le32_to_cpu(es->s_error_count));
|
||
if (es->s_first_error_time) {
|
||
- printk(KERN_NOTICE "EXT4-fs (%s): initial error at %u: %.*s:%d",
|
||
+ printk(KERN_NOTICE "EXT4-fs (%s): initial error at time %u: %.*s:%d",
|
||
sb->s_id, le32_to_cpu(es->s_first_error_time),
|
||
(int) sizeof(es->s_first_error_func),
|
||
es->s_first_error_func,
|
||
@@ -2649,7 +2650,7 @@ static void print_daily_error_info(unsigned long arg)
|
||
printk("\n");
|
||
}
|
||
if (es->s_last_error_time) {
|
||
- printk(KERN_NOTICE "EXT4-fs (%s): last error at %u: %.*s:%d",
|
||
+ printk(KERN_NOTICE "EXT4-fs (%s): last error at time %u: %.*s:%d",
|
||
sb->s_id, le32_to_cpu(es->s_last_error_time),
|
||
(int) sizeof(es->s_last_error_func),
|
||
es->s_last_error_func,
|
||
@@ -3413,16 +3414,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||
for (i = 0; i < 4; i++)
|
||
sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
|
||
sbi->s_def_hash_version = es->s_def_hash_version;
|
||
- i = le32_to_cpu(es->s_flags);
|
||
- if (i & EXT2_FLAGS_UNSIGNED_HASH)
|
||
- sbi->s_hash_unsigned = 3;
|
||
- else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
|
||
+ if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
|
||
+ i = le32_to_cpu(es->s_flags);
|
||
+ if (i & EXT2_FLAGS_UNSIGNED_HASH)
|
||
+ sbi->s_hash_unsigned = 3;
|
||
+ else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
|
||
#ifdef __CHAR_UNSIGNED__
|
||
- es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
|
||
- sbi->s_hash_unsigned = 3;
|
||
+ if (!(sb->s_flags & MS_RDONLY))
|
||
+ es->s_flags |=
|
||
+ cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
|
||
+ sbi->s_hash_unsigned = 3;
|
||
#else
|
||
- es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
|
||
+ if (!(sb->s_flags & MS_RDONLY))
|
||
+ es->s_flags |=
|
||
+ cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
|
||
#endif
|
||
+ }
|
||
}
|
||
|
||
/* Handle clustersize */
|
||
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
|
||
index b1aa7fd..5743e9d 100644
|
||
--- a/fs/ext4/xattr.c
|
||
+++ b/fs/ext4/xattr.c
|
||
@@ -840,16 +840,17 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
|
||
|
||
new_bh = sb_getblk(sb, block);
|
||
if (!new_bh) {
|
||
+ error = -ENOMEM;
|
||
getblk_failed:
|
||
ext4_free_blocks(handle, inode, NULL, block, 1,
|
||
EXT4_FREE_BLOCKS_METADATA);
|
||
- error = -EIO;
|
||
goto cleanup;
|
||
}
|
||
lock_buffer(new_bh);
|
||
error = ext4_journal_get_create_access(handle, new_bh);
|
||
if (error) {
|
||
unlock_buffer(new_bh);
|
||
+ error = -EIO;
|
||
goto getblk_failed;
|
||
}
|
||
memcpy(new_bh->b_data, s->base, new_bh->b_size);
|
||
@@ -1270,6 +1271,7 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
|
||
new_extra_isize = s_min_extra_isize;
|
||
kfree(is); is = NULL;
|
||
kfree(bs); bs = NULL;
|
||
+ brelse(bh);
|
||
goto retry;
|
||
}
|
||
error = -1;
|
||
diff --git a/fs/file.c b/fs/file.c
|
||
index c65dec1..ba6a6ec 100644
|
||
--- a/fs/file.c
|
||
+++ b/fs/file.c
|
||
@@ -47,7 +47,7 @@ static void *alloc_fdmem(size_t size)
|
||
* vmalloc() if the allocation size will be considered "large" by the VM.
|
||
*/
|
||
if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
|
||
- void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN);
|
||
+ void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY);
|
||
if (data != NULL)
|
||
return data;
|
||
}
|
||
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
|
||
index 373b251..f31c136 100644
|
||
--- a/fs/fuse/dir.c
|
||
+++ b/fs/fuse/dir.c
|
||
@@ -1103,6 +1103,8 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
|
||
return -EIO;
|
||
if (reclen > nbytes)
|
||
break;
|
||
+ if (memchr(dirent->name, '/', dirent->namelen) != NULL)
|
||
+ return -EIO;
|
||
|
||
over = filldir(dstbuf, dirent->name, dirent->namelen,
|
||
file->f_pos, dirent->ino, dirent->type);
|
||
@@ -1346,6 +1348,7 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
|
||
{
|
||
struct inode *inode = entry->d_inode;
|
||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||
+ struct fuse_inode *fi = get_fuse_inode(inode);
|
||
struct fuse_req *req;
|
||
struct fuse_setattr_in inarg;
|
||
struct fuse_attr_out outarg;
|
||
@@ -1376,8 +1379,10 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
|
||
if (IS_ERR(req))
|
||
return PTR_ERR(req);
|
||
|
||
- if (is_truncate)
|
||
+ if (is_truncate) {
|
||
fuse_set_nowrite(inode);
|
||
+ set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
|
||
+ }
|
||
|
||
memset(&inarg, 0, sizeof(inarg));
|
||
memset(&outarg, 0, sizeof(outarg));
|
||
@@ -1439,12 +1444,14 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
|
||
invalidate_inode_pages2(inode->i_mapping);
|
||
}
|
||
|
||
+ clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
|
||
return 0;
|
||
|
||
error:
|
||
if (is_truncate)
|
||
fuse_release_nowrite(inode);
|
||
|
||
+ clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
|
||
return err;
|
||
}
|
||
|
||
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
|
||
index 70651f1..6f6e5d0 100644
|
||
--- a/fs/fuse/file.c
|
||
+++ b/fs/fuse/file.c
|
||
@@ -515,7 +515,8 @@ static void fuse_read_update_size(struct inode *inode, loff_t size,
|
||
struct fuse_inode *fi = get_fuse_inode(inode);
|
||
|
||
spin_lock(&fc->lock);
|
||
- if (attr_ver == fi->attr_version && size < inode->i_size) {
|
||
+ if (attr_ver == fi->attr_version && size < inode->i_size &&
|
||
+ !test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {
|
||
fi->attr_version = ++fc->attr_version;
|
||
i_size_write(inode, size);
|
||
}
|
||
@@ -915,12 +916,16 @@ static ssize_t fuse_perform_write(struct file *file,
|
||
{
|
||
struct inode *inode = mapping->host;
|
||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||
+ struct fuse_inode *fi = get_fuse_inode(inode);
|
||
int err = 0;
|
||
ssize_t res = 0;
|
||
|
||
if (is_bad_inode(inode))
|
||
return -EIO;
|
||
|
||
+ if (inode->i_size < pos + iov_iter_count(ii))
|
||
+ set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
|
||
+
|
||
do {
|
||
struct fuse_req *req;
|
||
ssize_t count;
|
||
@@ -955,6 +960,7 @@ static ssize_t fuse_perform_write(struct file *file,
|
||
if (res > 0)
|
||
fuse_write_update_size(inode, pos);
|
||
|
||
+ clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
|
||
fuse_invalidate_attr(inode);
|
||
|
||
return res > 0 ? res : err;
|
||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
|
||
index d181926..81b96c5 100644
|
||
--- a/fs/fuse/fuse_i.h
|
||
+++ b/fs/fuse/fuse_i.h
|
||
@@ -103,6 +103,15 @@ struct fuse_inode {
|
||
|
||
/** List of writepage requestst (pending or sent) */
|
||
struct list_head writepages;
|
||
+
|
||
+ /** Miscellaneous bits describing inode state */
|
||
+ unsigned long state;
|
||
+};
|
||
+
|
||
+/** FUSE inode state bits */
|
||
+enum {
|
||
+ /** An operation changing file size is in progress */
|
||
+ FUSE_I_SIZE_UNSTABLE,
|
||
};
|
||
|
||
struct fuse_conn;
|
||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
|
||
index a59cf5e..a5c8b34 100644
|
||
--- a/fs/fuse/inode.c
|
||
+++ b/fs/fuse/inode.c
|
||
@@ -92,6 +92,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
|
||
fi->attr_version = 0;
|
||
fi->writectr = 0;
|
||
fi->orig_ino = 0;
|
||
+ fi->state = 0;
|
||
INIT_LIST_HEAD(&fi->write_files);
|
||
INIT_LIST_HEAD(&fi->queued_writes);
|
||
INIT_LIST_HEAD(&fi->writepages);
|
||
@@ -199,7 +200,8 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
|
||
loff_t oldsize;
|
||
|
||
spin_lock(&fc->lock);
|
||
- if (attr_version != 0 && fi->attr_version > attr_version) {
|
||
+ if ((attr_version != 0 && fi->attr_version > attr_version) ||
|
||
+ test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {
|
||
spin_unlock(&fc->lock);
|
||
return;
|
||
}
|
||
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
|
||
index 9b2ff0e8..40bd999 100644
|
||
--- a/fs/gfs2/aops.c
|
||
+++ b/fs/gfs2/aops.c
|
||
@@ -1012,6 +1012,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
|
||
{
|
||
struct file *file = iocb->ki_filp;
|
||
struct inode *inode = file->f_mapping->host;
|
||
+ struct address_space *mapping = inode->i_mapping;
|
||
struct gfs2_inode *ip = GFS2_I(inode);
|
||
struct gfs2_holder gh;
|
||
int rv;
|
||
@@ -1032,6 +1033,35 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
|
||
if (rv != 1)
|
||
goto out; /* dio not valid, fall back to buffered i/o */
|
||
|
||
+ /*
|
||
+ * Now since we are holding a deferred (CW) lock at this point, you
|
||
+ * might be wondering why this is ever needed. There is a case however
|
||
+ * where we've granted a deferred local lock against a cached exclusive
|
||
+ * glock. That is ok provided all granted local locks are deferred, but
|
||
+ * it also means that it is possible to encounter pages which are
|
||
+ * cached and possibly also mapped. So here we check for that and sort
|
||
+ * them out ahead of the dio. The glock state machine will take care of
|
||
+ * everything else.
|
||
+ *
|
||
+ * If in fact the cached glock state (gl->gl_state) is deferred (CW) in
|
||
+ * the first place, mapping->nr_pages will always be zero.
|
||
+ */
|
||
+ if (mapping->nrpages) {
|
||
+ loff_t lstart = offset & (PAGE_CACHE_SIZE - 1);
|
||
+ loff_t len = iov_length(iov, nr_segs);
|
||
+ loff_t end = PAGE_ALIGN(offset + len) - 1;
|
||
+
|
||
+ rv = 0;
|
||
+ if (len == 0)
|
||
+ goto out;
|
||
+ if (test_and_clear_bit(GIF_SW_PAGED, &ip->i_flags))
|
||
+ unmap_shared_mapping_range(ip->i_inode.i_mapping, offset, len);
|
||
+ rv = filemap_write_and_wait_range(mapping, lstart, end);
|
||
+ if (rv)
|
||
+ return rv;
|
||
+ truncate_inode_pages_range(mapping, lstart, end);
|
||
+ }
|
||
+
|
||
rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
|
||
offset, nr_segs, gfs2_get_block_direct,
|
||
NULL, NULL, 0);
|
||
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
|
||
index 6f3a18f..c0c529d 100644
|
||
--- a/fs/gfs2/ops_fstype.c
|
||
+++ b/fs/gfs2/ops_fstype.c
|
||
@@ -1298,8 +1298,18 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
|
||
if (IS_ERR(s))
|
||
goto error_bdev;
|
||
|
||
- if (s->s_root)
|
||
+ if (s->s_root) {
|
||
+ /*
|
||
+ * s_umount nests inside bd_mutex during
|
||
+ * __invalidate_device(). blkdev_put() acquires
|
||
+ * bd_mutex and can't be called under s_umount. Drop
|
||
+ * s_umount temporarily. This is safe as we're
|
||
+ * holding an active reference.
|
||
+ */
|
||
+ up_write(&s->s_umount);
|
||
blkdev_put(bdev, mode);
|
||
+ down_write(&s->s_umount);
|
||
+ }
|
||
|
||
memset(&args, 0, sizeof(args));
|
||
args.ar_quota = GFS2_QUOTA_DEFAULT;
|
||
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
|
||
index 2fa0089..46549c7 100644
|
||
--- a/fs/hpfs/dir.c
|
||
+++ b/fs/hpfs/dir.c
|
||
@@ -33,25 +33,27 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
|
||
if (whence == SEEK_DATA || whence == SEEK_HOLE)
|
||
return -EINVAL;
|
||
|
||
+ mutex_lock(&i->i_mutex);
|
||
hpfs_lock(s);
|
||
|
||
/*printk("dir lseek\n");*/
|
||
if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
|
||
- mutex_lock(&i->i_mutex);
|
||
pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1;
|
||
while (pos != new_off) {
|
||
if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
|
||
else goto fail;
|
||
if (pos == 12) goto fail;
|
||
}
|
||
- mutex_unlock(&i->i_mutex);
|
||
+ hpfs_add_pos(i, &filp->f_pos);
|
||
ok:
|
||
+ filp->f_pos = new_off;
|
||
hpfs_unlock(s);
|
||
- return filp->f_pos = new_off;
|
||
-fail:
|
||
mutex_unlock(&i->i_mutex);
|
||
+ return new_off;
|
||
+fail:
|
||
/*printk("illegal lseek: %016llx\n", new_off);*/
|
||
hpfs_unlock(s);
|
||
+ mutex_unlock(&i->i_mutex);
|
||
return -ESPIPE;
|
||
}
|
||
|
||
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
|
||
index 89d2a58..5ecfffe 100644
|
||
--- a/fs/hpfs/file.c
|
||
+++ b/fs/hpfs/file.c
|
||
@@ -116,9 +116,12 @@ static int hpfs_write_begin(struct file *file, struct address_space *mapping,
|
||
hpfs_get_block,
|
||
&hpfs_i(mapping->host)->mmu_private);
|
||
if (unlikely(ret)) {
|
||
- loff_t isize = mapping->host->i_size;
|
||
+ loff_t isize;
|
||
+ hpfs_lock(mapping->host->i_sb);
|
||
+ isize = mapping->host->i_size;
|
||
if (pos + len > isize)
|
||
vmtruncate(mapping->host, isize);
|
||
+ hpfs_unlock(mapping->host->i_sb);
|
||
}
|
||
|
||
return ret;
|
||
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
|
||
index e92a342..e379b87 100644
|
||
--- a/fs/isofs/inode.c
|
||
+++ b/fs/isofs/inode.c
|
||
@@ -68,7 +68,7 @@ static void isofs_put_super(struct super_block *sb)
|
||
return;
|
||
}
|
||
|
||
-static int isofs_read_inode(struct inode *);
|
||
+static int isofs_read_inode(struct inode *, int relocated);
|
||
static int isofs_statfs (struct dentry *, struct kstatfs *);
|
||
|
||
static struct kmem_cache *isofs_inode_cachep;
|
||
@@ -1264,7 +1264,7 @@ static int isofs_read_level3_size(struct inode *inode)
|
||
goto out;
|
||
}
|
||
|
||
-static int isofs_read_inode(struct inode *inode)
|
||
+static int isofs_read_inode(struct inode *inode, int relocated)
|
||
{
|
||
struct super_block *sb = inode->i_sb;
|
||
struct isofs_sb_info *sbi = ISOFS_SB(sb);
|
||
@@ -1409,7 +1409,7 @@ static int isofs_read_inode(struct inode *inode)
|
||
*/
|
||
|
||
if (!high_sierra) {
|
||
- parse_rock_ridge_inode(de, inode);
|
||
+ parse_rock_ridge_inode(de, inode, relocated);
|
||
/* if we want uid/gid set, override the rock ridge setting */
|
||
if (sbi->s_uid_set)
|
||
inode->i_uid = sbi->s_uid;
|
||
@@ -1488,9 +1488,10 @@ static int isofs_iget5_set(struct inode *ino, void *data)
|
||
* offset that point to the underlying meta-data for the inode. The
|
||
* code below is otherwise similar to the iget() code in
|
||
* include/linux/fs.h */
|
||
-struct inode *isofs_iget(struct super_block *sb,
|
||
- unsigned long block,
|
||
- unsigned long offset)
|
||
+struct inode *__isofs_iget(struct super_block *sb,
|
||
+ unsigned long block,
|
||
+ unsigned long offset,
|
||
+ int relocated)
|
||
{
|
||
unsigned long hashval;
|
||
struct inode *inode;
|
||
@@ -1512,7 +1513,7 @@ struct inode *isofs_iget(struct super_block *sb,
|
||
return ERR_PTR(-ENOMEM);
|
||
|
||
if (inode->i_state & I_NEW) {
|
||
- ret = isofs_read_inode(inode);
|
||
+ ret = isofs_read_inode(inode, relocated);
|
||
if (ret < 0) {
|
||
iget_failed(inode);
|
||
inode = ERR_PTR(ret);
|
||
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
|
||
index 0e73f63..50cd583 100644
|
||
--- a/fs/isofs/isofs.h
|
||
+++ b/fs/isofs/isofs.h
|
||
@@ -107,7 +107,7 @@ extern int iso_date(char *, int);
|
||
|
||
struct inode; /* To make gcc happy */
|
||
|
||
-extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
|
||
+extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *, int relocated);
|
||
extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
|
||
extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
|
||
|
||
@@ -118,9 +118,24 @@ extern struct dentry *isofs_lookup(struct inode *, struct dentry *, struct namei
|
||
extern struct buffer_head *isofs_bread(struct inode *, sector_t);
|
||
extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
|
||
|
||
-extern struct inode *isofs_iget(struct super_block *sb,
|
||
- unsigned long block,
|
||
- unsigned long offset);
|
||
+struct inode *__isofs_iget(struct super_block *sb,
|
||
+ unsigned long block,
|
||
+ unsigned long offset,
|
||
+ int relocated);
|
||
+
|
||
+static inline struct inode *isofs_iget(struct super_block *sb,
|
||
+ unsigned long block,
|
||
+ unsigned long offset)
|
||
+{
|
||
+ return __isofs_iget(sb, block, offset, 0);
|
||
+}
|
||
+
|
||
+static inline struct inode *isofs_iget_reloc(struct super_block *sb,
|
||
+ unsigned long block,
|
||
+ unsigned long offset)
|
||
+{
|
||
+ return __isofs_iget(sb, block, offset, 1);
|
||
+}
|
||
|
||
/* Because the inode number is no longer relevant to finding the
|
||
* underlying meta-data for an inode, we are free to choose a more
|
||
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
|
||
index 70e79d0..ee62cc0 100644
|
||
--- a/fs/isofs/rock.c
|
||
+++ b/fs/isofs/rock.c
|
||
@@ -288,12 +288,16 @@ int get_rock_ridge_filename(struct iso_directory_record *de,
|
||
goto out;
|
||
}
|
||
|
||
+#define RR_REGARD_XA 1
|
||
+#define RR_RELOC_DE 2
|
||
+
|
||
static int
|
||
parse_rock_ridge_inode_internal(struct iso_directory_record *de,
|
||
- struct inode *inode, int regard_xa)
|
||
+ struct inode *inode, int flags)
|
||
{
|
||
int symlink_len = 0;
|
||
int cnt, sig;
|
||
+ unsigned int reloc_block;
|
||
struct inode *reloc;
|
||
struct rock_ridge *rr;
|
||
int rootflag;
|
||
@@ -305,7 +309,7 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de,
|
||
|
||
init_rock_state(&rs, inode);
|
||
setup_rock_ridge(de, inode, &rs);
|
||
- if (regard_xa) {
|
||
+ if (flags & RR_REGARD_XA) {
|
||
rs.chr += 14;
|
||
rs.len -= 14;
|
||
if (rs.len < 0)
|
||
@@ -485,12 +489,22 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de,
|
||
"relocated directory\n");
|
||
goto out;
|
||
case SIG('C', 'L'):
|
||
- ISOFS_I(inode)->i_first_extent =
|
||
- isonum_733(rr->u.CL.location);
|
||
- reloc =
|
||
- isofs_iget(inode->i_sb,
|
||
- ISOFS_I(inode)->i_first_extent,
|
||
- 0);
|
||
+ if (flags & RR_RELOC_DE) {
|
||
+ printk(KERN_ERR
|
||
+ "ISOFS: Recursive directory relocation "
|
||
+ "is not supported\n");
|
||
+ goto eio;
|
||
+ }
|
||
+ reloc_block = isonum_733(rr->u.CL.location);
|
||
+ if (reloc_block == ISOFS_I(inode)->i_iget5_block &&
|
||
+ ISOFS_I(inode)->i_iget5_offset == 0) {
|
||
+ printk(KERN_ERR
|
||
+ "ISOFS: Directory relocation points to "
|
||
+ "itself\n");
|
||
+ goto eio;
|
||
+ }
|
||
+ ISOFS_I(inode)->i_first_extent = reloc_block;
|
||
+ reloc = isofs_iget_reloc(inode->i_sb, reloc_block, 0);
|
||
if (IS_ERR(reloc)) {
|
||
ret = PTR_ERR(reloc);
|
||
goto out;
|
||
@@ -637,9 +651,11 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit)
|
||
return rpnt;
|
||
}
|
||
|
||
-int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
|
||
+int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode,
|
||
+ int relocated)
|
||
{
|
||
- int result = parse_rock_ridge_inode_internal(de, inode, 0);
|
||
+ int flags = relocated ? RR_RELOC_DE : 0;
|
||
+ int result = parse_rock_ridge_inode_internal(de, inode, flags);
|
||
|
||
/*
|
||
* if rockridge flag was reset and we didn't look for attributes
|
||
@@ -647,7 +663,8 @@ int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
|
||
*/
|
||
if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1)
|
||
&& (ISOFS_SB(inode->i_sb)->s_rock == 2)) {
|
||
- result = parse_rock_ridge_inode_internal(de, inode, 14);
|
||
+ result = parse_rock_ridge_inode_internal(de, inode,
|
||
+ flags | RR_REGARD_XA);
|
||
}
|
||
return result;
|
||
}
|
||
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
|
||
index e5bfb11..f697468 100644
|
||
--- a/fs/jbd2/journal.c
|
||
+++ b/fs/jbd2/journal.c
|
||
@@ -662,6 +662,37 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid)
|
||
}
|
||
|
||
/*
|
||
+ * When this function returns the transaction corresponding to tid
|
||
+ * will be completed. If the transaction has currently running, start
|
||
+ * committing that transaction before waiting for it to complete. If
|
||
+ * the transaction id is stale, it is by definition already completed,
|
||
+ * so just return SUCCESS.
|
||
+ */
|
||
+int jbd2_complete_transaction(journal_t *journal, tid_t tid)
|
||
+{
|
||
+ int need_to_wait = 1;
|
||
+
|
||
+ read_lock(&journal->j_state_lock);
|
||
+ if (journal->j_running_transaction &&
|
||
+ journal->j_running_transaction->t_tid == tid) {
|
||
+ if (journal->j_commit_request != tid) {
|
||
+ /* transaction not yet started, so request it */
|
||
+ read_unlock(&journal->j_state_lock);
|
||
+ jbd2_log_start_commit(journal, tid);
|
||
+ goto wait_commit;
|
||
+ }
|
||
+ } else if (!(journal->j_committing_transaction &&
|
||
+ journal->j_committing_transaction->t_tid == tid))
|
||
+ need_to_wait = 0;
|
||
+ read_unlock(&journal->j_state_lock);
|
||
+ if (!need_to_wait)
|
||
+ return 0;
|
||
+wait_commit:
|
||
+ return jbd2_log_wait_commit(journal, tid);
|
||
+}
|
||
+EXPORT_SYMBOL(jbd2_complete_transaction);
|
||
+
|
||
+/*
|
||
* Log buffer allocation routines:
|
||
*/
|
||
|
||
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
|
||
index f567127..f512c69 100644
|
||
--- a/fs/jbd2/transaction.c
|
||
+++ b/fs/jbd2/transaction.c
|
||
@@ -1126,7 +1126,10 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
|
||
* once a transaction -bzzz
|
||
*/
|
||
jh->b_modified = 1;
|
||
- J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
|
||
+ if (handle->h_buffer_credits <= 0) {
|
||
+ ret = -ENOSPC;
|
||
+ goto out_unlock_bh;
|
||
+ }
|
||
handle->h_buffer_credits--;
|
||
}
|
||
|
||
@@ -1209,7 +1212,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
|
||
jbd2_journal_put_journal_head(jh);
|
||
out:
|
||
JBUFFER_TRACE(jh, "exit");
|
||
- WARN_ON(ret); /* All errors are bugs, so dump the stack */
|
||
return ret;
|
||
}
|
||
|
||
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c
|
||
index 16a5047..406d9cc 100644
|
||
--- a/fs/jffs2/compr_rtime.c
|
||
+++ b/fs/jffs2/compr_rtime.c
|
||
@@ -33,7 +33,7 @@ static int jffs2_rtime_compress(unsigned char *data_in,
|
||
unsigned char *cpage_out,
|
||
uint32_t *sourcelen, uint32_t *dstlen)
|
||
{
|
||
- short positions[256];
|
||
+ unsigned short positions[256];
|
||
int outpos = 0;
|
||
int pos=0;
|
||
|
||
@@ -74,7 +74,7 @@ static int jffs2_rtime_decompress(unsigned char *data_in,
|
||
unsigned char *cpage_out,
|
||
uint32_t srclen, uint32_t destlen)
|
||
{
|
||
- short positions[256];
|
||
+ unsigned short positions[256];
|
||
int outpos = 0;
|
||
int pos=0;
|
||
|
||
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
|
||
index e4619b0..fa35ff7 100644
|
||
--- a/fs/jffs2/nodelist.h
|
||
+++ b/fs/jffs2/nodelist.h
|
||
@@ -231,7 +231,7 @@ struct jffs2_tmp_dnode_info
|
||
uint32_t version;
|
||
uint32_t data_crc;
|
||
uint32_t partial_crc;
|
||
- uint16_t csize;
|
||
+ uint32_t csize;
|
||
uint16_t overlapped;
|
||
};
|
||
|
||
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
|
||
index ffa8f12..87044bc 100644
|
||
--- a/fs/jffs2/nodemgmt.c
|
||
+++ b/fs/jffs2/nodemgmt.c
|
||
@@ -139,6 +139,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||
spin_unlock(&c->erase_completion_lock);
|
||
|
||
schedule();
|
||
+ remove_wait_queue(&c->erase_wait, &wait);
|
||
} else
|
||
spin_unlock(&c->erase_completion_lock);
|
||
} else if (ret)
|
||
@@ -169,20 +170,25 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||
int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize,
|
||
uint32_t *len, uint32_t sumsize)
|
||
{
|
||
- int ret = -EAGAIN;
|
||
+ int ret;
|
||
minsize = PAD(minsize);
|
||
|
||
jffs2_dbg(1, "%s(): Requested 0x%x bytes\n", __func__, minsize);
|
||
|
||
- spin_lock(&c->erase_completion_lock);
|
||
- while(ret == -EAGAIN) {
|
||
+ while (true) {
|
||
+ spin_lock(&c->erase_completion_lock);
|
||
ret = jffs2_do_reserve_space(c, minsize, len, sumsize);
|
||
if (ret) {
|
||
jffs2_dbg(1, "%s(): looping, ret is %d\n",
|
||
__func__, ret);
|
||
}
|
||
+ spin_unlock(&c->erase_completion_lock);
|
||
+
|
||
+ if (ret == -EAGAIN)
|
||
+ cond_resched();
|
||
+ else
|
||
+ break;
|
||
}
|
||
- spin_unlock(&c->erase_completion_lock);
|
||
if (!ret)
|
||
ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1);
|
||
|
||
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
|
||
index c1a3e60..7f464c5 100644
|
||
--- a/fs/jfs/jfs_inode.c
|
||
+++ b/fs/jfs/jfs_inode.c
|
||
@@ -95,7 +95,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
|
||
|
||
if (insert_inode_locked(inode) < 0) {
|
||
rc = -EINVAL;
|
||
- goto fail_unlock;
|
||
+ goto fail_put;
|
||
}
|
||
|
||
inode_init_owner(inode, parent, mode);
|
||
@@ -156,7 +156,6 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
|
||
fail_drop:
|
||
dquot_drop(inode);
|
||
inode->i_flags |= S_NOQUOTA;
|
||
-fail_unlock:
|
||
clear_nlink(inode);
|
||
unlock_new_inode(inode);
|
||
fail_put:
|
||
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
|
||
index aff1c61..43ccfd6 100644
|
||
--- a/fs/lockd/svclock.c
|
||
+++ b/fs/lockd/svclock.c
|
||
@@ -769,6 +769,7 @@ nlmsvc_grant_blocked(struct nlm_block *block)
|
||
struct nlm_file *file = block->b_file;
|
||
struct nlm_lock *lock = &block->b_call->a_args.lock;
|
||
int error;
|
||
+ loff_t fl_start, fl_end;
|
||
|
||
dprintk("lockd: grant blocked lock %p\n", block);
|
||
|
||
@@ -786,9 +787,16 @@ nlmsvc_grant_blocked(struct nlm_block *block)
|
||
}
|
||
|
||
/* Try the lock operation again */
|
||
+ /* vfs_lock_file() can mangle fl_start and fl_end, but we need
|
||
+ * them unchanged for the GRANT_MSG
|
||
+ */
|
||
lock->fl.fl_flags |= FL_SLEEP;
|
||
+ fl_start = lock->fl.fl_start;
|
||
+ fl_end = lock->fl.fl_end;
|
||
error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
|
||
lock->fl.fl_flags &= ~FL_SLEEP;
|
||
+ lock->fl.fl_start = fl_start;
|
||
+ lock->fl.fl_end = fl_end;
|
||
|
||
switch (error) {
|
||
case 0:
|
||
diff --git a/fs/locks.c b/fs/locks.c
|
||
index fcc50ab..d4f1d89 100644
|
||
--- a/fs/locks.c
|
||
+++ b/fs/locks.c
|
||
@@ -1253,11 +1253,10 @@ int __break_lease(struct inode *inode, unsigned int mode)
|
||
|
||
restart:
|
||
break_time = flock->fl_break_time;
|
||
- if (break_time != 0) {
|
||
+ if (break_time != 0)
|
||
break_time -= jiffies;
|
||
- if (break_time == 0)
|
||
- break_time++;
|
||
- }
|
||
+ if (break_time == 0)
|
||
+ break_time++;
|
||
locks_insert_block(flock, new_fl);
|
||
unlock_flocks();
|
||
error = wait_event_interruptible_timeout(new_fl->fl_wait,
|
||
diff --git a/fs/namei.c b/fs/namei.c
|
||
index fcc9b20..90bcd7b 100644
|
||
--- a/fs/namei.c
|
||
+++ b/fs/namei.c
|
||
@@ -555,24 +555,22 @@ static int complete_walk(struct nameidata *nd)
|
||
|
||
static __always_inline void set_root(struct nameidata *nd)
|
||
{
|
||
- if (!nd->root.mnt)
|
||
- get_fs_root(current->fs, &nd->root);
|
||
+ get_fs_root(current->fs, &nd->root);
|
||
}
|
||
|
||
static int link_path_walk(const char *, struct nameidata *);
|
||
|
||
-static __always_inline void set_root_rcu(struct nameidata *nd)
|
||
+static __always_inline unsigned set_root_rcu(struct nameidata *nd)
|
||
{
|
||
- if (!nd->root.mnt) {
|
||
- struct fs_struct *fs = current->fs;
|
||
- unsigned seq;
|
||
+ struct fs_struct *fs = current->fs;
|
||
+ unsigned seq, res;
|
||
|
||
- do {
|
||
- seq = read_seqcount_begin(&fs->seq);
|
||
- nd->root = fs->root;
|
||
- nd->seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
|
||
- } while (read_seqcount_retry(&fs->seq, seq));
|
||
- }
|
||
+ do {
|
||
+ seq = read_seqcount_begin(&fs->seq);
|
||
+ nd->root = fs->root;
|
||
+ res = __read_seqcount_begin(&nd->root.dentry->d_seq);
|
||
+ } while (read_seqcount_retry(&fs->seq, seq));
|
||
+ return res;
|
||
}
|
||
|
||
static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
|
||
@@ -930,7 +928,8 @@ static void follow_mount_rcu(struct nameidata *nd)
|
||
|
||
static int follow_dotdot_rcu(struct nameidata *nd)
|
||
{
|
||
- set_root_rcu(nd);
|
||
+ if (!nd->root.mnt)
|
||
+ set_root_rcu(nd);
|
||
|
||
while (1) {
|
||
if (nd->path.dentry == nd->root.dentry &&
|
||
@@ -1033,7 +1032,8 @@ static void follow_mount(struct path *path)
|
||
|
||
static void follow_dotdot(struct nameidata *nd)
|
||
{
|
||
- set_root(nd);
|
||
+ if (!nd->root.mnt)
|
||
+ set_root(nd);
|
||
|
||
while(1) {
|
||
struct dentry *old = nd->path.dentry;
|
||
@@ -1637,7 +1637,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
|
||
if (flags & LOOKUP_RCU) {
|
||
br_read_lock(vfsmount_lock);
|
||
rcu_read_lock();
|
||
- set_root_rcu(nd);
|
||
+ nd->seq = set_root_rcu(nd);
|
||
} else {
|
||
set_root(nd);
|
||
path_get(&nd->root);
|
||
diff --git a/fs/namespace.c b/fs/namespace.c
|
||
index 7235146..bb62c96 100644
|
||
--- a/fs/namespace.c
|
||
+++ b/fs/namespace.c
|
||
@@ -1066,6 +1066,9 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill)
|
||
for (p = mnt; p; p = next_mnt(p, mnt))
|
||
list_move(&p->mnt_hash, &tmp_list);
|
||
|
||
+ list_for_each_entry(p, &tmp_list, mnt_hash)
|
||
+ list_del_init(&p->mnt_child);
|
||
+
|
||
if (propagate)
|
||
propagate_umount(&tmp_list);
|
||
|
||
@@ -1076,7 +1079,6 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill)
|
||
if (p->mnt_ns)
|
||
__mnt_make_shortterm(p);
|
||
p->mnt_ns = NULL;
|
||
- list_del_init(&p->mnt_child);
|
||
if (mnt_has_parent(p)) {
|
||
p->mnt_parent->mnt_ghosts++;
|
||
dentry_reset_mounted(p->mnt_mountpoint);
|
||
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
|
||
index aeed93a..9560fd7 100644
|
||
--- a/fs/ncpfs/dir.c
|
||
+++ b/fs/ncpfs/dir.c
|
||
@@ -1033,15 +1033,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
|
||
DPRINTK("ncp_rmdir: removing %s/%s\n",
|
||
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||
|
||
- /*
|
||
- * fail with EBUSY if there are still references to this
|
||
- * directory.
|
||
- */
|
||
- dentry_unhash(dentry);
|
||
- error = -EBUSY;
|
||
- if (!d_unhashed(dentry))
|
||
- goto out;
|
||
-
|
||
len = sizeof(__name);
|
||
error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
|
||
dentry->d_name.len, !ncp_preserve_case(dir));
|
||
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c
|
||
index 1f9a603..51f9ff2 100644
|
||
--- a/fs/nfs/blocklayout/extents.c
|
||
+++ b/fs/nfs/blocklayout/extents.c
|
||
@@ -44,7 +44,7 @@
|
||
static inline sector_t normalize(sector_t s, int base)
|
||
{
|
||
sector_t tmp = s; /* Since do_div modifies its argument */
|
||
- return s - do_div(tmp, base);
|
||
+ return s - sector_div(tmp, base);
|
||
}
|
||
|
||
static inline sector_t normalize_up(sector_t s, int base)
|
||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
|
||
index 95bfc24..27c2969 100644
|
||
--- a/fs/nfs/callback_xdr.c
|
||
+++ b/fs/nfs/callback_xdr.c
|
||
@@ -455,9 +455,9 @@ static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
|
||
args->csa_nrclists = ntohl(*p++);
|
||
args->csa_rclists = NULL;
|
||
if (args->csa_nrclists) {
|
||
- args->csa_rclists = kmalloc(args->csa_nrclists *
|
||
- sizeof(*args->csa_rclists),
|
||
- GFP_KERNEL);
|
||
+ args->csa_rclists = kmalloc_array(args->csa_nrclists,
|
||
+ sizeof(*args->csa_rclists),
|
||
+ GFP_KERNEL);
|
||
if (unlikely(args->csa_rclists == NULL))
|
||
goto out;
|
||
|
||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
|
||
index 89af1d2..16d16e5 100644
|
||
--- a/fs/nfs/delegation.c
|
||
+++ b/fs/nfs/delegation.c
|
||
@@ -540,16 +540,19 @@ int nfs_async_inode_return_delegation(struct inode *inode,
|
||
|
||
rcu_read_lock();
|
||
delegation = rcu_dereference(NFS_I(inode)->delegation);
|
||
+ if (delegation == NULL)
|
||
+ goto out_enoent;
|
||
|
||
- if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
|
||
- rcu_read_unlock();
|
||
- return -ENOENT;
|
||
- }
|
||
+ if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
|
||
+ goto out_enoent;
|
||
nfs_mark_return_delegation(server, delegation);
|
||
rcu_read_unlock();
|
||
|
||
nfs_delegation_run_state_manager(clp);
|
||
return 0;
|
||
+out_enoent:
|
||
+ rcu_read_unlock();
|
||
+ return -ENOENT;
|
||
}
|
||
|
||
static struct inode *
|
||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
|
||
index a55d0c8..2faed2f 100644
|
||
--- a/fs/nfs/inode.c
|
||
+++ b/fs/nfs/inode.c
|
||
@@ -224,6 +224,8 @@ nfs_find_actor(struct inode *inode, void *opaque)
|
||
|
||
if (NFS_FILEID(inode) != fattr->fileid)
|
||
return 0;
|
||
+ if ((S_IFMT & inode->i_mode) != (S_IFMT & fattr->mode))
|
||
+ return 0;
|
||
if (nfs_compare_fh(NFS_FH(inode), fh))
|
||
return 0;
|
||
if (is_bad_inode(inode) || NFS_STALE(inode))
|
||
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
|
||
index 7374c77..5e652f4 100644
|
||
--- a/fs/nfs/nfs3proc.c
|
||
+++ b/fs/nfs/nfs3proc.c
|
||
@@ -24,14 +24,14 @@
|
||
|
||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||
|
||
-/* A wrapper to handle the EJUKEBOX and EKEYEXPIRED error messages */
|
||
+/* A wrapper to handle the EJUKEBOX error messages */
|
||
static int
|
||
nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
|
||
{
|
||
int res;
|
||
do {
|
||
res = rpc_call_sync(clnt, msg, flags);
|
||
- if (res != -EJUKEBOX && res != -EKEYEXPIRED)
|
||
+ if (res != -EJUKEBOX)
|
||
break;
|
||
freezable_schedule_timeout_killable_unsafe(NFS_JUKEBOX_RETRY_TIME);
|
||
res = -ERESTARTSYS;
|
||
@@ -44,7 +44,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
|
||
static int
|
||
nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode)
|
||
{
|
||
- if (task->tk_status != -EJUKEBOX && task->tk_status != -EKEYEXPIRED)
|
||
+ if (task->tk_status != -EJUKEBOX)
|
||
return 0;
|
||
if (task->tk_status == -EJUKEBOX)
|
||
nfs_inc_stats(inode, NFSIOS_DELAY);
|
||
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
|
||
index 5acfd9e..4d64d5b 100644
|
||
--- a/fs/nfs/nfs4filelayout.c
|
||
+++ b/fs/nfs/nfs4filelayout.c
|
||
@@ -122,7 +122,6 @@ static int filelayout_async_handle_error(struct rpc_task *task,
|
||
break;
|
||
case -NFS4ERR_DELAY:
|
||
case -NFS4ERR_GRACE:
|
||
- case -EKEYEXPIRED:
|
||
rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
|
||
break;
|
||
case -NFS4ERR_RETRY_UNCACHED_REP:
|
||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
|
||
index 7c97bd8..720fa0b 100644
|
||
--- a/fs/nfs/nfs4proc.c
|
||
+++ b/fs/nfs/nfs4proc.c
|
||
@@ -319,7 +319,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
|
||
}
|
||
case -NFS4ERR_GRACE:
|
||
case -NFS4ERR_DELAY:
|
||
- case -EKEYEXPIRED:
|
||
ret = nfs4_delay(server->client, &exception->timeout);
|
||
if (ret != 0)
|
||
break;
|
||
@@ -1352,13 +1351,6 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
|
||
nfs_inode_find_state_and_recover(state->inode,
|
||
stateid);
|
||
nfs4_schedule_stateid_recovery(server, state);
|
||
- case -EKEYEXPIRED:
|
||
- /*
|
||
- * User RPCSEC_GSS context has expired.
|
||
- * We cannot recover this stateid now, so
|
||
- * skip it and allow recovery thread to
|
||
- * proceed.
|
||
- */
|
||
case -ENOMEM:
|
||
err = 0;
|
||
goto out;
|
||
@@ -2059,6 +2051,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
||
{
|
||
struct nfs4_closedata *calldata = data;
|
||
struct nfs4_state *state = calldata->state;
|
||
+ bool is_rdonly, is_wronly, is_rdwr;
|
||
int call_close = 0;
|
||
|
||
dprintk("%s: begin!\n", __func__);
|
||
@@ -2066,21 +2059,27 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
||
return;
|
||
|
||
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
|
||
- calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
|
||
spin_lock(&state->owner->so_lock);
|
||
+ is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
|
||
+ is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
|
||
+ is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
|
||
/* Calculate the change in open mode */
|
||
+ calldata->arg.fmode = 0;
|
||
if (state->n_rdwr == 0) {
|
||
- if (state->n_rdonly == 0) {
|
||
- call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
|
||
- call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
|
||
- calldata->arg.fmode &= ~FMODE_READ;
|
||
- }
|
||
- if (state->n_wronly == 0) {
|
||
- call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
|
||
- call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
|
||
- calldata->arg.fmode &= ~FMODE_WRITE;
|
||
- }
|
||
- }
|
||
+ if (state->n_rdonly == 0)
|
||
+ call_close |= is_rdonly;
|
||
+ else if (is_rdonly)
|
||
+ calldata->arg.fmode |= FMODE_READ;
|
||
+ if (state->n_wronly == 0)
|
||
+ call_close |= is_wronly;
|
||
+ else if (is_wronly)
|
||
+ calldata->arg.fmode |= FMODE_WRITE;
|
||
+ } else if (is_rdwr)
|
||
+ calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
|
||
+
|
||
+ if (calldata->arg.fmode == 0)
|
||
+ call_close |= is_rdwr;
|
||
+
|
||
spin_unlock(&state->owner->so_lock);
|
||
|
||
if (!call_close) {
|
||
@@ -3732,7 +3731,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
|
||
.rpc_argp = &args,
|
||
.rpc_resp = &res,
|
||
};
|
||
- int ret = -ENOMEM, npages, i, acl_len = 0;
|
||
+ int ret = -ENOMEM, npages, i;
|
||
+ size_t acl_len = 0;
|
||
|
||
npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||
/* As long as we're doing a round trip to the server anyway,
|
||
@@ -3918,13 +3918,11 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
|
||
dprintk("%s ERROR %d, Reset session\n", __func__,
|
||
task->tk_status);
|
||
nfs4_schedule_session_recovery(clp->cl_session);
|
||
- task->tk_status = 0;
|
||
- return -EAGAIN;
|
||
+ goto wait_on_recovery;
|
||
#endif /* CONFIG_NFS_V4_1 */
|
||
case -NFS4ERR_DELAY:
|
||
nfs_inc_server_stats(server, NFSIOS_DELAY);
|
||
case -NFS4ERR_GRACE:
|
||
- case -EKEYEXPIRED:
|
||
rpc_delay(task, NFS4_POLL_RETRY_MAX);
|
||
task->tk_status = 0;
|
||
return -EAGAIN;
|
||
@@ -4050,11 +4048,17 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
|
||
return;
|
||
|
||
switch (task->tk_status) {
|
||
- case -NFS4ERR_STALE_STATEID:
|
||
- case -NFS4ERR_EXPIRED:
|
||
case 0:
|
||
renew_lease(data->res.server, data->timestamp);
|
||
break;
|
||
+ case -NFS4ERR_ADMIN_REVOKED:
|
||
+ case -NFS4ERR_DELEG_REVOKED:
|
||
+ case -NFS4ERR_BAD_STATEID:
|
||
+ case -NFS4ERR_OLD_STATEID:
|
||
+ case -NFS4ERR_STALE_STATEID:
|
||
+ case -NFS4ERR_EXPIRED:
|
||
+ task->tk_status = 0;
|
||
+ break;
|
||
default:
|
||
if (nfs4_async_handle_error(task, data->res.server, NULL) ==
|
||
-EAGAIN) {
|
||
@@ -4216,6 +4220,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
|
||
status = 0;
|
||
}
|
||
request->fl_ops->fl_release_private(request);
|
||
+ request->fl_ops = NULL;
|
||
out:
|
||
return status;
|
||
}
|
||
@@ -4871,15 +4876,6 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
|
||
nfs4_schedule_stateid_recovery(server, state);
|
||
err = 0;
|
||
goto out;
|
||
- case -EKEYEXPIRED:
|
||
- /*
|
||
- * User RPCSEC_GSS context has expired.
|
||
- * We cannot recover this stateid now, so
|
||
- * skip it and allow recovery thread to
|
||
- * proceed.
|
||
- */
|
||
- err = 0;
|
||
- goto out;
|
||
case -ENOMEM:
|
||
case -NFS4ERR_DENIED:
|
||
/* kill_proc(fl->fl_pid, SIGLOST, 1); */
|
||
@@ -6095,7 +6091,8 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
|
||
status = nfs4_wait_for_completion_rpc_task(task);
|
||
if (status == 0)
|
||
status = task->tk_status;
|
||
- if (status == 0)
|
||
+ /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
|
||
+ if (status == 0 && lgp->res.layoutp->len)
|
||
status = pnfs_layout_process(lgp);
|
||
rpc_put_task(task);
|
||
dprintk("<-- %s status=%d\n", __func__, status);
|
||
@@ -6308,22 +6305,8 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
|
||
static void nfs4_layoutcommit_release(void *calldata)
|
||
{
|
||
struct nfs4_layoutcommit_data *data = calldata;
|
||
- struct pnfs_layout_segment *lseg, *tmp;
|
||
- unsigned long *bitlock = &NFS_I(data->args.inode)->flags;
|
||
|
||
pnfs_cleanup_layoutcommit(data);
|
||
- /* Matched by references in pnfs_set_layoutcommit */
|
||
- list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) {
|
||
- list_del_init(&lseg->pls_lc_list);
|
||
- if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
|
||
- &lseg->pls_flags))
|
||
- put_lseg(lseg);
|
||
- }
|
||
-
|
||
- clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
|
||
- smp_mb__after_clear_bit();
|
||
- wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
|
||
-
|
||
put_rpccred(data->cred);
|
||
kfree(data);
|
||
}
|
||
@@ -6405,7 +6388,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
|
||
switch (err) {
|
||
case 0:
|
||
case -NFS4ERR_WRONGSEC:
|
||
- case -NFS4ERR_NOTSUPP:
|
||
+ case -ENOTSUPP:
|
||
goto out;
|
||
default:
|
||
err = nfs4_handle_exception(server, err, &exception);
|
||
@@ -6437,7 +6420,7 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
||
* Fall back on "guess and check" method if
|
||
* the server doesn't support SECINFO_NO_NAME
|
||
*/
|
||
- if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) {
|
||
+ if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
|
||
err = nfs4_find_root_sec(server, fhandle, info);
|
||
goto out_freepage;
|
||
}
|
||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
|
||
index 7f0fcfc..461816b 100644
|
||
--- a/fs/nfs/nfs4state.c
|
||
+++ b/fs/nfs/nfs4state.c
|
||
@@ -1298,14 +1298,6 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
|
||
/* Mark the file as being 'closed' */
|
||
state->state = 0;
|
||
break;
|
||
- case -EKEYEXPIRED:
|
||
- /*
|
||
- * User RPCSEC_GSS context has expired.
|
||
- * We cannot recover this stateid now, so
|
||
- * skip it and allow recovery thread to
|
||
- * proceed.
|
||
- */
|
||
- break;
|
||
case -NFS4ERR_ADMIN_REVOKED:
|
||
case -NFS4ERR_STALE_STATEID:
|
||
case -NFS4ERR_BAD_STATEID:
|
||
@@ -1458,14 +1450,6 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
|
||
nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
|
||
}
|
||
|
||
-static void nfs4_warn_keyexpired(const char *s)
|
||
-{
|
||
- printk_ratelimited(KERN_WARNING "Error: state manager"
|
||
- " encountered RPCSEC_GSS session"
|
||
- " expired against NFSv4 server %s.\n",
|
||
- s);
|
||
-}
|
||
-
|
||
static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
|
||
{
|
||
switch (error) {
|
||
@@ -1497,10 +1481,6 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
|
||
set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
|
||
/* Zero session reset errors */
|
||
break;
|
||
- case -EKEYEXPIRED:
|
||
- /* Nothing we can do */
|
||
- nfs4_warn_keyexpired(clp->cl_hostname);
|
||
- break;
|
||
default:
|
||
return error;
|
||
}
|
||
@@ -1671,8 +1651,18 @@ static int nfs4_reset_session(struct nfs_client *clp)
|
||
|
||
nfs4_begin_drain_session(clp);
|
||
status = nfs4_proc_destroy_session(clp->cl_session);
|
||
- if (status && status != -NFS4ERR_BADSESSION &&
|
||
- status != -NFS4ERR_DEADSESSION) {
|
||
+ switch (status) {
|
||
+ case 0:
|
||
+ case -NFS4ERR_BADSESSION:
|
||
+ case -NFS4ERR_DEADSESSION:
|
||
+ break;
|
||
+ case -NFS4ERR_BACK_CHAN_BUSY:
|
||
+ case -NFS4ERR_DELAY:
|
||
+ set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
|
||
+ status = 0;
|
||
+ ssleep(1);
|
||
+ goto out;
|
||
+ default:
|
||
status = nfs4_recovery_handle_error(clp, status);
|
||
goto out;
|
||
}
|
||
@@ -1745,7 +1735,6 @@ static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
|
||
break;
|
||
|
||
case -EKEYEXPIRED:
|
||
- nfs4_warn_keyexpired(clp->cl_hostname);
|
||
case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
|
||
* in nfs4_exchange_id */
|
||
default:
|
||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
|
||
index c8ac9a1..8cf722f 100644
|
||
--- a/fs/nfs/nfs4xdr.c
|
||
+++ b/fs/nfs/nfs4xdr.c
|
||
@@ -2955,7 +2955,8 @@ static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
|
||
return -EIO;
|
||
}
|
||
|
||
-static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
|
||
+static bool __decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected,
|
||
+ int *nfs_retval)
|
||
{
|
||
__be32 *p;
|
||
uint32_t opnum;
|
||
@@ -2965,19 +2966,32 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
|
||
if (unlikely(!p))
|
||
goto out_overflow;
|
||
opnum = be32_to_cpup(p++);
|
||
- if (opnum != expected) {
|
||
- dprintk("nfs: Server returned operation"
|
||
- " %d but we issued a request for %d\n",
|
||
- opnum, expected);
|
||
- return -EIO;
|
||
- }
|
||
+ if (unlikely(opnum != expected))
|
||
+ goto out_bad_operation;
|
||
nfserr = be32_to_cpup(p);
|
||
- if (nfserr != NFS_OK)
|
||
- return nfs4_stat_to_errno(nfserr);
|
||
- return 0;
|
||
+ if (nfserr == NFS_OK)
|
||
+ *nfs_retval = 0;
|
||
+ else
|
||
+ *nfs_retval = nfs4_stat_to_errno(nfserr);
|
||
+ return true;
|
||
+out_bad_operation:
|
||
+ dprintk("nfs: Server returned operation"
|
||
+ " %d but we issued a request for %d\n",
|
||
+ opnum, expected);
|
||
+ *nfs_retval = -EREMOTEIO;
|
||
+ return false;
|
||
out_overflow:
|
||
print_overflow_msg(__func__, xdr);
|
||
- return -EIO;
|
||
+ *nfs_retval = -EIO;
|
||
+ return false;
|
||
+}
|
||
+
|
||
+static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
|
||
+{
|
||
+ int retval;
|
||
+
|
||
+ __decode_op_hdr(xdr, expected, &retval);
|
||
+ return retval;
|
||
}
|
||
|
||
/* Dummy routine */
|
||
@@ -4680,11 +4694,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
|
||
uint32_t savewords, bmlen, i;
|
||
int status;
|
||
|
||
- status = decode_op_hdr(xdr, OP_OPEN);
|
||
- if (status != -EIO)
|
||
- nfs_increment_open_seqid(status, res->seqid);
|
||
- if (!status)
|
||
- status = decode_stateid(xdr, &res->stateid);
|
||
+ if (!__decode_op_hdr(xdr, OP_OPEN, &status))
|
||
+ return status;
|
||
+ nfs_increment_open_seqid(status, res->seqid);
|
||
+ if (status)
|
||
+ return status;
|
||
+ status = decode_stateid(xdr, &res->stateid);
|
||
if (unlikely(status))
|
||
return status;
|
||
|
||
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
|
||
index 059e2c3..ae31182 100644
|
||
--- a/fs/nfs/pnfs.c
|
||
+++ b/fs/nfs/pnfs.c
|
||
@@ -1381,11 +1381,27 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
|
||
|
||
list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
|
||
if (lseg->pls_range.iomode == IOMODE_RW &&
|
||
- test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
|
||
+ test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
|
||
list_add(&lseg->pls_lc_list, listp);
|
||
}
|
||
}
|
||
|
||
+static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp)
|
||
+{
|
||
+ struct pnfs_layout_segment *lseg, *tmp;
|
||
+ unsigned long *bitlock = &NFS_I(inode)->flags;
|
||
+
|
||
+ /* Matched by references in pnfs_set_layoutcommit */
|
||
+ list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) {
|
||
+ list_del_init(&lseg->pls_lc_list);
|
||
+ put_lseg(lseg);
|
||
+ }
|
||
+
|
||
+ clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
|
||
+ smp_mb__after_clear_bit();
|
||
+ wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
|
||
+}
|
||
+
|
||
void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
|
||
{
|
||
if (lseg->pls_range.iomode == IOMODE_RW) {
|
||
@@ -1434,6 +1450,7 @@ void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data)
|
||
|
||
if (nfss->pnfs_curr_ld->cleanup_layoutcommit)
|
||
nfss->pnfs_curr_ld->cleanup_layoutcommit(data);
|
||
+ pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list);
|
||
}
|
||
|
||
/*
|
||
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
|
||
index b63b6f4..af9947e 100644
|
||
--- a/fs/nfs/proc.c
|
||
+++ b/fs/nfs/proc.c
|
||
@@ -47,39 +47,6 @@
|
||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||
|
||
/*
|
||
- * wrapper to handle the -EKEYEXPIRED error message. This should generally
|
||
- * only happen if using krb5 auth and a user's TGT expires. NFSv2 doesn't
|
||
- * support the NFSERR_JUKEBOX error code, but we handle this situation in the
|
||
- * same way that we handle that error with NFSv3.
|
||
- */
|
||
-static int
|
||
-nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
|
||
-{
|
||
- int res;
|
||
- do {
|
||
- res = rpc_call_sync(clnt, msg, flags);
|
||
- if (res != -EKEYEXPIRED)
|
||
- break;
|
||
- freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
|
||
- res = -ERESTARTSYS;
|
||
- } while (!fatal_signal_pending(current));
|
||
- return res;
|
||
-}
|
||
-
|
||
-#define rpc_call_sync(clnt, msg, flags) nfs_rpc_wrapper(clnt, msg, flags)
|
||
-
|
||
-static int
|
||
-nfs_async_handle_expired_key(struct rpc_task *task)
|
||
-{
|
||
- if (task->tk_status != -EKEYEXPIRED)
|
||
- return 0;
|
||
- task->tk_status = 0;
|
||
- rpc_restart_call(task);
|
||
- rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
|
||
- return 1;
|
||
-}
|
||
-
|
||
-/*
|
||
* Bare-bones access to getattr: this is for nfs_read_super.
|
||
*/
|
||
static int
|
||
@@ -365,8 +332,6 @@ static void nfs_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlink
|
||
|
||
static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
|
||
{
|
||
- if (nfs_async_handle_expired_key(task))
|
||
- return 0;
|
||
nfs_mark_for_revalidate(dir);
|
||
return 1;
|
||
}
|
||
@@ -386,8 +351,6 @@ static int
|
||
nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
|
||
struct inode *new_dir)
|
||
{
|
||
- if (nfs_async_handle_expired_key(task))
|
||
- return 0;
|
||
nfs_mark_for_revalidate(old_dir);
|
||
nfs_mark_for_revalidate(new_dir);
|
||
return 1;
|
||
@@ -641,9 +604,6 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
|
||
|
||
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
|
||
{
|
||
- if (nfs_async_handle_expired_key(task))
|
||
- return -EAGAIN;
|
||
-
|
||
nfs_invalidate_atime(data->inode);
|
||
if (task->tk_status >= 0) {
|
||
nfs_refresh_inode(data->inode, data->res.fattr);
|
||
@@ -668,9 +628,6 @@ static void nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_dat
|
||
|
||
static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
|
||
{
|
||
- if (nfs_async_handle_expired_key(task))
|
||
- return -EAGAIN;
|
||
-
|
||
if (task->tk_status >= 0)
|
||
nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
|
||
return 0;
|
||
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
|
||
index c074623..da8fd94 100644
|
||
--- a/fs/nfs/write.c
|
||
+++ b/fs/nfs/write.c
|
||
@@ -1751,12 +1751,12 @@ int __init nfs_init_writepagecache(void)
|
||
nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE,
|
||
nfs_wdata_cachep);
|
||
if (nfs_wdata_mempool == NULL)
|
||
- return -ENOMEM;
|
||
+ goto out_destroy_write_cache;
|
||
|
||
nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
|
||
nfs_wdata_cachep);
|
||
if (nfs_commit_mempool == NULL)
|
||
- return -ENOMEM;
|
||
+ goto out_destroy_write_mempool;
|
||
|
||
/*
|
||
* NFS congestion size, scale with available memory.
|
||
@@ -1779,6 +1779,12 @@ int __init nfs_init_writepagecache(void)
|
||
nfs_congestion_kb = 256*1024;
|
||
|
||
return 0;
|
||
+
|
||
+out_destroy_write_mempool:
|
||
+ mempool_destroy(nfs_wdata_mempool);
|
||
+out_destroy_write_cache:
|
||
+ kmem_cache_destroy(nfs_wdata_cachep);
|
||
+ return -ENOMEM;
|
||
}
|
||
|
||
void nfs_destroy_writepagecache(void)
|
||
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
|
||
index 9c51aff..435a9be1 100644
|
||
--- a/fs/nfsd/nfs4acl.c
|
||
+++ b/fs/nfsd/nfs4acl.c
|
||
@@ -373,8 +373,10 @@ sort_pacl(struct posix_acl *pacl)
|
||
* by uid/gid. */
|
||
int i, j;
|
||
|
||
- if (pacl->a_count <= 4)
|
||
- return; /* no users or groups */
|
||
+ /* no users or groups */
|
||
+ if (!pacl || pacl->a_count <= 4)
|
||
+ return;
|
||
+
|
||
i = 1;
|
||
while (pacl->a_entries[i].e_tag == ACL_USER)
|
||
i++;
|
||
@@ -498,13 +500,12 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
|
||
|
||
/*
|
||
* ACLs with no ACEs are treated differently in the inheritable
|
||
- * and effective cases: when there are no inheritable ACEs, we
|
||
- * set a zero-length default posix acl:
|
||
+ * and effective cases: when there are no inheritable ACEs,
|
||
+ * calls ->set_acl with a NULL ACL structure.
|
||
*/
|
||
- if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) {
|
||
- pacl = posix_acl_alloc(0, GFP_KERNEL);
|
||
- return pacl ? pacl : ERR_PTR(-ENOMEM);
|
||
- }
|
||
+ if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT))
|
||
+ return NULL;
|
||
+
|
||
/*
|
||
* When there are no effective ACEs, the following will end
|
||
* up setting a 3-element effective posix ACL with all
|
||
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
|
||
index 64198ed..22beaff 100644
|
||
--- a/fs/nfsd/nfs4proc.c
|
||
+++ b/fs/nfsd/nfs4proc.c
|
||
@@ -543,15 +543,6 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||
|
||
switch (create->cr_type) {
|
||
case NF4LNK:
|
||
- /* ugh! we have to null-terminate the linktext, or
|
||
- * vfs_symlink() will choke. it is always safe to
|
||
- * null-terminate by brute force, since at worst we
|
||
- * will overwrite the first byte of the create namelen
|
||
- * in the XDR buffer, which has already been extracted
|
||
- * during XDR decode.
|
||
- */
|
||
- create->cr_linkname[create->cr_linklen] = 0;
|
||
-
|
||
status = nfsd_symlink(rqstp, &cstate->current_fh,
|
||
create->cr_name, create->cr_namelen,
|
||
create->cr_linkname, create->cr_linklen,
|
||
@@ -904,14 +895,14 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||
|
||
nfs4_lock_state();
|
||
status = nfs4_preprocess_stateid_op(cstate, stateid, WR_STATE, &filp);
|
||
- if (filp)
|
||
- get_file(filp);
|
||
- nfs4_unlock_state();
|
||
-
|
||
if (status) {
|
||
+ nfs4_unlock_state();
|
||
dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
|
||
return status;
|
||
}
|
||
+ if (filp)
|
||
+ get_file(filp);
|
||
+ nfs4_unlock_state();
|
||
|
||
cnt = write->wr_buflen;
|
||
write->wr_how_written = write->wr_stable_how;
|
||
@@ -1245,6 +1236,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
|
||
/* If op is non-idempotent */
|
||
if (opdesc->op_flags & OP_MODIFIES_SOMETHING) {
|
||
plen = opdesc->op_rsize_bop(rqstp, op);
|
||
+ /*
|
||
+ * If there's still another operation, make sure
|
||
+ * we'll have space to at least encode an error:
|
||
+ */
|
||
+ if (resp->opcnt < args->opcnt)
|
||
+ plen += COMPOUND_ERR_SLACK_SPACE;
|
||
op->status = nfsd4_check_resp_size(resp, plen);
|
||
}
|
||
|
||
@@ -1412,7 +1409,8 @@ static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *o
|
||
|
||
static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
||
{
|
||
- return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32);
|
||
+ return (op_encode_hdr_size + 2 + XDR_QUADLEN(NFS4_VERIFIER_SIZE)) *
|
||
+ sizeof(__be32);
|
||
}
|
||
|
||
static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
|
||
index f90b197..a4b87c6 100644
|
||
--- a/fs/nfsd/nfs4state.c
|
||
+++ b/fs/nfsd/nfs4state.c
|
||
@@ -3476,9 +3476,16 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
|
||
static __be32
|
||
nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
|
||
{
|
||
- if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
|
||
+ struct nfs4_lockowner *lo = lockowner(stp->st_stateowner);
|
||
+
|
||
+ if (check_for_locks(stp->st_file, lo))
|
||
return nfserr_locks_held;
|
||
- release_lock_stateid(stp);
|
||
+ /*
|
||
+ * Currently there's a 1-1 lock stateid<->lockowner
|
||
+ * correspondance, and we have to delete the lockowner when we
|
||
+ * delete the lock stateid:
|
||
+ */
|
||
+ release_lockowner(lo);
|
||
return nfs_ok;
|
||
}
|
||
|
||
@@ -3918,6 +3925,10 @@ static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, c
|
||
|
||
if (!same_owner_str(&lo->lo_owner, owner, clid))
|
||
return false;
|
||
+ if (list_empty(&lo->lo_owner.so_stateids)) {
|
||
+ WARN_ON_ONCE(1);
|
||
+ return false;
|
||
+ }
|
||
lst = list_first_entry(&lo->lo_owner.so_stateids,
|
||
struct nfs4_ol_stateid, st_perstateowner);
|
||
return lst->st_file->fi_inode == inode;
|
||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
|
||
index cb997b1..04a1ce4 100644
|
||
--- a/fs/nfsd/nfs4xdr.c
|
||
+++ b/fs/nfsd/nfs4xdr.c
|
||
@@ -161,8 +161,8 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
|
||
*/
|
||
memcpy(p, argp->p, avail);
|
||
/* step to next page */
|
||
- argp->pagelist++;
|
||
argp->p = page_address(argp->pagelist[0]);
|
||
+ argp->pagelist++;
|
||
if (argp->pagelen < PAGE_SIZE) {
|
||
argp->end = argp->p + (argp->pagelen>>2);
|
||
argp->pagelen = 0;
|
||
@@ -465,7 +465,18 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
|
||
READ_BUF(4);
|
||
READ32(create->cr_linklen);
|
||
READ_BUF(create->cr_linklen);
|
||
- SAVEMEM(create->cr_linkname, create->cr_linklen);
|
||
+ /*
|
||
+ * The VFS will want a null-terminated string, and
|
||
+ * null-terminating in place isn't safe since this might
|
||
+ * end on a page boundary:
|
||
+ */
|
||
+ create->cr_linkname =
|
||
+ kmalloc(create->cr_linklen + 1, GFP_KERNEL);
|
||
+ if (!create->cr_linkname)
|
||
+ return nfserr_jukebox;
|
||
+ memcpy(create->cr_linkname, p, create->cr_linklen);
|
||
+ create->cr_linkname[create->cr_linklen] = '\0';
|
||
+ defer_free(argp, kfree, create->cr_linkname);
|
||
break;
|
||
case NF4BLK:
|
||
case NF4CHR:
|
||
@@ -2032,8 +2043,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
||
err = vfs_getattr(exp->ex_path.mnt, dentry, &stat);
|
||
if (err)
|
||
goto out_nfserr;
|
||
- if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL |
|
||
- FATTR4_WORD0_MAXNAME)) ||
|
||
+ if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
|
||
+ FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) ||
|
||
(bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
|
||
FATTR4_WORD1_SPACE_TOTAL))) {
|
||
err = vfs_statfs(&path, &statfs);
|
||
@@ -2410,6 +2421,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
||
WRITE64(stat.ino);
|
||
}
|
||
if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
|
||
+ if ((buflen -= 16) < 0)
|
||
+ goto out_resource;
|
||
WRITE32(3);
|
||
WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
|
||
WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD1);
|
||
@@ -3406,6 +3419,9 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
|
||
struct nfsd4_test_stateid_id *stateid, *next;
|
||
__be32 *p;
|
||
|
||
+ if (nfserr)
|
||
+ return nfserr;
|
||
+
|
||
RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids));
|
||
*p++ = htonl(test_stateid->ts_num_ids);
|
||
|
||
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
|
||
index d014727..4db777d 100644
|
||
--- a/fs/nfsd/nfsctl.c
|
||
+++ b/fs/nfsd/nfsctl.c
|
||
@@ -213,6 +213,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
|
||
struct sockaddr *sap = (struct sockaddr *)&address;
|
||
size_t salen = sizeof(address);
|
||
char *fo_path;
|
||
+ struct net *net = file->f_dentry->d_sb->s_fs_info;
|
||
|
||
/* sanity check */
|
||
if (size == 0)
|
||
@@ -225,7 +226,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
|
||
if (qword_get(&buf, fo_path, size) < 0)
|
||
return -EINVAL;
|
||
|
||
- if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0)
|
||
+ if (rpc_pton(net, fo_path, size, sap, salen) == 0)
|
||
return -EINVAL;
|
||
|
||
return nlmsvc_unlock_all_by_ip(sap);
|
||
@@ -389,6 +390,8 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||
{
|
||
char *mesg = buf;
|
||
int rv;
|
||
+ struct net *net = file->f_dentry->d_sb->s_fs_info;
|
||
+
|
||
if (size > 0) {
|
||
int newthreads;
|
||
rv = get_int(&mesg, &newthreads);
|
||
@@ -396,7 +399,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||
return rv;
|
||
if (newthreads < 0)
|
||
return -EINVAL;
|
||
- rv = nfsd_svc(NFS_PORT, newthreads);
|
||
+ rv = nfsd_svc(NFS_PORT, newthreads, net);
|
||
if (rv < 0)
|
||
return rv;
|
||
} else
|
||
@@ -438,6 +441,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
|
||
int len;
|
||
int npools;
|
||
int *nthreads;
|
||
+ struct net *net = file->f_dentry->d_sb->s_fs_info;
|
||
|
||
mutex_lock(&nfsd_mutex);
|
||
npools = nfsd_nrpools();
|
||
@@ -468,7 +472,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
|
||
if (nthreads[i] < 0)
|
||
goto out_free;
|
||
}
|
||
- rv = nfsd_set_nrthreads(i, nthreads);
|
||
+ rv = nfsd_set_nrthreads(i, nthreads, net);
|
||
if (rv)
|
||
goto out_free;
|
||
}
|
||
@@ -647,17 +651,21 @@ static ssize_t __write_ports_names(char *buf)
|
||
* a socket of a supported family/protocol, and we use it as an
|
||
* nfsd listener.
|
||
*/
|
||
-static ssize_t __write_ports_addfd(char *buf)
|
||
+static ssize_t __write_ports_addfd(char *buf, struct net *net)
|
||
{
|
||
char *mesg = buf;
|
||
int fd, err;
|
||
- struct net *net = &init_net;
|
||
|
||
err = get_int(&mesg, &fd);
|
||
if (err != 0 || fd < 0)
|
||
return -EINVAL;
|
||
|
||
- err = nfsd_create_serv();
|
||
+ if (svc_alien_sock(net, fd)) {
|
||
+ printk(KERN_ERR "%s: socket net is different to NFSd's one\n", __func__);
|
||
+ return -EINVAL;
|
||
+ }
|
||
+
|
||
+ err = nfsd_create_serv(net);
|
||
if (err != 0)
|
||
return err;
|
||
|
||
@@ -695,12 +703,11 @@ static ssize_t __write_ports_delfd(char *buf)
|
||
* A transport listener is added by writing it's transport name and
|
||
* a port number.
|
||
*/
|
||
-static ssize_t __write_ports_addxprt(char *buf)
|
||
+static ssize_t __write_ports_addxprt(char *buf, struct net *net)
|
||
{
|
||
char transport[16];
|
||
struct svc_xprt *xprt;
|
||
int port, err;
|
||
- struct net *net = &init_net;
|
||
|
||
if (sscanf(buf, "%15s %4u", transport, &port) != 2)
|
||
return -EINVAL;
|
||
@@ -708,7 +715,7 @@ static ssize_t __write_ports_addxprt(char *buf)
|
||
if (port < 1 || port > USHRT_MAX)
|
||
return -EINVAL;
|
||
|
||
- err = nfsd_create_serv();
|
||
+ err = nfsd_create_serv(net);
|
||
if (err != 0)
|
||
return err;
|
||
|
||
@@ -740,7 +747,7 @@ static ssize_t __write_ports_addxprt(char *buf)
|
||
* A transport listener is removed by writing a "-", it's transport
|
||
* name, and it's port number.
|
||
*/
|
||
-static ssize_t __write_ports_delxprt(char *buf)
|
||
+static ssize_t __write_ports_delxprt(char *buf, struct net *net)
|
||
{
|
||
struct svc_xprt *xprt;
|
||
char transport[16];
|
||
@@ -752,7 +759,7 @@ static ssize_t __write_ports_delxprt(char *buf)
|
||
if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
|
||
return -EINVAL;
|
||
|
||
- xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port);
|
||
+ xprt = svc_find_xprt(nfsd_serv, transport, net, AF_UNSPEC, port);
|
||
if (xprt == NULL)
|
||
return -ENOTCONN;
|
||
|
||
@@ -761,22 +768,23 @@ static ssize_t __write_ports_delxprt(char *buf)
|
||
return 0;
|
||
}
|
||
|
||
-static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
||
+static ssize_t __write_ports(struct file *file, char *buf, size_t size,
|
||
+ struct net *net)
|
||
{
|
||
if (size == 0)
|
||
return __write_ports_names(buf);
|
||
|
||
if (isdigit(buf[0]))
|
||
- return __write_ports_addfd(buf);
|
||
+ return __write_ports_addfd(buf, net);
|
||
|
||
if (buf[0] == '-' && isdigit(buf[1]))
|
||
return __write_ports_delfd(buf);
|
||
|
||
if (isalpha(buf[0]))
|
||
- return __write_ports_addxprt(buf);
|
||
+ return __write_ports_addxprt(buf, net);
|
||
|
||
if (buf[0] == '-' && isalpha(buf[1]))
|
||
- return __write_ports_delxprt(buf);
|
||
+ return __write_ports_delxprt(buf, net);
|
||
|
||
return -EINVAL;
|
||
}
|
||
@@ -855,9 +863,10 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
||
static ssize_t write_ports(struct file *file, char *buf, size_t size)
|
||
{
|
||
ssize_t rv;
|
||
+ struct net *net = file->f_dentry->d_sb->s_fs_info;
|
||
|
||
mutex_lock(&nfsd_mutex);
|
||
- rv = __write_ports(file, buf, size);
|
||
+ rv = __write_ports(file, buf, size, net);
|
||
mutex_unlock(&nfsd_mutex);
|
||
return rv;
|
||
}
|
||
@@ -1092,20 +1101,35 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
|
||
#endif
|
||
/* last one */ {""}
|
||
};
|
||
- return simple_fill_super(sb, 0x6e667364, nfsd_files);
|
||
+ struct net *net = data;
|
||
+ int ret;
|
||
+
|
||
+ ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
|
||
+ if (ret)
|
||
+ return ret;
|
||
+ sb->s_fs_info = get_net(net);
|
||
+ return 0;
|
||
}
|
||
|
||
static struct dentry *nfsd_mount(struct file_system_type *fs_type,
|
||
int flags, const char *dev_name, void *data)
|
||
{
|
||
- return mount_single(fs_type, flags, data, nfsd_fill_super);
|
||
+ return mount_ns(fs_type, flags, current->nsproxy->net_ns, nfsd_fill_super);
|
||
+}
|
||
+
|
||
+static void nfsd_umount(struct super_block *sb)
|
||
+{
|
||
+ struct net *net = sb->s_fs_info;
|
||
+
|
||
+ kill_litter_super(sb);
|
||
+ put_net(net);
|
||
}
|
||
|
||
static struct file_system_type nfsd_fs_type = {
|
||
.owner = THIS_MODULE,
|
||
.name = "nfsd",
|
||
.mount = nfsd_mount,
|
||
- .kill_sb = kill_litter_super,
|
||
+ .kill_sb = nfsd_umount,
|
||
};
|
||
|
||
#ifdef CONFIG_PROC_FS
|
||
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
|
||
index 1336a65..a0989a2 100644
|
||
--- a/fs/nfsd/nfsd.h
|
||
+++ b/fs/nfsd/nfsd.h
|
||
@@ -65,13 +65,13 @@ extern const struct seq_operations nfs_exports_op;
|
||
/*
|
||
* Function prototypes.
|
||
*/
|
||
-int nfsd_svc(unsigned short port, int nrservs);
|
||
+int nfsd_svc(unsigned short port, int nrservs, struct net *net);
|
||
int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
|
||
|
||
int nfsd_nrthreads(void);
|
||
int nfsd_nrpools(void);
|
||
int nfsd_get_nrthreads(int n, int *);
|
||
-int nfsd_set_nrthreads(int n, int *);
|
||
+int nfsd_set_nrthreads(int n, int *, struct net *);
|
||
|
||
static inline void nfsd_destroy(struct net *net)
|
||
{
|
||
@@ -101,7 +101,7 @@ enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
|
||
int nfsd_vers(int vers, enum vers_op change);
|
||
int nfsd_minorversion(u32 minorversion, enum vers_op change);
|
||
void nfsd_reset_versions(void);
|
||
-int nfsd_create_serv(void);
|
||
+int nfsd_create_serv(struct net *net);
|
||
|
||
extern int nfsd_max_blksize;
|
||
|
||
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
|
||
index 53459b0..ed8eedf 100644
|
||
--- a/fs/nfsd/nfssvc.c
|
||
+++ b/fs/nfsd/nfssvc.c
|
||
@@ -11,7 +11,6 @@
|
||
#include <linux/module.h>
|
||
#include <linux/fs_struct.h>
|
||
#include <linux/swap.h>
|
||
-#include <linux/nsproxy.h>
|
||
|
||
#include <linux/sunrpc/stats.h>
|
||
#include <linux/sunrpc/svcsock.h>
|
||
@@ -183,18 +182,18 @@ int nfsd_nrthreads(void)
|
||
return rv;
|
||
}
|
||
|
||
-static int nfsd_init_socks(int port)
|
||
+static int nfsd_init_socks(int port, struct net *net)
|
||
{
|
||
int error;
|
||
if (!list_empty(&nfsd_serv->sv_permsocks))
|
||
return 0;
|
||
|
||
- error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port,
|
||
+ error = svc_create_xprt(nfsd_serv, "udp", net, PF_INET, port,
|
||
SVC_SOCK_DEFAULTS);
|
||
if (error < 0)
|
||
return error;
|
||
|
||
- error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port,
|
||
+ error = svc_create_xprt(nfsd_serv, "tcp", net, PF_INET, port,
|
||
SVC_SOCK_DEFAULTS);
|
||
if (error < 0)
|
||
return error;
|
||
@@ -204,7 +203,7 @@ static int nfsd_init_socks(int port)
|
||
|
||
static bool nfsd_up = false;
|
||
|
||
-static int nfsd_startup(unsigned short port, int nrservs)
|
||
+static int nfsd_startup(unsigned short port, int nrservs, struct net *net)
|
||
{
|
||
int ret;
|
||
|
||
@@ -218,10 +217,10 @@ static int nfsd_startup(unsigned short port, int nrservs)
|
||
ret = nfsd_racache_init(2*nrservs);
|
||
if (ret)
|
||
return ret;
|
||
- ret = nfsd_init_socks(port);
|
||
+ ret = nfsd_init_socks(port, net);
|
||
if (ret)
|
||
goto out_racache;
|
||
- ret = lockd_up(&init_net);
|
||
+ ret = lockd_up(net);
|
||
if (ret)
|
||
goto out_racache;
|
||
ret = nfs4_state_start();
|
||
@@ -230,13 +229,13 @@ static int nfsd_startup(unsigned short port, int nrservs)
|
||
nfsd_up = true;
|
||
return 0;
|
||
out_lockd:
|
||
- lockd_down(&init_net);
|
||
+ lockd_down(net);
|
||
out_racache:
|
||
nfsd_racache_shutdown();
|
||
return ret;
|
||
}
|
||
|
||
-static void nfsd_shutdown(void)
|
||
+static void nfsd_shutdown(struct net *net)
|
||
{
|
||
/*
|
||
* write_ports can create the server without actually starting
|
||
@@ -247,14 +246,14 @@ static void nfsd_shutdown(void)
|
||
if (!nfsd_up)
|
||
return;
|
||
nfs4_state_shutdown();
|
||
- lockd_down(&init_net);
|
||
+ lockd_down(net);
|
||
nfsd_racache_shutdown();
|
||
nfsd_up = false;
|
||
}
|
||
|
||
static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
|
||
{
|
||
- nfsd_shutdown();
|
||
+ nfsd_shutdown(net);
|
||
|
||
svc_rpcb_cleanup(serv, net);
|
||
|
||
@@ -327,10 +326,9 @@ static int nfsd_get_default_max_blksize(void)
|
||
return ret;
|
||
}
|
||
|
||
-int nfsd_create_serv(void)
|
||
+int nfsd_create_serv(struct net *net)
|
||
{
|
||
int error;
|
||
- struct net *net = current->nsproxy->net_ns;
|
||
|
||
WARN_ON(!mutex_is_locked(&nfsd_mutex));
|
||
if (nfsd_serv) {
|
||
@@ -376,12 +374,11 @@ int nfsd_get_nrthreads(int n, int *nthreads)
|
||
return 0;
|
||
}
|
||
|
||
-int nfsd_set_nrthreads(int n, int *nthreads)
|
||
+int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
|
||
{
|
||
int i = 0;
|
||
int tot = 0;
|
||
int err = 0;
|
||
- struct net *net = &init_net;
|
||
|
||
WARN_ON(!mutex_is_locked(&nfsd_mutex));
|
||
|
||
@@ -436,11 +433,10 @@ int nfsd_set_nrthreads(int n, int *nthreads)
|
||
* this is the first time nrservs is nonzero.
|
||
*/
|
||
int
|
||
-nfsd_svc(unsigned short port, int nrservs)
|
||
+nfsd_svc(unsigned short port, int nrservs, struct net *net)
|
||
{
|
||
int error;
|
||
bool nfsd_up_before;
|
||
- struct net *net = &init_net;
|
||
|
||
mutex_lock(&nfsd_mutex);
|
||
dprintk("nfsd: creating service\n");
|
||
@@ -452,13 +448,13 @@ nfsd_svc(unsigned short port, int nrservs)
|
||
if (nrservs == 0 && nfsd_serv == NULL)
|
||
goto out;
|
||
|
||
- error = nfsd_create_serv();
|
||
+ error = nfsd_create_serv(net);
|
||
if (error)
|
||
goto out;
|
||
|
||
nfsd_up_before = nfsd_up;
|
||
|
||
- error = nfsd_startup(port, nrservs);
|
||
+ error = nfsd_startup(port, nrservs, net);
|
||
if (error)
|
||
goto out_destroy;
|
||
error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
|
||
@@ -471,7 +467,7 @@ nfsd_svc(unsigned short port, int nrservs)
|
||
error = nfsd_serv->sv_nrthreads - 1;
|
||
out_shutdown:
|
||
if (error < 0 && !nfsd_up_before)
|
||
- nfsd_shutdown();
|
||
+ nfsd_shutdown(net);
|
||
out_destroy:
|
||
nfsd_destroy(net); /* Release server */
|
||
out:
|
||
@@ -487,6 +483,8 @@ static int
|
||
nfsd(void *vrqstp)
|
||
{
|
||
struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
|
||
+ struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list);
|
||
+ struct net *net = perm_sock->xpt_net;
|
||
int err, preverr = 0;
|
||
|
||
/* Lock module and set up kernel thread */
|
||
@@ -561,7 +559,7 @@ nfsd(void *vrqstp)
|
||
/* Release the thread */
|
||
svc_exit_thread(rqstp);
|
||
|
||
- nfsd_destroy(&init_net);
|
||
+ nfsd_destroy(net);
|
||
|
||
/* Release module */
|
||
mutex_unlock(&nfsd_mutex);
|
||
@@ -672,7 +670,7 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file)
|
||
int nfsd_pool_stats_release(struct inode *inode, struct file *file)
|
||
{
|
||
int ret = seq_release(inode, file);
|
||
- struct net *net = &init_net;
|
||
+ struct net *net = inode->i_sb->s_fs_info;
|
||
|
||
mutex_lock(&nfsd_mutex);
|
||
/* this function really, really should have been called svc_put() */
|
||
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
|
||
index f031601..36620e6 100644
|
||
--- a/fs/nfsd/vfs.c
|
||
+++ b/fs/nfsd/vfs.c
|
||
@@ -297,41 +297,12 @@ commit_metadata(struct svc_fh *fhp)
|
||
}
|
||
|
||
/*
|
||
- * Set various file attributes.
|
||
- * N.B. After this call fhp needs an fh_put
|
||
+ * Go over the attributes and take care of the small differences between
|
||
+ * NFS semantics and what Linux expects.
|
||
*/
|
||
-__be32
|
||
-nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||
- int check_guard, time_t guardtime)
|
||
+static void
|
||
+nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
|
||
{
|
||
- struct dentry *dentry;
|
||
- struct inode *inode;
|
||
- int accmode = NFSD_MAY_SATTR;
|
||
- umode_t ftype = 0;
|
||
- __be32 err;
|
||
- int host_err;
|
||
- int size_change = 0;
|
||
-
|
||
- if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
|
||
- accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
|
||
- if (iap->ia_valid & ATTR_SIZE)
|
||
- ftype = S_IFREG;
|
||
-
|
||
- /* Get inode */
|
||
- err = fh_verify(rqstp, fhp, ftype, accmode);
|
||
- if (err)
|
||
- goto out;
|
||
-
|
||
- dentry = fhp->fh_dentry;
|
||
- inode = dentry->d_inode;
|
||
-
|
||
- /* Ignore any mode updates on symlinks */
|
||
- if (S_ISLNK(inode->i_mode))
|
||
- iap->ia_valid &= ~ATTR_MODE;
|
||
-
|
||
- if (!iap->ia_valid)
|
||
- goto out;
|
||
-
|
||
/*
|
||
* NFSv2 does not differentiate between "set-[ac]time-to-now"
|
||
* which only requires access, and "set-[ac]time-to-X" which
|
||
@@ -341,8 +312,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||
* convert to "set to now" instead of "set to explicit time"
|
||
*
|
||
* We only call inode_change_ok as the last test as technically
|
||
- * it is not an interface that we should be using. It is only
|
||
- * valid if the filesystem does not define it's own i_op->setattr.
|
||
+ * it is not an interface that we should be using.
|
||
*/
|
||
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
|
||
#define MAX_TOUCH_TIME_ERROR (30*60)
|
||
@@ -368,30 +338,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||
iap->ia_valid &= ~BOTH_TIME_SET;
|
||
}
|
||
}
|
||
-
|
||
- /*
|
||
- * The size case is special.
|
||
- * It changes the file as well as the attributes.
|
||
- */
|
||
- if (iap->ia_valid & ATTR_SIZE) {
|
||
- if (iap->ia_size < inode->i_size) {
|
||
- err = nfsd_permission(rqstp, fhp->fh_export, dentry,
|
||
- NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE);
|
||
- if (err)
|
||
- goto out;
|
||
- }
|
||
-
|
||
- host_err = get_write_access(inode);
|
||
- if (host_err)
|
||
- goto out_nfserr;
|
||
-
|
||
- size_change = 1;
|
||
- host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
|
||
- if (host_err) {
|
||
- put_write_access(inode);
|
||
- goto out_nfserr;
|
||
- }
|
||
- }
|
||
|
||
/* sanitize the mode change */
|
||
if (iap->ia_valid & ATTR_MODE) {
|
||
@@ -414,32 +360,120 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||
iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
|
||
}
|
||
}
|
||
+}
|
||
+
|
||
+static __be32
|
||
+nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||
+ struct iattr *iap)
|
||
+{
|
||
+ struct inode *inode = fhp->fh_dentry->d_inode;
|
||
+ int host_err;
|
||
+
|
||
+ if (iap->ia_size < inode->i_size) {
|
||
+ __be32 err;
|
||
+
|
||
+ err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
|
||
+ NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
|
||
+ if (err)
|
||
+ return err;
|
||
+ }
|
||
|
||
- /* Change the attributes. */
|
||
+ host_err = get_write_access(inode);
|
||
+ if (host_err)
|
||
+ goto out_nfserrno;
|
||
|
||
- iap->ia_valid |= ATTR_CTIME;
|
||
+ host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
|
||
+ if (host_err)
|
||
+ goto out_put_write_access;
|
||
+ return 0;
|
||
+
|
||
+out_put_write_access:
|
||
+ put_write_access(inode);
|
||
+out_nfserrno:
|
||
+ return nfserrno(host_err);
|
||
+}
|
||
|
||
- err = nfserr_notsync;
|
||
- if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
|
||
- host_err = nfsd_break_lease(inode);
|
||
+/*
|
||
+ * Set various file attributes. After this call fhp needs an fh_put.
|
||
+ */
|
||
+__be32
|
||
+nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||
+ int check_guard, time_t guardtime)
|
||
+{
|
||
+ struct dentry *dentry;
|
||
+ struct inode *inode;
|
||
+ int accmode = NFSD_MAY_SATTR;
|
||
+ umode_t ftype = 0;
|
||
+ __be32 err;
|
||
+ int host_err;
|
||
+ bool get_write_count;
|
||
+ int size_change = 0;
|
||
+
|
||
+ if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
|
||
+ accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
|
||
+ if (iap->ia_valid & ATTR_SIZE)
|
||
+ ftype = S_IFREG;
|
||
+
|
||
+ /* Callers that do fh_verify should do the fh_want_write: */
|
||
+ get_write_count = !fhp->fh_dentry;
|
||
+
|
||
+ /* Get inode */
|
||
+ err = fh_verify(rqstp, fhp, ftype, accmode);
|
||
+ if (err)
|
||
+ goto out;
|
||
+ if (get_write_count) {
|
||
+ host_err = fh_want_write(fhp);
|
||
if (host_err)
|
||
- goto out_nfserr;
|
||
- fh_lock(fhp);
|
||
+ return nfserrno(host_err);
|
||
+ }
|
||
|
||
- host_err = notify_change(dentry, iap);
|
||
- err = nfserrno(host_err);
|
||
- fh_unlock(fhp);
|
||
+ dentry = fhp->fh_dentry;
|
||
+ inode = dentry->d_inode;
|
||
+
|
||
+ /* Ignore any mode updates on symlinks */
|
||
+ if (S_ISLNK(inode->i_mode))
|
||
+ iap->ia_valid &= ~ATTR_MODE;
|
||
+
|
||
+ if (!iap->ia_valid)
|
||
+ goto out;
|
||
+
|
||
+ nfsd_sanitize_attrs(inode, iap);
|
||
+
|
||
+ /*
|
||
+ * The size case is special, it changes the file in addition to the
|
||
+ * attributes.
|
||
+ */
|
||
+ if (iap->ia_valid & ATTR_SIZE) {
|
||
+ err = nfsd_get_write_access(rqstp, fhp, iap);
|
||
+ if (err)
|
||
+ goto out;
|
||
+ size_change = 1;
|
||
}
|
||
+
|
||
+ iap->ia_valid |= ATTR_CTIME;
|
||
+
|
||
+ if (check_guard && guardtime != inode->i_ctime.tv_sec) {
|
||
+ err = nfserr_notsync;
|
||
+ goto out_put_write_access;
|
||
+ }
|
||
+
|
||
+ host_err = nfsd_break_lease(inode);
|
||
+ if (host_err)
|
||
+ goto out_put_write_access_nfserror;
|
||
+
|
||
+ fh_lock(fhp);
|
||
+ host_err = notify_change(dentry, iap);
|
||
+ fh_unlock(fhp);
|
||
+
|
||
+out_put_write_access_nfserror:
|
||
+ err = nfserrno(host_err);
|
||
+out_put_write_access:
|
||
if (size_change)
|
||
put_write_access(inode);
|
||
if (!err)
|
||
commit_metadata(fhp);
|
||
out:
|
||
return err;
|
||
-
|
||
-out_nfserr:
|
||
- err = nfserrno(host_err);
|
||
- goto out;
|
||
}
|
||
|
||
#if defined(CONFIG_NFSD_V2_ACL) || \
|
||
@@ -474,6 +508,9 @@ set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
|
||
char *buf = NULL;
|
||
int error = 0;
|
||
|
||
+ if (!pacl)
|
||
+ return vfs_setxattr(dentry, key, NULL, 0, 0);
|
||
+
|
||
buflen = posix_acl_xattr_size(pacl->a_count);
|
||
buf = kmalloc(buflen, GFP_KERNEL);
|
||
error = -ENOMEM;
|
||
@@ -794,9 +831,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
|
||
}
|
||
*filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
|
||
flags, current_cred());
|
||
- if (IS_ERR(*filp))
|
||
+ if (IS_ERR(*filp)) {
|
||
host_err = PTR_ERR(*filp);
|
||
- else {
|
||
+ *filp = NULL;
|
||
+ } else {
|
||
host_err = ima_file_check(*filp, may_flags);
|
||
|
||
if (may_flags & NFSD_MAY_64BIT_COOKIE)
|
||
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
|
||
index aa526be..204bfcf 100644
|
||
--- a/fs/nilfs2/inode.c
|
||
+++ b/fs/nilfs2/inode.c
|
||
@@ -24,6 +24,7 @@
|
||
#include <linux/buffer_head.h>
|
||
#include <linux/gfp.h>
|
||
#include <linux/mpage.h>
|
||
+#include <linux/pagemap.h>
|
||
#include <linux/writeback.h>
|
||
#include <linux/uio.h>
|
||
#include "nilfs.h"
|
||
@@ -195,10 +196,10 @@ static int nilfs_writepage(struct page *page, struct writeback_control *wbc)
|
||
|
||
static int nilfs_set_page_dirty(struct page *page)
|
||
{
|
||
+ struct inode *inode = page->mapping->host;
|
||
int ret = __set_page_dirty_nobuffers(page);
|
||
|
||
if (page_has_buffers(page)) {
|
||
- struct inode *inode = page->mapping->host;
|
||
unsigned nr_dirty = 0;
|
||
struct buffer_head *bh, *head;
|
||
|
||
@@ -221,6 +222,10 @@ static int nilfs_set_page_dirty(struct page *page)
|
||
|
||
if (nr_dirty)
|
||
nilfs_set_file_dirty(inode, nr_dirty);
|
||
+ } else if (ret) {
|
||
+ unsigned nr_dirty = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits);
|
||
+
|
||
+ nilfs_set_file_dirty(inode, nr_dirty);
|
||
}
|
||
return ret;
|
||
}
|
||
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c
|
||
index 3e7b2a0..f45b83f 100644
|
||
--- a/fs/nilfs2/page.c
|
||
+++ b/fs/nilfs2/page.c
|
||
@@ -94,6 +94,7 @@ void nilfs_forget_buffer(struct buffer_head *bh)
|
||
clear_buffer_nilfs_volatile(bh);
|
||
clear_buffer_nilfs_checked(bh);
|
||
clear_buffer_nilfs_redirected(bh);
|
||
+ clear_buffer_async_write(bh);
|
||
clear_buffer_dirty(bh);
|
||
if (nilfs_page_buffers_clean(page))
|
||
__nilfs_clear_page_dirty(page);
|
||
@@ -390,6 +391,7 @@ void nilfs_clear_dirty_pages(struct address_space *mapping)
|
||
bh = head = page_buffers(page);
|
||
do {
|
||
lock_buffer(bh);
|
||
+ clear_buffer_async_write(bh);
|
||
clear_buffer_dirty(bh);
|
||
clear_buffer_nilfs_volatile(bh);
|
||
clear_buffer_nilfs_checked(bh);
|
||
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
|
||
index 88e11fb..e0a5a18 100644
|
||
--- a/fs/nilfs2/segment.c
|
||
+++ b/fs/nilfs2/segment.c
|
||
@@ -662,7 +662,7 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode,
|
||
|
||
bh = head = page_buffers(page);
|
||
do {
|
||
- if (!buffer_dirty(bh))
|
||
+ if (!buffer_dirty(bh) || buffer_async_write(bh))
|
||
continue;
|
||
get_bh(bh);
|
||
list_add_tail(&bh->b_assoc_buffers, listp);
|
||
@@ -696,7 +696,8 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode,
|
||
for (i = 0; i < pagevec_count(&pvec); i++) {
|
||
bh = head = page_buffers(pvec.pages[i]);
|
||
do {
|
||
- if (buffer_dirty(bh)) {
|
||
+ if (buffer_dirty(bh) &&
|
||
+ !buffer_async_write(bh)) {
|
||
get_bh(bh);
|
||
list_add_tail(&bh->b_assoc_buffers,
|
||
listp);
|
||
@@ -1436,17 +1437,19 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci,
|
||
|
||
nilfs_clear_logs(&sci->sc_segbufs);
|
||
|
||
- err = nilfs_segctor_extend_segments(sci, nilfs, nadd);
|
||
- if (unlikely(err))
|
||
- return err;
|
||
-
|
||
if (sci->sc_stage.flags & NILFS_CF_SUFREED) {
|
||
err = nilfs_sufile_cancel_freev(nilfs->ns_sufile,
|
||
sci->sc_freesegs,
|
||
sci->sc_nfreesegs,
|
||
NULL);
|
||
WARN_ON(err); /* do not happen */
|
||
+ sci->sc_stage.flags &= ~NILFS_CF_SUFREED;
|
||
}
|
||
+
|
||
+ err = nilfs_segctor_extend_segments(sci, nilfs, nadd);
|
||
+ if (unlikely(err))
|
||
+ return err;
|
||
+
|
||
nadd = min_t(int, nadd << 1, SC_MAX_SEGDELTA);
|
||
sci->sc_stage = prev_stage;
|
||
}
|
||
@@ -1576,6 +1579,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci)
|
||
|
||
list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
|
||
b_assoc_buffers) {
|
||
+ set_buffer_async_write(bh);
|
||
if (bh->b_page != bd_page) {
|
||
if (bd_page) {
|
||
lock_page(bd_page);
|
||
@@ -1589,6 +1593,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci)
|
||
|
||
list_for_each_entry(bh, &segbuf->sb_payload_buffers,
|
||
b_assoc_buffers) {
|
||
+ set_buffer_async_write(bh);
|
||
if (bh == segbuf->sb_super_root) {
|
||
if (bh->b_page != bd_page) {
|
||
lock_page(bd_page);
|
||
@@ -1674,6 +1679,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err)
|
||
list_for_each_entry(segbuf, logs, sb_list) {
|
||
list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
|
||
b_assoc_buffers) {
|
||
+ clear_buffer_async_write(bh);
|
||
if (bh->b_page != bd_page) {
|
||
if (bd_page)
|
||
end_page_writeback(bd_page);
|
||
@@ -1683,6 +1689,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err)
|
||
|
||
list_for_each_entry(bh, &segbuf->sb_payload_buffers,
|
||
b_assoc_buffers) {
|
||
+ clear_buffer_async_write(bh);
|
||
if (bh == segbuf->sb_super_root) {
|
||
if (bh->b_page != bd_page) {
|
||
end_page_writeback(bd_page);
|
||
@@ -1752,6 +1759,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
|
||
b_assoc_buffers) {
|
||
set_buffer_uptodate(bh);
|
||
clear_buffer_dirty(bh);
|
||
+ clear_buffer_async_write(bh);
|
||
if (bh->b_page != bd_page) {
|
||
if (bd_page)
|
||
end_page_writeback(bd_page);
|
||
@@ -1773,6 +1781,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
|
||
b_assoc_buffers) {
|
||
set_buffer_uptodate(bh);
|
||
clear_buffer_dirty(bh);
|
||
+ clear_buffer_async_write(bh);
|
||
clear_buffer_delay(bh);
|
||
clear_buffer_nilfs_volatile(bh);
|
||
clear_buffer_nilfs_redirected(bh);
|
||
diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
|
||
index 5d18ad1..4f66e00 100644
|
||
--- a/fs/ocfs2/buffer_head_io.c
|
||
+++ b/fs/ocfs2/buffer_head_io.c
|
||
@@ -90,7 +90,6 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
|
||
* information for this bh as it's not marked locally
|
||
* uptodate. */
|
||
ret = -EIO;
|
||
- put_bh(bh);
|
||
mlog_errno(ret);
|
||
}
|
||
|
||
@@ -420,7 +419,6 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
|
||
|
||
if (!buffer_uptodate(bh)) {
|
||
ret = -EIO;
|
||
- put_bh(bh);
|
||
mlog_errno(ret);
|
||
}
|
||
|
||
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
|
||
index 005261c..dbc372e 100644
|
||
--- a/fs/ocfs2/dlm/dlmmaster.c
|
||
+++ b/fs/ocfs2/dlm/dlmmaster.c
|
||
@@ -653,12 +653,9 @@ void dlm_lockres_clear_refmap_bit(struct dlm_ctxt *dlm,
|
||
clear_bit(bit, res->refmap);
|
||
}
|
||
|
||
-
|
||
-void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm,
|
||
+static void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm,
|
||
struct dlm_lock_resource *res)
|
||
{
|
||
- assert_spin_locked(&res->spinlock);
|
||
-
|
||
res->inflight_locks++;
|
||
|
||
mlog(0, "%s: res %.*s, inflight++: now %u, %ps()\n", dlm->name,
|
||
@@ -666,6 +663,13 @@ void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm,
|
||
__builtin_return_address(0));
|
||
}
|
||
|
||
+void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm,
|
||
+ struct dlm_lock_resource *res)
|
||
+{
|
||
+ assert_spin_locked(&res->spinlock);
|
||
+ __dlm_lockres_grab_inflight_ref(dlm, res);
|
||
+}
|
||
+
|
||
void dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm,
|
||
struct dlm_lock_resource *res)
|
||
{
|
||
@@ -855,10 +859,8 @@ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm,
|
||
/* finally add the lockres to its hash bucket */
|
||
__dlm_insert_lockres(dlm, res);
|
||
|
||
- /* Grab inflight ref to pin the resource */
|
||
- spin_lock(&res->spinlock);
|
||
- dlm_lockres_grab_inflight_ref(dlm, res);
|
||
- spin_unlock(&res->spinlock);
|
||
+ /* since this lockres is new it doesn't not require the spinlock */
|
||
+ __dlm_lockres_grab_inflight_ref(dlm, res);
|
||
|
||
/* get an extra ref on the mle in case this is a BLOCK
|
||
* if so, the creator of the BLOCK may try to put the last
|
||
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
|
||
index 01ebfd0..d15b071 100644
|
||
--- a/fs/ocfs2/dlm/dlmrecovery.c
|
||
+++ b/fs/ocfs2/dlm/dlmrecovery.c
|
||
@@ -540,7 +540,10 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm)
|
||
/* success! see if any other nodes need recovery */
|
||
mlog(0, "DONE mastering recovery of %s:%u here(this=%u)!\n",
|
||
dlm->name, dlm->reco.dead_node, dlm->node_num);
|
||
- dlm_reset_recovery(dlm);
|
||
+ spin_lock(&dlm->spinlock);
|
||
+ __dlm_reset_recovery(dlm);
|
||
+ dlm->reco.state &= ~DLM_RECO_STATE_FINALIZE;
|
||
+ spin_unlock(&dlm->spinlock);
|
||
}
|
||
dlm_end_recovery(dlm);
|
||
|
||
@@ -698,6 +701,14 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
|
||
if (all_nodes_done) {
|
||
int ret;
|
||
|
||
+ /* Set this flag on recovery master to avoid
|
||
+ * a new recovery for another dead node start
|
||
+ * before the recovery is not done. That may
|
||
+ * cause recovery hung.*/
|
||
+ spin_lock(&dlm->spinlock);
|
||
+ dlm->reco.state |= DLM_RECO_STATE_FINALIZE;
|
||
+ spin_unlock(&dlm->spinlock);
|
||
+
|
||
/* all nodes are now in DLM_RECO_NODE_DATA_DONE state
|
||
* just send a finalize message to everyone and
|
||
* clean up */
|
||
@@ -1752,13 +1763,13 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
|
||
struct dlm_migratable_lockres *mres)
|
||
{
|
||
struct dlm_migratable_lock *ml;
|
||
- struct list_head *queue;
|
||
+ struct list_head *queue, *iter;
|
||
struct list_head *tmpq = NULL;
|
||
struct dlm_lock *newlock = NULL;
|
||
struct dlm_lockstatus *lksb = NULL;
|
||
int ret = 0;
|
||
int i, j, bad;
|
||
- struct dlm_lock *lock = NULL;
|
||
+ struct dlm_lock *lock;
|
||
u8 from = O2NM_MAX_NODES;
|
||
unsigned int added = 0;
|
||
__be64 c;
|
||
@@ -1793,14 +1804,16 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
|
||
/* MIGRATION ONLY! */
|
||
BUG_ON(!(mres->flags & DLM_MRES_MIGRATION));
|
||
|
||
+ lock = NULL;
|
||
spin_lock(&res->spinlock);
|
||
for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) {
|
||
tmpq = dlm_list_idx_to_ptr(res, j);
|
||
- list_for_each_entry(lock, tmpq, list) {
|
||
- if (lock->ml.cookie != ml->cookie)
|
||
- lock = NULL;
|
||
- else
|
||
+ list_for_each(iter, tmpq) {
|
||
+ lock = list_entry(iter,
|
||
+ struct dlm_lock, list);
|
||
+ if (lock->ml.cookie == ml->cookie)
|
||
break;
|
||
+ lock = NULL;
|
||
}
|
||
if (lock)
|
||
break;
|
||
@@ -2870,8 +2883,8 @@ int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
|
||
BUG();
|
||
}
|
||
dlm->reco.state &= ~DLM_RECO_STATE_FINALIZE;
|
||
+ __dlm_reset_recovery(dlm);
|
||
spin_unlock(&dlm->spinlock);
|
||
- dlm_reset_recovery(dlm);
|
||
dlm_kick_recovery_thread(dlm);
|
||
break;
|
||
default:
|
||
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
|
||
index 7602783..8021098 100644
|
||
--- a/fs/ocfs2/file.c
|
||
+++ b/fs/ocfs2/file.c
|
||
@@ -2389,8 +2389,8 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
|
||
|
||
if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
|
||
((file->f_flags & O_DIRECT) && !direct_io)) {
|
||
- ret = filemap_fdatawrite_range(file->f_mapping, pos,
|
||
- pos + count - 1);
|
||
+ ret = filemap_fdatawrite_range(file->f_mapping, *ppos,
|
||
+ *ppos + count - 1);
|
||
if (ret < 0)
|
||
written = ret;
|
||
|
||
@@ -2403,8 +2403,8 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
|
||
}
|
||
|
||
if (!ret)
|
||
- ret = filemap_fdatawait_range(file->f_mapping, pos,
|
||
- pos + count - 1);
|
||
+ ret = filemap_fdatawait_range(file->f_mapping, *ppos,
|
||
+ *ppos + count - 1);
|
||
}
|
||
|
||
/*
|
||
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
|
||
index 92fcd57..a40e5ce 100644
|
||
--- a/fs/ocfs2/quota_global.c
|
||
+++ b/fs/ocfs2/quota_global.c
|
||
@@ -712,6 +712,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
|
||
*/
|
||
if (status < 0)
|
||
mlog_errno(status);
|
||
+ /*
|
||
+ * Clear dq_off so that we search for the structure in quota file next
|
||
+ * time we acquire it. The structure might be deleted and reallocated
|
||
+ * elsewhere by another node while our dquot structure is on freelist.
|
||
+ */
|
||
+ dquot->dq_off = 0;
|
||
clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
|
||
out_trans:
|
||
ocfs2_commit_trans(osb, handle);
|
||
@@ -750,16 +756,17 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
|
||
status = ocfs2_lock_global_qf(info, 1);
|
||
if (status < 0)
|
||
goto out;
|
||
- if (!test_bit(DQ_READ_B, &dquot->dq_flags)) {
|
||
- status = ocfs2_qinfo_lock(info, 0);
|
||
- if (status < 0)
|
||
- goto out_dq;
|
||
- status = qtree_read_dquot(&info->dqi_gi, dquot);
|
||
- ocfs2_qinfo_unlock(info, 0);
|
||
- if (status < 0)
|
||
- goto out_dq;
|
||
- }
|
||
- set_bit(DQ_READ_B, &dquot->dq_flags);
|
||
+ status = ocfs2_qinfo_lock(info, 0);
|
||
+ if (status < 0)
|
||
+ goto out_dq;
|
||
+ /*
|
||
+ * We always want to read dquot structure from disk because we don't
|
||
+ * know what happened with it while it was on freelist.
|
||
+ */
|
||
+ status = qtree_read_dquot(&info->dqi_gi, dquot);
|
||
+ ocfs2_qinfo_unlock(info, 0);
|
||
+ if (status < 0)
|
||
+ goto out_dq;
|
||
|
||
OCFS2_DQUOT(dquot)->dq_use_count++;
|
||
OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
|
||
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
|
||
index f100bf7..b6cfcf2 100644
|
||
--- a/fs/ocfs2/quota_local.c
|
||
+++ b/fs/ocfs2/quota_local.c
|
||
@@ -1300,10 +1300,6 @@ int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
|
||
ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
|
||
|
||
out:
|
||
- /* Clear the read bit so that next time someone uses this
|
||
- * dquot he reads fresh info from disk and allocates local
|
||
- * dquot structure */
|
||
- clear_bit(DQ_READ_B, &dquot->dq_flags);
|
||
return status;
|
||
}
|
||
|
||
diff --git a/fs/pnode.c b/fs/pnode.c
|
||
index ab5fa9e..f61dcb4 100644
|
||
--- a/fs/pnode.c
|
||
+++ b/fs/pnode.c
|
||
@@ -333,8 +333,10 @@ static void __propagate_umount(struct mount *mnt)
|
||
* umount the child only if the child has no
|
||
* other children
|
||
*/
|
||
- if (child && list_empty(&child->mnt_mounts))
|
||
+ if (child && list_empty(&child->mnt_mounts)) {
|
||
+ list_del_init(&child->mnt_child);
|
||
list_move_tail(&child->mnt_hash, &mnt->mnt_hash);
|
||
+ }
|
||
}
|
||
}
|
||
|
||
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
|
||
index 5e325a4..6449602 100644
|
||
--- a/fs/posix_acl.c
|
||
+++ b/fs/posix_acl.c
|
||
@@ -155,6 +155,12 @@ posix_acl_equiv_mode(const struct posix_acl *acl, umode_t *mode_p)
|
||
umode_t mode = 0;
|
||
int not_equiv = 0;
|
||
|
||
+ /*
|
||
+ * A null ACL can always be presented as mode bits.
|
||
+ */
|
||
+ if (!acl)
|
||
+ return 0;
|
||
+
|
||
FOREACH_ACL_ENTRY(pa, acl, pe) {
|
||
switch (pa->e_tag) {
|
||
case ACL_USER_OBJ:
|
||
diff --git a/fs/proc/array.c b/fs/proc/array.c
|
||
index 2168d6a..e7bb0fe 100644
|
||
--- a/fs/proc/array.c
|
||
+++ b/fs/proc/array.c
|
||
@@ -205,7 +205,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
|
||
group_info = cred->group_info;
|
||
task_unlock(p);
|
||
|
||
- for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++)
|
||
+ for (g = 0; g < group_info->ngroups; g++)
|
||
seq_printf(m, "%d ", GROUP_AT(group_info, g));
|
||
put_cred(cred);
|
||
|
||
diff --git a/fs/proc/base.c b/fs/proc/base.c
|
||
index 712dc09..5ba3ab3 100644
|
||
--- a/fs/proc/base.c
|
||
+++ b/fs/proc/base.c
|
||
@@ -2092,6 +2092,7 @@ static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
|
||
if (rc)
|
||
goto out_mmput;
|
||
|
||
+ rc = -ENOENT;
|
||
down_read(&mm->mmap_sem);
|
||
vma = find_exact_vma(mm, vm_start, vm_end);
|
||
if (vma && vma->vm_file) {
|
||
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
|
||
index 205c922..6c61f11 100644
|
||
--- a/fs/proc/inode.c
|
||
+++ b/fs/proc/inode.c
|
||
@@ -443,12 +443,10 @@ static const struct file_operations proc_reg_file_ops_no_compat = {
|
||
|
||
struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
|
||
{
|
||
- struct inode * inode;
|
||
+ struct inode *inode = new_inode_pseudo(sb);
|
||
|
||
- inode = iget_locked(sb, de->low_ino);
|
||
- if (!inode)
|
||
- return NULL;
|
||
- if (inode->i_state & I_NEW) {
|
||
+ if (inode) {
|
||
+ inode->i_ino = de->low_ino;
|
||
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
||
PROC_I(inode)->fd = 0;
|
||
PROC_I(inode)->pde = de;
|
||
@@ -477,9 +475,7 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
|
||
inode->i_fop = de->proc_fops;
|
||
}
|
||
}
|
||
- unlock_new_inode(inode);
|
||
- } else
|
||
- pde_put(de);
|
||
+ }
|
||
return inode;
|
||
}
|
||
|
||
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
|
||
index d69a1d1..8b30687 100644
|
||
--- a/fs/quota/dquot.c
|
||
+++ b/fs/quota/dquot.c
|
||
@@ -580,9 +580,17 @@ int dquot_scan_active(struct super_block *sb,
|
||
dqstats_inc(DQST_LOOKUPS);
|
||
dqput(old_dquot);
|
||
old_dquot = dquot;
|
||
- ret = fn(dquot, priv);
|
||
- if (ret < 0)
|
||
- goto out;
|
||
+ /*
|
||
+ * ->release_dquot() can be racing with us. Our reference
|
||
+ * protects us from new calls to it so just wait for any
|
||
+ * outstanding call and recheck the DQ_ACTIVE_B after that.
|
||
+ */
|
||
+ wait_on_dquot(dquot);
|
||
+ if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
|
||
+ ret = fn(dquot, priv);
|
||
+ if (ret < 0)
|
||
+ goto out;
|
||
+ }
|
||
spin_lock(&dq_list_lock);
|
||
/* We are safe to continue now because our dquot could not
|
||
* be moved out of the inuse list while we hold the reference */
|
||
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
|
||
index 66c53b6..7c431ed 100644
|
||
--- a/fs/reiserfs/dir.c
|
||
+++ b/fs/reiserfs/dir.c
|
||
@@ -128,6 +128,7 @@ int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
|
||
char *d_name;
|
||
off_t d_off;
|
||
ino_t d_ino;
|
||
+ loff_t cur_pos = deh_offset(deh);
|
||
|
||
if (!de_visible(deh))
|
||
/* it is hidden entry */
|
||
@@ -200,8 +201,9 @@ int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
|
||
if (local_buf != small_buf) {
|
||
kfree(local_buf);
|
||
}
|
||
- // next entry should be looked for with such offset
|
||
- next_pos = deh_offset(deh) + 1;
|
||
+
|
||
+ /* deh_offset(deh) may be invalid now. */
|
||
+ next_pos = cur_pos + 1;
|
||
|
||
if (item_moved(&tmp_ih, &path_to_entry)) {
|
||
goto research;
|
||
diff --git a/fs/stat.c b/fs/stat.c
|
||
index ed26ba4..66e553f 100644
|
||
--- a/fs/stat.c
|
||
+++ b/fs/stat.c
|
||
@@ -58,14 +58,15 @@ EXPORT_SYMBOL(vfs_getattr);
|
||
|
||
int vfs_fstat(unsigned int fd, struct kstat *stat)
|
||
{
|
||
- struct file *f = fget_raw(fd);
|
||
+ int fput_needed;
|
||
+ struct file *f = fget_light(fd, &fput_needed);
|
||
int error = -EBADF;
|
||
|
||
if (f) {
|
||
error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
|
||
if (!error)
|
||
zpath_realsize(f->f_path.dentry, &stat->size);
|
||
- fput(f);
|
||
+ fput_light(f, fput_needed);
|
||
}
|
||
return error;
|
||
}
|
||
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
|
||
index c542c73..f9c90b5 100644
|
||
--- a/fs/ubifs/orphan.c
|
||
+++ b/fs/ubifs/orphan.c
|
||
@@ -130,13 +130,14 @@ void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
|
||
else if (inum > o->inum)
|
||
p = p->rb_right;
|
||
else {
|
||
- if (o->dnext) {
|
||
+ if (o->del) {
|
||
spin_unlock(&c->orphan_lock);
|
||
dbg_gen("deleted twice ino %lu",
|
||
(unsigned long)inum);
|
||
return;
|
||
}
|
||
if (o->cnext) {
|
||
+ o->del = 1;
|
||
o->dnext = c->orph_dnext;
|
||
c->orph_dnext = o;
|
||
spin_unlock(&c->orphan_lock);
|
||
@@ -447,6 +448,7 @@ static void erase_deleted(struct ubifs_info *c)
|
||
orphan = dnext;
|
||
dnext = orphan->dnext;
|
||
ubifs_assert(!orphan->new);
|
||
+ ubifs_assert(orphan->del);
|
||
rb_erase(&orphan->rb, &c->orph_tree);
|
||
list_del(&orphan->list);
|
||
c->tot_orphans -= 1;
|
||
@@ -536,6 +538,7 @@ static int insert_dead_orphan(struct ubifs_info *c, ino_t inum)
|
||
rb_link_node(&orphan->rb, parent, p);
|
||
rb_insert_color(&orphan->rb, &c->orph_tree);
|
||
list_add_tail(&orphan->list, &c->orph_list);
|
||
+ orphan->del = 1;
|
||
orphan->dnext = c->orph_dnext;
|
||
c->orph_dnext = orphan;
|
||
dbg_mnt("ino %lu, new %d, tot %d", (unsigned long)inum,
|
||
diff --git a/fs/ubifs/shrinker.c b/fs/ubifs/shrinker.c
|
||
index 9e1d056..e0a7a76 100644
|
||
--- a/fs/ubifs/shrinker.c
|
||
+++ b/fs/ubifs/shrinker.c
|
||
@@ -128,7 +128,6 @@ static int shrink_tnc(struct ubifs_info *c, int nr, int age, int *contention)
|
||
freed = ubifs_destroy_tnc_subtree(znode);
|
||
atomic_long_sub(freed, &ubifs_clean_zn_cnt);
|
||
atomic_long_sub(freed, &c->clean_zn_cnt);
|
||
- ubifs_assert(atomic_long_read(&c->clean_zn_cnt) >= 0);
|
||
total_freed += freed;
|
||
znode = zprev;
|
||
}
|
||
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
|
||
index 4971cb2..3f96261 100644
|
||
--- a/fs/ubifs/ubifs.h
|
||
+++ b/fs/ubifs/ubifs.h
|
||
@@ -905,6 +905,7 @@ struct ubifs_budget_req {
|
||
* @dnext: next orphan to delete
|
||
* @inum: inode number
|
||
* @new: %1 => added since the last commit, otherwise %0
|
||
+ * @del: %1 => delete pending, otherwise %0
|
||
*/
|
||
struct ubifs_orphan {
|
||
struct rb_node rb;
|
||
@@ -914,6 +915,7 @@ struct ubifs_orphan {
|
||
struct ubifs_orphan *dnext;
|
||
ino_t inum;
|
||
int new;
|
||
+ unsigned del:1;
|
||
};
|
||
|
||
/**
|
||
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
|
||
index 91f8ff5..6a6c1fd 100644
|
||
--- a/fs/xfs/xfs_ioctl.c
|
||
+++ b/fs/xfs/xfs_ioctl.c
|
||
@@ -400,7 +400,8 @@ xfs_attrlist_by_handle(
|
||
return -XFS_ERROR(EPERM);
|
||
if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t)))
|
||
return -XFS_ERROR(EFAULT);
|
||
- if (al_hreq.buflen > XATTR_LIST_MAX)
|
||
+ if (al_hreq.buflen < sizeof(struct attrlist) ||
|
||
+ al_hreq.buflen > XATTR_LIST_MAX)
|
||
return -XFS_ERROR(EINVAL);
|
||
|
||
/*
|
||
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
|
||
index a849a54..745ea4e 100644
|
||
--- a/fs/xfs/xfs_ioctl32.c
|
||
+++ b/fs/xfs/xfs_ioctl32.c
|
||
@@ -361,7 +361,8 @@ xfs_compat_attrlist_by_handle(
|
||
if (copy_from_user(&al_hreq, arg,
|
||
sizeof(compat_xfs_fsop_attrlist_handlereq_t)))
|
||
return -XFS_ERROR(EFAULT);
|
||
- if (al_hreq.buflen > XATTR_LIST_MAX)
|
||
+ if (al_hreq.buflen < sizeof(struct attrlist) ||
|
||
+ al_hreq.buflen > XATTR_LIST_MAX)
|
||
return -XFS_ERROR(EINVAL);
|
||
|
||
/*
|
||
diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h
|
||
index 3744d2a..2cddd2b 100644
|
||
--- a/include/crypto/scatterwalk.h
|
||
+++ b/include/crypto/scatterwalk.h
|
||
@@ -36,6 +36,7 @@ static inline void scatterwalk_sg_chain(struct scatterlist *sg1, int num,
|
||
{
|
||
sg_set_page(&sg1[num - 1], (void *)sg2, 0, 0);
|
||
sg1[num - 1].page_link &= ~0x02;
|
||
+ sg1[num - 1].page_link |= 0x01;
|
||
}
|
||
|
||
static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
|
||
@@ -43,7 +44,7 @@ static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
|
||
if (sg_is_last(sg))
|
||
return NULL;
|
||
|
||
- return (++sg)->length ? sg : (void *)sg_page(sg);
|
||
+ return (++sg)->length ? sg : sg_chain_ptr(sg);
|
||
}
|
||
|
||
static inline void scatterwalk_crypto_chain(struct scatterlist *head,
|
||
diff --git a/include/drm/drm_mem_util.h b/include/drm/drm_mem_util.h
|
||
index 6bd325f..19a2404 100644
|
||
--- a/include/drm/drm_mem_util.h
|
||
+++ b/include/drm/drm_mem_util.h
|
||
@@ -31,7 +31,7 @@
|
||
|
||
static __inline__ void *drm_calloc_large(size_t nmemb, size_t size)
|
||
{
|
||
- if (size != 0 && nmemb > ULONG_MAX / size)
|
||
+ if (size != 0 && nmemb > SIZE_MAX / size)
|
||
return NULL;
|
||
|
||
if (size * nmemb <= PAGE_SIZE)
|
||
@@ -44,7 +44,7 @@ static __inline__ void *drm_calloc_large(size_t nmemb, size_t size)
|
||
/* Modeled after cairo's malloc_ab, it's like calloc but without the zeroing. */
|
||
static __inline__ void *drm_malloc_ab(size_t nmemb, size_t size)
|
||
{
|
||
- if (size != 0 && nmemb > ULONG_MAX / size)
|
||
+ if (size != 0 && nmemb > SIZE_MAX / size)
|
||
return NULL;
|
||
|
||
if (size * nmemb <= PAGE_SIZE)
|
||
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
|
||
index 9242310..cbf2d9a 100644
|
||
--- a/include/drm/drm_mode.h
|
||
+++ b/include/drm/drm_mode.h
|
||
@@ -223,6 +223,8 @@ struct drm_mode_get_connector {
|
||
__u32 connection;
|
||
__u32 mm_width, mm_height; /**< HxW in millimeters */
|
||
__u32 subpixel;
|
||
+
|
||
+ __u32 pad;
|
||
};
|
||
|
||
#define DRM_MODE_PROP_PENDING (1<<0)
|
||
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
|
||
index 1a13caa..757f980 100644
|
||
--- a/include/drm/drm_pciids.h
|
||
+++ b/include/drm/drm_pciids.h
|
||
@@ -544,7 +544,7 @@
|
||
{0x1002, 0x9645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
|
||
{0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
|
||
{0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
|
||
- {0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
|
||
+ {0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
|
||
{0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
|
||
{0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
|
||
{0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
|
||
diff --git a/include/linux/audit.h b/include/linux/audit.h
|
||
index 21286bd..5815f1c 100644
|
||
--- a/include/linux/audit.h
|
||
+++ b/include/linux/audit.h
|
||
@@ -487,7 +487,7 @@ static inline void audit_syscall_exit(void *pt_regs)
|
||
{
|
||
if (unlikely(current->audit_context)) {
|
||
int success = is_syscall_success(pt_regs);
|
||
- int return_code = regs_return_value(pt_regs);
|
||
+ long return_code = regs_return_value(pt_regs);
|
||
|
||
__audit_syscall_exit(success, return_code);
|
||
}
|
||
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
|
||
index 5bab59b..424b381 100644
|
||
--- a/include/linux/binfmts.h
|
||
+++ b/include/linux/binfmts.h
|
||
@@ -113,9 +113,6 @@ extern void setup_new_exec(struct linux_binprm * bprm);
|
||
extern void would_dump(struct linux_binprm *, struct file *);
|
||
|
||
extern int suid_dumpable;
|
||
-#define SUID_DUMP_DISABLE 0 /* No setuid dumping */
|
||
-#define SUID_DUMP_USER 1 /* Dump as user of process */
|
||
-#define SUID_DUMP_ROOT 2 /* Dump as root */
|
||
|
||
/* Stack area protections */
|
||
#define EXSTACK_DEFAULT 0 /* Whatever the arch defaults to */
|
||
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
|
||
index a3b6b82..c1dde8e 100644
|
||
--- a/include/linux/bitops.h
|
||
+++ b/include/linux/bitops.h
|
||
@@ -185,6 +185,21 @@ static inline unsigned long __ffs64(u64 word)
|
||
|
||
#ifdef __KERNEL__
|
||
|
||
+#ifndef set_mask_bits
|
||
+#define set_mask_bits(ptr, _mask, _bits) \
|
||
+({ \
|
||
+ const typeof(*ptr) mask = (_mask), bits = (_bits); \
|
||
+ typeof(*ptr) old, new; \
|
||
+ \
|
||
+ do { \
|
||
+ old = ACCESS_ONCE(*ptr); \
|
||
+ new = (old & ~mask) | bits; \
|
||
+ } while (cmpxchg(ptr, old, new) != old); \
|
||
+ \
|
||
+ new; \
|
||
+})
|
||
+#endif
|
||
+
|
||
#ifndef find_last_bit
|
||
/**
|
||
* find_last_bit - find the last set bit in a memory region
|
||
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
|
||
index b2a3735..6719089 100644
|
||
--- a/include/linux/cgroup.h
|
||
+++ b/include/linux/cgroup.h
|
||
@@ -32,7 +32,6 @@ extern int cgroup_lock_is_held(void);
|
||
extern bool cgroup_lock_live_group(struct cgroup *cgrp);
|
||
extern void cgroup_unlock(void);
|
||
extern void cgroup_fork(struct task_struct *p);
|
||
-extern void cgroup_fork_callbacks(struct task_struct *p);
|
||
extern void cgroup_post_fork(struct task_struct *p);
|
||
extern void cgroup_exit(struct task_struct *p, int run_callbacks);
|
||
extern int cgroupstats_build(struct cgroupstats *stats,
|
||
@@ -508,16 +507,54 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(
|
||
return cgrp->subsys[subsys_id];
|
||
}
|
||
|
||
-/*
|
||
- * function to get the cgroup_subsys_state which allows for extra
|
||
- * rcu_dereference_check() conditions, such as locks used during the
|
||
- * cgroup_subsys::attach() methods.
|
||
+/**
|
||
+ * task_css_set_check - obtain a task's css_set with extra access conditions
|
||
+ * @task: the task to obtain css_set for
|
||
+ * @__c: extra condition expression to be passed to rcu_dereference_check()
|
||
+ *
|
||
+ * A task's css_set is RCU protected, initialized and exited while holding
|
||
+ * task_lock(), and can only be modified while holding both cgroup_mutex
|
||
+ * and task_lock() while the task is alive. This macro verifies that the
|
||
+ * caller is inside proper critical section and returns @task's css_set.
|
||
+ *
|
||
+ * The caller can also specify additional allowed conditions via @__c, such
|
||
+ * as locks used during the cgroup_subsys::attach() methods.
|
||
+ */
|
||
+#define task_css_set_check(task, __c) \
|
||
+ rcu_dereference_check((task)->cgroups, \
|
||
+ lockdep_is_held(&(task)->alloc_lock) || \
|
||
+ cgroup_lock_is_held() || (__c))
|
||
+
|
||
+/**
|
||
+ * task_subsys_state_check - obtain css for (task, subsys) w/ extra access conds
|
||
+ * @task: the target task
|
||
+ * @subsys_id: the target subsystem ID
|
||
+ * @__c: extra condition expression to be passed to rcu_dereference_check()
|
||
+ *
|
||
+ * Return the cgroup_subsys_state for the (@task, @subsys_id) pair. The
|
||
+ * synchronization rules are the same as task_css_set_check().
|
||
*/
|
||
#define task_subsys_state_check(task, subsys_id, __c) \
|
||
- rcu_dereference_check(task->cgroups->subsys[subsys_id], \
|
||
- lockdep_is_held(&task->alloc_lock) || \
|
||
- cgroup_lock_is_held() || (__c))
|
||
+ task_css_set_check((task), (__c))->subsys[(subsys_id)]
|
||
|
||
+/**
|
||
+ * task_css_set - obtain a task's css_set
|
||
+ * @task: the task to obtain css_set for
|
||
+ *
|
||
+ * See task_css_set_check().
|
||
+ */
|
||
+static inline struct css_set *task_css_set(struct task_struct *task)
|
||
+{
|
||
+ return task_css_set_check(task, false);
|
||
+}
|
||
+
|
||
+/**
|
||
+ * task_subsys_state - obtain css for (task, subsys)
|
||
+ * @task: the target task
|
||
+ * @subsys_id: the target subsystem ID
|
||
+ *
|
||
+ * See task_subsys_state_check().
|
||
+ */
|
||
static inline struct cgroup_subsys_state *
|
||
task_subsys_state(struct task_struct *task, int subsys_id)
|
||
{
|
||
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
|
||
index e5834aa..7970e31 100644
|
||
--- a/include/linux/compiler-gcc.h
|
||
+++ b/include/linux/compiler-gcc.h
|
||
@@ -5,6 +5,9 @@
|
||
/*
|
||
* Common definitions for all gcc versions go here.
|
||
*/
|
||
+#define GCC_VERSION (__GNUC__ * 10000 \
|
||
+ + __GNUC_MINOR__ * 100 \
|
||
+ + __GNUC_PATCHLEVEL__)
|
||
|
||
|
||
/* Optimization barrier */
|
||
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
|
||
index 2f40791..91b1aa8 100644
|
||
--- a/include/linux/compiler-gcc4.h
|
||
+++ b/include/linux/compiler-gcc4.h
|
||
@@ -31,6 +31,22 @@
|
||
|
||
#define __linktime_error(message) __attribute__((__error__(message)))
|
||
|
||
+/*
|
||
+ * GCC 'asm goto' miscompiles certain code sequences:
|
||
+ *
|
||
+ * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
|
||
+ *
|
||
+ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
|
||
+ * Fixed in GCC 4.8.2 and later versions.
|
||
+ *
|
||
+ * (asm goto is automatically volatile - the naming reflects this.)
|
||
+ */
|
||
+#if GCC_VERSION <= 40801
|
||
+# define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0)
|
||
+#else
|
||
+# define asm_volatile_goto(x...) do { asm goto(x); } while (0)
|
||
+#endif
|
||
+
|
||
#if __GNUC_MINOR__ >= 5
|
||
/*
|
||
* Mark a position in code as unreachable. This can be used to
|
||
diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h
|
||
index d8e636e..cba9593 100644
|
||
--- a/include/linux/compiler-intel.h
|
||
+++ b/include/linux/compiler-intel.h
|
||
@@ -27,5 +27,3 @@
|
||
#define __must_be_array(a) 0
|
||
|
||
#endif
|
||
-
|
||
-#define uninitialized_var(x) x
|
||
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
|
||
index 668f66b..bb48be7 100644
|
||
--- a/include/linux/cpuset.h
|
||
+++ b/include/linux/cpuset.h
|
||
@@ -74,12 +74,12 @@ extern int cpuset_slab_spread_node(void);
|
||
|
||
static inline int cpuset_do_page_mem_spread(void)
|
||
{
|
||
- return current->flags & PF_SPREAD_PAGE;
|
||
+ return task_spread_page(current);
|
||
}
|
||
|
||
static inline int cpuset_do_slab_mem_spread(void)
|
||
{
|
||
- return current->flags & PF_SPREAD_SLAB;
|
||
+ return task_spread_slab(current);
|
||
}
|
||
|
||
extern int current_cpuset_is_being_rebound(void);
|
||
diff --git a/include/linux/efi.h b/include/linux/efi.h
|
||
index eee8b0b..6bf8394 100644
|
||
--- a/include/linux/efi.h
|
||
+++ b/include/linux/efi.h
|
||
@@ -29,7 +29,12 @@
|
||
#define EFI_UNSUPPORTED ( 3 | (1UL << (BITS_PER_LONG-1)))
|
||
#define EFI_BAD_BUFFER_SIZE ( 4 | (1UL << (BITS_PER_LONG-1)))
|
||
#define EFI_BUFFER_TOO_SMALL ( 5 | (1UL << (BITS_PER_LONG-1)))
|
||
+#define EFI_NOT_READY ( 6 | (1UL << (BITS_PER_LONG-1)))
|
||
+#define EFI_DEVICE_ERROR ( 7 | (1UL << (BITS_PER_LONG-1)))
|
||
+#define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1)))
|
||
+#define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1)))
|
||
#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1)))
|
||
+#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1)))
|
||
|
||
typedef unsigned long efi_status_t;
|
||
typedef u8 efi_bool_t;
|
||
@@ -257,6 +262,7 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
|
||
unsigned long count,
|
||
u64 *max_size,
|
||
int *reset_type);
|
||
+typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long size);
|
||
|
||
/*
|
||
* EFI Configuration Table and GUID definitions
|
||
@@ -498,8 +504,14 @@ extern void efi_gettimeofday (struct timespec *ts);
|
||
extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */
|
||
#ifdef CONFIG_X86
|
||
extern void efi_free_boot_services(void);
|
||
+extern efi_status_t efi_query_variable_store(u32 attributes, unsigned long size);
|
||
#else
|
||
static inline void efi_free_boot_services(void) {}
|
||
+
|
||
+static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
|
||
+{
|
||
+ return EFI_SUCCESS;
|
||
+}
|
||
#endif
|
||
extern u64 efi_get_iobase (void);
|
||
extern u32 efi_mem_type (unsigned long phys_addr);
|
||
@@ -652,6 +664,7 @@ struct efivar_operations {
|
||
efi_get_variable_t *get_variable;
|
||
efi_get_next_variable_t *get_next_variable;
|
||
efi_set_variable_t *set_variable;
|
||
+ efi_query_variable_store_t *query_variable_store;
|
||
};
|
||
|
||
struct efivars {
|
||
@@ -660,7 +673,8 @@ struct efivars {
|
||
* 1) ->list - adds, removals, reads, writes
|
||
* 2) ops.[gs]et_variable() calls.
|
||
* It must not be held when creating sysfs entries or calling kmalloc.
|
||
- * ops.get_next_variable() is only called from register_efivars(),
|
||
+ * ops.get_next_variable() is only called from register_efivars()
|
||
+ * or efivar_update_sysfs_entries(),
|
||
* which is protected by the BKL, so that path is safe.
|
||
*/
|
||
spinlock_t lock;
|
||
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
|
||
index 4d259fc7..66e013b 100644
|
||
--- a/include/linux/firewire.h
|
||
+++ b/include/linux/firewire.h
|
||
@@ -186,6 +186,7 @@ struct fw_device {
|
||
unsigned irmc:1;
|
||
unsigned bc_implemented:2;
|
||
|
||
+ work_func_t workfn;
|
||
struct delayed_work work;
|
||
struct fw_attribute_group attribute_group;
|
||
};
|
||
diff --git a/include/linux/fs.h b/include/linux/fs.h
|
||
index 338eca4..a5fb99d 100644
|
||
--- a/include/linux/fs.h
|
||
+++ b/include/linux/fs.h
|
||
@@ -926,9 +926,11 @@ static inline loff_t i_size_read(const struct inode *inode)
|
||
static inline void i_size_write(struct inode *inode, loff_t i_size)
|
||
{
|
||
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
||
+ preempt_disable();
|
||
write_seqcount_begin(&inode->i_size_seqcount);
|
||
inode->i_size = i_size;
|
||
write_seqcount_end(&inode->i_size_seqcount);
|
||
+ preempt_enable();
|
||
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT)
|
||
preempt_disable();
|
||
inode->i_size = i_size;
|
||
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
|
||
index f80ca4a..bfbcd43 100644
|
||
--- a/include/linux/ftrace.h
|
||
+++ b/include/linux/ftrace.h
|
||
@@ -374,6 +374,7 @@ extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
|
||
extern int ftrace_arch_read_dyn_info(char *buf, int size);
|
||
|
||
extern int skip_trace(unsigned long ip);
|
||
+extern void ftrace_module_init(struct module *mod);
|
||
|
||
extern void ftrace_disable_daemon(void);
|
||
extern void ftrace_enable_daemon(void);
|
||
@@ -383,6 +384,7 @@ static inline int ftrace_force_update(void) { return 0; }
|
||
static inline void ftrace_disable_daemon(void) { }
|
||
static inline void ftrace_enable_daemon(void) { }
|
||
static inline void ftrace_release_mod(struct module *mod) {}
|
||
+static inline void ftrace_module_init(struct module *mod) {}
|
||
static inline int register_ftrace_command(struct ftrace_func_command *cmd)
|
||
{
|
||
return -EINVAL;
|
||
diff --git a/include/linux/hid.h b/include/linux/hid.h
|
||
index 72978c6..117bcf8 100644
|
||
--- a/include/linux/hid.h
|
||
+++ b/include/linux/hid.h
|
||
@@ -907,7 +907,7 @@ static inline int hid_hw_power(struct hid_device *hdev, int level)
|
||
return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0;
|
||
}
|
||
|
||
-void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||
int interrupt);
|
||
|
||
extern int hid_generic_init(void);
|
||
diff --git a/include/linux/hidraw.h b/include/linux/hidraw.h
|
||
index 4b88e69..45e9fcb 100644
|
||
--- a/include/linux/hidraw.h
|
||
+++ b/include/linux/hidraw.h
|
||
@@ -76,13 +76,13 @@ struct hidraw_list {
|
||
#ifdef CONFIG_HIDRAW
|
||
int hidraw_init(void);
|
||
void hidraw_exit(void);
|
||
-void hidraw_report_event(struct hid_device *, u8 *, int);
|
||
+int hidraw_report_event(struct hid_device *, u8 *, int);
|
||
int hidraw_connect(struct hid_device *);
|
||
void hidraw_disconnect(struct hid_device *);
|
||
#else
|
||
static inline int hidraw_init(void) { return 0; }
|
||
static inline void hidraw_exit(void) { }
|
||
-static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { }
|
||
+static inline int hidraw_report_event(struct hid_device *hid, u8 *data, int len) { return 0; }
|
||
static inline int hidraw_connect(struct hid_device *hid) { return -1; }
|
||
static inline void hidraw_disconnect(struct hid_device *hid) { }
|
||
#endif
|
||
diff --git a/include/linux/idr.h b/include/linux/idr.h
|
||
index 255491c..52a9da2 100644
|
||
--- a/include/linux/idr.h
|
||
+++ b/include/linux/idr.h
|
||
@@ -152,4 +152,15 @@ void ida_simple_remove(struct ida *ida, unsigned int id);
|
||
|
||
void __init idr_init_cache(void);
|
||
|
||
+/**
|
||
+ * idr_for_each_entry - iterate over an idr's elements of a given type
|
||
+ * @idp: idr handle
|
||
+ * @entry: the type * to use as cursor
|
||
+ * @id: id entry's key
|
||
+ */
|
||
+#define idr_for_each_entry(idp, entry, id) \
|
||
+ for (id = 0, entry = (typeof(entry))idr_get_next((idp), &(id)); \
|
||
+ entry != NULL; \
|
||
+ ++id, entry = (typeof(entry))idr_get_next((idp), &(id)))
|
||
+
|
||
#endif /* __IDR_H__ */
|
||
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
|
||
index 58404b0..b159b10 100644
|
||
--- a/include/linux/if_team.h
|
||
+++ b/include/linux/if_team.h
|
||
@@ -113,6 +113,7 @@ struct team {
|
||
|
||
const struct team_mode *mode;
|
||
struct team_mode_ops ops;
|
||
+ bool port_mtu_change_allowed;
|
||
long mode_priv[TEAM_MODE_PRIV_LONGS];
|
||
};
|
||
|
||
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
|
||
index 6ae21bc..5721000 100644
|
||
--- a/include/linux/irqdesc.h
|
||
+++ b/include/linux/irqdesc.h
|
||
@@ -27,6 +27,8 @@ struct module;
|
||
* @irq_count: stats field to detect stalled irqs
|
||
* @last_unhandled: aging timer for unhandled count
|
||
* @irqs_unhandled: stats field for spurious unhandled interrupts
|
||
+ * @threads_handled: stats field for deferred spurious detection of threaded handlers
|
||
+ * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers
|
||
* @lock: locking for SMP
|
||
* @affinity_hint: hint to user space for preferred irq affinity
|
||
* @affinity_notify: context for notification of affinity changes
|
||
@@ -52,6 +54,8 @@ struct irq_desc {
|
||
unsigned int irq_count; /* For detecting broken IRQs */
|
||
unsigned long last_unhandled; /* Aging timer for unhandled count */
|
||
unsigned int irqs_unhandled;
|
||
+ atomic_t threads_handled;
|
||
+ int threads_handled_last;
|
||
raw_spinlock_t lock;
|
||
struct cpumask *percpu_enabled;
|
||
#ifdef CONFIG_SMP
|
||
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
|
||
index dd6444f..2ffbf99 100644
|
||
--- a/include/linux/jbd2.h
|
||
+++ b/include/linux/jbd2.h
|
||
@@ -1178,6 +1178,7 @@ int __jbd2_log_start_commit(journal_t *journal, tid_t tid);
|
||
int jbd2_journal_start_commit(journal_t *journal, tid_t *tid);
|
||
int jbd2_journal_force_commit_nested(journal_t *journal);
|
||
int jbd2_log_wait_commit(journal_t *journal, tid_t tid);
|
||
+int jbd2_complete_transaction(journal_t *journal, tid_t tid);
|
||
int jbd2_log_do_checkpoint(journal_t *journal);
|
||
int jbd2_trans_will_send_data_barrier(journal_t *journal, tid_t tid);
|
||
|
||
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
|
||
index 265e2c3..f4e8578f 100644
|
||
--- a/include/linux/jiffies.h
|
||
+++ b/include/linux/jiffies.h
|
||
@@ -106,13 +106,13 @@ static inline u64 get_jiffies_64(void)
|
||
#define time_after(a,b) \
|
||
(typecheck(unsigned long, a) && \
|
||
typecheck(unsigned long, b) && \
|
||
- ((long)(b) - (long)(a) < 0))
|
||
+ ((long)((b) - (a)) < 0))
|
||
#define time_before(a,b) time_after(b,a)
|
||
|
||
#define time_after_eq(a,b) \
|
||
(typecheck(unsigned long, a) && \
|
||
typecheck(unsigned long, b) && \
|
||
- ((long)(a) - (long)(b) >= 0))
|
||
+ ((long)((a) - (b)) >= 0))
|
||
#define time_before_eq(a,b) time_after_eq(b,a)
|
||
|
||
/*
|
||
@@ -135,13 +135,13 @@ static inline u64 get_jiffies_64(void)
|
||
#define time_after64(a,b) \
|
||
(typecheck(__u64, a) && \
|
||
typecheck(__u64, b) && \
|
||
- ((__s64)(b) - (__s64)(a) < 0))
|
||
+ ((__s64)((b) - (a)) < 0))
|
||
#define time_before64(a,b) time_after64(b,a)
|
||
|
||
#define time_after_eq64(a,b) \
|
||
(typecheck(__u64, a) && \
|
||
typecheck(__u64, b) && \
|
||
- ((__s64)(a) - (__s64)(b) >= 0))
|
||
+ ((__s64)((a) - (b)) >= 0))
|
||
#define time_before_eq64(a,b) time_after_eq64(b,a)
|
||
|
||
/*
|
||
@@ -259,23 +259,11 @@ extern unsigned long preset_lpj;
|
||
#define SEC_JIFFIE_SC (32 - SHIFT_HZ)
|
||
#endif
|
||
#define NSEC_JIFFIE_SC (SEC_JIFFIE_SC + 29)
|
||
-#define USEC_JIFFIE_SC (SEC_JIFFIE_SC + 19)
|
||
#define SEC_CONVERSION ((unsigned long)((((u64)NSEC_PER_SEC << SEC_JIFFIE_SC) +\
|
||
TICK_NSEC -1) / (u64)TICK_NSEC))
|
||
|
||
#define NSEC_CONVERSION ((unsigned long)((((u64)1 << NSEC_JIFFIE_SC) +\
|
||
TICK_NSEC -1) / (u64)TICK_NSEC))
|
||
-#define USEC_CONVERSION \
|
||
- ((unsigned long)((((u64)NSEC_PER_USEC << USEC_JIFFIE_SC) +\
|
||
- TICK_NSEC -1) / (u64)TICK_NSEC))
|
||
-/*
|
||
- * USEC_ROUND is used in the timeval to jiffie conversion. See there
|
||
- * for more details. It is the scaled resolution rounding value. Note
|
||
- * that it is a 64-bit value. Since, when it is applied, we are already
|
||
- * in jiffies (albit scaled), it is nothing but the bits we will shift
|
||
- * off.
|
||
- */
|
||
-#define USEC_ROUND (u64)(((u64)1 << USEC_JIFFIE_SC) - 1)
|
||
/*
|
||
* The maximum jiffie value is (MAX_INT >> 1). Here we translate that
|
||
* into seconds. The 64-bit case will overflow if we are not careful,
|
||
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
|
||
index 7b69a81..bfbad4d 100644
|
||
--- a/include/linux/kernel.h
|
||
+++ b/include/linux/kernel.h
|
||
@@ -35,6 +35,7 @@
|
||
#define LLONG_MAX ((long long)(~0ULL>>1))
|
||
#define LLONG_MIN (-LLONG_MAX - 1)
|
||
#define ULLONG_MAX (~0ULL)
|
||
+#define SIZE_MAX (~(size_t)0)
|
||
|
||
#define STACK_MAGIC 0xdeadbeef
|
||
|
||
diff --git a/include/linux/libata.h b/include/linux/libata.h
|
||
index 7e13eb4..dd16deb 100644
|
||
--- a/include/linux/libata.h
|
||
+++ b/include/linux/libata.h
|
||
@@ -539,6 +539,7 @@ struct ata_host {
|
||
struct device *dev;
|
||
void __iomem * const *iomap;
|
||
unsigned int n_ports;
|
||
+ unsigned int n_tags; /* nr of NCQ tags */
|
||
void *private_data;
|
||
struct ata_port_operations *ops;
|
||
unsigned long flags;
|
||
@@ -762,6 +763,7 @@ struct ata_port {
|
||
unsigned long qc_allocated;
|
||
unsigned int qc_active;
|
||
int nr_active_links; /* #links with active qcs */
|
||
+ unsigned int last_tag; /* track next tag hw expects */
|
||
|
||
struct ata_link link; /* host default link */
|
||
struct ata_link *slave_link; /* see ata_slave_link_init() */
|
||
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
|
||
index fe07e5a..cc49b23 100644
|
||
--- a/include/linux/mempolicy.h
|
||
+++ b/include/linux/mempolicy.h
|
||
@@ -205,7 +205,7 @@ extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
|
||
extern bool init_nodemask_of_mempolicy(nodemask_t *mask);
|
||
extern bool mempolicy_nodemask_intersects(struct task_struct *tsk,
|
||
const nodemask_t *mask);
|
||
-extern unsigned slab_node(struct mempolicy *policy);
|
||
+extern unsigned slab_node(void);
|
||
|
||
extern enum zone_type policy_zone;
|
||
|
||
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
|
||
index 5788ad6..cb33f1a 100644
|
||
--- a/include/linux/mm_types.h
|
||
+++ b/include/linux/mm_types.h
|
||
@@ -311,6 +311,7 @@ struct mm_struct {
|
||
void (*unmap_area) (struct mm_struct *mm, unsigned long addr);
|
||
#endif
|
||
unsigned long mmap_base; /* base of mmap area */
|
||
+ unsigned long mmap_legacy_base; /* base of mmap area in bottom-up allocations */
|
||
unsigned long task_size; /* size of task vm space */
|
||
unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */
|
||
unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */
|
||
diff --git a/include/linux/msg.h b/include/linux/msg.h
|
||
index 56abf155..70fc369 100644
|
||
--- a/include/linux/msg.h
|
||
+++ b/include/linux/msg.h
|
||
@@ -76,9 +76,9 @@ struct msginfo {
|
||
|
||
/* one msg_msg structure for each message */
|
||
struct msg_msg {
|
||
- struct list_head m_list;
|
||
- long m_type;
|
||
- int m_ts; /* message text size */
|
||
+ struct list_head m_list;
|
||
+ long m_type;
|
||
+ size_t m_ts; /* message text size */
|
||
struct msg_msgseg* next;
|
||
void *security;
|
||
/* the actual message follows immediately */
|
||
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
|
||
index 3595a02..292645f 100644
|
||
--- a/include/linux/mtd/map.h
|
||
+++ b/include/linux/mtd/map.h
|
||
@@ -362,7 +362,7 @@ static inline map_word map_word_load_partial(struct map_info *map, map_word orig
|
||
bitpos = (map_bankwidth(map)-1-i)*8;
|
||
#endif
|
||
orig.x[0] &= ~(0xff << bitpos);
|
||
- orig.x[0] |= buf[i-start] << bitpos;
|
||
+ orig.x[0] |= (unsigned long)buf[i-start] << bitpos;
|
||
}
|
||
}
|
||
return orig;
|
||
@@ -381,7 +381,7 @@ static inline map_word map_word_ff(struct map_info *map)
|
||
|
||
if (map_bankwidth(map) < MAP_FF_LIMIT) {
|
||
int bw = 8 * map_bankwidth(map);
|
||
- r.x[0] = (1 << bw) - 1;
|
||
+ r.x[0] = (1UL << bw) - 1;
|
||
} else {
|
||
for (i=0; i<map_words(map); i++)
|
||
r.x[i] = ~0UL;
|
||
diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h
|
||
index 30b0c4e..43e038a 100644
|
||
--- a/include/linux/mv643xx_eth.h
|
||
+++ b/include/linux/mv643xx_eth.h
|
||
@@ -15,6 +15,8 @@
|
||
#define MV643XX_ETH_SIZE_REG_4 0x2224
|
||
#define MV643XX_ETH_BASE_ADDR_ENABLE_REG 0x2290
|
||
|
||
+#define MV643XX_TX_CSUM_DEFAULT_LIMIT 0
|
||
+
|
||
struct mv643xx_eth_shared_platform_data {
|
||
struct mbus_dram_target_info *dram;
|
||
struct platform_device *shared_smi;
|
||
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
|
||
index d146ca1..e6fe174 100644
|
||
--- a/include/linux/nbd.h
|
||
+++ b/include/linux/nbd.h
|
||
@@ -68,6 +68,7 @@ struct nbd_device {
|
||
u64 bytesize;
|
||
pid_t pid; /* pid of nbd-client, if attached */
|
||
int xmit_timeout;
|
||
+ int disconnect; /* a disconnect has been requested by user */
|
||
};
|
||
|
||
#endif
|
||
diff --git a/include/linux/net.h b/include/linux/net.h
|
||
index 95fea14..16b4996 100644
|
||
--- a/include/linux/net.h
|
||
+++ b/include/linux/net.h
|
||
@@ -198,6 +198,14 @@ struct proto_ops {
|
||
#endif
|
||
int (*sendmsg) (struct kiocb *iocb, struct socket *sock,
|
||
struct msghdr *m, size_t total_len);
|
||
+ /* Notes for implementing recvmsg:
|
||
+ * ===============================
|
||
+ * msg->msg_namelen should get updated by the recvmsg handlers
|
||
+ * iff msg_name != NULL. It is by default 0 to prevent
|
||
+ * returning uninitialized memory to user space. The recvfrom
|
||
+ * handlers can assume that msg.msg_name is either NULL or has
|
||
+ * a minimum size of sizeof(struct sockaddr_storage).
|
||
+ */
|
||
int (*recvmsg) (struct kiocb *iocb, struct socket *sock,
|
||
struct msghdr *m, size_t total_len,
|
||
int flags);
|
||
@@ -207,7 +215,7 @@ struct proto_ops {
|
||
int offset, size_t size, int flags);
|
||
ssize_t (*splice_read)(struct socket *sock, loff_t *ppos,
|
||
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
|
||
- void (*set_peek_off)(struct sock *sk, int val);
|
||
+ int (*set_peek_off)(struct sock *sk, int val);
|
||
};
|
||
|
||
#define DECLARE_SOCKADDR(type, dst, src) \
|
||
@@ -251,6 +259,52 @@ extern struct socket *sockfd_lookup(int fd, int *err);
|
||
#define sockfd_put(sock) fput(sock->file)
|
||
extern int net_ratelimit(void);
|
||
|
||
+#define net_ratelimited_function(function, ...) \
|
||
+do { \
|
||
+ if (net_ratelimit()) \
|
||
+ function(__VA_ARGS__); \
|
||
+} while (0)
|
||
+
|
||
+#define net_emerg_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_emerg, fmt, ##__VA_ARGS__)
|
||
+#define net_alert_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_alert, fmt, ##__VA_ARGS__)
|
||
+#define net_crit_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_crit, fmt, ##__VA_ARGS__)
|
||
+#define net_err_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_err, fmt, ##__VA_ARGS__)
|
||
+#define net_notice_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_notice, fmt, ##__VA_ARGS__)
|
||
+#define net_warn_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_warn, fmt, ##__VA_ARGS__)
|
||
+#define net_info_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_info, fmt, ##__VA_ARGS__)
|
||
+#define net_dbg_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
|
||
+
|
||
+#define net_ratelimited_function(function, ...) \
|
||
+do { \
|
||
+ if (net_ratelimit()) \
|
||
+ function(__VA_ARGS__); \
|
||
+} while (0)
|
||
+
|
||
+#define net_emerg_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_emerg, fmt, ##__VA_ARGS__)
|
||
+#define net_alert_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_alert, fmt, ##__VA_ARGS__)
|
||
+#define net_crit_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_crit, fmt, ##__VA_ARGS__)
|
||
+#define net_err_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_err, fmt, ##__VA_ARGS__)
|
||
+#define net_notice_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_notice, fmt, ##__VA_ARGS__)
|
||
+#define net_warn_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_warn, fmt, ##__VA_ARGS__)
|
||
+#define net_info_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_info, fmt, ##__VA_ARGS__)
|
||
+#define net_dbg_ratelimited(fmt, ...) \
|
||
+ net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
|
||
+
|
||
#define net_random() random32()
|
||
#define net_srandom(seed) srandom32((__force u32)seed)
|
||
|
||
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
||
index dc6c687..5b46501 100644
|
||
--- a/include/linux/netdevice.h
|
||
+++ b/include/linux/netdevice.h
|
||
@@ -1702,6 +1702,15 @@ static inline int dev_parse_header(const struct sk_buff *skb,
|
||
return dev->header_ops->parse(skb, haddr);
|
||
}
|
||
|
||
+static inline int dev_rebuild_header(struct sk_buff *skb)
|
||
+{
|
||
+ const struct net_device *dev = skb->dev;
|
||
+
|
||
+ if (!dev->header_ops || !dev->header_ops->rebuild)
|
||
+ return 0;
|
||
+ return dev->header_ops->rebuild(skb);
|
||
+}
|
||
+
|
||
typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len);
|
||
extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf);
|
||
static inline int unregister_gifconf(unsigned int family)
|
||
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
|
||
index d7dbf4e..0a7e4f4 100644
|
||
--- a/include/linux/pci_ids.h
|
||
+++ b/include/linux/pci_ids.h
|
||
@@ -752,6 +752,7 @@
|
||
#define PCI_DEVICE_ID_HP_CISSD 0x3238
|
||
#define PCI_DEVICE_ID_HP_CISSE 0x323a
|
||
#define PCI_DEVICE_ID_HP_CISSF 0x323b
|
||
+#define PCI_DEVICE_ID_HP_CISSH 0x323c
|
||
#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031
|
||
|
||
#define PCI_VENDOR_ID_PCTECH 0x1042
|
||
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
|
||
index 861b354..efe0889 100644
|
||
--- a/include/linux/perf_event.h
|
||
+++ b/include/linux/perf_event.h
|
||
@@ -392,13 +392,15 @@ struct perf_event_mmap_page {
|
||
/*
|
||
* Control data for the mmap() data buffer.
|
||
*
|
||
- * User-space reading the @data_head value should issue an rmb(), on
|
||
- * SMP capable platforms, after reading this value -- see
|
||
- * perf_event_wakeup().
|
||
+ * User-space reading the @data_head value should issue an smp_rmb(),
|
||
+ * after reading this value.
|
||
*
|
||
* When the mapping is PROT_WRITE the @data_tail value should be
|
||
- * written by userspace to reflect the last read data. In this case
|
||
- * the kernel will not over-write unread data.
|
||
+ * written by userspace to reflect the last read data, after issueing
|
||
+ * an smp_mb() to separate the data read from the ->data_tail store.
|
||
+ * In this case the kernel will not over-write unread data.
|
||
+ *
|
||
+ * See perf_output_put_handle() for the data ordering.
|
||
*/
|
||
__u64 data_head; /* head in the data section */
|
||
__u64 data_tail; /* user-space written tail */
|
||
diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h
|
||
index 9404854..ce2ab3d 100644
|
||
--- a/include/linux/pps_kernel.h
|
||
+++ b/include/linux/pps_kernel.h
|
||
@@ -43,7 +43,7 @@ struct pps_source_info {
|
||
int event, void *data); /* PPS echo function */
|
||
|
||
struct module *owner;
|
||
- struct device *dev;
|
||
+ struct device *dev; /* Parent device for device_create */
|
||
};
|
||
|
||
struct pps_event_time {
|
||
@@ -69,6 +69,7 @@ struct pps_device {
|
||
wait_queue_head_t queue; /* PPS event queue */
|
||
|
||
unsigned int id; /* PPS source unique ID */
|
||
+ void const *lookup_cookie; /* pps_lookup_dev only */
|
||
struct cdev cdev;
|
||
struct device *dev;
|
||
struct fasync_struct *async_queue; /* fasync method */
|
||
@@ -82,16 +83,26 @@ struct pps_device {
|
||
extern struct device_attribute pps_attrs[];
|
||
|
||
/*
|
||
+ * Internal functions.
|
||
+ *
|
||
+ * These are not actually part of the exported API, but this is a
|
||
+ * convenient header file to put them in.
|
||
+ */
|
||
+
|
||
+extern int pps_register_cdev(struct pps_device *pps);
|
||
+extern void pps_unregister_cdev(struct pps_device *pps);
|
||
+
|
||
+/*
|
||
* Exported functions
|
||
*/
|
||
|
||
extern struct pps_device *pps_register_source(
|
||
struct pps_source_info *info, int default_params);
|
||
extern void pps_unregister_source(struct pps_device *pps);
|
||
-extern int pps_register_cdev(struct pps_device *pps);
|
||
-extern void pps_unregister_cdev(struct pps_device *pps);
|
||
extern void pps_event(struct pps_device *pps,
|
||
struct pps_event_time *ts, int event, void *data);
|
||
+/* Look up a pps device by magic cookie */
|
||
+struct pps_device *pps_lookup_dev(void const *cookie);
|
||
|
||
static inline void timespec_to_pps_ktime(struct pps_ktime *kt,
|
||
struct timespec ts)
|
||
diff --git a/include/linux/printk.h b/include/linux/printk.h
|
||
index 0525927..d633115 100644
|
||
--- a/include/linux/printk.h
|
||
+++ b/include/linux/printk.h
|
||
@@ -101,9 +101,9 @@ asmlinkage __printf(1, 2) __cold
|
||
int printk(const char *fmt, ...);
|
||
|
||
/*
|
||
- * Special printk facility for scheduler use only, _DO_NOT_USE_ !
|
||
+ * Special printk facility for scheduler/timekeeping use only, _DO_NOT_USE_ !
|
||
*/
|
||
-__printf(1, 2) __cold int printk_sched(const char *fmt, ...);
|
||
+__printf(1, 2) __cold int printk_deferred(const char *fmt, ...);
|
||
|
||
/*
|
||
* Please don't use printk_ratelimit(), because it shares ratelimiting state
|
||
@@ -133,7 +133,7 @@ int printk(const char *s, ...)
|
||
return 0;
|
||
}
|
||
static inline __printf(1, 2) __cold
|
||
-int printk_sched(const char *s, ...)
|
||
+int printk_deferred(const char *s, ...)
|
||
{
|
||
return 0;
|
||
}
|
||
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
|
||
index 597e4fd..b3ae442 100644
|
||
--- a/include/linux/ptrace.h
|
||
+++ b/include/linux/ptrace.h
|
||
@@ -382,6 +382,9 @@ static inline void user_single_step_siginfo(struct task_struct *tsk,
|
||
* calling arch_ptrace_stop() when it would be superfluous. For example,
|
||
* if the thread has not been back to user mode since the last stop, the
|
||
* thread state might indicate that nothing needs to be done.
|
||
+ *
|
||
+ * This is guaranteed to be invoked once before a task stops for ptrace and
|
||
+ * may include arch-specific operations necessary prior to a ptrace stop.
|
||
*/
|
||
#define arch_ptrace_stop_needed(code, info) (0)
|
||
#endif
|
||
diff --git a/include/linux/random.h b/include/linux/random.h
|
||
index 7e58ad2..54b1fd3 100644
|
||
--- a/include/linux/random.h
|
||
+++ b/include/linux/random.h
|
||
@@ -87,9 +87,9 @@ static inline void prandom32_seed(struct rnd_state *state, u64 seed)
|
||
{
|
||
u32 i = (seed >> 32) ^ (seed << 10) ^ seed;
|
||
|
||
- state->s1 = __seed(i, 1);
|
||
- state->s2 = __seed(i, 7);
|
||
- state->s3 = __seed(i, 15);
|
||
+ state->s1 = __seed(i, 2);
|
||
+ state->s2 = __seed(i, 8);
|
||
+ state->s3 = __seed(i, 16);
|
||
}
|
||
|
||
#ifdef CONFIG_ARCH_RANDOM
|
||
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
||
index 8dea918..3fd25d8 100644
|
||
--- a/include/linux/sched.h
|
||
+++ b/include/linux/sched.h
|
||
@@ -146,6 +146,7 @@ extern void sched_update_nr_prod(int cpu, unsigned long nr, bool inc);
|
||
extern void sched_get_nr_running_avg(int *avg, int *iowait_avg);
|
||
|
||
extern void calc_global_load(unsigned long ticks);
|
||
+extern void update_cpu_load_nohz(void);
|
||
|
||
extern unsigned long get_parent_ip(unsigned long addr);
|
||
|
||
@@ -407,6 +408,10 @@ static inline void arch_pick_mmap_layout(struct mm_struct *mm) {}
|
||
extern void set_dumpable(struct mm_struct *mm, int value);
|
||
extern int get_dumpable(struct mm_struct *mm);
|
||
|
||
+#define SUID_DUMP_DISABLE 0 /* No setuid dumping */
|
||
+#define SUID_DUMP_USER 1 /* Dump as user of process */
|
||
+#define SUID_DUMP_ROOT 2 /* Dump as root */
|
||
+
|
||
/* mm flags */
|
||
/* dumpable bits */
|
||
#define MMF_DUMPABLE 0 /* core dump is permitted */
|
||
@@ -1237,6 +1242,7 @@ struct sched_entity {
|
||
struct sched_rt_entity {
|
||
struct list_head run_list;
|
||
unsigned long timeout;
|
||
+ unsigned long watchdog_stamp;
|
||
unsigned int time_slice;
|
||
int nr_cpus_allowed;
|
||
|
||
@@ -1837,8 +1843,6 @@ extern int task_free_unregister(struct notifier_block *n);
|
||
#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
|
||
#define PF_RANDOMIZE 0x00400000 /* randomize virtual address space */
|
||
#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */
|
||
-#define PF_SPREAD_PAGE 0x01000000 /* Spread page cache over cpuset */
|
||
-#define PF_SPREAD_SLAB 0x02000000 /* Spread some slab caches over cpuset */
|
||
#define PF_THREAD_BOUND 0x04000000 /* Thread bound to specific cpu */
|
||
#define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */
|
||
#define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */
|
||
@@ -1871,6 +1875,19 @@ extern int task_free_unregister(struct notifier_block *n);
|
||
#define used_math() tsk_used_math(current)
|
||
|
||
/* Per-process atomic flags. */
|
||
+#define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */
|
||
+#define PFA_SPREAD_SLAB 2 /* Spread some slab caches over cpuset */
|
||
+
|
||
+#define TASK_PFA_TEST(name, func) \
|
||
+ static inline bool task_##func(struct task_struct *p) \
|
||
+ { return test_bit(PFA_##name, &p->atomic_flags); }
|
||
+#define TASK_PFA_SET(name, func) \
|
||
+ static inline void task_set_##func(struct task_struct *p) \
|
||
+ { set_bit(PFA_##name, &p->atomic_flags); }
|
||
+#define TASK_PFA_CLEAR(name, func) \
|
||
+ static inline void task_clear_##func(struct task_struct *p) \
|
||
+ { clear_bit(PFA_##name, &p->atomic_flags); }
|
||
+
|
||
#define PFA_NO_NEW_PRIVS 0x00000001 /* May not gain new privileges. */
|
||
|
||
static inline bool task_no_new_privs(struct task_struct *p)
|
||
@@ -1982,6 +1999,14 @@ static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
|
||
}
|
||
#endif
|
||
|
||
+TASK_PFA_TEST(SPREAD_PAGE, spread_page)
|
||
+TASK_PFA_SET(SPREAD_PAGE, spread_page)
|
||
+TASK_PFA_CLEAR(SPREAD_PAGE, spread_page)
|
||
+
|
||
+TASK_PFA_TEST(SPREAD_SLAB, spread_slab)
|
||
+TASK_PFA_SET(SPREAD_SLAB, spread_slab)
|
||
+TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab)
|
||
+
|
||
/*
|
||
* Do not use outside of architecture code which knows its limitations.
|
||
*
|
||
@@ -2508,27 +2533,18 @@ static inline void threadgroup_change_end(struct task_struct *tsk)
|
||
*
|
||
* Lock the threadgroup @tsk belongs to. No new task is allowed to enter
|
||
* and member tasks aren't allowed to exit (as indicated by PF_EXITING) or
|
||
- * perform exec. This is useful for cases where the threadgroup needs to
|
||
- * stay stable across blockable operations.
|
||
+ * change ->group_leader/pid. This is useful for cases where the threadgroup
|
||
+ * needs to stay stable across blockable operations.
|
||
*
|
||
* fork and exit paths explicitly call threadgroup_change_{begin|end}() for
|
||
* synchronization. While held, no new task will be added to threadgroup
|
||
* and no existing live task will have its PF_EXITING set.
|
||
*
|
||
- * During exec, a task goes and puts its thread group through unusual
|
||
- * changes. After de-threading, exclusive access is assumed to resources
|
||
- * which are usually shared by tasks in the same group - e.g. sighand may
|
||
- * be replaced with a new one. Also, the exec'ing task takes over group
|
||
- * leader role including its pid. Exclude these changes while locked by
|
||
- * grabbing cred_guard_mutex which is used to synchronize exec path.
|
||
+ * de_thread() does threadgroup_change_{begin|end}() when a non-leader
|
||
+ * sub-thread becomes a new leader.
|
||
*/
|
||
static inline void threadgroup_lock(struct task_struct *tsk)
|
||
{
|
||
- /*
|
||
- * exec uses exit for de-threading nesting group_rwsem inside
|
||
- * cred_guard_mutex. Grab cred_guard_mutex first.
|
||
- */
|
||
- mutex_lock(&tsk->signal->cred_guard_mutex);
|
||
down_write(&tsk->signal->group_rwsem);
|
||
}
|
||
|
||
@@ -2541,7 +2557,6 @@ static inline void threadgroup_lock(struct task_struct *tsk)
|
||
static inline void threadgroup_unlock(struct task_struct *tsk)
|
||
{
|
||
up_write(&tsk->signal->group_rwsem);
|
||
- mutex_unlock(&tsk->signal->cred_guard_mutex);
|
||
}
|
||
#else
|
||
static inline void threadgroup_change_begin(struct task_struct *tsk) {}
|
||
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
|
||
index 828c803..fb444a6 100644
|
||
--- a/include/linux/serial_core.h
|
||
+++ b/include/linux/serial_core.h
|
||
@@ -47,7 +47,11 @@
|
||
#define PORT_U6_16550A 19 /* ST-Ericsson U6xxx internal UART */
|
||
#define PORT_TEGRA 20 /* NVIDIA Tegra internal UART */
|
||
#define PORT_XR17D15X 21 /* Exar XR17D15x UART */
|
||
-#define PORT_MAX_8250 21 /* max port ID */
|
||
+#define PORT_BRCM_TRUMANAGE 25
|
||
+#define PORT_ALTR_16550_F32 26 /* Altera 16550 UART with 32 FIFOs */
|
||
+#define PORT_ALTR_16550_F64 27 /* Altera 16550 UART with 64 FIFOs */
|
||
+#define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
|
||
+#define PORT_MAX_8250 28 /* max port ID */
|
||
|
||
/*
|
||
* ARM specific type numbers. These are not currently guaranteed
|
||
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
||
index dc4d49a..4424db2 100644
|
||
--- a/include/linux/skbuff.h
|
||
+++ b/include/linux/skbuff.h
|
||
@@ -640,11 +640,21 @@ static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
|
||
{
|
||
return skb->head + skb->end;
|
||
}
|
||
+
|
||
+static inline unsigned int skb_end_offset(const struct sk_buff *skb)
|
||
+{
|
||
+ return skb->end;
|
||
+}
|
||
#else
|
||
static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
|
||
{
|
||
return skb->end;
|
||
}
|
||
+
|
||
+static inline unsigned int skb_end_offset(const struct sk_buff *skb)
|
||
+{
|
||
+ return skb->end - skb->head;
|
||
+}
|
||
#endif
|
||
|
||
/* Internal */
|
||
@@ -760,6 +770,16 @@ static inline int skb_cloned(const struct sk_buff *skb)
|
||
(atomic_read(&skb_shinfo(skb)->dataref) & SKB_DATAREF_MASK) != 1;
|
||
}
|
||
|
||
+static inline int skb_unclone(struct sk_buff *skb, gfp_t pri)
|
||
+{
|
||
+ might_sleep_if(pri & __GFP_WAIT);
|
||
+
|
||
+ if (skb_cloned(skb))
|
||
+ return pskb_expand_head(skb, 0, 0, pri);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
/**
|
||
* skb_header_cloned - is the header a clone
|
||
* @skb: buffer to check
|
||
@@ -1198,6 +1218,11 @@ static inline int skb_pagelen(const struct sk_buff *skb)
|
||
return len + skb_headlen(skb);
|
||
}
|
||
|
||
+static inline bool skb_has_frags(const struct sk_buff *skb)
|
||
+{
|
||
+ return skb_shinfo(skb)->nr_frags;
|
||
+}
|
||
+
|
||
/**
|
||
* __skb_fill_page_desc - initialise a paged fragment in an skb
|
||
* @skb: buffer containing fragment to be initialised
|
||
@@ -1649,6 +1674,22 @@ static inline void skb_orphan(struct sk_buff *skb)
|
||
}
|
||
|
||
/**
|
||
+ * skb_orphan_frags - orphan the frags contained in a buffer
|
||
+ * @skb: buffer to orphan frags from
|
||
+ * @gfp_mask: allocation mask for replacement pages
|
||
+ *
|
||
+ * For each frag in the SKB which needs a destructor (i.e. has an
|
||
+ * owner) create a copy of that frag and release the original
|
||
+ * page by calling the destructor.
|
||
+ */
|
||
+static inline int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask)
|
||
+{
|
||
+ if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)))
|
||
+ return 0;
|
||
+ return skb_copy_ubufs(skb, gfp_mask);
|
||
+}
|
||
+
|
||
+/**
|
||
* __skb_queue_purge - empty a list
|
||
* @list: list to empty
|
||
*
|
||
@@ -2144,6 +2185,8 @@ extern int skb_shift(struct sk_buff *tgt, struct sk_buff *skb,
|
||
extern struct sk_buff *skb_segment(struct sk_buff *skb,
|
||
netdev_features_t features);
|
||
|
||
+unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
|
||
+
|
||
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
|
||
int len, void *buffer)
|
||
{
|
||
@@ -2557,7 +2600,7 @@ static inline bool skb_is_recycleable(const struct sk_buff *skb, int skb_size)
|
||
return false;
|
||
|
||
skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
|
||
- if (skb_end_pointer(skb) - skb->head < skb_size)
|
||
+ if (skb_end_offset(skb) < skb_size)
|
||
return false;
|
||
|
||
if (skb_shared(skb) || skb_cloned(skb))
|
||
diff --git a/include/linux/slab.h b/include/linux/slab.h
|
||
index a595dce..67d5d94 100644
|
||
--- a/include/linux/slab.h
|
||
+++ b/include/linux/slab.h
|
||
@@ -242,7 +242,7 @@ size_t ksize(const void *);
|
||
*/
|
||
static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)
|
||
{
|
||
- if (size != 0 && n > ULONG_MAX / size)
|
||
+ if (size != 0 && n > SIZE_MAX / size)
|
||
return NULL;
|
||
return __kmalloc(n * size, flags);
|
||
}
|
||
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
|
||
index cb4ac69..e4c6cec 100644
|
||
--- a/include/linux/sunrpc/svcsock.h
|
||
+++ b/include/linux/sunrpc/svcsock.h
|
||
@@ -42,6 +42,7 @@ void svc_sock_update_bufs(struct svc_serv *serv);
|
||
int svc_sock_names(struct svc_serv *serv, char *buf,
|
||
const size_t buflen,
|
||
const char *toclose);
|
||
+bool svc_alien_sock(struct net *net, int fd);
|
||
int svc_addsock(struct svc_serv *serv, const int fd,
|
||
char *name_return, const size_t len);
|
||
void svc_init_xprt_sock(void);
|
||
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
|
||
index bd96ecd..c49c363 100644
|
||
--- a/include/linux/tracepoint.h
|
||
+++ b/include/linux/tracepoint.h
|
||
@@ -60,6 +60,12 @@ struct tp_module {
|
||
unsigned int num_tracepoints;
|
||
struct tracepoint * const *tracepoints_ptrs;
|
||
};
|
||
+bool trace_module_has_bad_taint(struct module *mod);
|
||
+#else
|
||
+static inline bool trace_module_has_bad_taint(struct module *mod)
|
||
+{
|
||
+ return false;
|
||
+}
|
||
#endif /* CONFIG_MODULES */
|
||
|
||
struct tracepoint_iter {
|
||
diff --git a/include/linux/usb.h b/include/linux/usb.h
|
||
index 53bead6..64995f1 100644
|
||
--- a/include/linux/usb.h
|
||
+++ b/include/linux/usb.h
|
||
@@ -755,6 +755,22 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
|
||
.bcdDevice_hi = (hi)
|
||
|
||
/**
|
||
+ * USB_DEVICE_INTERFACE_CLASS - describe a usb device with a specific interface class
|
||
+ * @vend: the 16 bit USB Vendor ID
|
||
+ * @prod: the 16 bit USB Product ID
|
||
+ * @cl: bInterfaceClass value
|
||
+ *
|
||
+ * This macro is used to create a struct usb_device_id that matches a
|
||
+ * specific interface class of devices.
|
||
+ */
|
||
+#define USB_DEVICE_INTERFACE_CLASS(vend, prod, cl) \
|
||
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
|
||
+ USB_DEVICE_ID_MATCH_INT_CLASS, \
|
||
+ .idVendor = (vend), \
|
||
+ .idProduct = (prod), \
|
||
+ .bInterfaceClass = (cl)
|
||
+
|
||
+/**
|
||
* USB_DEVICE_INTERFACE_PROTOCOL - describe a usb device with a specific interface protocol
|
||
* @vend: the 16 bit USB Vendor ID
|
||
* @prod: the 16 bit USB Product ID
|
||
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
|
||
index 3329306..7c3d8eb 100644
|
||
--- a/include/linux/usb/hcd.h
|
||
+++ b/include/linux/usb/hcd.h
|
||
@@ -411,7 +411,7 @@ extern int usb_hcd_pci_probe(struct pci_dev *dev,
|
||
extern void usb_hcd_pci_remove(struct pci_dev *dev);
|
||
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
|
||
|
||
-#ifdef CONFIG_PM_SLEEP
|
||
+#ifdef CONFIG_PM
|
||
extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
|
||
#endif
|
||
#endif /* CONFIG_PCI */
|
||
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
|
||
index 4742838..56dc033 100644
|
||
--- a/include/linux/usb/serial.h
|
||
+++ b/include/linux/usb/serial.h
|
||
@@ -66,6 +66,7 @@
|
||
* port.
|
||
* @flags: usb serial port flags
|
||
* @write_wait: a wait_queue_head_t used by the port.
|
||
+ * @delta_msr_wait: modem-status-change wait queue
|
||
* @work: work queue entry for the line discipline waking up.
|
||
* @throttled: nonzero if the read urb is inactive to throttle the device
|
||
* @throttle_req: nonzero if the tty wants to throttle us
|
||
@@ -112,6 +113,7 @@ struct usb_serial_port {
|
||
|
||
unsigned long flags;
|
||
wait_queue_head_t write_wait;
|
||
+ wait_queue_head_t delta_msr_wait;
|
||
struct work_struct work;
|
||
char throttled;
|
||
char throttle_req;
|
||
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
|
||
index bdf4b00..82e12ad 100644
|
||
--- a/include/linux/virtio_console.h
|
||
+++ b/include/linux/virtio_console.h
|
||
@@ -39,7 +39,7 @@
|
||
#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */
|
||
#define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */
|
||
|
||
-#define VIRTIO_CONSOLE_BAD_ID (~(u32)0)
|
||
+#define VIRTIO_CONSOLE_BAD_ID (~(__u32)0)
|
||
|
||
struct virtio_console_config {
|
||
/* colums of the screens */
|
||
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
|
||
index a7a683e..a8c2ef6 100644
|
||
--- a/include/net/cipso_ipv4.h
|
||
+++ b/include/net/cipso_ipv4.h
|
||
@@ -290,6 +290,7 @@ static inline int cipso_v4_validate(const struct sk_buff *skb,
|
||
unsigned char err_offset = 0;
|
||
u8 opt_len = opt[1];
|
||
u8 opt_iter;
|
||
+ u8 tag_len;
|
||
|
||
if (opt_len < 8) {
|
||
err_offset = 1;
|
||
@@ -302,11 +303,12 @@ static inline int cipso_v4_validate(const struct sk_buff *skb,
|
||
}
|
||
|
||
for (opt_iter = 6; opt_iter < opt_len;) {
|
||
- if (opt[opt_iter + 1] > (opt_len - opt_iter)) {
|
||
+ tag_len = opt[opt_iter + 1];
|
||
+ if ((tag_len == 0) || (opt[opt_iter + 1] > (opt_len - opt_iter))) {
|
||
err_offset = opt_iter + 1;
|
||
goto out;
|
||
}
|
||
- opt_iter += opt[opt_iter + 1];
|
||
+ opt_iter += tag_len;
|
||
}
|
||
|
||
out:
|
||
diff --git a/include/net/dst.h b/include/net/dst.h
|
||
index 8197ead..1efe71a 100644
|
||
--- a/include/net/dst.h
|
||
+++ b/include/net/dst.h
|
||
@@ -464,10 +464,22 @@ static inline struct dst_entry *xfrm_lookup(struct net *net,
|
||
{
|
||
return dst_orig;
|
||
}
|
||
+
|
||
+static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst)
|
||
+{
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
#else
|
||
extern struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
|
||
const struct flowi *fl, struct sock *sk,
|
||
int flags);
|
||
+
|
||
+/* skb attached with this dst needs transformation if dst->xfrm is valid */
|
||
+static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst)
|
||
+{
|
||
+ return dst->xfrm;
|
||
+}
|
||
#endif
|
||
|
||
#endif /* _NET_DST_H */
|
||
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
|
||
index 2040bff..2d64364 100644
|
||
--- a/include/net/inetpeer.h
|
||
+++ b/include/net/inetpeer.h
|
||
@@ -114,16 +114,9 @@ static inline void inet_peer_refcheck(const struct inet_peer *p)
|
||
/* can be called with or without local BH being disabled */
|
||
static inline int inet_getid(struct inet_peer *p, int more)
|
||
{
|
||
- int old, new;
|
||
more++;
|
||
inet_peer_refcheck(p);
|
||
- do {
|
||
- old = atomic_read(&p->ip_id_count);
|
||
- new = old + more;
|
||
- if (!new)
|
||
- new = 1;
|
||
- } while (atomic_cmpxchg(&p->ip_id_count, old, new) != old);
|
||
- return new;
|
||
+ return atomic_add_return(more, &p->ip_id_count) - more;
|
||
}
|
||
|
||
#endif /* _NET_INETPEER_H */
|
||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
|
||
index 9210bdc..aa12b39 100644
|
||
--- a/include/net/mac80211.h
|
||
+++ b/include/net/mac80211.h
|
||
@@ -1174,6 +1174,10 @@ enum sta_notify_cmd {
|
||
* @IEEE80211_HW_SCAN_WHILE_IDLE: The device can do hw scan while
|
||
* being idle (i.e. mac80211 doesn't have to go idle-off during the
|
||
* the scan).
|
||
+ *
|
||
+ * @IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL: On this hardware TX BA session
|
||
+ * should be tear down once BAR frame will not be acked.
|
||
+ *
|
||
*/
|
||
enum ieee80211_hw_flags {
|
||
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
|
||
@@ -1201,6 +1205,7 @@ enum ieee80211_hw_flags {
|
||
IEEE80211_HW_AP_LINK_PS = 1<<22,
|
||
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23,
|
||
IEEE80211_HW_SCAN_WHILE_IDLE = 1<<24,
|
||
+ IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL = 1<<26,
|
||
};
|
||
|
||
/**
|
||
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
|
||
index a5f7993..8d64abf 100644
|
||
--- a/include/net/regulatory.h
|
||
+++ b/include/net/regulatory.h
|
||
@@ -97,7 +97,7 @@ struct ieee80211_reg_rule {
|
||
|
||
struct ieee80211_regdomain {
|
||
u32 n_reg_rules;
|
||
- char alpha2[2];
|
||
+ char alpha2[3];
|
||
u8 dfs_region;
|
||
struct ieee80211_reg_rule reg_rules[];
|
||
};
|
||
diff --git a/include/scsi/osd_ore.h b/include/scsi/osd_ore.h
|
||
index a5f9b96..6ca3265 100644
|
||
--- a/include/scsi/osd_ore.h
|
||
+++ b/include/scsi/osd_ore.h
|
||
@@ -102,6 +102,7 @@ struct ore_striping_info {
|
||
unsigned unit_off;
|
||
unsigned cur_pg;
|
||
unsigned cur_comp;
|
||
+ unsigned maxdevUnits;
|
||
};
|
||
|
||
struct ore_io_state;
|
||
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
|
||
index c425062..ab240bb 100644
|
||
--- a/include/sound/memalloc.h
|
||
+++ b/include/sound/memalloc.h
|
||
@@ -101,7 +101,7 @@ static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
|
||
static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
|
||
{
|
||
dma_addr_t addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
|
||
- addr &= PAGE_MASK;
|
||
+ addr &= ~((dma_addr_t)PAGE_SIZE - 1);
|
||
return addr + offset % PAGE_SIZE;
|
||
}
|
||
|
||
diff --git a/include/trace/events/block.h b/include/trace/events/block.h
|
||
index 05c5e61..048e265 100644
|
||
--- a/include/trace/events/block.h
|
||
+++ b/include/trace/events/block.h
|
||
@@ -81,6 +81,7 @@ DEFINE_EVENT(block_rq_with_error, block_rq_requeue,
|
||
* block_rq_complete - block IO operation completed by device driver
|
||
* @q: queue containing the block operation request
|
||
* @rq: block operations request
|
||
+ * @nr_bytes: number of completed bytes
|
||
*
|
||
* The block_rq_complete tracepoint event indicates that some portion
|
||
* of operation request has been completed by the device driver. If
|
||
@@ -88,11 +89,37 @@ DEFINE_EVENT(block_rq_with_error, block_rq_requeue,
|
||
* do for the request. If @rq->bio is non-NULL then there is
|
||
* additional work required to complete the request.
|
||
*/
|
||
-DEFINE_EVENT(block_rq_with_error, block_rq_complete,
|
||
+TRACE_EVENT(block_rq_complete,
|
||
|
||
- TP_PROTO(struct request_queue *q, struct request *rq),
|
||
+ TP_PROTO(struct request_queue *q, struct request *rq,
|
||
+ unsigned int nr_bytes),
|
||
|
||
- TP_ARGS(q, rq)
|
||
+ TP_ARGS(q, rq, nr_bytes),
|
||
+
|
||
+ TP_STRUCT__entry(
|
||
+ __field( dev_t, dev )
|
||
+ __field( sector_t, sector )
|
||
+ __field( unsigned int, nr_sector )
|
||
+ __field( int, errors )
|
||
+ __array( char, rwbs, RWBS_LEN )
|
||
+ __dynamic_array( char, cmd, blk_cmd_buf_len(rq) )
|
||
+ ),
|
||
+
|
||
+ TP_fast_assign(
|
||
+ __entry->dev = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
|
||
+ __entry->sector = blk_rq_pos(rq);
|
||
+ __entry->nr_sector = nr_bytes >> 9;
|
||
+ __entry->errors = rq->errors;
|
||
+
|
||
+ blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, nr_bytes);
|
||
+ blk_dump_cmd(__get_str(cmd), rq);
|
||
+ ),
|
||
+
|
||
+ TP_printk("%d,%d %s (%s) %llu + %u [%d]",
|
||
+ MAJOR(__entry->dev), MINOR(__entry->dev),
|
||
+ __entry->rwbs, __get_str(cmd),
|
||
+ (unsigned long long)__entry->sector,
|
||
+ __entry->nr_sector, __entry->errors)
|
||
);
|
||
|
||
DECLARE_EVENT_CLASS(block_rq,
|
||
diff --git a/include/trace/events/module.h b/include/trace/events/module.h
|
||
index 1619327..ca298c7 100644
|
||
--- a/include/trace/events/module.h
|
||
+++ b/include/trace/events/module.h
|
||
@@ -78,7 +78,7 @@ DECLARE_EVENT_CLASS(module_refcnt,
|
||
|
||
TP_fast_assign(
|
||
__entry->ip = ip;
|
||
- __entry->refcnt = __this_cpu_read(mod->refptr->incs) + __this_cpu_read(mod->refptr->decs);
|
||
+ __entry->refcnt = __this_cpu_read(mod->refptr->incs) - __this_cpu_read(mod->refptr->decs);
|
||
__assign_str(name, mod->name);
|
||
),
|
||
|
||
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
|
||
index 5d675a7..4517d21 100644
|
||
--- a/include/trace/ftrace.h
|
||
+++ b/include/trace/ftrace.h
|
||
@@ -380,7 +380,8 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \
|
||
__data_size += (len) * sizeof(type);
|
||
|
||
#undef __string
|
||
-#define __string(item, src) __dynamic_array(char, item, strlen(src) + 1)
|
||
+#define __string(item, src) __dynamic_array(char, item, \
|
||
+ strlen((src) ? (const char *)(src) : "(null)") + 1)
|
||
|
||
#undef DECLARE_EVENT_CLASS
|
||
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
|
||
@@ -505,7 +506,7 @@ static inline notrace int ftrace_get_offsets_##call( \
|
||
|
||
#undef __assign_str
|
||
#define __assign_str(dst, src) \
|
||
- strcpy(__get_str(dst), src);
|
||
+ strcpy(__get_str(dst), (src) ? (const char *)(src) : "(null)");
|
||
|
||
#undef TP_fast_assign
|
||
#define TP_fast_assign(args...) args
|
||
diff --git a/include/trace/syscall.h b/include/trace/syscall.h
|
||
index 31966a4..51b72d8 100644
|
||
--- a/include/trace/syscall.h
|
||
+++ b/include/trace/syscall.h
|
||
@@ -4,6 +4,7 @@
|
||
#include <linux/tracepoint.h>
|
||
#include <linux/unistd.h>
|
||
#include <linux/ftrace_event.h>
|
||
+#include <linux/thread_info.h>
|
||
|
||
#include <asm/ptrace.h>
|
||
|
||
@@ -54,4 +55,18 @@ int perf_sysexit_enable(struct ftrace_event_call *call);
|
||
void perf_sysexit_disable(struct ftrace_event_call *call);
|
||
#endif
|
||
|
||
+#if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_HAVE_SYSCALL_TRACEPOINTS)
|
||
+static inline void syscall_tracepoint_update(struct task_struct *p)
|
||
+{
|
||
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
|
||
+ set_tsk_thread_flag(p, TIF_SYSCALL_TRACEPOINT);
|
||
+ else
|
||
+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACEPOINT);
|
||
+}
|
||
+#else
|
||
+static inline void syscall_tracepoint_update(struct task_struct *p)
|
||
+{
|
||
+}
|
||
+#endif
|
||
+
|
||
#endif /* _TRACE_SYSCALL_H */
|
||
diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
|
||
index cb94668..d4635cd 100644
|
||
--- a/include/xen/interface/io/netif.h
|
||
+++ b/include/xen/interface/io/netif.h
|
||
@@ -13,6 +13,24 @@
|
||
#include "../grant_table.h"
|
||
|
||
/*
|
||
+ * Older implementation of Xen network frontend / backend has an
|
||
+ * implicit dependency on the MAX_SKB_FRAGS as the maximum number of
|
||
+ * ring slots a skb can use. Netfront / netback may not work as
|
||
+ * expected when frontend and backend have different MAX_SKB_FRAGS.
|
||
+ *
|
||
+ * A better approach is to add mechanism for netfront / netback to
|
||
+ * negotiate this value. However we cannot fix all possible
|
||
+ * frontends, so we need to define a value which states the minimum
|
||
+ * slots backend must support.
|
||
+ *
|
||
+ * The minimum value derives from older Linux kernel's MAX_SKB_FRAGS
|
||
+ * (18), which is proved to work with most frontends. Any new backend
|
||
+ * which doesn't negotiate with frontend should expect frontend to
|
||
+ * send a valid packet using slots up to this value.
|
||
+ */
|
||
+#define XEN_NETIF_NR_SLOTS_MIN 18
|
||
+
|
||
+/*
|
||
* Notifications after enqueuing any type of message should be conditional on
|
||
* the appropriate req_event or rsp_event field in the shared ring.
|
||
* If the client sends notification for rx requests then it should specify
|
||
@@ -47,6 +65,7 @@
|
||
#define _XEN_NETTXF_extra_info (3)
|
||
#define XEN_NETTXF_extra_info (1U<<_XEN_NETTXF_extra_info)
|
||
|
||
+#define XEN_NETIF_MAX_TX_SIZE 0xFFFF
|
||
struct xen_netif_tx_request {
|
||
grant_ref_t gref; /* Reference to buffer page */
|
||
uint16_t offset; /* Offset within buffer page */
|
||
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
|
||
index 75271b9..7d28aff 100644
|
||
--- a/include/xen/interface/io/ring.h
|
||
+++ b/include/xen/interface/io/ring.h
|
||
@@ -188,6 +188,11 @@ struct __name##_back_ring { \
|
||
#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \
|
||
(((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r))
|
||
|
||
+/* Ill-behaved frontend determination: Can there be this many requests? */
|
||
+#define RING_REQUEST_PROD_OVERFLOW(_r, _prod) \
|
||
+ (((_prod) - (_r)->rsp_prod_pvt) > RING_SIZE(_r))
|
||
+
|
||
+
|
||
#define RING_PUSH_REQUESTS(_r) do { \
|
||
wmb(); /* back sees requests /before/ updated producer index */ \
|
||
(_r)->sring->req_prod = (_r)->req_prod_pvt; \
|
||
diff --git a/init/Kconfig b/init/Kconfig
|
||
index 11a5a22..770d720 100644
|
||
--- a/init/Kconfig
|
||
+++ b/init/Kconfig
|
||
@@ -575,6 +575,7 @@ config LOG_BUF_SHIFT
|
||
int "Kernel log buffer size (16 => 64KB, 17 => 128KB)"
|
||
range 12 21
|
||
default 17
|
||
+ depends on PRINTK
|
||
help
|
||
Select kernel log buffer size as a power of 2.
|
||
Examples:
|
||
diff --git a/init/main.c b/init/main.c
|
||
index 71d4c64..f91924b 100644
|
||
--- a/init/main.c
|
||
+++ b/init/main.c
|
||
@@ -607,6 +607,10 @@ asmlinkage void __init start_kernel(void)
|
||
if (efi_enabled(EFI_RUNTIME_SERVICES))
|
||
efi_enter_virtual_mode();
|
||
#endif
|
||
+#ifdef CONFIG_X86_ESPFIX64
|
||
+ /* Should be run before the first non-init thread is created */
|
||
+ init_espfix_bsp();
|
||
+#endif
|
||
thread_info_cache_init();
|
||
cred_init();
|
||
fork_init(totalram_pages);
|
||
diff --git a/ipc/msg.c b/ipc/msg.c
|
||
index 7385de2..25f1a61 100644
|
||
--- a/ipc/msg.c
|
||
+++ b/ipc/msg.c
|
||
@@ -296,7 +296,9 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
|
||
}
|
||
atomic_sub(msq->q_cbytes, &ns->msg_bytes);
|
||
security_msg_queue_free(msq);
|
||
+ ipc_lock_by_ptr(&msq->q_perm);
|
||
ipc_rcu_putref(msq);
|
||
+ ipc_unlock(&msq->q_perm);
|
||
}
|
||
|
||
/*
|
||
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
|
||
index 26143d3..52be05a 100644
|
||
--- a/ipc/msgutil.c
|
||
+++ b/ipc/msgutil.c
|
||
@@ -39,15 +39,15 @@ struct msg_msgseg {
|
||
/* the next part of the message follows immediately */
|
||
};
|
||
|
||
-#define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
|
||
-#define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
|
||
+#define DATALEN_MSG ((size_t)PAGE_SIZE-sizeof(struct msg_msg))
|
||
+#define DATALEN_SEG ((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
|
||
|
||
-struct msg_msg *load_msg(const void __user *src, int len)
|
||
+struct msg_msg *load_msg(const void __user *src, size_t len)
|
||
{
|
||
struct msg_msg *msg;
|
||
struct msg_msgseg **pseg;
|
||
int err;
|
||
- int alen;
|
||
+ size_t alen;
|
||
|
||
alen = len;
|
||
if (alen > DATALEN_MSG)
|
||
@@ -101,9 +101,9 @@ struct msg_msg *load_msg(const void __user *src, int len)
|
||
return ERR_PTR(err);
|
||
}
|
||
|
||
-int store_msg(void __user *dest, struct msg_msg *msg, int len)
|
||
+int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
|
||
{
|
||
- int alen;
|
||
+ size_t alen;
|
||
struct msg_msgseg *seg;
|
||
|
||
alen = len;
|
||
diff --git a/ipc/util.h b/ipc/util.h
|
||
index 6f5c20b..0bfc934 100644
|
||
--- a/ipc/util.h
|
||
+++ b/ipc/util.h
|
||
@@ -138,8 +138,8 @@ int ipc_parse_version (int *cmd);
|
||
#endif
|
||
|
||
extern void free_msg(struct msg_msg *msg);
|
||
-extern struct msg_msg *load_msg(const void __user *src, int len);
|
||
-extern int store_msg(void __user *dest, struct msg_msg *msg, int len);
|
||
+extern struct msg_msg *load_msg(const void __user *src, size_t len);
|
||
+extern int store_msg(void __user *dest, struct msg_msg *msg, size_t len);
|
||
|
||
extern void recompute_msgmni(struct ipc_namespace *);
|
||
|
||
diff --git a/kernel/audit.c b/kernel/audit.c
|
||
index 1c7f2c6..b4efae8 100644
|
||
--- a/kernel/audit.c
|
||
+++ b/kernel/audit.c
|
||
@@ -625,7 +625,7 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
|
||
char *ctx = NULL;
|
||
u32 len;
|
||
|
||
- if (!audit_enabled) {
|
||
+ if (!audit_enabled && msg_type != AUDIT_USER_AVC) {
|
||
*ab = NULL;
|
||
return rc;
|
||
}
|
||
@@ -684,6 +684,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||
|
||
switch (msg_type) {
|
||
case AUDIT_GET:
|
||
+ status_set.mask = 0;
|
||
status_set.enabled = audit_enabled;
|
||
status_set.failure = audit_failure;
|
||
status_set.pid = audit_pid;
|
||
@@ -695,7 +696,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||
&status_set, sizeof(status_set));
|
||
break;
|
||
case AUDIT_SET:
|
||
- if (nlh->nlmsg_len < sizeof(struct audit_status))
|
||
+ if (nlmsg_len(nlh) < sizeof(struct audit_status))
|
||
return -EINVAL;
|
||
status_get = (struct audit_status *)data;
|
||
if (status_get->mask & AUDIT_STATUS_ENABLED) {
|
||
@@ -1167,7 +1168,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
|
||
|
||
/* Wait for auditd to drain the queue a little */
|
||
DECLARE_WAITQUEUE(wait, current);
|
||
- set_current_state(TASK_INTERRUPTIBLE);
|
||
+ set_current_state(TASK_UNINTERRUPTIBLE);
|
||
add_wait_queue(&audit_backlog_wait, &wait);
|
||
|
||
if (audit_backlog_limit &&
|
||
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
|
||
index 4b96415..fb34250 100644
|
||
--- a/kernel/auditsc.c
|
||
+++ b/kernel/auditsc.c
|
||
@@ -869,6 +869,22 @@ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
|
||
return AUDIT_BUILD_CONTEXT;
|
||
}
|
||
|
||
+static int audit_in_mask(const struct audit_krule *rule, unsigned long val)
|
||
+{
|
||
+ int word, bit;
|
||
+
|
||
+ if (val > 0xffffffff)
|
||
+ return false;
|
||
+
|
||
+ word = AUDIT_WORD(val);
|
||
+ if (word >= AUDIT_BITMASK_SIZE)
|
||
+ return false;
|
||
+
|
||
+ bit = AUDIT_BIT(val);
|
||
+
|
||
+ return rule->mask[word] & bit;
|
||
+}
|
||
+
|
||
/* At syscall entry and exit time, this filter is called if the
|
||
* audit_state is not low enough that auditing cannot take place, but is
|
||
* also not high enough that we already know we have to write an audit
|
||
@@ -886,11 +902,8 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
|
||
|
||
rcu_read_lock();
|
||
if (!list_empty(list)) {
|
||
- int word = AUDIT_WORD(ctx->major);
|
||
- int bit = AUDIT_BIT(ctx->major);
|
||
-
|
||
list_for_each_entry_rcu(e, list, list) {
|
||
- if ((e->rule.mask[word] & bit) == bit &&
|
||
+ if (audit_in_mask(&e->rule, ctx->major) &&
|
||
audit_filter_rules(tsk, &e->rule, ctx, NULL,
|
||
&state, false)) {
|
||
rcu_read_unlock();
|
||
@@ -910,20 +923,16 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
|
||
static int audit_filter_inode_name(struct task_struct *tsk,
|
||
struct audit_names *n,
|
||
struct audit_context *ctx) {
|
||
- int word, bit;
|
||
int h = audit_hash_ino((u32)n->ino);
|
||
struct list_head *list = &audit_inode_hash[h];
|
||
struct audit_entry *e;
|
||
enum audit_state state;
|
||
|
||
- word = AUDIT_WORD(ctx->major);
|
||
- bit = AUDIT_BIT(ctx->major);
|
||
-
|
||
if (list_empty(list))
|
||
return 0;
|
||
|
||
list_for_each_entry_rcu(e, list, list) {
|
||
- if ((e->rule.mask[word] & bit) == bit &&
|
||
+ if (audit_in_mask(&e->rule, ctx->major) &&
|
||
audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) {
|
||
ctx->current_state = state;
|
||
return 1;
|
||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
|
||
index d9a82fe..38f8b89 100644
|
||
--- a/kernel/cgroup.c
|
||
+++ b/kernel/cgroup.c
|
||
@@ -3876,6 +3876,11 @@ static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||
{
|
||
struct cgroup *c_parent = dentry->d_parent->d_fsdata;
|
||
|
||
+ /* Do not accept '\n' to prevent making /proc/<pid>/cgroup unparsable.
|
||
+ */
|
||
+ if (strchr(dentry->d_name.name, '\n'))
|
||
+ return -EINVAL;
|
||
+
|
||
/* the vfs holds inode->i_mutex already */
|
||
return cgroup_create(c_parent, dentry, mode | S_IFDIR);
|
||
}
|
||
@@ -4557,41 +4562,19 @@ void cgroup_fork(struct task_struct *child)
|
||
}
|
||
|
||
/**
|
||
- * cgroup_fork_callbacks - run fork callbacks
|
||
- * @child: the new task
|
||
- *
|
||
- * Called on a new task very soon before adding it to the
|
||
- * tasklist. No need to take any locks since no-one can
|
||
- * be operating on this task.
|
||
- */
|
||
-void cgroup_fork_callbacks(struct task_struct *child)
|
||
-{
|
||
- if (need_forkexit_callback) {
|
||
- int i;
|
||
- /*
|
||
- * forkexit callbacks are only supported for builtin
|
||
- * subsystems, and the builtin section of the subsys array is
|
||
- * immutable, so we don't need to lock the subsys array here.
|
||
- */
|
||
- for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
|
||
- struct cgroup_subsys *ss = subsys[i];
|
||
- if (ss->fork)
|
||
- ss->fork(child);
|
||
- }
|
||
- }
|
||
-}
|
||
-
|
||
-/**
|
||
* cgroup_post_fork - called on a new task after adding it to the task list
|
||
* @child: the task in question
|
||
*
|
||
- * Adds the task to the list running through its css_set if necessary.
|
||
- * Has to be after the task is visible on the task list in case we race
|
||
- * with the first call to cgroup_iter_start() - to guarantee that the
|
||
- * new task ends up on its list.
|
||
+ * Adds the task to the list running through its css_set if necessary and
|
||
+ * call the subsystem fork() callbacks. Has to be after the task is
|
||
+ * visible on the task list in case we race with the first call to
|
||
+ * cgroup_iter_start() - to guarantee that the new task ends up on its
|
||
+ * list.
|
||
*/
|
||
void cgroup_post_fork(struct task_struct *child)
|
||
{
|
||
+ int i;
|
||
+
|
||
/*
|
||
* use_task_css_set_links is set to 1 before we walk the tasklist
|
||
* under the tasklist_lock and we read it here after we added the child
|
||
@@ -4611,7 +4594,21 @@ void cgroup_post_fork(struct task_struct *child)
|
||
task_unlock(child);
|
||
write_unlock(&css_set_lock);
|
||
}
|
||
+
|
||
+ /*
|
||
+ * Call ss->fork(). This must happen after @child is linked on
|
||
+ * css_set; otherwise, @child might change state between ->fork()
|
||
+ * and addition to css_set.
|
||
+ */
|
||
+ if (need_forkexit_callback) {
|
||
+ for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
|
||
+ struct cgroup_subsys *ss = subsys[i];
|
||
+ if (ss->fork)
|
||
+ ss->fork(child);
|
||
+ }
|
||
+ }
|
||
}
|
||
+
|
||
/**
|
||
* cgroup_exit - detach cgroup from exiting task
|
||
* @tsk: pointer to task_struct of exiting process
|
||
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
|
||
index f86e939..a902e2a 100644
|
||
--- a/kernel/cgroup_freezer.c
|
||
+++ b/kernel/cgroup_freezer.c
|
||
@@ -186,23 +186,15 @@ static void freezer_fork(struct task_struct *task)
|
||
{
|
||
struct freezer *freezer;
|
||
|
||
- /*
|
||
- * No lock is needed, since the task isn't on tasklist yet,
|
||
- * so it can't be moved to another cgroup, which means the
|
||
- * freezer won't be removed and will be valid during this
|
||
- * function call. Nevertheless, apply RCU read-side critical
|
||
- * section to suppress RCU lockdep false positives.
|
||
- */
|
||
rcu_read_lock();
|
||
freezer = task_freezer(task);
|
||
- rcu_read_unlock();
|
||
|
||
/*
|
||
* The root cgroup is non-freezable, so we can skip the
|
||
* following check.
|
||
*/
|
||
if (!freezer->css.cgroup->parent)
|
||
- return;
|
||
+ goto out;
|
||
|
||
spin_lock_irq(&freezer->lock);
|
||
BUG_ON(freezer->state == CGROUP_FROZEN);
|
||
@@ -210,7 +202,10 @@ static void freezer_fork(struct task_struct *task)
|
||
/* Locking avoids race with FREEZING -> THAWED transitions. */
|
||
if (freezer->state == CGROUP_FREEZING)
|
||
freeze_task(task);
|
||
+
|
||
spin_unlock_irq(&freezer->lock);
|
||
+out:
|
||
+ rcu_read_unlock();
|
||
}
|
||
|
||
/*
|
||
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
|
||
index 8fe6f6b6..7f3bde5 100644
|
||
--- a/kernel/cpuset.c
|
||
+++ b/kernel/cpuset.c
|
||
@@ -326,13 +326,14 @@ static void cpuset_update_task_spread_flag(struct cpuset *cs,
|
||
struct task_struct *tsk)
|
||
{
|
||
if (is_spread_page(cs))
|
||
- tsk->flags |= PF_SPREAD_PAGE;
|
||
+ task_set_spread_page(tsk);
|
||
else
|
||
- tsk->flags &= ~PF_SPREAD_PAGE;
|
||
+ task_clear_spread_page(tsk);
|
||
+
|
||
if (is_spread_slab(cs))
|
||
- tsk->flags |= PF_SPREAD_SLAB;
|
||
+ task_set_spread_slab(tsk);
|
||
else
|
||
- tsk->flags &= ~PF_SPREAD_SLAB;
|
||
+ task_clear_spread_slab(tsk);
|
||
}
|
||
|
||
/*
|
||
@@ -983,8 +984,10 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
|
||
need_loop = task_has_mempolicy(tsk) ||
|
||
!nodes_intersects(*newmems, tsk->mems_allowed);
|
||
|
||
- if (need_loop)
|
||
+ if (need_loop) {
|
||
+ local_irq_disable();
|
||
write_seqcount_begin(&tsk->mems_allowed_seq);
|
||
+ }
|
||
|
||
nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
|
||
mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP1);
|
||
@@ -992,8 +995,10 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
|
||
mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP2);
|
||
tsk->mems_allowed = *newmems;
|
||
|
||
- if (need_loop)
|
||
+ if (need_loop) {
|
||
write_seqcount_end(&tsk->mems_allowed_seq);
|
||
+ local_irq_enable();
|
||
+ }
|
||
|
||
task_unlock(tsk);
|
||
}
|
||
@@ -1148,7 +1153,13 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
|
||
|
||
int current_cpuset_is_being_rebound(void)
|
||
{
|
||
- return task_cs(current) == cpuset_being_rebound;
|
||
+ int ret;
|
||
+
|
||
+ rcu_read_lock();
|
||
+ ret = task_cs(current) == cpuset_being_rebound;
|
||
+ rcu_read_unlock();
|
||
+
|
||
+ return ret;
|
||
}
|
||
|
||
static int update_relax_domain_level(struct cpuset *cs, s64 val)
|
||
@@ -2334,9 +2345,9 @@ int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
|
||
|
||
task_lock(current);
|
||
cs = nearest_hardwall_ancestor(task_cs(current));
|
||
+ allowed = node_isset(node, cs->mems_allowed);
|
||
task_unlock(current);
|
||
|
||
- allowed = node_isset(node, cs->mems_allowed);
|
||
mutex_unlock(&callback_mutex);
|
||
return allowed;
|
||
}
|
||
diff --git a/kernel/events/core.c b/kernel/events/core.c
|
||
index b23ce32..acbcfdd 100644
|
||
--- a/kernel/events/core.c
|
||
+++ b/kernel/events/core.c
|
||
@@ -36,6 +36,7 @@
|
||
#include <linux/perf_event.h>
|
||
#include <linux/ftrace_event.h>
|
||
#include <linux/hw_breakpoint.h>
|
||
+#include <linux/compat.h>
|
||
|
||
#include "internal.h"
|
||
|
||
@@ -1713,6 +1714,16 @@ perf_install_in_context(struct perf_event_context *ctx,
|
||
*/
|
||
if (ctx->is_active) {
|
||
raw_spin_unlock_irq(&ctx->lock);
|
||
+ /*
|
||
+ * Reload the task pointer, it might have been changed by
|
||
+ * a concurrent perf_event_context_sched_out().
|
||
+ */
|
||
+ task = ctx->task;
|
||
+ /*
|
||
+ * Reload the task pointer, it might have been changed by
|
||
+ * a concurrent perf_event_context_sched_out().
|
||
+ */
|
||
+ task = ctx->task;
|
||
goto retry;
|
||
}
|
||
|
||
@@ -3364,6 +3375,25 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||
return 0;
|
||
}
|
||
|
||
+#ifdef CONFIG_COMPAT
|
||
+static long perf_compat_ioctl(struct file *file, unsigned int cmd,
|
||
+ unsigned long arg)
|
||
+{
|
||
+ switch (_IOC_NR(cmd)) {
|
||
+ case _IOC_NR(PERF_EVENT_IOC_SET_FILTER):
|
||
+ /* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case */
|
||
+ if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
|
||
+ cmd &= ~IOCSIZE_MASK;
|
||
+ cmd |= sizeof(void *) << IOCSIZE_SHIFT;
|
||
+ }
|
||
+ break;
|
||
+ }
|
||
+ return perf_ioctl(file, cmd, arg);
|
||
+}
|
||
+#else
|
||
+# define perf_compat_ioctl NULL
|
||
+#endif
|
||
+
|
||
int perf_event_task_enable(void)
|
||
{
|
||
struct perf_event *event;
|
||
@@ -3835,7 +3865,7 @@ static const struct file_operations perf_fops = {
|
||
.read = perf_read,
|
||
.poll = perf_poll,
|
||
.unlocked_ioctl = perf_ioctl,
|
||
- .compat_ioctl = perf_ioctl,
|
||
+ .compat_ioctl = perf_compat_ioctl,
|
||
.mmap = perf_mmap,
|
||
.fasync = perf_fasync,
|
||
};
|
||
@@ -4879,6 +4909,9 @@ struct swevent_htable {
|
||
|
||
/* Recursion avoidance in each contexts */
|
||
int recursion[PERF_NR_CONTEXTS];
|
||
+
|
||
+ /* Keeps track of cpu being initialized/exited */
|
||
+ bool online;
|
||
};
|
||
|
||
static DEFINE_PER_CPU(struct swevent_htable, swevent_htable);
|
||
@@ -5126,8 +5159,14 @@ static int perf_swevent_add(struct perf_event *event, int flags)
|
||
hwc->state = !(flags & PERF_EF_START);
|
||
|
||
head = find_swevent_head(swhash, event);
|
||
- if (WARN_ON_ONCE(!head))
|
||
+ if (!head) {
|
||
+ /*
|
||
+ * We can race with cpu hotplug code. Do not
|
||
+ * WARN if the cpu just got unplugged.
|
||
+ */
|
||
+ WARN_ON_ONCE(swhash->online);
|
||
return -EINVAL;
|
||
+ }
|
||
|
||
hlist_add_head_rcu(&event->hlist_entry, head);
|
||
|
||
@@ -5900,6 +5939,7 @@ int perf_pmu_register(struct pmu *pmu, char *name, int type)
|
||
if (pmu->pmu_cpu_context)
|
||
goto got_cpu_context;
|
||
|
||
+ ret = -ENOMEM;
|
||
pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);
|
||
if (!pmu->pmu_cpu_context)
|
||
goto free_dev;
|
||
@@ -6375,6 +6415,9 @@ SYSCALL_DEFINE5(perf_event_open,
|
||
if (attr.freq) {
|
||
if (attr.sample_freq > sysctl_perf_event_sample_rate)
|
||
return -EINVAL;
|
||
+ } else {
|
||
+ if (attr.sample_period & (1ULL << 63))
|
||
+ return -EINVAL;
|
||
}
|
||
|
||
/*
|
||
@@ -7128,8 +7171,10 @@ int perf_event_init_task(struct task_struct *child)
|
||
|
||
for_each_task_context_nr(ctxn) {
|
||
ret = perf_event_init_context(child, ctxn);
|
||
- if (ret)
|
||
+ if (ret) {
|
||
+ perf_event_free_task(child);
|
||
return ret;
|
||
+ }
|
||
}
|
||
|
||
return 0;
|
||
@@ -7152,6 +7197,7 @@ static void __cpuinit perf_event_init_cpu(int cpu)
|
||
struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
|
||
|
||
mutex_lock(&swhash->hlist_mutex);
|
||
+ swhash->online = true;
|
||
if (swhash->hlist_refcount > 0) {
|
||
struct swevent_hlist *hlist;
|
||
|
||
@@ -7175,14 +7221,14 @@ static void perf_pmu_rotate_stop(struct pmu *pmu)
|
||
static void __perf_event_exit_context(void *__info)
|
||
{
|
||
struct perf_event_context *ctx = __info;
|
||
- struct perf_event *event, *tmp;
|
||
+ struct perf_event *event;
|
||
|
||
perf_pmu_rotate_stop(ctx->pmu);
|
||
|
||
- list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry)
|
||
- __perf_remove_from_context(event);
|
||
- list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry)
|
||
+ rcu_read_lock();
|
||
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
|
||
__perf_remove_from_context(event);
|
||
+ rcu_read_unlock();
|
||
}
|
||
|
||
static void perf_event_exit_cpu_context(int cpu)
|
||
@@ -7215,11 +7261,12 @@ static void perf_event_exit_cpu(int cpu)
|
||
{
|
||
struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
|
||
|
||
+ perf_event_exit_cpu_context(cpu);
|
||
+
|
||
mutex_lock(&swhash->hlist_mutex);
|
||
+ swhash->online = false;
|
||
swevent_hlist_release(swhash);
|
||
mutex_unlock(&swhash->hlist_mutex);
|
||
-
|
||
- perf_event_exit_cpu_context(cpu);
|
||
}
|
||
#else
|
||
static inline void perf_event_exit_cpu(int cpu) { }
|
||
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
|
||
index 6ddaba4..4636ecc 100644
|
||
--- a/kernel/events/ring_buffer.c
|
||
+++ b/kernel/events/ring_buffer.c
|
||
@@ -75,10 +75,31 @@ static void perf_output_put_handle(struct perf_output_handle *handle)
|
||
goto out;
|
||
|
||
/*
|
||
- * Publish the known good head. Rely on the full barrier implied
|
||
- * by atomic_dec_and_test() order the rb->head read and this
|
||
- * write.
|
||
+ * Since the mmap() consumer (userspace) can run on a different CPU:
|
||
+ *
|
||
+ * kernel user
|
||
+ *
|
||
+ * READ ->data_tail READ ->data_head
|
||
+ * smp_mb() (A) smp_rmb() (C)
|
||
+ * WRITE $data READ $data
|
||
+ * smp_wmb() (B) smp_mb() (D)
|
||
+ * STORE ->data_head WRITE ->data_tail
|
||
+ *
|
||
+ * Where A pairs with D, and B pairs with C.
|
||
+ *
|
||
+ * I don't think A needs to be a full barrier because we won't in fact
|
||
+ * write data until we see the store from userspace. So we simply don't
|
||
+ * issue the data WRITE until we observe it. Be conservative for now.
|
||
+ *
|
||
+ * OTOH, D needs to be a full barrier since it separates the data READ
|
||
+ * from the tail WRITE.
|
||
+ *
|
||
+ * For B a WMB is sufficient since it separates two WRITEs, and for C
|
||
+ * an RMB is sufficient since it separates two READs.
|
||
+ *
|
||
+ * See perf_output_begin().
|
||
*/
|
||
+ smp_wmb();
|
||
rb->user_page->data_head = head;
|
||
|
||
/*
|
||
@@ -142,9 +163,11 @@ int perf_output_begin(struct perf_output_handle *handle,
|
||
* Userspace could choose to issue a mb() before updating the
|
||
* tail pointer. So that all reads will be completed before the
|
||
* write is issued.
|
||
+ *
|
||
+ * See perf_output_put_handle().
|
||
*/
|
||
tail = ACCESS_ONCE(rb->user_page->data_tail);
|
||
- smp_rmb();
|
||
+ smp_mb();
|
||
offset = head = local_read(&rb->head);
|
||
head += size;
|
||
if (unlikely(!perf_output_space(rb, tail, offset, head)))
|
||
diff --git a/kernel/exit.c b/kernel/exit.c
|
||
index 6506b85..f28427b 100644
|
||
--- a/kernel/exit.c
|
||
+++ b/kernel/exit.c
|
||
@@ -766,9 +766,6 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
|
||
struct list_head *dead)
|
||
{
|
||
list_move_tail(&p->sibling, &p->real_parent->children);
|
||
-
|
||
- if (p->exit_state == EXIT_DEAD)
|
||
- return;
|
||
/*
|
||
* If this is a threaded reparent there is no need to
|
||
* notify anyone anything has happened.
|
||
@@ -776,9 +773,19 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
|
||
if (same_thread_group(p->real_parent, father))
|
||
return;
|
||
|
||
- /* We don't want people slaying init. */
|
||
+ /*
|
||
+ * We don't want people slaying init.
|
||
+ *
|
||
+ * Note: we do this even if it is EXIT_DEAD, wait_task_zombie()
|
||
+ * can change ->exit_state to EXIT_ZOMBIE. If this is the final
|
||
+ * state, do_notify_parent() was already called and ->exit_signal
|
||
+ * doesn't matter.
|
||
+ */
|
||
p->exit_signal = SIGCHLD;
|
||
|
||
+ if (p->exit_state == EXIT_DEAD)
|
||
+ return;
|
||
+
|
||
/* If it has exited notify the new parent about this child's death. */
|
||
if (!p->ptrace &&
|
||
p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
|
||
diff --git a/kernel/fork.c b/kernel/fork.c
|
||
index fbaec8c..c48862f 100644
|
||
--- a/kernel/fork.c
|
||
+++ b/kernel/fork.c
|
||
@@ -1184,7 +1184,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||
{
|
||
int retval;
|
||
struct task_struct *p;
|
||
- int cgroup_callbacks_done = 0;
|
||
|
||
if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
|
||
return ERR_PTR(-EINVAL);
|
||
@@ -1346,7 +1345,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||
goto bad_fork_cleanup_policy;
|
||
retval = audit_alloc(p);
|
||
if (retval)
|
||
- goto bad_fork_cleanup_policy;
|
||
+ goto bad_fork_cleanup_perf;
|
||
/* copy all the process information */
|
||
retval = copy_semundo(clone_flags, p);
|
||
if (retval)
|
||
@@ -1443,12 +1442,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||
p->group_leader = p;
|
||
INIT_LIST_HEAD(&p->thread_group);
|
||
|
||
- /* Now that the task is set up, run cgroup callbacks if
|
||
- * necessary. We need to run them before the task is visible
|
||
- * on the tasklist. */
|
||
- cgroup_fork_callbacks(p);
|
||
- cgroup_callbacks_done = 1;
|
||
-
|
||
/* Need tasklist lock for parent etc handling! */
|
||
write_lock_irq(&tasklist_lock);
|
||
|
||
@@ -1517,7 +1510,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||
|
||
total_forks++;
|
||
spin_unlock(¤t->sighand->siglock);
|
||
+ syscall_tracepoint_update(p);
|
||
write_unlock_irq(&tasklist_lock);
|
||
+
|
||
proc_fork_connector(p);
|
||
cgroup_post_fork(p);
|
||
if (clone_flags & CLONE_THREAD)
|
||
@@ -1554,15 +1549,16 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||
exit_sem(p);
|
||
bad_fork_cleanup_audit:
|
||
audit_free(p);
|
||
-bad_fork_cleanup_policy:
|
||
+bad_fork_cleanup_perf:
|
||
perf_event_free_task(p);
|
||
+bad_fork_cleanup_policy:
|
||
#ifdef CONFIG_NUMA
|
||
mpol_put(p->mempolicy);
|
||
bad_fork_cleanup_cgroup:
|
||
#endif
|
||
if (clone_flags & CLONE_THREAD)
|
||
threadgroup_change_end(current);
|
||
- cgroup_exit(p, cgroup_callbacks_done);
|
||
+ cgroup_exit(p, 0);
|
||
delayacct_tsk_free(p);
|
||
module_put(task_thread_info(p)->exec_domain->module);
|
||
bad_fork_cleanup_count:
|
||
diff --git a/kernel/futex.c b/kernel/futex.c
|
||
index 6a1cf47..3a24f26 100644
|
||
--- a/kernel/futex.c
|
||
+++ b/kernel/futex.c
|
||
@@ -286,7 +286,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
|
||
put_page(page);
|
||
/* serialize against __split_huge_page_splitting() */
|
||
local_irq_disable();
|
||
- if (likely(__get_user_pages_fast(address, 1, 1, &page) == 1)) {
|
||
+ if (likely(__get_user_pages_fast(address, 1, !ro, &page) == 1)) {
|
||
page_head = compound_head(page);
|
||
/*
|
||
* page_head is valid pointer but we must pin
|
||
@@ -738,6 +738,11 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
|
||
if (!p)
|
||
return -ESRCH;
|
||
|
||
+ if (!p->mm) {
|
||
+ put_task_struct(p);
|
||
+ return -EPERM;
|
||
+ }
|
||
+
|
||
/*
|
||
* We need to look at the task state flags to figure out,
|
||
* whether the task is exiting. To protect against the do_exit
|
||
@@ -2446,6 +2451,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||
* shared futexes. We need to compare the keys:
|
||
*/
|
||
if (match_futex(&q.key, &key2)) {
|
||
+ queue_unlock(&q, hb);
|
||
ret = -EINVAL;
|
||
goto out_put_keys;
|
||
}
|
||
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
|
||
index a78cbf4..3c9ca94 100644
|
||
--- a/kernel/hrtimer.c
|
||
+++ b/kernel/hrtimer.c
|
||
@@ -233,6 +233,11 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
|
||
goto again;
|
||
}
|
||
timer->base = new_base;
|
||
+ } else {
|
||
+ if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
|
||
+ cpu = this_cpu;
|
||
+ goto again;
|
||
+ }
|
||
}
|
||
return new_base;
|
||
}
|
||
@@ -568,6 +573,23 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
|
||
|
||
cpu_base->expires_next.tv64 = expires_next.tv64;
|
||
|
||
+ /*
|
||
+ * If a hang was detected in the last timer interrupt then we
|
||
+ * leave the hang delay active in the hardware. We want the
|
||
+ * system to make progress. That also prevents the following
|
||
+ * scenario:
|
||
+ * T1 expires 50ms from now
|
||
+ * T2 expires 5s from now
|
||
+ *
|
||
+ * T1 is removed, so this code is called and would reprogram
|
||
+ * the hardware to 5s from now. Any hrtimer_start after that
|
||
+ * will not reprogram the hardware due to hang_detected being
|
||
+ * set. So we'd effectivly block all timers until the T2 event
|
||
+ * fires.
|
||
+ */
|
||
+ if (cpu_base->hang_detected)
|
||
+ return;
|
||
+
|
||
if (cpu_base->expires_next.tv64 != KTIME_MAX)
|
||
tick_program_event(cpu_base->expires_next, 1);
|
||
}
|
||
@@ -964,11 +986,8 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
|
||
/* Remove an active timer from the queue: */
|
||
ret = remove_hrtimer(timer, base);
|
||
|
||
- /* Switch the timer base, if necessary: */
|
||
- new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
|
||
-
|
||
if (mode & HRTIMER_MODE_REL) {
|
||
- tim = ktime_add_safe(tim, new_base->get_time());
|
||
+ tim = ktime_add_safe(tim, base->get_time());
|
||
/*
|
||
* CONFIG_TIME_LOW_RES is a temporary way for architectures
|
||
* to signal that they simply return xtime in
|
||
@@ -983,6 +1002,9 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
|
||
|
||
hrtimer_set_expires_range_ns(timer, tim, delta_ns);
|
||
|
||
+ /* Switch the timer base, if necessary: */
|
||
+ new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
|
||
+
|
||
timer_stats_hrtimer_set_start_info(timer);
|
||
|
||
leftmost = enqueue_hrtimer(timer, new_base);
|
||
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
|
||
index 5f225bf..5413064 100644
|
||
--- a/kernel/irq/irqdesc.c
|
||
+++ b/kernel/irq/irqdesc.c
|
||
@@ -275,6 +275,7 @@ struct irq_desc *irq_to_desc(unsigned int irq)
|
||
{
|
||
return (irq < NR_IRQS) ? irq_desc + irq : NULL;
|
||
}
|
||
+EXPORT_SYMBOL(irq_to_desc);
|
||
|
||
static void free_desc(unsigned int irq)
|
||
{
|
||
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
|
||
index b42c245..85d135b 100644
|
||
--- a/kernel/irq/manage.c
|
||
+++ b/kernel/irq/manage.c
|
||
@@ -837,8 +837,8 @@ static int irq_thread(void *data)
|
||
irq_thread_check_affinity(desc, action);
|
||
|
||
action_ret = handler_fn(desc, action);
|
||
- if (!noirqdebug)
|
||
- note_interrupt(action->irq, desc, action_ret);
|
||
+ if (action_ret == IRQ_HANDLED)
|
||
+ atomic_inc(&desc->threads_handled);
|
||
|
||
wake_threads_waitq(desc);
|
||
}
|
||
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
|
||
index 7b5f012..febcee3c 100644
|
||
--- a/kernel/irq/spurious.c
|
||
+++ b/kernel/irq/spurious.c
|
||
@@ -265,21 +265,119 @@ try_misrouted_irq(unsigned int irq, struct irq_desc *desc,
|
||
return action && (action->flags & IRQF_IRQPOLL);
|
||
}
|
||
|
||
+#define SPURIOUS_DEFERRED 0x80000000
|
||
+
|
||
void note_interrupt(unsigned int irq, struct irq_desc *desc,
|
||
irqreturn_t action_ret)
|
||
{
|
||
if (desc->istate & IRQS_POLL_INPROGRESS)
|
||
return;
|
||
|
||
- /* we get here again via the threaded handler */
|
||
- if (action_ret == IRQ_WAKE_THREAD)
|
||
- return;
|
||
-
|
||
if (bad_action_ret(action_ret)) {
|
||
report_bad_irq(irq, desc, action_ret);
|
||
return;
|
||
}
|
||
|
||
+ /*
|
||
+ * We cannot call note_interrupt from the threaded handler
|
||
+ * because we need to look at the compound of all handlers
|
||
+ * (primary and threaded). Aside of that in the threaded
|
||
+ * shared case we have no serialization against an incoming
|
||
+ * hardware interrupt while we are dealing with a threaded
|
||
+ * result.
|
||
+ *
|
||
+ * So in case a thread is woken, we just note the fact and
|
||
+ * defer the analysis to the next hardware interrupt.
|
||
+ *
|
||
+ * The threaded handlers store whether they sucessfully
|
||
+ * handled an interrupt and we check whether that number
|
||
+ * changed versus the last invocation.
|
||
+ *
|
||
+ * We could handle all interrupts with the delayed by one
|
||
+ * mechanism, but for the non forced threaded case we'd just
|
||
+ * add pointless overhead to the straight hardirq interrupts
|
||
+ * for the sake of a few lines less code.
|
||
+ */
|
||
+ if (action_ret & IRQ_WAKE_THREAD) {
|
||
+ /*
|
||
+ * There is a thread woken. Check whether one of the
|
||
+ * shared primary handlers returned IRQ_HANDLED. If
|
||
+ * not we defer the spurious detection to the next
|
||
+ * interrupt.
|
||
+ */
|
||
+ if (action_ret == IRQ_WAKE_THREAD) {
|
||
+ int handled;
|
||
+ /*
|
||
+ * We use bit 31 of thread_handled_last to
|
||
+ * denote the deferred spurious detection
|
||
+ * active. No locking necessary as
|
||
+ * thread_handled_last is only accessed here
|
||
+ * and we have the guarantee that hard
|
||
+ * interrupts are not reentrant.
|
||
+ */
|
||
+ if (!(desc->threads_handled_last & SPURIOUS_DEFERRED)) {
|
||
+ desc->threads_handled_last |= SPURIOUS_DEFERRED;
|
||
+ return;
|
||
+ }
|
||
+ /*
|
||
+ * Check whether one of the threaded handlers
|
||
+ * returned IRQ_HANDLED since the last
|
||
+ * interrupt happened.
|
||
+ *
|
||
+ * For simplicity we just set bit 31, as it is
|
||
+ * set in threads_handled_last as well. So we
|
||
+ * avoid extra masking. And we really do not
|
||
+ * care about the high bits of the handled
|
||
+ * count. We just care about the count being
|
||
+ * different than the one we saw before.
|
||
+ */
|
||
+ handled = atomic_read(&desc->threads_handled);
|
||
+ handled |= SPURIOUS_DEFERRED;
|
||
+ if (handled != desc->threads_handled_last) {
|
||
+ action_ret = IRQ_HANDLED;
|
||
+ /*
|
||
+ * Note: We keep the SPURIOUS_DEFERRED
|
||
+ * bit set. We are handling the
|
||
+ * previous invocation right now.
|
||
+ * Keep it for the current one, so the
|
||
+ * next hardware interrupt will
|
||
+ * account for it.
|
||
+ */
|
||
+ desc->threads_handled_last = handled;
|
||
+ } else {
|
||
+ /*
|
||
+ * None of the threaded handlers felt
|
||
+ * responsible for the last interrupt
|
||
+ *
|
||
+ * We keep the SPURIOUS_DEFERRED bit
|
||
+ * set in threads_handled_last as we
|
||
+ * need to account for the current
|
||
+ * interrupt as well.
|
||
+ */
|
||
+ action_ret = IRQ_NONE;
|
||
+ }
|
||
+ } else {
|
||
+ /*
|
||
+ * One of the primary handlers returned
|
||
+ * IRQ_HANDLED. So we don't care about the
|
||
+ * threaded handlers on the same line. Clear
|
||
+ * the deferred detection bit.
|
||
+ *
|
||
+ * In theory we could/should check whether the
|
||
+ * deferred bit is set and take the result of
|
||
+ * the previous run into account here as
|
||
+ * well. But it's really not worth the
|
||
+ * trouble. If every other interrupt is
|
||
+ * handled we never trigger the spurious
|
||
+ * detector. And if this is just the one out
|
||
+ * of 100k unhandled ones which is handled
|
||
+ * then we merily delay the spurious detection
|
||
+ * by one hard interrupt. Not a real problem.
|
||
+ */
|
||
+ desc->threads_handled_last &= ~SPURIOUS_DEFERRED;
|
||
+ }
|
||
+ }
|
||
+
|
||
if (unlikely(action_ret == IRQ_NONE)) {
|
||
/*
|
||
* If we are seeing only the odd spurious IRQ caused by
|
||
diff --git a/kernel/module.c b/kernel/module.c
|
||
index 8597217..5e39896 100644
|
||
--- a/kernel/module.c
|
||
+++ b/kernel/module.c
|
||
@@ -2951,6 +2951,9 @@ static struct module *load_module(void __user *umod,
|
||
/* This has to be done once we're sure module name is unique. */
|
||
dynamic_debug_setup(info.debug, info.num_debug);
|
||
|
||
+ /* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
|
||
+ ftrace_module_init(mod);
|
||
+
|
||
/* Find duplicate symbols */
|
||
err = verify_export_symbols(mod);
|
||
if (err < 0)
|
||
diff --git a/kernel/power/process.c b/kernel/power/process.c
|
||
index bd9e3b9..8908e6c 100644
|
||
--- a/kernel/power/process.c
|
||
+++ b/kernel/power/process.c
|
||
@@ -197,6 +197,7 @@ void thaw_processes(void)
|
||
|
||
printk("Restarting tasks ... ");
|
||
|
||
+ __usermodehelper_set_disable_depth(UMH_FREEZING);
|
||
thaw_workqueues();
|
||
|
||
read_lock(&tasklist_lock);
|
||
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
|
||
index 0de2857..91c04f1 100644
|
||
--- a/kernel/power/snapshot.c
|
||
+++ b/kernel/power/snapshot.c
|
||
@@ -1398,7 +1398,11 @@ int hibernate_preallocate_memory(void)
|
||
* highmem and non-highmem zones separately.
|
||
*/
|
||
pages_highmem = preallocate_image_highmem(highmem / 2);
|
||
- alloc = (count - max_size) - pages_highmem;
|
||
+ alloc = count - max_size;
|
||
+ if (alloc > pages_highmem)
|
||
+ alloc -= pages_highmem;
|
||
+ else
|
||
+ alloc = 0;
|
||
pages = preallocate_image_memory(alloc, avail_normal);
|
||
if (pages < alloc) {
|
||
/* We have exhausted non-highmem pages, try highmem. */
|
||
diff --git a/kernel/printk.c b/kernel/printk.c
|
||
index fb41e3a..67877ac 100644
|
||
--- a/kernel/printk.c
|
||
+++ b/kernel/printk.c
|
||
@@ -875,9 +875,9 @@ static int console_trylock_for_printk(unsigned int cpu)
|
||
}
|
||
}
|
||
printk_cpu = UINT_MAX;
|
||
+ raw_spin_unlock(&logbuf_lock);
|
||
if (wake)
|
||
up(&console_sem);
|
||
- raw_spin_unlock(&logbuf_lock);
|
||
return retval;
|
||
}
|
||
static const char recursion_bug_msg [] =
|
||
@@ -1725,7 +1725,7 @@ late_initcall(printk_late_init);
|
||
|
||
#if defined CONFIG_PRINTK
|
||
|
||
-int printk_sched(const char *fmt, ...)
|
||
+int printk_deferred(const char *fmt, ...)
|
||
{
|
||
unsigned long flags;
|
||
va_list args;
|
||
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
|
||
index daf4394..a143236 100644
|
||
--- a/kernel/ptrace.c
|
||
+++ b/kernel/ptrace.c
|
||
@@ -254,7 +254,8 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
|
||
smp_rmb();
|
||
if (task->mm)
|
||
dumpable = get_dumpable(task->mm);
|
||
- if (!dumpable && !ptrace_has_cap(task_user_ns(task), mode))
|
||
+ if (dumpable != SUID_DUMP_USER &&
|
||
+ !ptrace_has_cap(task_user_ns(task), mode))
|
||
return -EPERM;
|
||
|
||
return security_ptrace_access_check(task, mode);
|
||
diff --git a/kernel/rtmutex-debug.h b/kernel/rtmutex-debug.h
|
||
index 14193d5..ab29b6a 100644
|
||
--- a/kernel/rtmutex-debug.h
|
||
+++ b/kernel/rtmutex-debug.h
|
||
@@ -31,3 +31,8 @@ static inline int debug_rt_mutex_detect_deadlock(struct rt_mutex_waiter *waiter,
|
||
{
|
||
return (waiter != NULL);
|
||
}
|
||
+
|
||
+static inline void rt_mutex_print_deadlock(struct rt_mutex_waiter *w)
|
||
+{
|
||
+ debug_rt_mutex_print_deadlock(w);
|
||
+}
|
||
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
|
||
index a3772b6..bf34632 100644
|
||
--- a/kernel/rtmutex.c
|
||
+++ b/kernel/rtmutex.c
|
||
@@ -81,6 +81,47 @@ static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
|
||
owner = *p;
|
||
} while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
|
||
}
|
||
+
|
||
+/*
|
||
+ * Safe fastpath aware unlock:
|
||
+ * 1) Clear the waiters bit
|
||
+ * 2) Drop lock->wait_lock
|
||
+ * 3) Try to unlock the lock with cmpxchg
|
||
+ */
|
||
+static inline bool unlock_rt_mutex_safe(struct rt_mutex *lock)
|
||
+ __releases(lock->wait_lock)
|
||
+{
|
||
+ struct task_struct *owner = rt_mutex_owner(lock);
|
||
+
|
||
+ clear_rt_mutex_waiters(lock);
|
||
+ raw_spin_unlock(&lock->wait_lock);
|
||
+ /*
|
||
+ * If a new waiter comes in between the unlock and the cmpxchg
|
||
+ * we have two situations:
|
||
+ *
|
||
+ * unlock(wait_lock);
|
||
+ * lock(wait_lock);
|
||
+ * cmpxchg(p, owner, 0) == owner
|
||
+ * mark_rt_mutex_waiters(lock);
|
||
+ * acquire(lock);
|
||
+ * or:
|
||
+ *
|
||
+ * unlock(wait_lock);
|
||
+ * lock(wait_lock);
|
||
+ * mark_rt_mutex_waiters(lock);
|
||
+ *
|
||
+ * cmpxchg(p, owner, 0) != owner
|
||
+ * enqueue_waiter();
|
||
+ * unlock(wait_lock);
|
||
+ * lock(wait_lock);
|
||
+ * wake waiter();
|
||
+ * unlock(wait_lock);
|
||
+ * lock(wait_lock);
|
||
+ * acquire(lock);
|
||
+ */
|
||
+ return rt_mutex_cmpxchg(lock, owner, NULL);
|
||
+}
|
||
+
|
||
#else
|
||
# define rt_mutex_cmpxchg(l,c,n) (0)
|
||
static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
|
||
@@ -88,6 +129,17 @@ static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
|
||
lock->owner = (struct task_struct *)
|
||
((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
|
||
}
|
||
+
|
||
+/*
|
||
+ * Simple slow path only version: lock->owner is protected by lock->wait_lock.
|
||
+ */
|
||
+static inline bool unlock_rt_mutex_safe(struct rt_mutex *lock)
|
||
+ __releases(lock->wait_lock)
|
||
+{
|
||
+ lock->owner = NULL;
|
||
+ raw_spin_unlock(&lock->wait_lock);
|
||
+ return true;
|
||
+}
|
||
#endif
|
||
|
||
/*
|
||
@@ -141,6 +193,11 @@ static void rt_mutex_adjust_prio(struct task_struct *task)
|
||
*/
|
||
int max_lock_depth = 1024;
|
||
|
||
+static inline struct rt_mutex *task_blocked_on_lock(struct task_struct *p)
|
||
+{
|
||
+ return p->pi_blocked_on ? p->pi_blocked_on->lock : NULL;
|
||
+}
|
||
+
|
||
/*
|
||
* Adjust the priority chain. Also used for deadlock detection.
|
||
* Decreases task's usage by one - may thus free the task.
|
||
@@ -149,6 +206,7 @@ int max_lock_depth = 1024;
|
||
static int rt_mutex_adjust_prio_chain(struct task_struct *task,
|
||
int deadlock_detect,
|
||
struct rt_mutex *orig_lock,
|
||
+ struct rt_mutex *next_lock,
|
||
struct rt_mutex_waiter *orig_waiter,
|
||
struct task_struct *top_task)
|
||
{
|
||
@@ -182,7 +240,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
|
||
}
|
||
put_task_struct(task);
|
||
|
||
- return deadlock_detect ? -EDEADLK : 0;
|
||
+ return -EDEADLK;
|
||
}
|
||
retry:
|
||
/*
|
||
@@ -207,13 +265,32 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
|
||
goto out_unlock_pi;
|
||
|
||
/*
|
||
+ * We dropped all locks after taking a refcount on @task, so
|
||
+ * the task might have moved on in the lock chain or even left
|
||
+ * the chain completely and blocks now on an unrelated lock or
|
||
+ * on @orig_lock.
|
||
+ *
|
||
+ * We stored the lock on which @task was blocked in @next_lock,
|
||
+ * so we can detect the chain change.
|
||
+ */
|
||
+ if (next_lock != waiter->lock)
|
||
+ goto out_unlock_pi;
|
||
+
|
||
+ /*
|
||
* Drop out, when the task has no waiters. Note,
|
||
* top_waiter can be NULL, when we are in the deboosting
|
||
* mode!
|
||
*/
|
||
- if (top_waiter && (!task_has_pi_waiters(task) ||
|
||
- top_waiter != task_top_pi_waiter(task)))
|
||
- goto out_unlock_pi;
|
||
+ if (top_waiter) {
|
||
+ if (!task_has_pi_waiters(task))
|
||
+ goto out_unlock_pi;
|
||
+ /*
|
||
+ * If deadlock detection is off, we stop here if we
|
||
+ * are not the top pi waiter of the task.
|
||
+ */
|
||
+ if (!detect_deadlock && top_waiter != task_top_pi_waiter(task))
|
||
+ goto out_unlock_pi;
|
||
+ }
|
||
|
||
/*
|
||
* When deadlock detection is off then we check, if further
|
||
@@ -229,11 +306,16 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
|
||
goto retry;
|
||
}
|
||
|
||
- /* Deadlock detection */
|
||
+ /*
|
||
+ * Deadlock detection. If the lock is the same as the original
|
||
+ * lock which caused us to walk the lock chain or if the
|
||
+ * current lock is owned by the task which initiated the chain
|
||
+ * walk, we detected a deadlock.
|
||
+ */
|
||
if (lock == orig_lock || rt_mutex_owner(lock) == top_task) {
|
||
debug_rt_mutex_deadlock(deadlock_detect, orig_waiter, lock);
|
||
raw_spin_unlock(&lock->wait_lock);
|
||
- ret = deadlock_detect ? -EDEADLK : 0;
|
||
+ ret = -EDEADLK;
|
||
goto out_unlock_pi;
|
||
}
|
||
|
||
@@ -280,11 +362,26 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
|
||
__rt_mutex_adjust_prio(task);
|
||
}
|
||
|
||
+ /*
|
||
+ * Check whether the task which owns the current lock is pi
|
||
+ * blocked itself. If yes we store a pointer to the lock for
|
||
+ * the lock chain change detection above. After we dropped
|
||
+ * task->pi_lock next_lock cannot be dereferenced anymore.
|
||
+ */
|
||
+ next_lock = task_blocked_on_lock(task);
|
||
+
|
||
raw_spin_unlock_irqrestore(&task->pi_lock, flags);
|
||
|
||
top_waiter = rt_mutex_top_waiter(lock);
|
||
raw_spin_unlock(&lock->wait_lock);
|
||
|
||
+ /*
|
||
+ * We reached the end of the lock chain. Stop right here. No
|
||
+ * point to go back just to figure that out.
|
||
+ */
|
||
+ if (!next_lock)
|
||
+ goto out_put_task;
|
||
+
|
||
if (!detect_deadlock && waiter != top_waiter)
|
||
goto out_put_task;
|
||
|
||
@@ -395,8 +492,21 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
|
||
{
|
||
struct task_struct *owner = rt_mutex_owner(lock);
|
||
struct rt_mutex_waiter *top_waiter = waiter;
|
||
- unsigned long flags;
|
||
+ struct rt_mutex *next_lock;
|
||
int chain_walk = 0, res;
|
||
+ unsigned long flags;
|
||
+
|
||
+ /*
|
||
+ * Early deadlock detection. We really don't want the task to
|
||
+ * enqueue on itself just to untangle the mess later. It's not
|
||
+ * only an optimization. We drop the locks, so another waiter
|
||
+ * can come in before the chain walk detects the deadlock. So
|
||
+ * the other will detect the deadlock and return -EDEADLOCK,
|
||
+ * which is wrong, as the other waiter is not in a deadlock
|
||
+ * situation.
|
||
+ */
|
||
+ if (owner == task)
|
||
+ return -EDEADLK;
|
||
|
||
raw_spin_lock_irqsave(&task->pi_lock, flags);
|
||
__rt_mutex_adjust_prio(task);
|
||
@@ -417,20 +527,28 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
|
||
if (!owner)
|
||
return 0;
|
||
|
||
+ raw_spin_lock_irqsave(&owner->pi_lock, flags);
|
||
if (waiter == rt_mutex_top_waiter(lock)) {
|
||
- raw_spin_lock_irqsave(&owner->pi_lock, flags);
|
||
plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters);
|
||
plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
|
||
|
||
__rt_mutex_adjust_prio(owner);
|
||
if (owner->pi_blocked_on)
|
||
chain_walk = 1;
|
||
- raw_spin_unlock_irqrestore(&owner->pi_lock, flags);
|
||
- }
|
||
- else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock))
|
||
+ } else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) {
|
||
chain_walk = 1;
|
||
+ }
|
||
+
|
||
+ /* Store the lock on which owner is blocked or NULL */
|
||
+ next_lock = task_blocked_on_lock(owner);
|
||
|
||
- if (!chain_walk)
|
||
+ raw_spin_unlock_irqrestore(&owner->pi_lock, flags);
|
||
+ /*
|
||
+ * Even if full deadlock detection is on, if the owner is not
|
||
+ * blocked itself, we can avoid finding this out in the chain
|
||
+ * walk.
|
||
+ */
|
||
+ if (!chain_walk || !next_lock)
|
||
return 0;
|
||
|
||
/*
|
||
@@ -442,8 +560,8 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
|
||
|
||
raw_spin_unlock(&lock->wait_lock);
|
||
|
||
- res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter,
|
||
- task);
|
||
+ res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock,
|
||
+ next_lock, waiter, task);
|
||
|
||
raw_spin_lock(&lock->wait_lock);
|
||
|
||
@@ -453,7 +571,8 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
|
||
/*
|
||
* Wake up the next waiter on the lock.
|
||
*
|
||
- * Remove the top waiter from the current tasks waiter list and wake it up.
|
||
+ * Remove the top waiter from the current tasks pi waiter list and
|
||
+ * wake it up.
|
||
*
|
||
* Called with lock->wait_lock held.
|
||
*/
|
||
@@ -474,10 +593,23 @@ static void wakeup_next_waiter(struct rt_mutex *lock)
|
||
*/
|
||
plist_del(&waiter->pi_list_entry, ¤t->pi_waiters);
|
||
|
||
- rt_mutex_set_owner(lock, NULL);
|
||
+ /*
|
||
+ * As we are waking up the top waiter, and the waiter stays
|
||
+ * queued on the lock until it gets the lock, this lock
|
||
+ * obviously has waiters. Just set the bit here and this has
|
||
+ * the added benefit of forcing all new tasks into the
|
||
+ * slow path making sure no task of lower priority than
|
||
+ * the top waiter can steal this lock.
|
||
+ */
|
||
+ lock->owner = (void *) RT_MUTEX_HAS_WAITERS;
|
||
|
||
raw_spin_unlock_irqrestore(¤t->pi_lock, flags);
|
||
|
||
+ /*
|
||
+ * It's safe to dereference waiter as it cannot go away as
|
||
+ * long as we hold lock->wait_lock. The waiter task needs to
|
||
+ * acquire it in order to dequeue the waiter.
|
||
+ */
|
||
wake_up_process(waiter->task);
|
||
}
|
||
|
||
@@ -492,8 +624,8 @@ static void remove_waiter(struct rt_mutex *lock,
|
||
{
|
||
int first = (waiter == rt_mutex_top_waiter(lock));
|
||
struct task_struct *owner = rt_mutex_owner(lock);
|
||
+ struct rt_mutex *next_lock = NULL;
|
||
unsigned long flags;
|
||
- int chain_walk = 0;
|
||
|
||
raw_spin_lock_irqsave(¤t->pi_lock, flags);
|
||
plist_del(&waiter->list_entry, &lock->wait_list);
|
||
@@ -517,15 +649,15 @@ static void remove_waiter(struct rt_mutex *lock,
|
||
}
|
||
__rt_mutex_adjust_prio(owner);
|
||
|
||
- if (owner->pi_blocked_on)
|
||
- chain_walk = 1;
|
||
+ /* Store the lock on which owner is blocked or NULL */
|
||
+ next_lock = task_blocked_on_lock(owner);
|
||
|
||
raw_spin_unlock_irqrestore(&owner->pi_lock, flags);
|
||
}
|
||
|
||
WARN_ON(!plist_node_empty(&waiter->pi_list_entry));
|
||
|
||
- if (!chain_walk)
|
||
+ if (!next_lock)
|
||
return;
|
||
|
||
/* gets dropped in rt_mutex_adjust_prio_chain()! */
|
||
@@ -533,7 +665,7 @@ static void remove_waiter(struct rt_mutex *lock,
|
||
|
||
raw_spin_unlock(&lock->wait_lock);
|
||
|
||
- rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current);
|
||
+ rt_mutex_adjust_prio_chain(owner, 0, lock, next_lock, NULL, current);
|
||
|
||
raw_spin_lock(&lock->wait_lock);
|
||
}
|
||
@@ -546,6 +678,7 @@ static void remove_waiter(struct rt_mutex *lock,
|
||
void rt_mutex_adjust_pi(struct task_struct *task)
|
||
{
|
||
struct rt_mutex_waiter *waiter;
|
||
+ struct rt_mutex *next_lock;
|
||
unsigned long flags;
|
||
|
||
raw_spin_lock_irqsave(&task->pi_lock, flags);
|
||
@@ -555,12 +688,13 @@ void rt_mutex_adjust_pi(struct task_struct *task)
|
||
raw_spin_unlock_irqrestore(&task->pi_lock, flags);
|
||
return;
|
||
}
|
||
-
|
||
+ next_lock = waiter->lock;
|
||
raw_spin_unlock_irqrestore(&task->pi_lock, flags);
|
||
|
||
/* gets dropped in rt_mutex_adjust_prio_chain()! */
|
||
get_task_struct(task);
|
||
- rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task);
|
||
+
|
||
+ rt_mutex_adjust_prio_chain(task, 0, NULL, next_lock, NULL, task);
|
||
}
|
||
|
||
/**
|
||
@@ -612,6 +746,26 @@ __rt_mutex_slowlock(struct rt_mutex *lock, int state,
|
||
return ret;
|
||
}
|
||
|
||
+static void rt_mutex_handle_deadlock(int res, int detect_deadlock,
|
||
+ struct rt_mutex_waiter *w)
|
||
+{
|
||
+ /*
|
||
+ * If the result is not -EDEADLOCK or the caller requested
|
||
+ * deadlock detection, nothing to do here.
|
||
+ */
|
||
+ if (res != -EDEADLOCK || detect_deadlock)
|
||
+ return;
|
||
+
|
||
+ /*
|
||
+ * Yell lowdly and stop the task right here.
|
||
+ */
|
||
+ rt_mutex_print_deadlock(w);
|
||
+ while (1) {
|
||
+ set_current_state(TASK_INTERRUPTIBLE);
|
||
+ schedule();
|
||
+ }
|
||
+}
|
||
+
|
||
/*
|
||
* Slow path lock function:
|
||
*/
|
||
@@ -649,8 +803,10 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
|
||
|
||
set_current_state(TASK_RUNNING);
|
||
|
||
- if (unlikely(ret))
|
||
+ if (unlikely(ret)) {
|
||
remove_waiter(lock, &waiter);
|
||
+ rt_mutex_handle_deadlock(ret, detect_deadlock, &waiter);
|
||
+ }
|
||
|
||
/*
|
||
* try_to_take_rt_mutex() sets the waiter bit
|
||
@@ -706,12 +862,49 @@ rt_mutex_slowunlock(struct rt_mutex *lock)
|
||
|
||
rt_mutex_deadlock_account_unlock(current);
|
||
|
||
- if (!rt_mutex_has_waiters(lock)) {
|
||
- lock->owner = NULL;
|
||
- raw_spin_unlock(&lock->wait_lock);
|
||
- return;
|
||
+ /*
|
||
+ * We must be careful here if the fast path is enabled. If we
|
||
+ * have no waiters queued we cannot set owner to NULL here
|
||
+ * because of:
|
||
+ *
|
||
+ * foo->lock->owner = NULL;
|
||
+ * rtmutex_lock(foo->lock); <- fast path
|
||
+ * free = atomic_dec_and_test(foo->refcnt);
|
||
+ * rtmutex_unlock(foo->lock); <- fast path
|
||
+ * if (free)
|
||
+ * kfree(foo);
|
||
+ * raw_spin_unlock(foo->lock->wait_lock);
|
||
+ *
|
||
+ * So for the fastpath enabled kernel:
|
||
+ *
|
||
+ * Nothing can set the waiters bit as long as we hold
|
||
+ * lock->wait_lock. So we do the following sequence:
|
||
+ *
|
||
+ * owner = rt_mutex_owner(lock);
|
||
+ * clear_rt_mutex_waiters(lock);
|
||
+ * raw_spin_unlock(&lock->wait_lock);
|
||
+ * if (cmpxchg(&lock->owner, owner, 0) == owner)
|
||
+ * return;
|
||
+ * goto retry;
|
||
+ *
|
||
+ * The fastpath disabled variant is simple as all access to
|
||
+ * lock->owner is serialized by lock->wait_lock:
|
||
+ *
|
||
+ * lock->owner = NULL;
|
||
+ * raw_spin_unlock(&lock->wait_lock);
|
||
+ */
|
||
+ while (!rt_mutex_has_waiters(lock)) {
|
||
+ /* Drops lock->wait_lock ! */
|
||
+ if (unlock_rt_mutex_safe(lock) == true)
|
||
+ return;
|
||
+ /* Relock the rtmutex and try again */
|
||
+ raw_spin_lock(&lock->wait_lock);
|
||
}
|
||
|
||
+ /*
|
||
+ * The wakeup next waiter path does not suffer from the above
|
||
+ * race. See the comments there.
|
||
+ */
|
||
wakeup_next_waiter(lock);
|
||
|
||
raw_spin_unlock(&lock->wait_lock);
|
||
@@ -958,7 +1151,8 @@ int rt_mutex_start_proxy_lock(struct rt_mutex *lock,
|
||
return 1;
|
||
}
|
||
|
||
- ret = task_blocks_on_rt_mutex(lock, waiter, task, detect_deadlock);
|
||
+ /* We enforce deadlock detection for futexes */
|
||
+ ret = task_blocks_on_rt_mutex(lock, waiter, task, 1);
|
||
|
||
if (ret && !rt_mutex_owner(lock)) {
|
||
/*
|
||
diff --git a/kernel/rtmutex.h b/kernel/rtmutex.h
|
||
index a1a1dd0..f6a1f3c 100644
|
||
--- a/kernel/rtmutex.h
|
||
+++ b/kernel/rtmutex.h
|
||
@@ -24,3 +24,8 @@
|
||
#define debug_rt_mutex_print_deadlock(w) do { } while (0)
|
||
#define debug_rt_mutex_detect_deadlock(w,d) (d)
|
||
#define debug_rt_mutex_reset_waiter(w) do { } while (0)
|
||
+
|
||
+static inline void rt_mutex_print_deadlock(struct rt_mutex_waiter *w)
|
||
+{
|
||
+ WARN(1, "rtmutex deadlock detected\n");
|
||
+}
|
||
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
||
index 5da13d7..a14740d 100644
|
||
--- a/kernel/sched/core.c
|
||
+++ b/kernel/sched/core.c
|
||
@@ -715,8 +715,6 @@ int tg_nop(struct task_group *tg, void *data)
|
||
}
|
||
#endif
|
||
|
||
-void update_cpu_load(struct rq *this_rq);
|
||
-
|
||
static void set_load_weight(struct task_struct *p)
|
||
{
|
||
int prio = p->static_prio - MAX_RT_PRIO;
|
||
@@ -1340,7 +1338,7 @@ static int select_fallback_rq(int cpu, struct task_struct *p)
|
||
* leave kernel.
|
||
*/
|
||
if (p->mm && printk_ratelimit()) {
|
||
- printk_sched("process %d (%s) no longer affine to cpu%d\n",
|
||
+ printk_deferred("process %d (%s) no longer affine to cpu%d\n",
|
||
task_pid_nr(p), p->comm, cpu);
|
||
}
|
||
}
|
||
@@ -1690,7 +1688,7 @@ static void try_to_wake_up_local(struct task_struct *p)
|
||
struct rq *rq = task_rq(p);
|
||
|
||
if (rq != this_rq() || p == current) {
|
||
- printk_sched("%s: Failed to wakeup task %d (%s), rq = %p, this_rq = %p, p = %p, current = %p\n",
|
||
+ printk_deferred("%s: Failed to wakeup task %d (%s), rq = %p, this_rq = %p, p = %p, current = %p\n",
|
||
__func__, task_pid_nr(p), p->comm, rq,
|
||
this_rq(), p, current);
|
||
return;
|
||
@@ -2659,22 +2657,13 @@ decay_load_missed(unsigned long load, unsigned long missed_updates, int idx)
|
||
* scheduler tick (TICK_NSEC). With tickless idle this will not be called
|
||
* every tick. We fix it up based on jiffies.
|
||
*/
|
||
-void update_cpu_load(struct rq *this_rq)
|
||
+static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
|
||
+ unsigned long pending_updates)
|
||
{
|
||
- unsigned long this_load = this_rq->load.weight;
|
||
- unsigned long curr_jiffies = jiffies;
|
||
- unsigned long pending_updates;
|
||
int i, scale;
|
||
|
||
this_rq->nr_load_updates++;
|
||
|
||
- /* Avoid repeated calls on same jiffy, when moving in and out of idle */
|
||
- if (curr_jiffies == this_rq->last_load_update_tick)
|
||
- return;
|
||
-
|
||
- pending_updates = curr_jiffies - this_rq->last_load_update_tick;
|
||
- this_rq->last_load_update_tick = curr_jiffies;
|
||
-
|
||
/* Update our load: */
|
||
this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */
|
||
for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
|
||
@@ -2699,9 +2688,78 @@ void update_cpu_load(struct rq *this_rq)
|
||
sched_avg_update(this_rq);
|
||
}
|
||
|
||
+#ifdef CONFIG_NO_HZ
|
||
+/*
|
||
+ * There is no sane way to deal with nohz on smp when using jiffies because the
|
||
+ * cpu doing the jiffies update might drift wrt the cpu doing the jiffy reading
|
||
+ * causing off-by-one errors in observed deltas; {0,2} instead of {1,1}.
|
||
+ *
|
||
+ * Therefore we cannot use the delta approach from the regular tick since that
|
||
+ * would seriously skew the load calculation. However we'll make do for those
|
||
+ * updates happening while idle (nohz_idle_balance) or coming out of idle
|
||
+ * (tick_nohz_idle_exit).
|
||
+ *
|
||
+ * This means we might still be one tick off for nohz periods.
|
||
+ */
|
||
+
|
||
+/*
|
||
+ * Called from nohz_idle_balance() to update the load ratings before doing the
|
||
+ * idle balance.
|
||
+ */
|
||
+void update_idle_cpu_load(struct rq *this_rq)
|
||
+{
|
||
+ unsigned long curr_jiffies = ACCESS_ONCE(jiffies);
|
||
+ unsigned long load = this_rq->load.weight;
|
||
+ unsigned long pending_updates;
|
||
+
|
||
+ /*
|
||
+ * bail if there's load or we're actually up-to-date.
|
||
+ */
|
||
+ if (load || curr_jiffies == this_rq->last_load_update_tick)
|
||
+ return;
|
||
+
|
||
+ pending_updates = curr_jiffies - this_rq->last_load_update_tick;
|
||
+ this_rq->last_load_update_tick = curr_jiffies;
|
||
+
|
||
+ __update_cpu_load(this_rq, load, pending_updates);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Called from tick_nohz_idle_exit() -- try and fix up the ticks we missed.
|
||
+ */
|
||
+void update_cpu_load_nohz(void)
|
||
+{
|
||
+ struct rq *this_rq = this_rq();
|
||
+ unsigned long curr_jiffies = ACCESS_ONCE(jiffies);
|
||
+ unsigned long pending_updates;
|
||
+
|
||
+ if (curr_jiffies == this_rq->last_load_update_tick)
|
||
+ return;
|
||
+
|
||
+ raw_spin_lock(&this_rq->lock);
|
||
+ pending_updates = curr_jiffies - this_rq->last_load_update_tick;
|
||
+ if (pending_updates) {
|
||
+ this_rq->last_load_update_tick = curr_jiffies;
|
||
+ /*
|
||
+ * We were idle, this means load 0, the current load might be
|
||
+ * !0 due to remote wakeups and the sort.
|
||
+ */
|
||
+ __update_cpu_load(this_rq, 0, pending_updates);
|
||
+ }
|
||
+ raw_spin_unlock(&this_rq->lock);
|
||
+}
|
||
+#endif /* CONFIG_NO_HZ */
|
||
+
|
||
+/*
|
||
+ * Called from scheduler_tick()
|
||
+ */
|
||
static void update_cpu_load_active(struct rq *this_rq)
|
||
{
|
||
- update_cpu_load(this_rq);
|
||
+ /*
|
||
+ * See the mess around update_idle_cpu_load() / update_cpu_load_nohz().
|
||
+ */
|
||
+ this_rq->last_load_update_tick = jiffies;
|
||
+ __update_cpu_load(this_rq, this_rq->load.weight, 1);
|
||
|
||
calc_load_account_active(this_rq);
|
||
}
|
||
@@ -5433,16 +5491,25 @@ static void sd_free_ctl_entry(struct ctl_table **tablep)
|
||
*tablep = NULL;
|
||
}
|
||
|
||
+static int min_load_idx = 0;
|
||
+static int max_load_idx = CPU_LOAD_IDX_MAX-1;
|
||
+
|
||
static void
|
||
set_table_entry(struct ctl_table *entry,
|
||
const char *procname, void *data, int maxlen,
|
||
- umode_t mode, proc_handler *proc_handler)
|
||
+ umode_t mode, proc_handler *proc_handler,
|
||
+ bool load_idx)
|
||
{
|
||
entry->procname = procname;
|
||
entry->data = data;
|
||
entry->maxlen = maxlen;
|
||
entry->mode = mode;
|
||
entry->proc_handler = proc_handler;
|
||
+
|
||
+ if (load_idx) {
|
||
+ entry->extra1 = &min_load_idx;
|
||
+ entry->extra2 = &max_load_idx;
|
||
+ }
|
||
}
|
||
|
||
static struct ctl_table *
|
||
@@ -5454,30 +5521,30 @@ sd_alloc_ctl_domain_table(struct sched_domain *sd)
|
||
return NULL;
|
||
|
||
set_table_entry(&table[0], "min_interval", &sd->min_interval,
|
||
- sizeof(long), 0644, proc_doulongvec_minmax);
|
||
+ sizeof(long), 0644, proc_doulongvec_minmax, false);
|
||
set_table_entry(&table[1], "max_interval", &sd->max_interval,
|
||
- sizeof(long), 0644, proc_doulongvec_minmax);
|
||
+ sizeof(long), 0644, proc_doulongvec_minmax, false);
|
||
set_table_entry(&table[2], "busy_idx", &sd->busy_idx,
|
||
- sizeof(int), 0644, proc_dointvec_minmax);
|
||
+ sizeof(int), 0644, proc_dointvec_minmax, true);
|
||
set_table_entry(&table[3], "idle_idx", &sd->idle_idx,
|
||
- sizeof(int), 0644, proc_dointvec_minmax);
|
||
+ sizeof(int), 0644, proc_dointvec_minmax, true);
|
||
set_table_entry(&table[4], "newidle_idx", &sd->newidle_idx,
|
||
- sizeof(int), 0644, proc_dointvec_minmax);
|
||
+ sizeof(int), 0644, proc_dointvec_minmax, true);
|
||
set_table_entry(&table[5], "wake_idx", &sd->wake_idx,
|
||
- sizeof(int), 0644, proc_dointvec_minmax);
|
||
+ sizeof(int), 0644, proc_dointvec_minmax, true);
|
||
set_table_entry(&table[6], "forkexec_idx", &sd->forkexec_idx,
|
||
- sizeof(int), 0644, proc_dointvec_minmax);
|
||
+ sizeof(int), 0644, proc_dointvec_minmax, true);
|
||
set_table_entry(&table[7], "busy_factor", &sd->busy_factor,
|
||
- sizeof(int), 0644, proc_dointvec_minmax);
|
||
+ sizeof(int), 0644, proc_dointvec_minmax, false);
|
||
set_table_entry(&table[8], "imbalance_pct", &sd->imbalance_pct,
|
||
- sizeof(int), 0644, proc_dointvec_minmax);
|
||
+ sizeof(int), 0644, proc_dointvec_minmax, false);
|
||
set_table_entry(&table[9], "cache_nice_tries",
|
||
&sd->cache_nice_tries,
|
||
- sizeof(int), 0644, proc_dointvec_minmax);
|
||
+ sizeof(int), 0644, proc_dointvec_minmax, false);
|
||
set_table_entry(&table[10], "flags", &sd->flags,
|
||
- sizeof(int), 0644, proc_dointvec_minmax);
|
||
+ sizeof(int), 0644, proc_dointvec_minmax, false);
|
||
set_table_entry(&table[11], "name", sd->name,
|
||
- CORENAME_MAX_SIZE, 0444, proc_dostring);
|
||
+ CORENAME_MAX_SIZE, 0444, proc_dostring, false);
|
||
/* &table[12] is terminator */
|
||
|
||
return table;
|
||
@@ -8017,7 +8084,12 @@ static int tg_set_cfs_bandwidth(struct task_group *tg, u64 period, u64 quota)
|
||
|
||
runtime_enabled = quota != RUNTIME_INF;
|
||
runtime_was_enabled = cfs_b->quota != RUNTIME_INF;
|
||
- account_cfs_bandwidth_used(runtime_enabled, runtime_was_enabled);
|
||
+ /*
|
||
+ * If we need to toggle cfs_bandwidth_used, off->on must occur
|
||
+ * before making related changes, and on->off must occur afterwards
|
||
+ */
|
||
+ if (runtime_enabled && !runtime_was_enabled)
|
||
+ cfs_bandwidth_usage_inc();
|
||
raw_spin_lock_irq(&cfs_b->lock);
|
||
cfs_b->period = ns_to_ktime(period);
|
||
cfs_b->quota = quota;
|
||
@@ -8043,6 +8115,8 @@ static int tg_set_cfs_bandwidth(struct task_group *tg, u64 period, u64 quota)
|
||
unthrottle_cfs_rq(cfs_rq);
|
||
raw_spin_unlock_irq(&rq->lock);
|
||
}
|
||
+ if (runtime_was_enabled && !runtime_enabled)
|
||
+ cfs_bandwidth_usage_dec();
|
||
out_unlock:
|
||
mutex_unlock(&cfs_constraints_mutex);
|
||
|
||
diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c
|
||
index d72586f..beb9a8f 100644
|
||
--- a/kernel/sched/cpupri.c
|
||
+++ b/kernel/sched/cpupri.c
|
||
@@ -68,8 +68,7 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p,
|
||
int idx = 0;
|
||
int task_pri = convert_prio(p->prio);
|
||
|
||
- if (task_pri >= MAX_RT_PRIO)
|
||
- return 0;
|
||
+ BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES);
|
||
|
||
for (idx = 0; idx < task_pri; idx++) {
|
||
struct cpupri_vec *vec = &cp->pri_to_cpu[idx];
|
||
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
|
||
index c00829e..20e311b 100644
|
||
--- a/kernel/sched/debug.c
|
||
+++ b/kernel/sched/debug.c
|
||
@@ -215,6 +215,14 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
|
||
SEQ_printf(m, " .%-30s: %d\n", "load_tg",
|
||
atomic_read(&cfs_rq->tg->load_weight));
|
||
#endif
|
||
+#ifdef CONFIG_CFS_BANDWIDTH
|
||
+ SEQ_printf(m, " .%-30s: %d\n", "tg->cfs_bandwidth.timer_active",
|
||
+ cfs_rq->tg->cfs_bandwidth.timer_active);
|
||
+ SEQ_printf(m, " .%-30s: %d\n", "throttled",
|
||
+ cfs_rq->throttled);
|
||
+ SEQ_printf(m, " .%-30s: %d\n", "throttle_count",
|
||
+ cfs_rq->throttle_count);
|
||
+#endif
|
||
|
||
print_cfs_group_stats(m, cpu, cfs_rq->tg);
|
||
#endif
|
||
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
|
||
index 62f8598..c9ad0d0 100644
|
||
--- a/kernel/sched/fair.c
|
||
+++ b/kernel/sched/fair.c
|
||
@@ -1401,13 +1401,14 @@ static inline bool cfs_bandwidth_used(void)
|
||
return static_key_false(&__cfs_bandwidth_used);
|
||
}
|
||
|
||
-void account_cfs_bandwidth_used(int enabled, int was_enabled)
|
||
+void cfs_bandwidth_usage_inc(void)
|
||
{
|
||
- /* only need to count groups transitioning between enabled/!enabled */
|
||
- if (enabled && !was_enabled)
|
||
- static_key_slow_inc(&__cfs_bandwidth_used);
|
||
- else if (!enabled && was_enabled)
|
||
- static_key_slow_dec(&__cfs_bandwidth_used);
|
||
+ static_key_slow_inc(&__cfs_bandwidth_used);
|
||
+}
|
||
+
|
||
+void cfs_bandwidth_usage_dec(void)
|
||
+{
|
||
+ static_key_slow_dec(&__cfs_bandwidth_used);
|
||
}
|
||
#else /* HAVE_JUMP_LABEL */
|
||
static bool cfs_bandwidth_used(void)
|
||
@@ -1415,7 +1416,8 @@ static bool cfs_bandwidth_used(void)
|
||
return true;
|
||
}
|
||
|
||
-void account_cfs_bandwidth_used(int enabled, int was_enabled) {}
|
||
+void cfs_bandwidth_usage_inc(void) {}
|
||
+void cfs_bandwidth_usage_dec(void) {}
|
||
#endif /* HAVE_JUMP_LABEL */
|
||
|
||
/*
|
||
@@ -1663,6 +1665,8 @@ static void throttle_cfs_rq(struct cfs_rq *cfs_rq)
|
||
cfs_rq->throttled_timestamp = rq->clock;
|
||
raw_spin_lock(&cfs_b->lock);
|
||
list_add_tail_rcu(&cfs_rq->throttled_list, &cfs_b->throttled_cfs_rq);
|
||
+ if (!cfs_b->timer_active)
|
||
+ __start_cfs_bandwidth(cfs_b);
|
||
raw_spin_unlock(&cfs_b->lock);
|
||
}
|
||
|
||
@@ -1775,6 +1779,13 @@ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun)
|
||
if (idle)
|
||
goto out_unlock;
|
||
|
||
+ /*
|
||
+ * if we have relooped after returning idle once, we need to update our
|
||
+ * status as actually running, so that other cpus doing
|
||
+ * __start_cfs_bandwidth will stop trying to cancel us.
|
||
+ */
|
||
+ cfs_b->timer_active = 1;
|
||
+
|
||
__refill_cfs_bandwidth_runtime(cfs_b);
|
||
|
||
if (!throttled) {
|
||
@@ -1835,7 +1846,13 @@ static const u64 min_bandwidth_expiration = 2 * NSEC_PER_MSEC;
|
||
/* how long we wait to gather additional slack before distributing */
|
||
static const u64 cfs_bandwidth_slack_period = 5 * NSEC_PER_MSEC;
|
||
|
||
-/* are we near the end of the current quota period? */
|
||
+/*
|
||
+ * Are we near the end of the current quota period?
|
||
+ *
|
||
+ * Requires cfs_b->lock for hrtimer_expires_remaining to be safe against the
|
||
+ * hrtimer base being cleared by __hrtimer_start_range_ns. In the case of
|
||
+ * migrate_hrtimers, base is never cleared, so we are fine.
|
||
+ */
|
||
static int runtime_refresh_within(struct cfs_bandwidth *cfs_b, u64 min_expire)
|
||
{
|
||
struct hrtimer *refresh_timer = &cfs_b->period_timer;
|
||
@@ -1911,10 +1928,12 @@ static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b)
|
||
u64 expires;
|
||
|
||
/* confirm we're still not at a refresh boundary */
|
||
- if (runtime_refresh_within(cfs_b, min_bandwidth_expiration))
|
||
+ raw_spin_lock(&cfs_b->lock);
|
||
+ if (runtime_refresh_within(cfs_b, min_bandwidth_expiration)) {
|
||
+ raw_spin_unlock(&cfs_b->lock);
|
||
return;
|
||
+ }
|
||
|
||
- raw_spin_lock(&cfs_b->lock);
|
||
if (cfs_b->quota != RUNTIME_INF && cfs_b->runtime > slice) {
|
||
runtime = cfs_b->runtime;
|
||
cfs_b->runtime = 0;
|
||
@@ -2039,11 +2058,11 @@ void __start_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
|
||
* (timer_active==0 becomes visible before the hrtimer call-back
|
||
* terminates). In either case we ensure that it's re-programmed
|
||
*/
|
||
- while (unlikely(hrtimer_active(&cfs_b->period_timer))) {
|
||
+ while (unlikely(hrtimer_active(&cfs_b->period_timer)) &&
|
||
+ hrtimer_try_to_cancel(&cfs_b->period_timer) < 0) {
|
||
+ /* bounce the lock to allow do_sched_cfs_period_timer to run */
|
||
raw_spin_unlock(&cfs_b->lock);
|
||
- /* ensure cfs_b->lock is available while we wait */
|
||
- hrtimer_cancel(&cfs_b->period_timer);
|
||
-
|
||
+ cpu_relax();
|
||
raw_spin_lock(&cfs_b->lock);
|
||
/* if someone else restarted the timer then we're done */
|
||
if (cfs_b->timer_active)
|
||
@@ -5061,7 +5080,7 @@ static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle)
|
||
|
||
raw_spin_lock_irq(&this_rq->lock);
|
||
update_rq_clock(this_rq);
|
||
- update_cpu_load(this_rq);
|
||
+ update_idle_cpu_load(this_rq);
|
||
raw_spin_unlock_irq(&this_rq->lock);
|
||
|
||
rebalance_domains(balance_cpu, CPU_IDLE);
|
||
@@ -5289,15 +5308,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
|
||
struct cfs_rq *cfs_rq = cfs_rq_of(se);
|
||
|
||
/*
|
||
- * Ensure the task's vruntime is normalized, so that when its
|
||
+ * Ensure the task's vruntime is normalized, so that when it's
|
||
* switched back to the fair class the enqueue_entity(.flags=0) will
|
||
* do the right thing.
|
||
*
|
||
- * If it was on_rq, then the dequeue_entity(.flags=0) will already
|
||
- * have normalized the vruntime, if it was !on_rq, then only when
|
||
+ * If it's on_rq, then the dequeue_entity(.flags=0) will already
|
||
+ * have normalized the vruntime, if it's !on_rq, then only when
|
||
* the task is sleeping will it still have non-normalized vruntime.
|
||
*/
|
||
- if (!se->on_rq && p->state != TASK_RUNNING) {
|
||
+ if (!p->on_rq && p->state != TASK_RUNNING) {
|
||
/*
|
||
* Fix up our vruntime so that the current sleep doesn't
|
||
* cause 'unlimited' sleep bonus.
|
||
@@ -5492,7 +5511,8 @@ void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
|
||
se->cfs_rq = parent->my_q;
|
||
|
||
se->my_q = cfs_rq;
|
||
- update_load_set(&se->load, 0);
|
||
+ /* guarantee group entities always have weight */
|
||
+ update_load_set(&se->load, NICE_0_LOAD);
|
||
se->parent = parent;
|
||
}
|
||
|
||
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
|
||
index 3d4b1e2..526c77d 100644
|
||
--- a/kernel/sched/rt.c
|
||
+++ b/kernel/sched/rt.c
|
||
@@ -783,6 +783,19 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
|
||
const struct cpumask *span;
|
||
|
||
span = sched_rt_period_mask();
|
||
+#ifdef CONFIG_RT_GROUP_SCHED
|
||
+ /*
|
||
+ * FIXME: isolated CPUs should really leave the root task group,
|
||
+ * whether they are isolcpus or were isolated via cpusets, lest
|
||
+ * the timer run on a CPU which does not service all runqueues,
|
||
+ * potentially leaving other CPUs indefinitely throttled. If
|
||
+ * isolation is really required, the user will turn the throttle
|
||
+ * off to kill the perturbations it causes anyway. Meanwhile,
|
||
+ * this maintains functionality for boot and/or troubleshooting.
|
||
+ */
|
||
+ if (rt_b == &root_task_group.rt_bandwidth)
|
||
+ span = cpu_online_mask;
|
||
+#endif
|
||
for_each_cpu(i, span) {
|
||
int enqueue = 0;
|
||
struct rt_rq *rt_rq = sched_rt_period_rt_rq(rt_b, i);
|
||
@@ -871,7 +884,7 @@ static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq)
|
||
|
||
if (!once) {
|
||
once = true;
|
||
- printk_sched("sched: RT throttling activated\n");
|
||
+ printk_deferred("sched: RT throttling activated\n");
|
||
}
|
||
} else {
|
||
/*
|
||
@@ -943,6 +956,13 @@ inc_rt_prio_smp(struct rt_rq *rt_rq, int prio, int prev_prio)
|
||
{
|
||
struct rq *rq = rq_of_rt_rq(rt_rq);
|
||
|
||
+#ifdef CONFIG_RT_GROUP_SCHED
|
||
+ /*
|
||
+ * Change rq's cpupri only if rt_rq is the top queue.
|
||
+ */
|
||
+ if (&rq->rt != rt_rq)
|
||
+ return;
|
||
+#endif
|
||
if (rq->online && prio < prev_prio)
|
||
cpupri_set(&rq->rd->cpupri, rq->cpu, prio);
|
||
}
|
||
@@ -952,6 +972,13 @@ dec_rt_prio_smp(struct rt_rq *rt_rq, int prio, int prev_prio)
|
||
{
|
||
struct rq *rq = rq_of_rt_rq(rt_rq);
|
||
|
||
+#ifdef CONFIG_RT_GROUP_SCHED
|
||
+ /*
|
||
+ * Change rq's cpupri only if rt_rq is the top queue.
|
||
+ */
|
||
+ if (&rq->rt != rt_rq)
|
||
+ return;
|
||
+#endif
|
||
if (rq->online && rt_rq->highest_prio.curr != prev_prio)
|
||
cpupri_set(&rq->rd->cpupri, rq->cpu, rt_rq->highest_prio.curr);
|
||
}
|
||
@@ -1975,7 +2002,11 @@ static void watchdog(struct rq *rq, struct task_struct *p)
|
||
if (soft != RLIM_INFINITY) {
|
||
unsigned long next;
|
||
|
||
- p->rt.timeout++;
|
||
+ if (p->rt.watchdog_stamp != jiffies) {
|
||
+ p->rt.timeout++;
|
||
+ p->rt.watchdog_stamp = jiffies;
|
||
+ }
|
||
+
|
||
next = DIV_ROUND_UP(min(soft, hard), USEC_PER_SEC/HZ);
|
||
if (p->rt.timeout > next)
|
||
p->cputime_expires.sched_exp = p->se.sum_exec_runtime;
|
||
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
|
||
index 9b8ed6b..008194f 100644
|
||
--- a/kernel/sched/sched.h
|
||
+++ b/kernel/sched/sched.h
|
||
@@ -885,7 +885,7 @@ extern void resched_cpu(int cpu);
|
||
extern struct rt_bandwidth def_rt_bandwidth;
|
||
extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime);
|
||
|
||
-extern void update_cpu_load(struct rq *this_rq);
|
||
+extern void update_idle_cpu_load(struct rq *this_rq);
|
||
|
||
#ifdef CONFIG_CGROUP_CPUACCT
|
||
#include <linux/cgroup.h>
|
||
@@ -1153,7 +1153,8 @@ extern void print_rt_stats(struct seq_file *m, int cpu);
|
||
extern void init_cfs_rq(struct cfs_rq *cfs_rq);
|
||
extern void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq);
|
||
|
||
-extern void account_cfs_bandwidth_used(int enabled, int was_enabled);
|
||
+extern void cfs_bandwidth_usage_inc(void);
|
||
+extern void cfs_bandwidth_usage_dec(void);
|
||
|
||
#ifdef CONFIG_NO_HZ
|
||
enum rq_nohz_flag_bits {
|
||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
|
||
index c35fe53..7364c50 100644
|
||
--- a/kernel/sysctl.c
|
||
+++ b/kernel/sysctl.c
|
||
@@ -144,6 +144,11 @@ static int min_percpu_pagelist_fract = 8;
|
||
static int ngroups_max = NGROUPS_MAX;
|
||
static const int cap_last_cap = CAP_LAST_CAP;
|
||
|
||
+/*this is needed for proc_doulongvec_minmax of sysctl_hung_task_timeout_secs */
|
||
+#ifdef CONFIG_DETECT_HUNG_TASK
|
||
+static unsigned long hung_task_timeout_max = (LONG_MAX/HZ);
|
||
+#endif
|
||
+
|
||
#ifdef CONFIG_INOTIFY_USER
|
||
#include <linux/inotify.h>
|
||
#endif
|
||
@@ -906,6 +911,7 @@ static struct ctl_table kern_table[] = {
|
||
.maxlen = sizeof(unsigned long),
|
||
.mode = 0644,
|
||
.proc_handler = proc_dohung_task_timeout_secs,
|
||
+ .extra2 = &hung_task_timeout_max,
|
||
},
|
||
{
|
||
.procname = "hung_task_warnings",
|
||
diff --git a/kernel/time.c b/kernel/time.c
|
||
index ba744cf..a095290 100644
|
||
--- a/kernel/time.c
|
||
+++ b/kernel/time.c
|
||
@@ -487,17 +487,20 @@ EXPORT_SYMBOL(usecs_to_jiffies);
|
||
* that a remainder subtract here would not do the right thing as the
|
||
* resolution values don't fall on second boundries. I.e. the line:
|
||
* nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding.
|
||
+ * Note that due to the small error in the multiplier here, this
|
||
+ * rounding is incorrect for sufficiently large values of tv_nsec, but
|
||
+ * well formed timespecs should have tv_nsec < NSEC_PER_SEC, so we're
|
||
+ * OK.
|
||
*
|
||
* Rather, we just shift the bits off the right.
|
||
*
|
||
* The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec
|
||
* value to a scaled second value.
|
||
*/
|
||
-unsigned long
|
||
-timespec_to_jiffies(const struct timespec *value)
|
||
+static unsigned long
|
||
+__timespec_to_jiffies(unsigned long sec, long nsec)
|
||
{
|
||
- unsigned long sec = value->tv_sec;
|
||
- long nsec = value->tv_nsec + TICK_NSEC - 1;
|
||
+ nsec = nsec + TICK_NSEC - 1;
|
||
|
||
if (sec >= MAX_SEC_IN_JIFFIES){
|
||
sec = MAX_SEC_IN_JIFFIES;
|
||
@@ -508,6 +511,13 @@ timespec_to_jiffies(const struct timespec *value)
|
||
(NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
|
||
|
||
}
|
||
+
|
||
+unsigned long
|
||
+timespec_to_jiffies(const struct timespec *value)
|
||
+{
|
||
+ return __timespec_to_jiffies(value->tv_sec, value->tv_nsec);
|
||
+}
|
||
+
|
||
EXPORT_SYMBOL(timespec_to_jiffies);
|
||
|
||
void
|
||
@@ -524,31 +534,27 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value)
|
||
}
|
||
EXPORT_SYMBOL(jiffies_to_timespec);
|
||
|
||
-/* Same for "timeval"
|
||
+/*
|
||
+ * We could use a similar algorithm to timespec_to_jiffies (with a
|
||
+ * different multiplier for usec instead of nsec). But this has a
|
||
+ * problem with rounding: we can't exactly add TICK_NSEC - 1 to the
|
||
+ * usec value, since it's not necessarily integral.
|
||
*
|
||
- * Well, almost. The problem here is that the real system resolution is
|
||
- * in nanoseconds and the value being converted is in micro seconds.
|
||
- * Also for some machines (those that use HZ = 1024, in-particular),
|
||
- * there is a LARGE error in the tick size in microseconds.
|
||
-
|
||
- * The solution we use is to do the rounding AFTER we convert the
|
||
- * microsecond part. Thus the USEC_ROUND, the bits to be shifted off.
|
||
- * Instruction wise, this should cost only an additional add with carry
|
||
- * instruction above the way it was done above.
|
||
+ * We could instead round in the intermediate scaled representation
|
||
+ * (i.e. in units of 1/2^(large scale) jiffies) but that's also
|
||
+ * perilous: the scaling introduces a small positive error, which
|
||
+ * combined with a division-rounding-upward (i.e. adding 2^(scale) - 1
|
||
+ * units to the intermediate before shifting) leads to accidental
|
||
+ * overflow and overestimates.
|
||
+ *
|
||
+ * At the cost of one additional multiplication by a constant, just
|
||
+ * use the timespec implementation.
|
||
*/
|
||
unsigned long
|
||
timeval_to_jiffies(const struct timeval *value)
|
||
{
|
||
- unsigned long sec = value->tv_sec;
|
||
- long usec = value->tv_usec;
|
||
-
|
||
- if (sec >= MAX_SEC_IN_JIFFIES){
|
||
- sec = MAX_SEC_IN_JIFFIES;
|
||
- usec = 0;
|
||
- }
|
||
- return (((u64)sec * SEC_CONVERSION) +
|
||
- (((u64)usec * USEC_CONVERSION + USEC_ROUND) >>
|
||
- (USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
|
||
+ return __timespec_to_jiffies(value->tv_sec,
|
||
+ value->tv_usec * NSEC_PER_USEC);
|
||
}
|
||
EXPORT_SYMBOL(timeval_to_jiffies);
|
||
|
||
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
|
||
index 1454aa2..f0239cc 100644
|
||
--- a/kernel/time/alarmtimer.c
|
||
+++ b/kernel/time/alarmtimer.c
|
||
@@ -731,6 +731,9 @@ static int alarm_timer_create(struct k_itimer *new_timer)
|
||
if (!alarmtimer_get_rtcdev())
|
||
return -ENOTSUPP;
|
||
|
||
+ if (flags & ~TIMER_ABSTIME)
|
||
+ return -EINVAL;
|
||
+
|
||
if (!capable(CAP_WAKE_ALARM))
|
||
return -EPERM;
|
||
|
||
@@ -745,18 +748,22 @@ static int alarm_timer_create(struct k_itimer *new_timer)
|
||
* @new_timer: k_itimer pointer
|
||
* @cur_setting: itimerspec data to fill
|
||
*
|
||
- * Copies the itimerspec data out from the k_itimer
|
||
+ * Copies out the current itimerspec data
|
||
*/
|
||
static void alarm_timer_get(struct k_itimer *timr,
|
||
struct itimerspec *cur_setting)
|
||
{
|
||
- memset(cur_setting, 0, sizeof(struct itimerspec));
|
||
+ ktime_t relative_expiry_time =
|
||
+ alarm_expires_remaining(&(timr->it.alarm.alarmtimer));
|
||
|
||
- cur_setting->it_interval =
|
||
- ktime_to_timespec(timr->it.alarm.interval);
|
||
- cur_setting->it_value =
|
||
- ktime_to_timespec(timr->it.alarm.alarmtimer.node.expires);
|
||
- return;
|
||
+ if (ktime_to_ns(relative_expiry_time) > 0) {
|
||
+ cur_setting->it_value = ktime_to_timespec(relative_expiry_time);
|
||
+ } else {
|
||
+ cur_setting->it_value.tv_sec = 0;
|
||
+ cur_setting->it_value.tv_nsec = 0;
|
||
+ }
|
||
+
|
||
+ cur_setting->it_interval = ktime_to_timespec(timr->it.alarm.interval);
|
||
}
|
||
|
||
/**
|
||
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
|
||
index 9cd928f..4d7ee79 100644
|
||
--- a/kernel/time/clockevents.c
|
||
+++ b/kernel/time/clockevents.c
|
||
@@ -30,29 +30,64 @@ static RAW_NOTIFIER_HEAD(clockevents_chain);
|
||
/* Protection for the above */
|
||
static DEFINE_RAW_SPINLOCK(clockevents_lock);
|
||
|
||
-/**
|
||
- * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
|
||
- * @latch: value to convert
|
||
- * @evt: pointer to clock event device descriptor
|
||
- *
|
||
- * Math helper, returns latch value converted to nanoseconds (bound checked)
|
||
- */
|
||
-u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
|
||
+static u64 cev_delta2ns(unsigned long latch, struct clock_event_device *evt,
|
||
+ bool ismax)
|
||
{
|
||
u64 clc = (u64) latch << evt->shift;
|
||
+ u64 rnd;
|
||
|
||
if (unlikely(!evt->mult)) {
|
||
evt->mult = 1;
|
||
WARN_ON(1);
|
||
}
|
||
+ rnd = (u64) evt->mult - 1;
|
||
+
|
||
+ /*
|
||
+ * Upper bound sanity check. If the backwards conversion is
|
||
+ * not equal latch, we know that the above shift overflowed.
|
||
+ */
|
||
+ if ((clc >> evt->shift) != (u64)latch)
|
||
+ clc = ~0ULL;
|
||
+
|
||
+ /*
|
||
+ * Scaled math oddities:
|
||
+ *
|
||
+ * For mult <= (1 << shift) we can safely add mult - 1 to
|
||
+ * prevent integer rounding loss. So the backwards conversion
|
||
+ * from nsec to device ticks will be correct.
|
||
+ *
|
||
+ * For mult > (1 << shift), i.e. device frequency is > 1GHz we
|
||
+ * need to be careful. Adding mult - 1 will result in a value
|
||
+ * which when converted back to device ticks can be larger
|
||
+ * than latch by up to (mult - 1) >> shift. For the min_delta
|
||
+ * calculation we still want to apply this in order to stay
|
||
+ * above the minimum device ticks limit. For the upper limit
|
||
+ * we would end up with a latch value larger than the upper
|
||
+ * limit of the device, so we omit the add to stay below the
|
||
+ * device upper boundary.
|
||
+ *
|
||
+ * Also omit the add if it would overflow the u64 boundary.
|
||
+ */
|
||
+ if ((~0ULL - clc > rnd) &&
|
||
+ (!ismax || evt->mult <= (1U << evt->shift)))
|
||
+ clc += rnd;
|
||
|
||
do_div(clc, evt->mult);
|
||
- if (clc < 1000)
|
||
- clc = 1000;
|
||
- if (clc > KTIME_MAX)
|
||
- clc = KTIME_MAX;
|
||
|
||
- return clc;
|
||
+ /* Deltas less than 1usec are pointless noise */
|
||
+ return clc > 1000 ? clc : 1000;
|
||
+}
|
||
+
|
||
+/**
|
||
+ * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
|
||
+ * @latch: value to convert
|
||
+ * @evt: pointer to clock event device descriptor
|
||
+ *
|
||
+ * Math helper, returns latch value converted to nanoseconds (bound checked)
|
||
+ */
|
||
+u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
|
||
+{
|
||
+ return cev_delta2ns(latch, evt, false);
|
||
}
|
||
EXPORT_SYMBOL_GPL(clockevent_delta2ns);
|
||
|
||
@@ -108,7 +143,8 @@ static int clockevents_increase_min_delta(struct clock_event_device *dev)
|
||
{
|
||
/* Nothing to do if we already reached the limit */
|
||
if (dev->min_delta_ns >= MIN_DELTA_LIMIT) {
|
||
- printk(KERN_WARNING "CE: Reprogramming failure. Giving up\n");
|
||
+ printk_deferred(KERN_WARNING
|
||
+ "CE: Reprogramming failure. Giving up\n");
|
||
dev->next_event.tv64 = KTIME_MAX;
|
||
return -ETIME;
|
||
}
|
||
@@ -121,9 +157,10 @@ static int clockevents_increase_min_delta(struct clock_event_device *dev)
|
||
if (dev->min_delta_ns > MIN_DELTA_LIMIT)
|
||
dev->min_delta_ns = MIN_DELTA_LIMIT;
|
||
|
||
- printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n",
|
||
- dev->name ? dev->name : "?",
|
||
- (unsigned long long) dev->min_delta_ns);
|
||
+ printk_deferred(KERN_WARNING
|
||
+ "CE: %s increased min_delta_ns to %llu nsec\n",
|
||
+ dev->name ? dev->name : "?",
|
||
+ (unsigned long long) dev->min_delta_ns);
|
||
return 0;
|
||
}
|
||
|
||
@@ -318,8 +355,8 @@ static void clockevents_config(struct clock_event_device *dev,
|
||
sec = 600;
|
||
|
||
clockevents_calc_mult_shift(dev, freq, sec);
|
||
- dev->min_delta_ns = clockevent_delta2ns(dev->min_delta_ticks, dev);
|
||
- dev->max_delta_ns = clockevent_delta2ns(dev->max_delta_ticks, dev);
|
||
+ dev->min_delta_ns = cev_delta2ns(dev->min_delta_ticks, dev, false);
|
||
+ dev->max_delta_ns = cev_delta2ns(dev->max_delta_ticks, dev, true);
|
||
}
|
||
|
||
/**
|
||
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
|
||
index a470154..955560e 100644
|
||
--- a/kernel/time/jiffies.c
|
||
+++ b/kernel/time/jiffies.c
|
||
@@ -51,7 +51,13 @@
|
||
* HZ shrinks, so values greater than 8 overflow 32bits when
|
||
* HZ=100.
|
||
*/
|
||
+#if HZ < 34
|
||
+#define JIFFIES_SHIFT 6
|
||
+#elif HZ < 67
|
||
+#define JIFFIES_SHIFT 7
|
||
+#else
|
||
#define JIFFIES_SHIFT 8
|
||
+#endif
|
||
|
||
static cycle_t jiffies_read(struct clocksource *cs)
|
||
{
|
||
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
|
||
index f35d21e..e5933dc 100644
|
||
--- a/kernel/time/tick-sched.c
|
||
+++ b/kernel/time/tick-sched.c
|
||
@@ -593,6 +593,7 @@ void tick_nohz_idle_exit(void)
|
||
/* Update jiffies first */
|
||
select_nohz_load_balancer(0);
|
||
tick_do_update_jiffies64(now);
|
||
+ update_cpu_load_nohz();
|
||
|
||
#ifndef CONFIG_VIRT_CPU_ACCOUNTING
|
||
/*
|
||
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
|
||
index 55ec875..3ddad53 100644
|
||
--- a/kernel/time/timekeeping.c
|
||
+++ b/kernel/time/timekeeping.c
|
||
@@ -1033,7 +1033,8 @@ static void timekeeping_adjust(s64 offset)
|
||
*
|
||
* Returns the unconsumed cycles.
|
||
*/
|
||
-static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
|
||
+static cycle_t logarithmic_accumulation(cycle_t offset, int shift,
|
||
+ unsigned int *clock_set)
|
||
{
|
||
u64 nsecps = (u64)NSEC_PER_SEC << timekeeper.shift;
|
||
u64 raw_nsecs;
|
||
@@ -1055,7 +1056,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
|
||
timekeeper.xtime.tv_sec += leap;
|
||
timekeeper.wall_to_monotonic.tv_sec -= leap;
|
||
if (leap)
|
||
- clock_was_set_delayed();
|
||
+ *clock_set = 1;
|
||
}
|
||
|
||
/* Accumulate raw time */
|
||
@@ -1087,6 +1088,7 @@ static void update_wall_time(void)
|
||
struct clocksource *clock;
|
||
cycle_t offset;
|
||
int shift = 0, maxshift;
|
||
+ unsigned int clock_set = 0;
|
||
unsigned long flags;
|
||
|
||
write_seqlock_irqsave(&timekeeper.lock, flags);
|
||
@@ -1122,7 +1124,7 @@ static void update_wall_time(void)
|
||
maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1;
|
||
shift = min(shift, maxshift);
|
||
while (offset >= timekeeper.cycle_interval) {
|
||
- offset = logarithmic_accumulation(offset, shift);
|
||
+ offset = logarithmic_accumulation(offset, shift, &clock_set);
|
||
if(offset < timekeeper.cycle_interval<<shift)
|
||
shift--;
|
||
}
|
||
@@ -1176,7 +1178,7 @@ static void update_wall_time(void)
|
||
timekeeper.xtime.tv_sec += leap;
|
||
timekeeper.wall_to_monotonic.tv_sec -= leap;
|
||
if (leap)
|
||
- clock_was_set_delayed();
|
||
+ clock_set = 1;
|
||
}
|
||
|
||
timekeeping_update(false);
|
||
@@ -1184,6 +1186,8 @@ static void update_wall_time(void)
|
||
out:
|
||
write_sequnlock_irqrestore(&timekeeper.lock, flags);
|
||
|
||
+ if (clock_set)
|
||
+ clock_was_set_delayed();
|
||
}
|
||
|
||
/**
|
||
diff --git a/kernel/timer.c b/kernel/timer.c
|
||
index 7c38b51..5a2b451 100644
|
||
--- a/kernel/timer.c
|
||
+++ b/kernel/timer.c
|
||
@@ -844,7 +844,7 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
|
||
|
||
bit = find_last_bit(&mask, BITS_PER_LONG);
|
||
|
||
- mask = (1 << bit) - 1;
|
||
+ mask = (1UL << bit) - 1;
|
||
|
||
expires_limit = expires_limit & ~(mask);
|
||
|
||
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
|
||
index 06f7940..097ed06 100644
|
||
--- a/kernel/trace/blktrace.c
|
||
+++ b/kernel/trace/blktrace.c
|
||
@@ -685,6 +685,7 @@ void blk_trace_shutdown(struct request_queue *q)
|
||
* blk_add_trace_rq - Add a trace for a request oriented action
|
||
* @q: queue the io is for
|
||
* @rq: the source request
|
||
+ * @nr_bytes: number of completed bytes
|
||
* @what: the action
|
||
*
|
||
* Description:
|
||
@@ -692,7 +693,7 @@ void blk_trace_shutdown(struct request_queue *q)
|
||
*
|
||
**/
|
||
static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
|
||
- u32 what)
|
||
+ unsigned int nr_bytes, u32 what)
|
||
{
|
||
struct blk_trace *bt = q->blk_trace;
|
||
|
||
@@ -701,11 +702,11 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
|
||
|
||
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
|
||
what |= BLK_TC_ACT(BLK_TC_PC);
|
||
- __blk_add_trace(bt, 0, blk_rq_bytes(rq), rq->cmd_flags,
|
||
+ __blk_add_trace(bt, 0, nr_bytes, rq->cmd_flags,
|
||
what, rq->errors, rq->cmd_len, rq->cmd);
|
||
} else {
|
||
what |= BLK_TC_ACT(BLK_TC_FS);
|
||
- __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq),
|
||
+ __blk_add_trace(bt, blk_rq_pos(rq), nr_bytes,
|
||
rq->cmd_flags, what, rq->errors, 0, NULL);
|
||
}
|
||
}
|
||
@@ -713,33 +714,34 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
|
||
static void blk_add_trace_rq_abort(void *ignore,
|
||
struct request_queue *q, struct request *rq)
|
||
{
|
||
- blk_add_trace_rq(q, rq, BLK_TA_ABORT);
|
||
+ blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_ABORT);
|
||
}
|
||
|
||
static void blk_add_trace_rq_insert(void *ignore,
|
||
struct request_queue *q, struct request *rq)
|
||
{
|
||
- blk_add_trace_rq(q, rq, BLK_TA_INSERT);
|
||
+ blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_INSERT);
|
||
}
|
||
|
||
static void blk_add_trace_rq_issue(void *ignore,
|
||
struct request_queue *q, struct request *rq)
|
||
{
|
||
- blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
|
||
+ blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_ISSUE);
|
||
}
|
||
|
||
static void blk_add_trace_rq_requeue(void *ignore,
|
||
struct request_queue *q,
|
||
struct request *rq)
|
||
{
|
||
- blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
|
||
+ blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_REQUEUE);
|
||
}
|
||
|
||
static void blk_add_trace_rq_complete(void *ignore,
|
||
struct request_queue *q,
|
||
- struct request *rq)
|
||
+ struct request *rq,
|
||
+ unsigned int nr_bytes)
|
||
{
|
||
- blk_add_trace_rq(q, rq, BLK_TA_COMPLETE);
|
||
+ blk_add_trace_rq(q, rq, nr_bytes, BLK_TA_COMPLETE);
|
||
}
|
||
|
||
/**
|
||
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
|
||
index e101cf9..b113a42 100644
|
||
--- a/kernel/trace/ftrace.c
|
||
+++ b/kernel/trace/ftrace.c
|
||
@@ -222,6 +222,23 @@ static void update_global_ops(void)
|
||
global_ops.func = func;
|
||
}
|
||
|
||
+static void ftrace_sync(struct work_struct *work)
|
||
+{
|
||
+ /*
|
||
+ * This function is just a stub to implement a hard force
|
||
+ * of synchronize_sched(). This requires synchronizing
|
||
+ * tasks even in userspace and idle.
|
||
+ *
|
||
+ * Yes, function tracing is rude.
|
||
+ */
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||
+static void update_function_graph_func(void);
|
||
+#else
|
||
+static inline void update_function_graph_func(void) { }
|
||
+#endif
|
||
+
|
||
static void update_ftrace_function(void)
|
||
{
|
||
ftrace_func_t func;
|
||
@@ -240,6 +257,8 @@ static void update_ftrace_function(void)
|
||
else
|
||
func = ftrace_ops_list_func;
|
||
|
||
+ update_function_graph_func();
|
||
+
|
||
#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
|
||
ftrace_trace_function = func;
|
||
#else
|
||
@@ -312,9 +331,6 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list,
|
||
|
||
static int __register_ftrace_function(struct ftrace_ops *ops)
|
||
{
|
||
- if (ftrace_disabled)
|
||
- return -ENODEV;
|
||
-
|
||
if (FTRACE_WARN_ON(ops == &global_ops))
|
||
return -EINVAL;
|
||
|
||
@@ -348,9 +364,6 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
|
||
{
|
||
int ret;
|
||
|
||
- if (ftrace_disabled)
|
||
- return -ENODEV;
|
||
-
|
||
if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED)))
|
||
return -EBUSY;
|
||
|
||
@@ -365,16 +378,6 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
|
||
} else if (ops->flags & FTRACE_OPS_FL_CONTROL) {
|
||
ret = remove_ftrace_list_ops(&ftrace_control_list,
|
||
&control_ops, ops);
|
||
- if (!ret) {
|
||
- /*
|
||
- * The ftrace_ops is now removed from the list,
|
||
- * so there'll be no new users. We must ensure
|
||
- * all current users are done before we free
|
||
- * the control data.
|
||
- */
|
||
- synchronize_sched();
|
||
- control_ops_free(ops);
|
||
- }
|
||
} else
|
||
ret = remove_ftrace_ops(&ftrace_ops_list, ops);
|
||
|
||
@@ -384,13 +387,6 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
|
||
if (ftrace_enabled)
|
||
update_ftrace_function();
|
||
|
||
- /*
|
||
- * Dynamic ops may be freed, we must make sure that all
|
||
- * callers are done before leaving this function.
|
||
- */
|
||
- if (ops->flags & FTRACE_OPS_FL_DYNAMIC)
|
||
- synchronize_sched();
|
||
-
|
||
return 0;
|
||
}
|
||
|
||
@@ -694,7 +690,7 @@ static int ftrace_profile_init(void)
|
||
int cpu;
|
||
int ret = 0;
|
||
|
||
- for_each_online_cpu(cpu) {
|
||
+ for_each_possible_cpu(cpu) {
|
||
ret = ftrace_profile_init_cpu(cpu);
|
||
if (ret)
|
||
break;
|
||
@@ -1940,10 +1936,15 @@ static void ftrace_startup_enable(int command)
|
||
static int ftrace_startup(struct ftrace_ops *ops, int command)
|
||
{
|
||
bool hash_enable = true;
|
||
+ int ret;
|
||
|
||
if (unlikely(ftrace_disabled))
|
||
return -ENODEV;
|
||
|
||
+ ret = __register_ftrace_function(ops);
|
||
+ if (ret)
|
||
+ return ret;
|
||
+
|
||
ftrace_start_up++;
|
||
command |= FTRACE_UPDATE_CALLS;
|
||
|
||
@@ -1965,12 +1966,17 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)
|
||
return 0;
|
||
}
|
||
|
||
-static void ftrace_shutdown(struct ftrace_ops *ops, int command)
|
||
+static int ftrace_shutdown(struct ftrace_ops *ops, int command)
|
||
{
|
||
bool hash_disable = true;
|
||
+ int ret;
|
||
|
||
if (unlikely(ftrace_disabled))
|
||
- return;
|
||
+ return -ENODEV;
|
||
+
|
||
+ ret = __unregister_ftrace_function(ops);
|
||
+ if (ret)
|
||
+ return ret;
|
||
|
||
ftrace_start_up--;
|
||
/*
|
||
@@ -2004,10 +2010,42 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command)
|
||
command |= FTRACE_UPDATE_TRACE_FUNC;
|
||
}
|
||
|
||
- if (!command || !ftrace_enabled)
|
||
- return;
|
||
+ if (!command || !ftrace_enabled) {
|
||
+ /*
|
||
+ * If these are control ops, they still need their
|
||
+ * per_cpu field freed. Since, function tracing is
|
||
+ * not currently active, we can just free them
|
||
+ * without synchronizing all CPUs.
|
||
+ */
|
||
+ if (ops->flags & FTRACE_OPS_FL_CONTROL)
|
||
+ control_ops_free(ops);
|
||
+ return 0;
|
||
+ }
|
||
|
||
ftrace_run_update_code(command);
|
||
+
|
||
+ /*
|
||
+ * Dynamic ops may be freed, we must make sure that all
|
||
+ * callers are done before leaving this function.
|
||
+ * The same goes for freeing the per_cpu data of the control
|
||
+ * ops.
|
||
+ *
|
||
+ * Again, normal synchronize_sched() is not good enough.
|
||
+ * We need to do a hard force of sched synchronization.
|
||
+ * This is because we use preempt_disable() to do RCU, but
|
||
+ * the function tracers can be called where RCU is not watching
|
||
+ * (like before user_exit()). We can not rely on the RCU
|
||
+ * infrastructure to do the synchronization, thus we must do it
|
||
+ * ourselves.
|
||
+ */
|
||
+ if (ops->flags & (FTRACE_OPS_FL_DYNAMIC | FTRACE_OPS_FL_CONTROL)) {
|
||
+ schedule_on_each_cpu(ftrace_sync);
|
||
+
|
||
+ if (ops->flags & FTRACE_OPS_FL_CONTROL)
|
||
+ control_ops_free(ops);
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
}
|
||
|
||
static void ftrace_startup_sysctl(void)
|
||
@@ -2036,12 +2074,57 @@ static cycle_t ftrace_update_time;
|
||
static unsigned long ftrace_update_cnt;
|
||
unsigned long ftrace_update_tot_cnt;
|
||
|
||
-static int ops_traces_mod(struct ftrace_ops *ops)
|
||
+static inline int ops_traces_mod(struct ftrace_ops *ops)
|
||
{
|
||
- struct ftrace_hash *hash;
|
||
+ /*
|
||
+ * Filter_hash being empty will default to trace module.
|
||
+ * But notrace hash requires a test of individual module functions.
|
||
+ */
|
||
+ return ftrace_hash_empty(ops->filter_hash) &&
|
||
+ ftrace_hash_empty(ops->notrace_hash);
|
||
+}
|
||
|
||
- hash = ops->filter_hash;
|
||
- return ftrace_hash_empty(hash);
|
||
+/*
|
||
+ * Check if the current ops references the record.
|
||
+ *
|
||
+ * If the ops traces all functions, then it was already accounted for.
|
||
+ * If the ops does not trace the current record function, skip it.
|
||
+ * If the ops ignores the function via notrace filter, skip it.
|
||
+ */
|
||
+static inline bool
|
||
+ops_references_rec(struct ftrace_ops *ops, struct dyn_ftrace *rec)
|
||
+{
|
||
+ /* If ops isn't enabled, ignore it */
|
||
+ if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
|
||
+ return 0;
|
||
+
|
||
+ /* If ops traces all mods, we already accounted for it */
|
||
+ if (ops_traces_mod(ops))
|
||
+ return 0;
|
||
+
|
||
+ /* The function must be in the filter */
|
||
+ if (!ftrace_hash_empty(ops->filter_hash) &&
|
||
+ !ftrace_lookup_ip(ops->filter_hash, rec->ip))
|
||
+ return 0;
|
||
+
|
||
+ /* If in notrace hash, we ignore it too */
|
||
+ if (ftrace_lookup_ip(ops->notrace_hash, rec->ip))
|
||
+ return 0;
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static int referenced_filters(struct dyn_ftrace *rec)
|
||
+{
|
||
+ struct ftrace_ops *ops;
|
||
+ int cnt = 0;
|
||
+
|
||
+ for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) {
|
||
+ if (ops_references_rec(ops, rec))
|
||
+ cnt++;
|
||
+ }
|
||
+
|
||
+ return cnt;
|
||
}
|
||
|
||
static int ftrace_update_code(struct module *mod)
|
||
@@ -2050,6 +2133,7 @@ static int ftrace_update_code(struct module *mod)
|
||
struct dyn_ftrace *p;
|
||
cycle_t start, stop;
|
||
unsigned long ref = 0;
|
||
+ bool test = false;
|
||
int i;
|
||
|
||
/*
|
||
@@ -2063,9 +2147,12 @@ static int ftrace_update_code(struct module *mod)
|
||
|
||
for (ops = ftrace_ops_list;
|
||
ops != &ftrace_list_end; ops = ops->next) {
|
||
- if (ops->flags & FTRACE_OPS_FL_ENABLED &&
|
||
- ops_traces_mod(ops))
|
||
- ref++;
|
||
+ if (ops->flags & FTRACE_OPS_FL_ENABLED) {
|
||
+ if (ops_traces_mod(ops))
|
||
+ ref++;
|
||
+ else
|
||
+ test = true;
|
||
+ }
|
||
}
|
||
}
|
||
|
||
@@ -2075,12 +2162,16 @@ static int ftrace_update_code(struct module *mod)
|
||
for (pg = ftrace_new_pgs; pg; pg = pg->next) {
|
||
|
||
for (i = 0; i < pg->index; i++) {
|
||
+ int cnt = ref;
|
||
+
|
||
/* If something went wrong, bail without enabling anything */
|
||
if (unlikely(ftrace_disabled))
|
||
return -1;
|
||
|
||
p = &pg->records[i];
|
||
- p->flags = ref;
|
||
+ if (test)
|
||
+ cnt += referenced_filters(p);
|
||
+ p->flags = cnt;
|
||
|
||
/*
|
||
* Do the initial record conversion from mcount jump
|
||
@@ -2100,7 +2191,7 @@ static int ftrace_update_code(struct module *mod)
|
||
* conversion puts the module to the correct state, thus
|
||
* passing the ftrace_make_call check.
|
||
*/
|
||
- if (ftrace_start_up && ref) {
|
||
+ if (ftrace_start_up && cnt) {
|
||
int failed = __ftrace_replace_code(p, 1);
|
||
if (failed)
|
||
ftrace_bug(failed, p->ip);
|
||
@@ -2873,16 +2964,13 @@ static void __enable_ftrace_function_probe(void)
|
||
if (i == FTRACE_FUNC_HASHSIZE)
|
||
return;
|
||
|
||
- ret = __register_ftrace_function(&trace_probe_ops);
|
||
- if (!ret)
|
||
- ret = ftrace_startup(&trace_probe_ops, 0);
|
||
+ ret = ftrace_startup(&trace_probe_ops, 0);
|
||
|
||
ftrace_probe_registered = 1;
|
||
}
|
||
|
||
static void __disable_ftrace_function_probe(void)
|
||
{
|
||
- int ret;
|
||
int i;
|
||
|
||
if (!ftrace_probe_registered)
|
||
@@ -2895,9 +2983,7 @@ static void __disable_ftrace_function_probe(void)
|
||
}
|
||
|
||
/* no more funcs left */
|
||
- ret = __unregister_ftrace_function(&trace_probe_ops);
|
||
- if (!ret)
|
||
- ftrace_shutdown(&trace_probe_ops, 0);
|
||
+ ftrace_shutdown(&trace_probe_ops, 0);
|
||
|
||
ftrace_probe_registered = 0;
|
||
}
|
||
@@ -3841,16 +3927,11 @@ static void ftrace_init_module(struct module *mod,
|
||
ftrace_process_locs(mod, start, end);
|
||
}
|
||
|
||
-static int ftrace_module_notify_enter(struct notifier_block *self,
|
||
- unsigned long val, void *data)
|
||
+void ftrace_module_init(struct module *mod)
|
||
{
|
||
- struct module *mod = data;
|
||
-
|
||
- if (val == MODULE_STATE_COMING)
|
||
- ftrace_init_module(mod, mod->ftrace_callsites,
|
||
- mod->ftrace_callsites +
|
||
- mod->num_ftrace_callsites);
|
||
- return 0;
|
||
+ ftrace_init_module(mod, mod->ftrace_callsites,
|
||
+ mod->ftrace_callsites +
|
||
+ mod->num_ftrace_callsites);
|
||
}
|
||
|
||
static int ftrace_module_notify_exit(struct notifier_block *self,
|
||
@@ -3864,11 +3945,6 @@ static int ftrace_module_notify_exit(struct notifier_block *self,
|
||
return 0;
|
||
}
|
||
#else
|
||
-static int ftrace_module_notify_enter(struct notifier_block *self,
|
||
- unsigned long val, void *data)
|
||
-{
|
||
- return 0;
|
||
-}
|
||
static int ftrace_module_notify_exit(struct notifier_block *self,
|
||
unsigned long val, void *data)
|
||
{
|
||
@@ -3876,11 +3952,6 @@ static int ftrace_module_notify_exit(struct notifier_block *self,
|
||
}
|
||
#endif /* CONFIG_MODULES */
|
||
|
||
-struct notifier_block ftrace_module_enter_nb = {
|
||
- .notifier_call = ftrace_module_notify_enter,
|
||
- .priority = INT_MAX, /* Run before anything that can use kprobes */
|
||
-};
|
||
-
|
||
struct notifier_block ftrace_module_exit_nb = {
|
||
.notifier_call = ftrace_module_notify_exit,
|
||
.priority = INT_MIN, /* Run after anything that can remove kprobes */
|
||
@@ -3917,10 +3988,6 @@ void __init ftrace_init(void)
|
||
__start_mcount_loc,
|
||
__stop_mcount_loc);
|
||
|
||
- ret = register_module_notifier(&ftrace_module_enter_nb);
|
||
- if (ret)
|
||
- pr_warning("Failed to register trace ftrace module enter notifier\n");
|
||
-
|
||
ret = register_module_notifier(&ftrace_module_exit_nb);
|
||
if (ret)
|
||
pr_warning("Failed to register trace ftrace module exit notifier\n");
|
||
@@ -3948,12 +4015,15 @@ device_initcall(ftrace_nodyn_init);
|
||
static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; }
|
||
static inline void ftrace_startup_enable(int command) { }
|
||
/* Keep as macros so we do not need to define the commands */
|
||
-# define ftrace_startup(ops, command) \
|
||
- ({ \
|
||
- (ops)->flags |= FTRACE_OPS_FL_ENABLED; \
|
||
- 0; \
|
||
+# define ftrace_startup(ops, command) \
|
||
+ ({ \
|
||
+ int ___ret = __register_ftrace_function(ops); \
|
||
+ if (!___ret) \
|
||
+ (ops)->flags |= FTRACE_OPS_FL_ENABLED; \
|
||
+ ___ret; \
|
||
})
|
||
-# define ftrace_shutdown(ops, command) do { } while (0)
|
||
+# define ftrace_shutdown(ops, command) __unregister_ftrace_function(ops)
|
||
+
|
||
# define ftrace_startup_sysctl() do { } while (0)
|
||
# define ftrace_shutdown_sysctl() do { } while (0)
|
||
|
||
@@ -4323,15 +4393,8 @@ int register_ftrace_function(struct ftrace_ops *ops)
|
||
|
||
mutex_lock(&ftrace_lock);
|
||
|
||
- if (unlikely(ftrace_disabled))
|
||
- goto out_unlock;
|
||
-
|
||
- ret = __register_ftrace_function(ops);
|
||
- if (!ret)
|
||
- ret = ftrace_startup(ops, 0);
|
||
+ ret = ftrace_startup(ops, 0);
|
||
|
||
-
|
||
- out_unlock:
|
||
mutex_unlock(&ftrace_lock);
|
||
return ret;
|
||
}
|
||
@@ -4348,9 +4411,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops)
|
||
int ret;
|
||
|
||
mutex_lock(&ftrace_lock);
|
||
- ret = __unregister_ftrace_function(ops);
|
||
- if (!ret)
|
||
- ftrace_shutdown(ops, 0);
|
||
+ ret = ftrace_shutdown(ops, 0);
|
||
mutex_unlock(&ftrace_lock);
|
||
|
||
return ret;
|
||
@@ -4410,6 +4471,7 @@ int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
|
||
trace_func_graph_ret_t ftrace_graph_return =
|
||
(trace_func_graph_ret_t)ftrace_stub;
|
||
trace_func_graph_ent_t ftrace_graph_entry = ftrace_graph_entry_stub;
|
||
+static trace_func_graph_ent_t __ftrace_graph_entry = ftrace_graph_entry_stub;
|
||
|
||
/* Try to assign a return stack array on FTRACE_RETSTACK_ALLOC_SIZE tasks. */
|
||
static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list)
|
||
@@ -4544,6 +4606,36 @@ ftrace_suspend_notifier_call(struct notifier_block *bl, unsigned long state,
|
||
return NOTIFY_DONE;
|
||
}
|
||
|
||
+/* Just a place holder for function graph */
|
||
+static struct ftrace_ops fgraph_ops __read_mostly = {
|
||
+ .func = ftrace_stub,
|
||
+ .flags = FTRACE_OPS_FL_GLOBAL,
|
||
+};
|
||
+
|
||
+static int ftrace_graph_entry_test(struct ftrace_graph_ent *trace)
|
||
+{
|
||
+ if (!ftrace_ops_test(&global_ops, trace->func))
|
||
+ return 0;
|
||
+ return __ftrace_graph_entry(trace);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * The function graph tracer should only trace the functions defined
|
||
+ * by set_ftrace_filter and set_ftrace_notrace. If another function
|
||
+ * tracer ops is registered, the graph tracer requires testing the
|
||
+ * function against the global ops, and not just trace any function
|
||
+ * that any ftrace_ops registered.
|
||
+ */
|
||
+static void update_function_graph_func(void)
|
||
+{
|
||
+ if (ftrace_ops_list == &ftrace_list_end ||
|
||
+ (ftrace_ops_list == &global_ops &&
|
||
+ global_ops.next == &ftrace_list_end))
|
||
+ ftrace_graph_entry = __ftrace_graph_entry;
|
||
+ else
|
||
+ ftrace_graph_entry = ftrace_graph_entry_test;
|
||
+}
|
||
+
|
||
int register_ftrace_graph(trace_func_graph_ret_t retfunc,
|
||
trace_func_graph_ent_t entryfunc)
|
||
{
|
||
@@ -4568,9 +4660,18 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
|
||
}
|
||
|
||
ftrace_graph_return = retfunc;
|
||
- ftrace_graph_entry = entryfunc;
|
||
|
||
- ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET);
|
||
+ /*
|
||
+ * Update the indirect function to the entryfunc, and the
|
||
+ * function that gets called to the entry_test first. Then
|
||
+ * call the update fgraph entry function to determine if
|
||
+ * the entryfunc should be called directly or not.
|
||
+ */
|
||
+ __ftrace_graph_entry = entryfunc;
|
||
+ ftrace_graph_entry = ftrace_graph_entry_test;
|
||
+ update_function_graph_func();
|
||
+
|
||
+ ret = ftrace_startup(&fgraph_ops, FTRACE_START_FUNC_RET);
|
||
|
||
out:
|
||
mutex_unlock(&ftrace_lock);
|
||
@@ -4587,7 +4688,8 @@ void unregister_ftrace_graph(void)
|
||
ftrace_graph_active--;
|
||
ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
|
||
ftrace_graph_entry = ftrace_graph_entry_stub;
|
||
- ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET);
|
||
+ __ftrace_graph_entry = ftrace_graph_entry_stub;
|
||
+ ftrace_shutdown(&fgraph_ops, FTRACE_STOP_FUNC_RET);
|
||
unregister_pm_notifier(&ftrace_suspend_notifier);
|
||
unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
|
||
|
||
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
|
||
index 2866783..bd0f1c4 100644
|
||
--- a/kernel/trace/ring_buffer.c
|
||
+++ b/kernel/trace/ring_buffer.c
|
||
@@ -2008,6 +2008,13 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
|
||
write &= RB_WRITE_MASK;
|
||
tail = write - length;
|
||
|
||
+ /*
|
||
+ * If this is the first commit on the page, then it has the same
|
||
+ * timestamp as the page itself.
|
||
+ */
|
||
+ if (!tail)
|
||
+ delta = 0;
|
||
+
|
||
/* See if we shot pass the end of this buffer page */
|
||
if (unlikely(write > BUF_PAGE_SIZE))
|
||
return rb_move_tail(cpu_buffer, length, tail,
|
||
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
|
||
index b713674..8ab1bf8 100644
|
||
--- a/kernel/trace/trace.c
|
||
+++ b/kernel/trace/trace.c
|
||
@@ -592,9 +592,12 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
|
||
if (isspace(ch)) {
|
||
parser->buffer[parser->idx] = 0;
|
||
parser->cont = false;
|
||
- } else {
|
||
+ } else if (parser->idx < parser->size - 1) {
|
||
parser->cont = true;
|
||
parser->buffer[parser->idx++] = ch;
|
||
+ } else {
|
||
+ ret = -EINVAL;
|
||
+ goto out;
|
||
}
|
||
|
||
*ppos += read;
|
||
@@ -1052,7 +1055,6 @@ void tracing_start(void)
|
||
|
||
arch_spin_unlock(&ftrace_max_lock);
|
||
|
||
- ftrace_start();
|
||
out:
|
||
raw_spin_unlock_irqrestore(&tracing_start_lock, flags);
|
||
}
|
||
@@ -1068,7 +1070,6 @@ void tracing_stop(void)
|
||
struct ring_buffer *buffer;
|
||
unsigned long flags;
|
||
|
||
- ftrace_stop();
|
||
raw_spin_lock_irqsave(&tracing_start_lock, flags);
|
||
if (trace_stop_count++)
|
||
goto out;
|
||
@@ -2828,8 +2829,12 @@ int set_tracer_flag(unsigned int mask, int enabled)
|
||
if (mask == TRACE_ITER_RECORD_CMD)
|
||
trace_event_enable_cmd_record(enabled);
|
||
|
||
- if (mask == TRACE_ITER_OVERWRITE)
|
||
+ if (mask == TRACE_ITER_OVERWRITE) {
|
||
ring_buffer_change_overwrite(global_trace.buffer, enabled);
|
||
+#ifdef CONFIG_TRACER_MAX_TRACE
|
||
+ ring_buffer_change_overwrite(max_tr.buffer, enabled);
|
||
+#endif
|
||
+ }
|
||
|
||
return 0;
|
||
}
|
||
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
|
||
index fee3752..d01adb7 100644
|
||
--- a/kernel/trace/trace_event_perf.c
|
||
+++ b/kernel/trace/trace_event_perf.c
|
||
@@ -26,7 +26,7 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
|
||
{
|
||
/* The ftrace function trace is allowed only for root. */
|
||
if (ftrace_event_is_function(tp_event) &&
|
||
- perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
|
||
+ perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
|
||
return -EPERM;
|
||
|
||
/* No tracing, just counting, so no obvious leak */
|
||
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
|
||
index 29111da..2f737f5 100644
|
||
--- a/kernel/trace/trace_events.c
|
||
+++ b/kernel/trace/trace_events.c
|
||
@@ -1354,6 +1354,16 @@ static void trace_module_add_events(struct module *mod)
|
||
struct ftrace_module_file_ops *file_ops = NULL;
|
||
struct ftrace_event_call **call, **start, **end;
|
||
|
||
+ if (!mod->num_trace_events)
|
||
+ return;
|
||
+
|
||
+ /* Don't add infrastructure for mods without tracepoints */
|
||
+ if (trace_module_has_bad_taint(mod)) {
|
||
+ pr_err("%s: module has bad taint, not creating trace events\n",
|
||
+ mod->name);
|
||
+ return;
|
||
+ }
|
||
+
|
||
start = mod->trace_events;
|
||
end = mod->trace_events + mod->num_trace_events;
|
||
|
||
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
|
||
index d96ba22..7840b34 100644
|
||
--- a/kernel/tracepoint.c
|
||
+++ b/kernel/tracepoint.c
|
||
@@ -628,17 +628,25 @@ void tracepoint_iter_reset(struct tracepoint_iter *iter)
|
||
EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
|
||
|
||
#ifdef CONFIG_MODULES
|
||
+bool trace_module_has_bad_taint(struct module *mod)
|
||
+{
|
||
+ return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP));
|
||
+}
|
||
+
|
||
static int tracepoint_module_coming(struct module *mod)
|
||
{
|
||
struct tp_module *tp_mod, *iter;
|
||
int ret = 0;
|
||
|
||
+ if (!mod->num_tracepoints)
|
||
+ return 0;
|
||
+
|
||
/*
|
||
* We skip modules that taint the kernel, especially those with different
|
||
* module headers (for forced load), to make sure we don't cause a crash.
|
||
* Staging and out-of-tree GPL modules are fine.
|
||
*/
|
||
- if (mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)))
|
||
+ if (trace_module_has_bad_taint(mod))
|
||
return 0;
|
||
mutex_lock(&tracepoints_mutex);
|
||
tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL);
|
||
@@ -676,6 +684,9 @@ static int tracepoint_module_going(struct module *mod)
|
||
{
|
||
struct tp_module *pos;
|
||
|
||
+ if (!mod->num_tracepoints)
|
||
+ return 0;
|
||
+
|
||
mutex_lock(&tracepoints_mutex);
|
||
tracepoint_update_probe_range(mod->tracepoints_ptrs,
|
||
mod->tracepoints_ptrs + mod->num_tracepoints);
|
||
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
|
||
index e6ad770..ed10010 100644
|
||
--- a/kernel/workqueue.c
|
||
+++ b/kernel/workqueue.c
|
||
@@ -1886,12 +1886,19 @@ static void destroy_worker(struct worker *worker)
|
||
if (worker->flags & WORKER_IDLE)
|
||
pool->nr_idle--;
|
||
|
||
+ /*
|
||
+ * Once WORKER_DIE is set, the kworker may destroy itself at any
|
||
+ * point. Pin to ensure the task stays until we're done with it.
|
||
+ */
|
||
+ get_task_struct(worker->task);
|
||
+
|
||
list_del_init(&worker->entry);
|
||
worker->flags |= WORKER_DIE;
|
||
|
||
spin_unlock_irq(&gcwq->lock);
|
||
|
||
kthread_stop(worker->task);
|
||
+ put_task_struct(worker->task);
|
||
kfree(worker);
|
||
|
||
spin_lock_irq(&gcwq->lock);
|
||
@@ -2262,6 +2269,15 @@ __acquires(&gcwq->lock)
|
||
dump_stack();
|
||
}
|
||
|
||
+ /*
|
||
+ * The following prevents a kworker from hogging CPU on !PREEMPT
|
||
+ * kernels, where a requeueing work item waiting for something to
|
||
+ * happen could deadlock with stop_machine as such work item could
|
||
+ * indefinitely requeue itself while all other CPUs are trapped in
|
||
+ * stop_machine.
|
||
+ */
|
||
+ cond_resched();
|
||
+
|
||
spin_lock_irq(&gcwq->lock);
|
||
|
||
/* clear cpu intensive status */
|
||
diff --git a/lib/Makefile b/lib/Makefile
|
||
index c02286e..041931d 100644
|
||
--- a/lib/Makefile
|
||
+++ b/lib/Makefile
|
||
@@ -41,6 +41,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
|
||
lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
|
||
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
|
||
|
||
+GCOV_PROFILE_hweight.o := n
|
||
CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
|
||
obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
|
||
|
||
diff --git a/lib/btree.c b/lib/btree.c
|
||
index 5cf9e74..53a773e 100644
|
||
--- a/lib/btree.c
|
||
+++ b/lib/btree.c
|
||
@@ -198,6 +198,7 @@ EXPORT_SYMBOL_GPL(btree_init);
|
||
|
||
void btree_destroy(struct btree_head *head)
|
||
{
|
||
+ mempool_free(head->node, head->mempool);
|
||
mempool_destroy(head->mempool);
|
||
head->mempool = NULL;
|
||
}
|
||
diff --git a/lib/idr.c b/lib/idr.c
|
||
index e90d2d0..f402f14 100644
|
||
--- a/lib/idr.c
|
||
+++ b/lib/idr.c
|
||
@@ -39,6 +39,14 @@
|
||
static struct kmem_cache *idr_layer_cache;
|
||
static DEFINE_SPINLOCK(simple_ida_lock);
|
||
|
||
+/* the maximum ID which can be allocated given idr->layers */
|
||
+static int idr_max(int layers)
|
||
+{
|
||
+ int bits = min_t(int, layers * IDR_BITS, MAX_ID_SHIFT);
|
||
+
|
||
+ return (1 << bits) - 1;
|
||
+}
|
||
+
|
||
static struct idr_layer *get_from_free_list(struct idr *idp)
|
||
{
|
||
struct idr_layer *p;
|
||
@@ -223,7 +231,7 @@ static int idr_get_empty_slot(struct idr *idp, int starting_id,
|
||
* Add a new layer to the top of the tree if the requested
|
||
* id is larger than the currently allocated space.
|
||
*/
|
||
- while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) {
|
||
+ while (id > idr_max(layers)) {
|
||
layers++;
|
||
if (!p->count) {
|
||
/* special case: if the tree is currently empty,
|
||
@@ -265,7 +273,7 @@ static int idr_get_empty_slot(struct idr *idp, int starting_id,
|
||
|
||
static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
|
||
{
|
||
- struct idr_layer *pa[MAX_LEVEL];
|
||
+ struct idr_layer *pa[MAX_LEVEL + 1];
|
||
int id;
|
||
|
||
id = idr_get_empty_slot(idp, starting_id, pa);
|
||
@@ -357,7 +365,7 @@ static void idr_remove_warning(int id)
|
||
static void sub_remove(struct idr *idp, int shift, int id)
|
||
{
|
||
struct idr_layer *p = idp->top;
|
||
- struct idr_layer **pa[MAX_LEVEL];
|
||
+ struct idr_layer **pa[MAX_LEVEL + 1];
|
||
struct idr_layer ***paa = &pa[0];
|
||
struct idr_layer *to_free;
|
||
int n;
|
||
@@ -451,16 +459,16 @@ void idr_remove_all(struct idr *idp)
|
||
int n, id, max;
|
||
int bt_mask;
|
||
struct idr_layer *p;
|
||
- struct idr_layer *pa[MAX_LEVEL];
|
||
+ struct idr_layer *pa[MAX_LEVEL + 1];
|
||
struct idr_layer **paa = &pa[0];
|
||
|
||
n = idp->layers * IDR_BITS;
|
||
p = idp->top;
|
||
rcu_assign_pointer(idp->top, NULL);
|
||
- max = 1 << n;
|
||
+ max = idr_max(idp->layers);
|
||
|
||
id = 0;
|
||
- while (id < max) {
|
||
+ while (id >= 0 && id <= max) {
|
||
while (n > IDR_BITS && p) {
|
||
n -= IDR_BITS;
|
||
*paa++ = p;
|
||
@@ -519,7 +527,7 @@ void *idr_find(struct idr *idp, int id)
|
||
/* Mask off upper bits we don't use for the search. */
|
||
id &= MAX_ID_MASK;
|
||
|
||
- if (id >= (1 << n))
|
||
+ if (id > idr_max(p->layer + 1))
|
||
return NULL;
|
||
BUG_ON(n == 0);
|
||
|
||
@@ -555,15 +563,15 @@ int idr_for_each(struct idr *idp,
|
||
{
|
||
int n, id, max, error = 0;
|
||
struct idr_layer *p;
|
||
- struct idr_layer *pa[MAX_LEVEL];
|
||
+ struct idr_layer *pa[MAX_LEVEL + 1];
|
||
struct idr_layer **paa = &pa[0];
|
||
|
||
n = idp->layers * IDR_BITS;
|
||
p = rcu_dereference_raw(idp->top);
|
||
- max = 1 << n;
|
||
+ max = idr_max(idp->layers);
|
||
|
||
id = 0;
|
||
- while (id < max) {
|
||
+ while (id >= 0 && id <= max) {
|
||
while (n > 0 && p) {
|
||
n -= IDR_BITS;
|
||
*paa++ = p;
|
||
@@ -601,7 +609,7 @@ EXPORT_SYMBOL(idr_for_each);
|
||
*/
|
||
void *idr_get_next(struct idr *idp, int *nextidp)
|
||
{
|
||
- struct idr_layer *p, *pa[MAX_LEVEL];
|
||
+ struct idr_layer *p, *pa[MAX_LEVEL + 1];
|
||
struct idr_layer **paa = &pa[0];
|
||
int id = *nextidp;
|
||
int n, max;
|
||
@@ -611,9 +619,9 @@ void *idr_get_next(struct idr *idp, int *nextidp)
|
||
if (!p)
|
||
return NULL;
|
||
n = (p->layer + 1) * IDR_BITS;
|
||
- max = 1 << n;
|
||
+ max = idr_max(p->layer + 1);
|
||
|
||
- while (id < max) {
|
||
+ while (id >= 0 && id <= max) {
|
||
while (n > 0 && p) {
|
||
n -= IDR_BITS;
|
||
*paa++ = p;
|
||
@@ -787,7 +795,7 @@ EXPORT_SYMBOL(ida_pre_get);
|
||
*/
|
||
int ida_get_new_above(struct ida *ida, int starting_id, int *p_id)
|
||
{
|
||
- struct idr_layer *pa[MAX_LEVEL];
|
||
+ struct idr_layer *pa[MAX_LEVEL + 1];
|
||
struct ida_bitmap *bitmap;
|
||
unsigned long flags;
|
||
int idr_id = starting_id / IDA_BITMAP_BITS;
|
||
diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c
|
||
index e3edc5f..a5f3d0e 100644
|
||
--- a/lib/lzo/lzo1x_decompress_safe.c
|
||
+++ b/lib/lzo/lzo1x_decompress_safe.c
|
||
@@ -19,11 +19,31 @@
|
||
#include <linux/lzo.h>
|
||
#include "lzodefs.h"
|
||
|
||
-#define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x))
|
||
-#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x))
|
||
-#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun
|
||
-#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun
|
||
-#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun
|
||
+#define HAVE_IP(t, x) \
|
||
+ (((size_t)(ip_end - ip) >= (size_t)(t + x)) && \
|
||
+ (((t + x) >= t) && ((t + x) >= x)))
|
||
+
|
||
+#define HAVE_OP(t, x) \
|
||
+ (((size_t)(op_end - op) >= (size_t)(t + x)) && \
|
||
+ (((t + x) >= t) && ((t + x) >= x)))
|
||
+
|
||
+#define NEED_IP(t, x) \
|
||
+ do { \
|
||
+ if (!HAVE_IP(t, x)) \
|
||
+ goto input_overrun; \
|
||
+ } while (0)
|
||
+
|
||
+#define NEED_OP(t, x) \
|
||
+ do { \
|
||
+ if (!HAVE_OP(t, x)) \
|
||
+ goto output_overrun; \
|
||
+ } while (0)
|
||
+
|
||
+#define TEST_LB(m_pos) \
|
||
+ do { \
|
||
+ if ((m_pos) < out) \
|
||
+ goto lookbehind_overrun; \
|
||
+ } while (0)
|
||
|
||
int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
unsigned char *out, size_t *out_len)
|
||
@@ -58,14 +78,14 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
while (unlikely(*ip == 0)) {
|
||
t += 255;
|
||
ip++;
|
||
- NEED_IP(1);
|
||
+ NEED_IP(1, 0);
|
||
}
|
||
t += 15 + *ip++;
|
||
}
|
||
t += 3;
|
||
copy_literal_run:
|
||
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||
- if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) {
|
||
+ if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) {
|
||
const unsigned char *ie = ip + t;
|
||
unsigned char *oe = op + t;
|
||
do {
|
||
@@ -83,8 +103,8 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
} else
|
||
#endif
|
||
{
|
||
- NEED_OP(t);
|
||
- NEED_IP(t + 3);
|
||
+ NEED_OP(t, 0);
|
||
+ NEED_IP(t, 3);
|
||
do {
|
||
*op++ = *ip++;
|
||
} while (--t > 0);
|
||
@@ -97,7 +117,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
m_pos -= t >> 2;
|
||
m_pos -= *ip++ << 2;
|
||
TEST_LB(m_pos);
|
||
- NEED_OP(2);
|
||
+ NEED_OP(2, 0);
|
||
op[0] = m_pos[0];
|
||
op[1] = m_pos[1];
|
||
op += 2;
|
||
@@ -121,10 +141,10 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
while (unlikely(*ip == 0)) {
|
||
t += 255;
|
||
ip++;
|
||
- NEED_IP(1);
|
||
+ NEED_IP(1, 0);
|
||
}
|
||
t += 31 + *ip++;
|
||
- NEED_IP(2);
|
||
+ NEED_IP(2, 0);
|
||
}
|
||
m_pos = op - 1;
|
||
next = get_unaligned_le16(ip);
|
||
@@ -139,10 +159,10 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
while (unlikely(*ip == 0)) {
|
||
t += 255;
|
||
ip++;
|
||
- NEED_IP(1);
|
||
+ NEED_IP(1, 0);
|
||
}
|
||
t += 7 + *ip++;
|
||
- NEED_IP(2);
|
||
+ NEED_IP(2, 0);
|
||
}
|
||
next = get_unaligned_le16(ip);
|
||
ip += 2;
|
||
@@ -156,7 +176,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||
if (op - m_pos >= 8) {
|
||
unsigned char *oe = op + t;
|
||
- if (likely(HAVE_OP(t + 15))) {
|
||
+ if (likely(HAVE_OP(t, 15))) {
|
||
do {
|
||
COPY8(op, m_pos);
|
||
op += 8;
|
||
@@ -168,7 +188,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
# endif
|
||
} while (op < oe);
|
||
op = oe;
|
||
- if (HAVE_IP(6)) {
|
||
+ if (HAVE_IP(6, 0)) {
|
||
state = next;
|
||
COPY4(op, ip);
|
||
op += next;
|
||
@@ -176,7 +196,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
continue;
|
||
}
|
||
} else {
|
||
- NEED_OP(t);
|
||
+ NEED_OP(t, 0);
|
||
do {
|
||
*op++ = *m_pos++;
|
||
} while (op < oe);
|
||
@@ -185,7 +205,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
#endif
|
||
{
|
||
unsigned char *oe = op + t;
|
||
- NEED_OP(t);
|
||
+ NEED_OP(t, 0);
|
||
op[0] = m_pos[0];
|
||
op[1] = m_pos[1];
|
||
op += 2;
|
||
@@ -198,15 +218,15 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
||
state = next;
|
||
t = next;
|
||
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||
- if (likely(HAVE_IP(6) && HAVE_OP(4))) {
|
||
+ if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) {
|
||
COPY4(op, ip);
|
||
op += t;
|
||
ip += t;
|
||
} else
|
||
#endif
|
||
{
|
||
- NEED_IP(t + 3);
|
||
- NEED_OP(t);
|
||
+ NEED_IP(t, 3);
|
||
+ NEED_OP(t, 0);
|
||
while (t > 0) {
|
||
*op++ = *ip++;
|
||
t--;
|
||
diff --git a/lib/nlattr.c b/lib/nlattr.c
|
||
index 4226dfe..60abf1b 100644
|
||
--- a/lib/nlattr.c
|
||
+++ b/lib/nlattr.c
|
||
@@ -13,6 +13,7 @@
|
||
#include <linux/skbuff.h>
|
||
#include <linux/string.h>
|
||
#include <linux/types.h>
|
||
+#include <linux/ratelimit.h>
|
||
#include <net/netlink.h>
|
||
|
||
static const u16 nla_attr_minlen[NLA_TYPE_MAX+1] = {
|
||
@@ -197,8 +198,8 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
|
||
}
|
||
|
||
if (unlikely(rem > 0))
|
||
- printk(KERN_WARNING "netlink: %d bytes leftover after parsing "
|
||
- "attributes.\n", rem);
|
||
+ pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n",
|
||
+ rem, current->comm);
|
||
|
||
err = 0;
|
||
errout:
|
||
@@ -299,9 +300,15 @@ int nla_memcmp(const struct nlattr *nla, const void *data,
|
||
*/
|
||
int nla_strcmp(const struct nlattr *nla, const char *str)
|
||
{
|
||
- int len = strlen(str) + 1;
|
||
- int d = nla_len(nla) - len;
|
||
+ int len = strlen(str);
|
||
+ char *buf = nla_data(nla);
|
||
+ int attrlen = nla_len(nla);
|
||
+ int d;
|
||
|
||
+ if (attrlen > 0 && buf[attrlen - 1] == '\0')
|
||
+ attrlen--;
|
||
+
|
||
+ d = attrlen - len;
|
||
if (d == 0)
|
||
d = memcmp(nla_data(nla), str, len);
|
||
|
||
diff --git a/lib/random32.c b/lib/random32.c
|
||
index 938bde5..aa95712 100644
|
||
--- a/lib/random32.c
|
||
+++ b/lib/random32.c
|
||
@@ -92,7 +92,7 @@ void srandom32(u32 entropy)
|
||
*/
|
||
for_each_possible_cpu (i) {
|
||
struct rnd_state *state = &per_cpu(net_rand_state, i);
|
||
- state->s1 = __seed(state->s1 ^ entropy, 1);
|
||
+ state->s1 = __seed(state->s1 ^ entropy, 2);
|
||
}
|
||
}
|
||
EXPORT_SYMBOL(srandom32);
|
||
@@ -109,9 +109,9 @@ static int __init random32_init(void)
|
||
struct rnd_state *state = &per_cpu(net_rand_state,i);
|
||
|
||
#define LCG(x) ((x) * 69069) /* super-duper LCG */
|
||
- state->s1 = __seed(LCG(i + jiffies), 1);
|
||
- state->s2 = __seed(LCG(state->s1), 7);
|
||
- state->s3 = __seed(LCG(state->s2), 15);
|
||
+ state->s1 = __seed(LCG(i + jiffies), 2);
|
||
+ state->s2 = __seed(LCG(state->s1), 8);
|
||
+ state->s3 = __seed(LCG(state->s2), 16);
|
||
|
||
/* "warm it up" */
|
||
prandom32(state);
|
||
@@ -138,9 +138,9 @@ static int __init random32_reseed(void)
|
||
u32 seeds[3];
|
||
|
||
get_random_bytes(&seeds, sizeof(seeds));
|
||
- state->s1 = __seed(seeds[0], 1);
|
||
- state->s2 = __seed(seeds[1], 7);
|
||
- state->s3 = __seed(seeds[2], 15);
|
||
+ state->s1 = __seed(seeds[0], 2);
|
||
+ state->s2 = __seed(seeds[1], 8);
|
||
+ state->s3 = __seed(seeds[2], 16);
|
||
|
||
/* mix it in */
|
||
prandom32(state);
|
||
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
|
||
index 547a01f..387d912 100644
|
||
--- a/lib/scatterlist.c
|
||
+++ b/lib/scatterlist.c
|
||
@@ -421,7 +421,8 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
|
||
if (miter->addr) {
|
||
miter->__offset += miter->consumed;
|
||
|
||
- if (miter->__flags & SG_MITER_TO_SG)
|
||
+ if ((miter->__flags & SG_MITER_TO_SG) &&
|
||
+ !PageSlab(miter->page))
|
||
flush_kernel_dcache_page(miter->page);
|
||
|
||
if (miter->__flags & SG_MITER_ATOMIC) {
|
||
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
|
||
index 0b3c622..ddd07c6 100644
|
||
--- a/lib/vsprintf.c
|
||
+++ b/lib/vsprintf.c
|
||
@@ -25,6 +25,7 @@
|
||
#include <linux/kallsyms.h>
|
||
#include <linux/uaccess.h>
|
||
#include <linux/ioport.h>
|
||
+#include <linux/cred.h>
|
||
#include <net/addrconf.h>
|
||
|
||
#include <asm/page.h> /* for PAGE_SIZE */
|
||
@@ -926,16 +927,43 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||
* %pK cannot be used in IRQ context because its test
|
||
* for CAP_SYSLOG would be meaningless.
|
||
*/
|
||
- if (in_irq() || in_serving_softirq() || in_nmi()) {
|
||
+ if (kptr_restrict && (in_irq() || in_serving_softirq() ||
|
||
+ in_nmi())) {
|
||
if (spec.field_width == -1)
|
||
spec.field_width = 2 * sizeof(void *);
|
||
return string(buf, end, "pK-error", spec);
|
||
}
|
||
- if (!((kptr_restrict == 0) ||
|
||
- (kptr_restrict == 1 &&
|
||
- has_capability_noaudit(current, CAP_SYSLOG))))
|
||
+
|
||
+ switch (kptr_restrict) {
|
||
+ case 0:
|
||
+ /* Always print %pK values */
|
||
+ break;
|
||
+ case 1: {
|
||
+ /*
|
||
+ * Only print the real pointer value if the current
|
||
+ * process has CAP_SYSLOG and is running with the
|
||
+ * same credentials it started with. This is because
|
||
+ * access to files is checked at open() time, but %pK
|
||
+ * checks permission at read() time. We don't want to
|
||
+ * leak pointer values if a binary opens a file using
|
||
+ * %pK and then elevates privileges before reading it.
|
||
+ */
|
||
+ const struct cred *cred = current_cred();
|
||
+
|
||
+ if (!has_capability_noaudit(current, CAP_SYSLOG) ||
|
||
+ (cred->euid != cred->uid) ||
|
||
+ (cred->egid != cred->gid))
|
||
+ ptr = NULL;
|
||
+ break;
|
||
+ }
|
||
+ case 2:
|
||
+ default:
|
||
+ /* Always print 0's for %pK */
|
||
ptr = NULL;
|
||
+ break;
|
||
+ }
|
||
break;
|
||
+
|
||
case 'N':
|
||
switch (fmt[1]) {
|
||
case 'F':
|
||
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
|
||
index af20b77..eb7c0dc 100644
|
||
--- a/mm/hugetlb.c
|
||
+++ b/mm/hugetlb.c
|
||
@@ -1065,6 +1065,7 @@ static void return_unused_surplus_pages(struct hstate *h,
|
||
while (nr_pages--) {
|
||
if (!free_pool_huge_page(h, &node_states[N_HIGH_MEMORY], 1))
|
||
break;
|
||
+ cond_resched_lock(&hugetlb_lock);
|
||
}
|
||
}
|
||
|
||
@@ -1434,6 +1435,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
|
||
while (min_count < persistent_huge_pages(h)) {
|
||
if (!free_pool_huge_page(h, nodes_allowed, 0))
|
||
break;
|
||
+ cond_resched_lock(&hugetlb_lock);
|
||
}
|
||
while (count < persistent_huge_pages(h)) {
|
||
if (!adjust_pool_surplus(h, nodes_allowed, 1))
|
||
@@ -2257,6 +2259,31 @@ static void set_huge_ptep_writable(struct vm_area_struct *vma,
|
||
update_mmu_cache(vma, address, ptep);
|
||
}
|
||
|
||
+static int is_hugetlb_entry_migration(pte_t pte)
|
||
+{
|
||
+ swp_entry_t swp;
|
||
+
|
||
+ if (huge_pte_none(pte) || pte_present(pte))
|
||
+ return 0;
|
||
+ swp = pte_to_swp_entry(pte);
|
||
+ if (non_swap_entry(swp) && is_migration_entry(swp))
|
||
+ return 1;
|
||
+ else
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int is_hugetlb_entry_hwpoisoned(pte_t pte)
|
||
+{
|
||
+ swp_entry_t swp;
|
||
+
|
||
+ if (huge_pte_none(pte) || pte_present(pte))
|
||
+ return 0;
|
||
+ swp = pte_to_swp_entry(pte);
|
||
+ if (non_swap_entry(swp) && is_hwpoison_entry(swp))
|
||
+ return 1;
|
||
+ else
|
||
+ return 0;
|
||
+}
|
||
|
||
int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
||
struct vm_area_struct *vma)
|
||
@@ -2284,7 +2311,24 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
||
|
||
spin_lock(&dst->page_table_lock);
|
||
spin_lock_nested(&src->page_table_lock, SINGLE_DEPTH_NESTING);
|
||
- if (!huge_pte_none(huge_ptep_get(src_pte))) {
|
||
+ entry = huge_ptep_get(src_pte);
|
||
+ if (huge_pte_none(entry)) { /* skip none entry */
|
||
+ ;
|
||
+ } else if (unlikely(is_hugetlb_entry_migration(entry) ||
|
||
+ is_hugetlb_entry_hwpoisoned(entry))) {
|
||
+ swp_entry_t swp_entry = pte_to_swp_entry(entry);
|
||
+
|
||
+ if (is_write_migration_entry(swp_entry) && cow) {
|
||
+ /*
|
||
+ * COW mappings require pages in both
|
||
+ * parent and child to be set to read.
|
||
+ */
|
||
+ make_migration_entry_read(&swp_entry);
|
||
+ entry = swp_entry_to_pte(swp_entry);
|
||
+ set_huge_pte_at(src, addr, src_pte, entry);
|
||
+ }
|
||
+ set_huge_pte_at(dst, addr, dst_pte, entry);
|
||
+ } else {
|
||
if (cow)
|
||
huge_ptep_set_wrprotect(src, addr, src_pte);
|
||
entry = huge_ptep_get(src_pte);
|
||
@@ -2302,32 +2346,6 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
||
return -ENOMEM;
|
||
}
|
||
|
||
-static int is_hugetlb_entry_migration(pte_t pte)
|
||
-{
|
||
- swp_entry_t swp;
|
||
-
|
||
- if (huge_pte_none(pte) || pte_present(pte))
|
||
- return 0;
|
||
- swp = pte_to_swp_entry(pte);
|
||
- if (non_swap_entry(swp) && is_migration_entry(swp))
|
||
- return 1;
|
||
- else
|
||
- return 0;
|
||
-}
|
||
-
|
||
-static int is_hugetlb_entry_hwpoisoned(pte_t pte)
|
||
-{
|
||
- swp_entry_t swp;
|
||
-
|
||
- if (huge_pte_none(pte) || pte_present(pte))
|
||
- return 0;
|
||
- swp = pte_to_swp_entry(pte);
|
||
- if (non_swap_entry(swp) && is_hwpoison_entry(swp))
|
||
- return 1;
|
||
- else
|
||
- return 0;
|
||
-}
|
||
-
|
||
void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
|
||
unsigned long end, struct page *ref_page)
|
||
{
|
||
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
|
||
index 45eb621..ad6ee88 100644
|
||
--- a/mm/kmemleak.c
|
||
+++ b/mm/kmemleak.c
|
||
@@ -750,7 +750,9 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp)
|
||
}
|
||
|
||
spin_lock_irqsave(&object->lock, flags);
|
||
- if (ptr + size > object->pointer + object->size) {
|
||
+ if (size == SIZE_MAX) {
|
||
+ size = object->pointer + object->size - ptr;
|
||
+ } else if (ptr + size > object->pointer + object->size) {
|
||
kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr);
|
||
dump_object_info(object);
|
||
kmem_cache_free(scan_area_cache, area);
|
||
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
|
||
index b68c8f6..7205016 100644
|
||
--- a/mm/memory-failure.c
|
||
+++ b/mm/memory-failure.c
|
||
@@ -208,9 +208,9 @@ static int kill_proc(struct task_struct *t, unsigned long addr, int trapno,
|
||
#endif
|
||
si.si_addr_lsb = compound_trans_order(compound_head(page)) + PAGE_SHIFT;
|
||
|
||
- if ((flags & MF_ACTION_REQUIRED) && t == current) {
|
||
+ if ((flags & MF_ACTION_REQUIRED) && t->mm == current->mm) {
|
||
si.si_code = BUS_MCEERR_AR;
|
||
- ret = force_sig_info(SIGBUS, &si, t);
|
||
+ ret = force_sig_info(SIGBUS, &si, current);
|
||
} else {
|
||
/*
|
||
* Don't use force here, it's convenient if the signal
|
||
@@ -382,10 +382,12 @@ static void kill_procs(struct list_head *to_kill, int forcekill, int trapno,
|
||
}
|
||
}
|
||
|
||
-static int task_early_kill(struct task_struct *tsk)
|
||
+static int task_early_kill(struct task_struct *tsk, int force_early)
|
||
{
|
||
if (!tsk->mm)
|
||
return 0;
|
||
+ if (force_early)
|
||
+ return 1;
|
||
if (tsk->flags & PF_MCE_PROCESS)
|
||
return !!(tsk->flags & PF_MCE_EARLY);
|
||
return sysctl_memory_failure_early_kill;
|
||
@@ -395,7 +397,7 @@ static int task_early_kill(struct task_struct *tsk)
|
||
* Collect processes when the error hit an anonymous page.
|
||
*/
|
||
static void collect_procs_anon(struct page *page, struct list_head *to_kill,
|
||
- struct to_kill **tkc)
|
||
+ struct to_kill **tkc, int force_early)
|
||
{
|
||
struct vm_area_struct *vma;
|
||
struct task_struct *tsk;
|
||
@@ -409,7 +411,7 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
|
||
for_each_process (tsk) {
|
||
struct anon_vma_chain *vmac;
|
||
|
||
- if (!task_early_kill(tsk))
|
||
+ if (!task_early_kill(tsk, force_early))
|
||
continue;
|
||
list_for_each_entry(vmac, &av->head, same_anon_vma) {
|
||
vma = vmac->vma;
|
||
@@ -427,7 +429,7 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
|
||
* Collect processes when the error hit a file mapped page.
|
||
*/
|
||
static void collect_procs_file(struct page *page, struct list_head *to_kill,
|
||
- struct to_kill **tkc)
|
||
+ struct to_kill **tkc, int force_early)
|
||
{
|
||
struct vm_area_struct *vma;
|
||
struct task_struct *tsk;
|
||
@@ -439,7 +441,7 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
|
||
for_each_process(tsk) {
|
||
pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
|
||
|
||
- if (!task_early_kill(tsk))
|
||
+ if (!task_early_kill(tsk, force_early))
|
||
continue;
|
||
|
||
vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff,
|
||
@@ -465,7 +467,8 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
|
||
* First preallocate one tokill structure outside the spin locks,
|
||
* so that we can kill at least one process reasonably reliable.
|
||
*/
|
||
-static void collect_procs(struct page *page, struct list_head *tokill)
|
||
+static void collect_procs(struct page *page, struct list_head *tokill,
|
||
+ int force_early)
|
||
{
|
||
struct to_kill *tk;
|
||
|
||
@@ -476,9 +479,9 @@ static void collect_procs(struct page *page, struct list_head *tokill)
|
||
if (!tk)
|
||
return;
|
||
if (PageAnon(page))
|
||
- collect_procs_anon(page, tokill, &tk);
|
||
+ collect_procs_anon(page, tokill, &tk, force_early);
|
||
else
|
||
- collect_procs_file(page, tokill, &tk);
|
||
+ collect_procs_file(page, tokill, &tk, force_early);
|
||
kfree(tk);
|
||
}
|
||
|
||
@@ -948,7 +951,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
|
||
* there's nothing that can be done.
|
||
*/
|
||
if (kill)
|
||
- collect_procs(ppage, &tokill);
|
||
+ collect_procs(ppage, &tokill, flags & MF_ACTION_REQUIRED);
|
||
|
||
if (hpage != ppage)
|
||
lock_page(ppage);
|
||
@@ -1061,15 +1064,16 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
|
||
return 0;
|
||
} else if (PageHuge(hpage)) {
|
||
/*
|
||
- * Check "just unpoisoned", "filter hit", and
|
||
- * "race with other subpage."
|
||
+ * Check "filter hit" and "race with other subpage."
|
||
*/
|
||
lock_page(hpage);
|
||
- if (!PageHWPoison(hpage)
|
||
- || (hwpoison_filter(p) && TestClearPageHWPoison(p))
|
||
- || (p != hpage && TestSetPageHWPoison(hpage))) {
|
||
- atomic_long_sub(nr_pages, &mce_bad_pages);
|
||
- return 0;
|
||
+ if (PageHWPoison(hpage)) {
|
||
+ if ((hwpoison_filter(p) && TestClearPageHWPoison(p))
|
||
+ || (p != hpage && TestSetPageHWPoison(hpage))) {
|
||
+ atomic_long_sub(nr_pages, &mce_bad_pages);
|
||
+ unlock_page(hpage);
|
||
+ return 0;
|
||
+ }
|
||
}
|
||
set_page_hwpoison_huge_page(hpage);
|
||
res = dequeue_hwpoisoned_huge_page(hpage);
|
||
@@ -1121,6 +1125,8 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
|
||
*/
|
||
if (!PageHWPoison(p)) {
|
||
printk(KERN_ERR "MCE %#lx: just unpoisoned\n", pfn);
|
||
+ atomic_long_sub(nr_pages, &mce_bad_pages);
|
||
+ put_page(hpage);
|
||
res = 0;
|
||
goto out;
|
||
}
|
||
@@ -1447,10 +1453,18 @@ static int soft_offline_huge_page(struct page *page, int flags)
|
||
return ret;
|
||
}
|
||
done:
|
||
- if (!PageHWPoison(hpage))
|
||
- atomic_long_add(1 << compound_trans_order(hpage), &mce_bad_pages);
|
||
- set_page_hwpoison_huge_page(hpage);
|
||
- dequeue_hwpoisoned_huge_page(hpage);
|
||
+ /* overcommit hugetlb page will be freed to buddy */
|
||
+ if (PageHuge(hpage)) {
|
||
+ if (!PageHWPoison(hpage))
|
||
+ atomic_long_add(1 << compound_trans_order(hpage),
|
||
+ &mce_bad_pages);
|
||
+ set_page_hwpoison_huge_page(hpage);
|
||
+ dequeue_hwpoisoned_huge_page(hpage);
|
||
+ } else {
|
||
+ SetPageHWPoison(page);
|
||
+ atomic_long_inc(&mce_bad_pages);
|
||
+ }
|
||
+
|
||
/* keep elevated page count for bad page */
|
||
return ret;
|
||
}
|
||
diff --git a/mm/memory.c b/mm/memory.c
|
||
index 571c3c1..6b0897e 100644
|
||
--- a/mm/memory.c
|
||
+++ b/mm/memory.c
|
||
@@ -1890,12 +1890,17 @@ int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
|
||
unsigned long address, unsigned int fault_flags)
|
||
{
|
||
struct vm_area_struct *vma;
|
||
+ vm_flags_t vm_flags;
|
||
int ret;
|
||
|
||
vma = find_extend_vma(mm, address);
|
||
if (!vma || address < vma->vm_start)
|
||
return -EFAULT;
|
||
|
||
+ vm_flags = (fault_flags & FAULT_FLAG_WRITE) ? VM_WRITE : VM_READ;
|
||
+ if (!(vm_flags & vma->vm_flags))
|
||
+ return -EFAULT;
|
||
+
|
||
ret = handle_mm_fault(mm, vma, address, fault_flags);
|
||
if (ret & VM_FAULT_ERROR) {
|
||
if (ret & VM_FAULT_OOM)
|
||
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
|
||
index 46cb63b..82c6242 100644
|
||
--- a/mm/mempolicy.c
|
||
+++ b/mm/mempolicy.c
|
||
@@ -566,24 +566,24 @@ static inline int check_pgd_range(struct vm_area_struct *vma,
|
||
* If pagelist != NULL then isolate pages from the LRU and
|
||
* put them on the pagelist.
|
||
*/
|
||
-static struct vm_area_struct *
|
||
+static int
|
||
check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
|
||
const nodemask_t *nodes, unsigned long flags, void *private)
|
||
{
|
||
- int err;
|
||
- struct vm_area_struct *first, *vma, *prev;
|
||
+ int err = 0;
|
||
+ struct vm_area_struct *vma, *prev;
|
||
|
||
|
||
- first = find_vma(mm, start);
|
||
- if (!first)
|
||
- return ERR_PTR(-EFAULT);
|
||
+ vma = find_vma(mm, start);
|
||
+ if (!vma)
|
||
+ return -EFAULT;
|
||
prev = NULL;
|
||
- for (vma = first; vma && vma->vm_start < end; vma = vma->vm_next) {
|
||
+ for (; vma && vma->vm_start < end; vma = vma->vm_next) {
|
||
if (!(flags & MPOL_MF_DISCONTIG_OK)) {
|
||
if (!vma->vm_next && vma->vm_end < end)
|
||
- return ERR_PTR(-EFAULT);
|
||
+ return -EFAULT;
|
||
if (prev && prev->vm_end < vma->vm_start)
|
||
- return ERR_PTR(-EFAULT);
|
||
+ return -EFAULT;
|
||
}
|
||
if (!is_vm_hugetlb_page(vma) &&
|
||
((flags & MPOL_MF_STRICT) ||
|
||
@@ -597,14 +597,12 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
|
||
start = vma->vm_start;
|
||
err = check_pgd_range(vma, start, endvma, nodes,
|
||
flags, private);
|
||
- if (err) {
|
||
- first = ERR_PTR(err);
|
||
+ if (err)
|
||
break;
|
||
- }
|
||
}
|
||
prev = vma;
|
||
}
|
||
- return first;
|
||
+ return err;
|
||
}
|
||
|
||
/*
|
||
@@ -945,16 +943,15 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
|
||
{
|
||
nodemask_t nmask;
|
||
LIST_HEAD(pagelist);
|
||
- int err = 0;
|
||
- struct vm_area_struct *vma;
|
||
+ int err;
|
||
|
||
nodes_clear(nmask);
|
||
node_set(source, nmask);
|
||
|
||
- vma = check_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
|
||
+ err = check_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
|
||
flags | MPOL_MF_DISCONTIG_OK, &pagelist);
|
||
- if (IS_ERR(vma))
|
||
- return PTR_ERR(vma);
|
||
+ if (err)
|
||
+ return err;
|
||
|
||
if (!list_empty(&pagelist)) {
|
||
err = migrate_pages(&pagelist, new_node_page, dest,
|
||
@@ -1058,16 +1055,17 @@ int do_migrate_pages(struct mm_struct *mm,
|
||
|
||
/*
|
||
* Allocate a new page for page migration based on vma policy.
|
||
- * Start assuming that page is mapped by vma pointed to by @private.
|
||
+ * Start by assuming the page is mapped by the same vma as contains @start.
|
||
* Search forward from there, if not. N.B., this assumes that the
|
||
* list of pages handed to migrate_pages()--which is how we get here--
|
||
* is in virtual address order.
|
||
*/
|
||
-static struct page *new_vma_page(struct page *page, unsigned long private, int **x)
|
||
+static struct page *new_page(struct page *page, unsigned long start, int **x)
|
||
{
|
||
- struct vm_area_struct *vma = (struct vm_area_struct *)private;
|
||
+ struct vm_area_struct *vma;
|
||
unsigned long uninitialized_var(address);
|
||
|
||
+ vma = find_vma(current->mm, start);
|
||
while (vma) {
|
||
address = page_address_in_vma(page, vma);
|
||
if (address != -EFAULT)
|
||
@@ -1093,7 +1091,7 @@ int do_migrate_pages(struct mm_struct *mm,
|
||
return -ENOSYS;
|
||
}
|
||
|
||
-static struct page *new_vma_page(struct page *page, unsigned long private, int **x)
|
||
+static struct page *new_page(struct page *page, unsigned long start, int **x)
|
||
{
|
||
return NULL;
|
||
}
|
||
@@ -1103,7 +1101,6 @@ static long do_mbind(unsigned long start, unsigned long len,
|
||
unsigned short mode, unsigned short mode_flags,
|
||
nodemask_t *nmask, unsigned long flags)
|
||
{
|
||
- struct vm_area_struct *vma;
|
||
struct mm_struct *mm = current->mm;
|
||
struct mempolicy *new;
|
||
unsigned long end;
|
||
@@ -1167,19 +1164,17 @@ static long do_mbind(unsigned long start, unsigned long len,
|
||
if (err)
|
||
goto mpol_out;
|
||
|
||
- vma = check_range(mm, start, end, nmask,
|
||
+ err = check_range(mm, start, end, nmask,
|
||
flags | MPOL_MF_INVERT, &pagelist);
|
||
|
||
- err = PTR_ERR(vma);
|
||
- if (!IS_ERR(vma)) {
|
||
+ if (!err) {
|
||
int nr_failed = 0;
|
||
|
||
err = mbind_range(mm, start, end, new);
|
||
|
||
if (!list_empty(&pagelist)) {
|
||
- nr_failed = migrate_pages(&pagelist, new_vma_page,
|
||
- (unsigned long)vma,
|
||
- false, true);
|
||
+ nr_failed = migrate_pages(&pagelist, new_page,
|
||
+ start, false, true);
|
||
if (nr_failed)
|
||
putback_lru_pages(&pagelist);
|
||
}
|
||
@@ -1614,8 +1609,14 @@ static unsigned interleave_nodes(struct mempolicy *policy)
|
||
* task can change it's policy. The system default policy requires no
|
||
* such protection.
|
||
*/
|
||
-unsigned slab_node(struct mempolicy *policy)
|
||
+unsigned slab_node(void)
|
||
{
|
||
+ struct mempolicy *policy;
|
||
+
|
||
+ if (in_interrupt())
|
||
+ return numa_node_id();
|
||
+
|
||
+ policy = current->mempolicy;
|
||
if (!policy || policy->flags & MPOL_F_LOCAL)
|
||
return numa_node_id();
|
||
|
||
@@ -1996,7 +1997,6 @@ struct mempolicy *__mpol_dup(struct mempolicy *old)
|
||
} else
|
||
*new = *old;
|
||
|
||
- rcu_read_lock();
|
||
if (current_cpuset_is_being_rebound()) {
|
||
nodemask_t mems = cpuset_mems_allowed(current);
|
||
if (new->flags & MPOL_F_REBINDING)
|
||
@@ -2004,7 +2004,6 @@ struct mempolicy *__mpol_dup(struct mempolicy *old)
|
||
else
|
||
mpol_rebind_policy(new, &mems, MPOL_REBIND_ONCE);
|
||
}
|
||
- rcu_read_unlock();
|
||
atomic_set(&new->refcnt, 1);
|
||
return new;
|
||
}
|
||
diff --git a/mm/migrate.c b/mm/migrate.c
|
||
index 99ff32a..c18e804 100644
|
||
--- a/mm/migrate.c
|
||
+++ b/mm/migrate.c
|
||
@@ -140,8 +140,11 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
|
||
|
||
get_page(new);
|
||
pte = pte_mkold(mk_pte(new, vma->vm_page_prot));
|
||
+
|
||
+ /* Recheck VMA as permissions can change since migration started */
|
||
if (is_write_migration_entry(entry))
|
||
- pte = pte_mkwrite(pte);
|
||
+ pte = maybe_mkwrite(pte, vma);
|
||
+
|
||
#ifdef CONFIG_HUGETLB_PAGE
|
||
if (PageHuge(new))
|
||
pte = pte_mkhuge(pte);
|
||
diff --git a/mm/mlock.c b/mm/mlock.c
|
||
index 029f234..39a36db 100644
|
||
--- a/mm/mlock.c
|
||
+++ b/mm/mlock.c
|
||
@@ -78,6 +78,7 @@ void __clear_page_mlock(struct page *page)
|
||
*/
|
||
void mlock_vma_page(struct page *page)
|
||
{
|
||
+ /* Serialize with page migration */
|
||
BUG_ON(!PageLocked(page));
|
||
|
||
if (!TestSetPageMlocked(page)) {
|
||
@@ -105,6 +106,7 @@ void mlock_vma_page(struct page *page)
|
||
*/
|
||
void munlock_vma_page(struct page *page)
|
||
{
|
||
+ /* For try_to_munlock() and to serialize with page migration */
|
||
BUG_ON(!PageLocked(page));
|
||
|
||
if (TestClearPageMlocked(page)) {
|
||
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
|
||
index d012c75..e696d5e 100644
|
||
--- a/mm/page-writeback.c
|
||
+++ b/mm/page-writeback.c
|
||
@@ -1075,11 +1075,11 @@ static unsigned long dirty_poll_interval(unsigned long dirty,
|
||
return 1;
|
||
}
|
||
|
||
-static long bdi_max_pause(struct backing_dev_info *bdi,
|
||
- unsigned long bdi_dirty)
|
||
+static unsigned long bdi_max_pause(struct backing_dev_info *bdi,
|
||
+ unsigned long bdi_dirty)
|
||
{
|
||
- long bw = bdi->avg_write_bandwidth;
|
||
- long t;
|
||
+ unsigned long bw = bdi->avg_write_bandwidth;
|
||
+ unsigned long t;
|
||
|
||
/*
|
||
* Limit pause time for small memory systems. If sleeping for too long
|
||
@@ -1091,7 +1091,7 @@ static long bdi_max_pause(struct backing_dev_info *bdi,
|
||
t = bdi_dirty / (1 + bw / roundup_pow_of_two(1 + HZ / 8));
|
||
t++;
|
||
|
||
- return min_t(long, t, MAX_PAUSE);
|
||
+ return min_t(unsigned long, t, MAX_PAUSE);
|
||
}
|
||
|
||
static long bdi_min_pause(struct backing_dev_info *bdi,
|
||
@@ -1996,11 +1996,12 @@ int __set_page_dirty_nobuffers(struct page *page)
|
||
if (!TestSetPageDirty(page)) {
|
||
struct address_space *mapping = page_mapping(page);
|
||
struct address_space *mapping2;
|
||
+ unsigned long flags;
|
||
|
||
if (!mapping)
|
||
return 1;
|
||
|
||
- spin_lock_irq(&mapping->tree_lock);
|
||
+ spin_lock_irqsave(&mapping->tree_lock, flags);
|
||
mapping2 = page_mapping(page);
|
||
if (mapping2) { /* Race with truncate? */
|
||
BUG_ON(mapping2 != mapping);
|
||
@@ -2009,7 +2010,7 @@ int __set_page_dirty_nobuffers(struct page *page)
|
||
radix_tree_tag_set(&mapping->page_tree,
|
||
page_index(page), PAGECACHE_TAG_DIRTY);
|
||
}
|
||
- spin_unlock_irq(&mapping->tree_lock);
|
||
+ spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||
if (mapping->host) {
|
||
/* !PageAnon && !swapper_space */
|
||
__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
|
||
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
|
||
index f11c87d..b02c67f 100644
|
||
--- a/mm/page_alloc.c
|
||
+++ b/mm/page_alloc.c
|
||
@@ -2349,7 +2349,7 @@ static inline int
|
||
gfp_to_alloc_flags(gfp_t gfp_mask)
|
||
{
|
||
int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET;
|
||
- const gfp_t wait = gfp_mask & __GFP_WAIT;
|
||
+ const bool atomic = !(gfp_mask & (__GFP_WAIT | __GFP_NO_KSWAPD));
|
||
|
||
/* __GFP_HIGH is assumed to be the same as ALLOC_HIGH to save a branch. */
|
||
BUILD_BUG_ON(__GFP_HIGH != (__force gfp_t) ALLOC_HIGH);
|
||
@@ -2358,20 +2358,20 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
|
||
* The caller may dip into page reserves a bit more if the caller
|
||
* cannot run direct reclaim, or if the caller has realtime scheduling
|
||
* policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will
|
||
- * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH).
|
||
+ * set both ALLOC_HARDER (atomic == true) and ALLOC_HIGH (__GFP_HIGH).
|
||
*/
|
||
alloc_flags |= (__force int) (gfp_mask & __GFP_HIGH);
|
||
|
||
- if (!wait) {
|
||
+ if (atomic) {
|
||
/*
|
||
- * Not worth trying to allocate harder for
|
||
- * __GFP_NOMEMALLOC even if it can't schedule.
|
||
+ * Not worth trying to allocate harder for __GFP_NOMEMALLOC even
|
||
+ * if it can't schedule.
|
||
*/
|
||
- if (!(gfp_mask & __GFP_NOMEMALLOC))
|
||
+ if (!(gfp_mask & __GFP_NOMEMALLOC))
|
||
alloc_flags |= ALLOC_HARDER;
|
||
/*
|
||
- * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
|
||
- * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
|
||
+ * Ignore cpuset mems for GFP_ATOMIC rather than fail, see the
|
||
+ * comment for __cpuset_node_allowed_softwall().
|
||
*/
|
||
alloc_flags &= ~ALLOC_CPUSET;
|
||
} else if (unlikely(rt_task(current)) && !in_interrupt())
|
||
@@ -4470,25 +4470,24 @@ static inline void setup_usemap(struct pglist_data *pgdat, struct zone *zone,
|
||
|
||
#ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
|
||
|
||
-/* Return a sensible default order for the pageblock size. */
|
||
-static inline int pageblock_default_order(void)
|
||
-{
|
||
- if (HPAGE_SHIFT > PAGE_SHIFT)
|
||
- return HUGETLB_PAGE_ORDER;
|
||
-
|
||
- return MAX_ORDER-1;
|
||
-}
|
||
-
|
||
/* Initialise the number of pages represented by NR_PAGEBLOCK_BITS */
|
||
-static inline void __init set_pageblock_order(unsigned int order)
|
||
+static inline void __init set_pageblock_order(void)
|
||
{
|
||
+ unsigned int order;
|
||
+
|
||
/* Check that pageblock_nr_pages has not already been setup */
|
||
if (pageblock_order)
|
||
return;
|
||
|
||
+ if (HPAGE_SHIFT > PAGE_SHIFT)
|
||
+ order = HUGETLB_PAGE_ORDER;
|
||
+ else
|
||
+ order = MAX_ORDER - 1;
|
||
+
|
||
/*
|
||
* Assume the largest contiguous order of interest is a huge page.
|
||
- * This value may be variable depending on boot parameters on IA64
|
||
+ * This value may be variable depending on boot parameters on IA64 and
|
||
+ * powerpc.
|
||
*/
|
||
pageblock_order = order;
|
||
}
|
||
@@ -4496,15 +4495,13 @@ static inline void __init set_pageblock_order(unsigned int order)
|
||
|
||
/*
|
||
* When CONFIG_HUGETLB_PAGE_SIZE_VARIABLE is not set, set_pageblock_order()
|
||
- * and pageblock_default_order() are unused as pageblock_order is set
|
||
- * at compile-time. See include/linux/pageblock-flags.h for the values of
|
||
- * pageblock_order based on the kernel config
|
||
+ * is unused as pageblock_order is set at compile-time. See
|
||
+ * include/linux/pageblock-flags.h for the values of pageblock_order based on
|
||
+ * the kernel config
|
||
*/
|
||
-static inline int pageblock_default_order(unsigned int order)
|
||
+static inline void set_pageblock_order(void)
|
||
{
|
||
- return MAX_ORDER-1;
|
||
}
|
||
-#define set_pageblock_order(x) do {} while (0)
|
||
|
||
#endif /* CONFIG_HUGETLB_PAGE_SIZE_VARIABLE */
|
||
|
||
@@ -4592,7 +4589,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
|
||
if (!size)
|
||
continue;
|
||
|
||
- set_pageblock_order(pageblock_default_order());
|
||
+ set_pageblock_order();
|
||
setup_usemap(pgdat, zone, zone_start_pfn, size);
|
||
ret = init_currently_empty_zone(zone, zone_start_pfn,
|
||
size, MEMMAP_EARLY);
|
||
diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c
|
||
index 405d331..6f3db37 100644
|
||
--- a/mm/percpu-vm.c
|
||
+++ b/mm/percpu-vm.c
|
||
@@ -108,7 +108,7 @@ static int pcpu_alloc_pages(struct pcpu_chunk *chunk,
|
||
int page_start, int page_end)
|
||
{
|
||
const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD;
|
||
- unsigned int cpu;
|
||
+ unsigned int cpu, tcpu;
|
||
int i;
|
||
|
||
for_each_possible_cpu(cpu) {
|
||
@@ -116,14 +116,23 @@ static int pcpu_alloc_pages(struct pcpu_chunk *chunk,
|
||
struct page **pagep = &pages[pcpu_page_idx(cpu, i)];
|
||
|
||
*pagep = alloc_pages_node(cpu_to_node(cpu), gfp, 0);
|
||
- if (!*pagep) {
|
||
- pcpu_free_pages(chunk, pages, populated,
|
||
- page_start, page_end);
|
||
- return -ENOMEM;
|
||
- }
|
||
+ if (!*pagep)
|
||
+ goto err;
|
||
}
|
||
}
|
||
return 0;
|
||
+
|
||
+err:
|
||
+ while (--i >= page_start)
|
||
+ __free_page(pages[pcpu_page_idx(cpu, i)]);
|
||
+
|
||
+ for_each_possible_cpu(tcpu) {
|
||
+ if (tcpu == cpu)
|
||
+ break;
|
||
+ for (i = page_start; i < page_end; i++)
|
||
+ __free_page(pages[pcpu_page_idx(tcpu, i)]);
|
||
+ }
|
||
+ return -ENOMEM;
|
||
}
|
||
|
||
/**
|
||
@@ -263,6 +272,7 @@ static int pcpu_map_pages(struct pcpu_chunk *chunk,
|
||
__pcpu_unmap_pages(pcpu_chunk_addr(chunk, tcpu, page_start),
|
||
page_end - page_start);
|
||
}
|
||
+ pcpu_post_unmap_tlb_flush(chunk, page_start, page_end);
|
||
return err;
|
||
}
|
||
|
||
diff --git a/mm/percpu.c b/mm/percpu.c
|
||
index bb4be74..5f6042b 100644
|
||
--- a/mm/percpu.c
|
||
+++ b/mm/percpu.c
|
||
@@ -612,7 +612,7 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void)
|
||
chunk->map = pcpu_mem_zalloc(PCPU_DFL_MAP_ALLOC *
|
||
sizeof(chunk->map[0]));
|
||
if (!chunk->map) {
|
||
- kfree(chunk);
|
||
+ pcpu_mem_free(chunk, pcpu_chunk_struct_size);
|
||
return NULL;
|
||
}
|
||
|
||
@@ -1907,6 +1907,8 @@ void __init setup_per_cpu_areas(void)
|
||
|
||
if (pcpu_setup_first_chunk(ai, fc) < 0)
|
||
panic("Failed to initialize percpu areas.");
|
||
+
|
||
+ pcpu_free_alloc_info(ai);
|
||
}
|
||
|
||
#endif /* CONFIG_SMP */
|
||
diff --git a/mm/rmap.c b/mm/rmap.c
|
||
index aa95e59..ecce3ec 100644
|
||
--- a/mm/rmap.c
|
||
+++ b/mm/rmap.c
|
||
@@ -103,6 +103,7 @@ static inline void anon_vma_free(struct anon_vma *anon_vma)
|
||
* LOCK should suffice since the actual taking of the lock must
|
||
* happen _before_ what follows.
|
||
*/
|
||
+ might_sleep();
|
||
if (mutex_is_locked(&anon_vma->root->mutex)) {
|
||
anon_vma_lock(anon_vma);
|
||
anon_vma_unlock(anon_vma);
|
||
@@ -476,8 +477,9 @@ struct anon_vma *page_get_anon_vma(struct page *page)
|
||
* above cannot corrupt).
|
||
*/
|
||
if (!page_mapped(page)) {
|
||
+ rcu_read_unlock();
|
||
put_anon_vma(anon_vma);
|
||
- anon_vma = NULL;
|
||
+ return NULL;
|
||
}
|
||
out:
|
||
rcu_read_unlock();
|
||
@@ -527,9 +529,9 @@ struct anon_vma *page_lock_anon_vma(struct page *page)
|
||
}
|
||
|
||
if (!page_mapped(page)) {
|
||
+ rcu_read_unlock();
|
||
put_anon_vma(anon_vma);
|
||
- anon_vma = NULL;
|
||
- goto out;
|
||
+ return NULL;
|
||
}
|
||
|
||
/* we pinned the anon_vma, its safe to sleep */
|
||
@@ -623,7 +625,11 @@ pte_t *__page_check_address(struct page *page, struct mm_struct *mm,
|
||
spinlock_t *ptl;
|
||
|
||
if (unlikely(PageHuge(page))) {
|
||
+ /* when pud is not present, pte will be NULL */
|
||
pte = huge_pte_offset(mm, address);
|
||
+ if (!pte)
|
||
+ return NULL;
|
||
+
|
||
ptl = &mm->page_table_lock;
|
||
goto check;
|
||
}
|
||
@@ -1437,9 +1443,19 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
|
||
BUG_ON(!page || PageAnon(page));
|
||
|
||
if (locked_vma) {
|
||
- mlock_vma_page(page); /* no-op if already mlocked */
|
||
- if (page == check_page)
|
||
+ if (page == check_page) {
|
||
+ /* we know we have check_page locked */
|
||
+ mlock_vma_page(page);
|
||
ret = SWAP_MLOCK;
|
||
+ } else if (trylock_page(page)) {
|
||
+ /*
|
||
+ * If we can lock the page, perform mlock.
|
||
+ * Otherwise leave the page alone, it will be
|
||
+ * eventually encountered again later.
|
||
+ */
|
||
+ mlock_vma_page(page);
|
||
+ unlock_page(page);
|
||
+ }
|
||
continue; /* don't unmap */
|
||
}
|
||
|
||
@@ -1711,10 +1727,9 @@ void __put_anon_vma(struct anon_vma *anon_vma)
|
||
{
|
||
struct anon_vma *root = anon_vma->root;
|
||
|
||
+ anon_vma_free(anon_vma);
|
||
if (root != anon_vma && atomic_dec_and_test(&root->refcount))
|
||
anon_vma_free(root);
|
||
-
|
||
- anon_vma_free(anon_vma);
|
||
}
|
||
|
||
#ifdef CONFIG_MIGRATION
|
||
diff --git a/mm/shmem.c b/mm/shmem.c
|
||
index 4489566..2e4d10d 100644
|
||
--- a/mm/shmem.c
|
||
+++ b/mm/shmem.c
|
||
@@ -76,6 +76,17 @@ static struct vfsmount *shm_mnt;
|
||
/* Symlink up to this size is kmalloc'ed instead of using a swappable page */
|
||
#define SHORT_SYMLINK_LEN 128
|
||
|
||
+/*
|
||
+ * vmtruncate_range() communicates with shmem_fault via
|
||
+ * inode->i_private (with i_mutex making sure that it has only one user at
|
||
+ * a time): we would prefer not to enlarge the shmem inode just for that.
|
||
+ */
|
||
+struct shmem_falloc {
|
||
+ wait_queue_head_t *waitq; /* faults into hole wait for punch to end */
|
||
+ pgoff_t start; /* start of range currently being fallocated */
|
||
+ pgoff_t next; /* the next page offset to be fallocated */
|
||
+};
|
||
+
|
||
struct shmem_xattr {
|
||
struct list_head list; /* anchored by shmem_inode_info->xattr_list */
|
||
char *name; /* xattr name */
|
||
@@ -488,22 +499,19 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
|
||
}
|
||
|
||
index = start;
|
||
- for ( ; ; ) {
|
||
+ while (index <= end) {
|
||
cond_resched();
|
||
pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
|
||
min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1,
|
||
pvec.pages, indices);
|
||
if (!pvec.nr) {
|
||
- if (index == start)
|
||
+ /* If all gone or hole-punch, we're done */
|
||
+ if (index == start || end != -1)
|
||
break;
|
||
+ /* But if truncating, restart to make sure all gone */
|
||
index = start;
|
||
continue;
|
||
}
|
||
- if (index == start && indices[0] > end) {
|
||
- shmem_deswap_pagevec(&pvec);
|
||
- pagevec_release(&pvec);
|
||
- break;
|
||
- }
|
||
mem_cgroup_uncharge_start();
|
||
for (i = 0; i < pagevec_count(&pvec); i++) {
|
||
struct page *page = pvec.pages[i];
|
||
@@ -513,8 +521,12 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
|
||
break;
|
||
|
||
if (radix_tree_exceptional_entry(page)) {
|
||
- nr_swaps_freed += !shmem_free_swap(mapping,
|
||
- index, page);
|
||
+ if (shmem_free_swap(mapping, index, page)) {
|
||
+ /* Swap was replaced by page: retry */
|
||
+ index--;
|
||
+ break;
|
||
+ }
|
||
+ nr_swaps_freed++;
|
||
continue;
|
||
}
|
||
|
||
@@ -522,6 +534,11 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
|
||
if (page->mapping == mapping) {
|
||
VM_BUG_ON(PageWriteback(page));
|
||
truncate_inode_page(mapping, page);
|
||
+ } else {
|
||
+ /* Page was replaced by swap: retry */
|
||
+ unlock_page(page);
|
||
+ index--;
|
||
+ break;
|
||
}
|
||
unlock_page(page);
|
||
}
|
||
@@ -1060,6 +1077,63 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||
int error;
|
||
int ret = VM_FAULT_LOCKED;
|
||
|
||
+ /*
|
||
+ * Trinity finds that probing a hole which tmpfs is punching can
|
||
+ * prevent the hole-punch from ever completing: which in turn
|
||
+ * locks writers out with its hold on i_mutex. So refrain from
|
||
+ * faulting pages into the hole while it's being punched. Although
|
||
+ * shmem_truncate_range() does remove the additions, it may be unable to
|
||
+ * keep up, as each new page needs its own unmap_mapping_range() call,
|
||
+ * and the i_mmap tree grows ever slower to scan if new vmas are added.
|
||
+ *
|
||
+ * It does not matter if we sometimes reach this check just before the
|
||
+ * hole-punch begins, so that one fault then races with the punch:
|
||
+ * we just need to make racing faults a rare case.
|
||
+ *
|
||
+ * The implementation below would be much simpler if we just used a
|
||
+ * standard mutex or completion: but we cannot take i_mutex in fault,
|
||
+ * and bloating every shmem inode for this unlikely case would be sad.
|
||
+ */
|
||
+ if (unlikely(inode->i_private)) {
|
||
+ struct shmem_falloc *shmem_falloc;
|
||
+
|
||
+ spin_lock(&inode->i_lock);
|
||
+ shmem_falloc = inode->i_private;
|
||
+ if (shmem_falloc &&
|
||
+ vmf->pgoff >= shmem_falloc->start &&
|
||
+ vmf->pgoff < shmem_falloc->next) {
|
||
+ wait_queue_head_t *shmem_falloc_waitq;
|
||
+ DEFINE_WAIT(shmem_fault_wait);
|
||
+
|
||
+ ret = VM_FAULT_NOPAGE;
|
||
+ if ((vmf->flags & FAULT_FLAG_ALLOW_RETRY) &&
|
||
+ !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
|
||
+ /* It's polite to up mmap_sem if we can */
|
||
+ up_read(&vma->vm_mm->mmap_sem);
|
||
+ ret = VM_FAULT_RETRY;
|
||
+ }
|
||
+
|
||
+ shmem_falloc_waitq = shmem_falloc->waitq;
|
||
+ prepare_to_wait(shmem_falloc_waitq, &shmem_fault_wait,
|
||
+ TASK_UNINTERRUPTIBLE);
|
||
+ spin_unlock(&inode->i_lock);
|
||
+ schedule();
|
||
+
|
||
+ /*
|
||
+ * shmem_falloc_waitq points into the vmtruncate_range()
|
||
+ * stack of the hole-punching task: shmem_falloc_waitq
|
||
+ * is usually invalid by the time we reach here, but
|
||
+ * finish_wait() does not dereference it in that case;
|
||
+ * though i_lock needed lest racing with wake_up_all().
|
||
+ */
|
||
+ spin_lock(&inode->i_lock);
|
||
+ finish_wait(shmem_falloc_waitq, &shmem_fault_wait);
|
||
+ spin_unlock(&inode->i_lock);
|
||
+ return ret;
|
||
+ }
|
||
+ spin_unlock(&inode->i_lock);
|
||
+ }
|
||
+
|
||
error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret);
|
||
if (error)
|
||
return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);
|
||
@@ -1071,6 +1145,47 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||
return ret;
|
||
}
|
||
|
||
+int vmtruncate_range(struct inode *inode, loff_t lstart, loff_t lend)
|
||
+{
|
||
+ /*
|
||
+ * If the underlying filesystem is not going to provide
|
||
+ * a way to truncate a range of blocks (punch a hole) -
|
||
+ * we should return failure right now.
|
||
+ * Only CONFIG_SHMEM shmem.c ever supported i_op->truncate_range().
|
||
+ */
|
||
+ if (inode->i_op->truncate_range != shmem_truncate_range)
|
||
+ return -ENOSYS;
|
||
+
|
||
+ mutex_lock(&inode->i_mutex);
|
||
+ {
|
||
+ struct shmem_falloc shmem_falloc;
|
||
+ struct address_space *mapping = inode->i_mapping;
|
||
+ loff_t unmap_start = round_up(lstart, PAGE_SIZE);
|
||
+ loff_t unmap_end = round_down(1 + lend, PAGE_SIZE) - 1;
|
||
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq);
|
||
+
|
||
+ shmem_falloc.waitq = &shmem_falloc_waitq;
|
||
+ shmem_falloc.start = unmap_start >> PAGE_SHIFT;
|
||
+ shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT;
|
||
+ spin_lock(&inode->i_lock);
|
||
+ inode->i_private = &shmem_falloc;
|
||
+ spin_unlock(&inode->i_lock);
|
||
+
|
||
+ if ((u64)unmap_end > (u64)unmap_start)
|
||
+ unmap_mapping_range(mapping, unmap_start,
|
||
+ 1 + unmap_end - unmap_start, 0);
|
||
+ shmem_truncate_range(inode, lstart, lend);
|
||
+ /* No need to unmap again: hole-punching leaves COWed pages */
|
||
+
|
||
+ spin_lock(&inode->i_lock);
|
||
+ inode->i_private = NULL;
|
||
+ wake_up_all(&shmem_falloc_waitq);
|
||
+ spin_unlock(&inode->i_lock);
|
||
+ }
|
||
+ mutex_unlock(&inode->i_mutex);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
#ifdef CONFIG_NUMA
|
||
static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
|
||
{
|
||
@@ -1610,8 +1725,10 @@ static int shmem_rename(struct inode *old_dir, struct dentry *old_dentry, struct
|
||
|
||
if (new_dentry->d_inode) {
|
||
(void) shmem_unlink(new_dir, new_dentry);
|
||
- if (they_are_dirs)
|
||
+ if (they_are_dirs) {
|
||
+ drop_nlink(new_dentry->d_inode);
|
||
drop_nlink(old_dir);
|
||
+ }
|
||
} else if (they_are_dirs) {
|
||
drop_nlink(old_dir);
|
||
inc_nlink(new_dir);
|
||
@@ -2547,6 +2664,12 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
|
||
}
|
||
EXPORT_SYMBOL_GPL(shmem_truncate_range);
|
||
|
||
+int vmtruncate_range(struct inode *inode, loff_t lstart, loff_t lend)
|
||
+{
|
||
+ /* Only CONFIG_SHMEM shmem.c ever supported i_op->truncate_range(). */
|
||
+ return -ENOSYS;
|
||
+}
|
||
+
|
||
#define shmem_vm_ops generic_file_vm_ops
|
||
#define shmem_file_operations ramfs_file_operations
|
||
#define shmem_get_inode(sb, dir, mode, dev, flags) ramfs_get_inode(sb, dir, mode, dev)
|
||
diff --git a/mm/slab.c b/mm/slab.c
|
||
index da2bb68..3714dd9 100644
|
||
--- a/mm/slab.c
|
||
+++ b/mm/slab.c
|
||
@@ -3321,7 +3321,7 @@ static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
|
||
|
||
#ifdef CONFIG_NUMA
|
||
/*
|
||
- * Try allocating on another node if PF_SPREAD_SLAB|PF_MEMPOLICY.
|
||
+ * Try allocating on another node if PFA_SPREAD_SLAB|PF_MEMPOLICY.
|
||
*
|
||
* If we are in_interrupt, then process context, including cpusets and
|
||
* mempolicy, may not apply and should not be used for allocation policy.
|
||
@@ -3336,7 +3336,7 @@ static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags)
|
||
if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
|
||
nid_alloc = cpuset_slab_spread_node();
|
||
else if (current->mempolicy)
|
||
- nid_alloc = slab_node(current->mempolicy);
|
||
+ nid_alloc = slab_node();
|
||
if (nid_alloc != nid_here)
|
||
return ____cache_alloc_node(cachep, flags, nid_alloc);
|
||
return NULL;
|
||
@@ -3368,7 +3368,7 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
|
||
|
||
retry_cpuset:
|
||
cpuset_mems_cookie = get_mems_allowed();
|
||
- zonelist = node_zonelist(slab_node(current->mempolicy), flags);
|
||
+ zonelist = node_zonelist(slab_node(), flags);
|
||
|
||
retry:
|
||
/*
|
||
@@ -3562,7 +3562,7 @@ __do_cache_alloc(struct kmem_cache *cache, gfp_t flags)
|
||
{
|
||
void *objp;
|
||
|
||
- if (unlikely(current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY))) {
|
||
+ if (unlikely((current->flags & PF_MEMPOLICY) || cpuset_do_slab_mem_spread())) {
|
||
objp = alternate_node_alloc(cache, flags);
|
||
if (objp)
|
||
goto out;
|
||
diff --git a/mm/slub.c b/mm/slub.c
|
||
index e6dd97f..0533769 100644
|
||
--- a/mm/slub.c
|
||
+++ b/mm/slub.c
|
||
@@ -1617,7 +1617,7 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags,
|
||
|
||
do {
|
||
cpuset_mems_cookie = get_mems_allowed();
|
||
- zonelist = node_zonelist(slab_node(current->mempolicy), flags);
|
||
+ zonelist = node_zonelist(slab_node(), flags);
|
||
for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
|
||
struct kmem_cache_node *n;
|
||
|
||
diff --git a/mm/swap.c b/mm/swap.c
|
||
index 5c13f13..f689e9a 100644
|
||
--- a/mm/swap.c
|
||
+++ b/mm/swap.c
|
||
@@ -30,6 +30,7 @@
|
||
#include <linux/backing-dev.h>
|
||
#include <linux/memcontrol.h>
|
||
#include <linux/gfp.h>
|
||
+#include <linux/hugetlb.h>
|
||
|
||
#include "internal.h"
|
||
|
||
@@ -68,13 +69,26 @@ static void __put_compound_page(struct page *page)
|
||
{
|
||
compound_page_dtor *dtor;
|
||
|
||
- __page_cache_release(page);
|
||
+ if (!PageHuge(page))
|
||
+ __page_cache_release(page);
|
||
dtor = get_compound_page_dtor(page);
|
||
(*dtor)(page);
|
||
}
|
||
|
||
static void put_compound_page(struct page *page)
|
||
{
|
||
+ /*
|
||
+ * hugetlbfs pages cannot be split from under us. If this is a
|
||
+ * hugetlbfs page, check refcount on head page and release the page if
|
||
+ * the refcount becomes zero.
|
||
+ */
|
||
+ if (PageHuge(page)) {
|
||
+ page = compound_head(page);
|
||
+ if (put_page_testzero(page))
|
||
+ __put_compound_page(page);
|
||
+ return;
|
||
+ }
|
||
+
|
||
if (unlikely(PageTail(page))) {
|
||
/* __split_huge_page_refcount can run under us */
|
||
struct page *page_head = compound_trans_head(page);
|
||
@@ -159,8 +173,20 @@ bool __get_page_tail(struct page *page)
|
||
*/
|
||
unsigned long flags;
|
||
bool got = false;
|
||
- struct page *page_head = compound_trans_head(page);
|
||
+ struct page *page_head;
|
||
+
|
||
+ /*
|
||
+ * If this is a hugetlbfs page it cannot be split under us. Simply
|
||
+ * increment refcount for the head page.
|
||
+ */
|
||
+ if (PageHuge(page)) {
|
||
+ page_head = compound_head(page);
|
||
+ atomic_inc(&page_head->_count);
|
||
+ got = true;
|
||
+ goto out;
|
||
+ }
|
||
|
||
+ page_head = compound_trans_head(page);
|
||
if (likely(page != page_head && get_page_unless_zero(page_head))) {
|
||
/*
|
||
* page_head wasn't a dangling pointer but it
|
||
@@ -178,6 +204,7 @@ bool __get_page_tail(struct page *page)
|
||
if (unlikely(!got))
|
||
put_page(page_head);
|
||
}
|
||
+out:
|
||
return got;
|
||
}
|
||
EXPORT_SYMBOL(__get_page_tail);
|
||
diff --git a/mm/truncate.c b/mm/truncate.c
|
||
index 4224627..f38055c 100644
|
||
--- a/mm/truncate.c
|
||
+++ b/mm/truncate.c
|
||
@@ -603,31 +603,6 @@ int vmtruncate(struct inode *inode, loff_t newsize)
|
||
}
|
||
EXPORT_SYMBOL(vmtruncate);
|
||
|
||
-int vmtruncate_range(struct inode *inode, loff_t lstart, loff_t lend)
|
||
-{
|
||
- struct address_space *mapping = inode->i_mapping;
|
||
- loff_t holebegin = round_up(lstart, PAGE_SIZE);
|
||
- loff_t holelen = 1 + lend - holebegin;
|
||
-
|
||
- /*
|
||
- * If the underlying filesystem is not going to provide
|
||
- * a way to truncate a range of blocks (punch a hole) -
|
||
- * we should return failure right now.
|
||
- */
|
||
- if (!inode->i_op->truncate_range)
|
||
- return -ENOSYS;
|
||
-
|
||
- mutex_lock(&inode->i_mutex);
|
||
- inode_dio_wait(inode);
|
||
- unmap_mapping_range(mapping, holebegin, holelen, 1);
|
||
- inode->i_op->truncate_range(inode, lstart, lend);
|
||
- /* unmap again to remove racily COWed private pages */
|
||
- unmap_mapping_range(mapping, holebegin, holelen, 1);
|
||
- mutex_unlock(&inode->i_mutex);
|
||
-
|
||
- return 0;
|
||
-}
|
||
-
|
||
/**
|
||
* truncate_pagecache_range - unmap and remove pagecache that is hole-punched
|
||
* @inode: inode
|
||
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
|
||
index 2e074aa..c260b5e 100644
|
||
--- a/mm/vmalloc.c
|
||
+++ b/mm/vmalloc.c
|
||
@@ -390,6 +390,12 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
|
||
if (unlikely(!va))
|
||
return ERR_PTR(-ENOMEM);
|
||
|
||
+ /*
|
||
+ * Only scan the relevant parts containing pointers to other objects
|
||
+ * to avoid false negatives.
|
||
+ */
|
||
+ kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask & GFP_RECLAIM_MASK);
|
||
+
|
||
retry:
|
||
spin_lock(&vmap_area_lock);
|
||
/*
|
||
@@ -1758,11 +1764,11 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,
|
||
insert_vmalloc_vmlist(area);
|
||
|
||
/*
|
||
- * A ref_count = 3 is needed because the vm_struct and vmap_area
|
||
- * structures allocated in the __get_vm_area_node() function contain
|
||
- * references to the virtual address of the vmalloc'ed block.
|
||
+ * A ref_count = 2 is needed because vm_struct allocated in
|
||
+ * __get_vm_area_node() contains a reference to the virtual address of
|
||
+ * the vmalloc'ed block.
|
||
*/
|
||
- kmemleak_alloc(addr, real_size, 3, gfp_mask);
|
||
+ kmemleak_alloc(addr, real_size, 2, gfp_mask);
|
||
|
||
return addr;
|
||
|
||
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
||
index ff9a8b2..dd082d7 100644
|
||
--- a/mm/vmscan.c
|
||
+++ b/mm/vmscan.c
|
||
@@ -2940,7 +2940,10 @@ static int kswapd(void *p)
|
||
}
|
||
}
|
||
|
||
+ tsk->flags &= ~(PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD);
|
||
current->reclaim_state = NULL;
|
||
+ lockdep_clear_current_reclaim_state();
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
|
||
index 912613c..37c486c 100644
|
||
--- a/net/8021q/vlan_core.c
|
||
+++ b/net/8021q/vlan_core.c
|
||
@@ -96,8 +96,11 @@ EXPORT_SYMBOL(vlan_dev_vlan_id);
|
||
|
||
static struct sk_buff *vlan_reorder_header(struct sk_buff *skb)
|
||
{
|
||
- if (skb_cow(skb, skb_headroom(skb)) < 0)
|
||
+ if (skb_cow(skb, skb_headroom(skb)) < 0) {
|
||
+ kfree_skb(skb);
|
||
return NULL;
|
||
+ }
|
||
+
|
||
memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN);
|
||
skb->mac_header += VLAN_HLEN;
|
||
return skb;
|
||
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
|
||
index 8f45392..cf88c2f 100644
|
||
--- a/net/8021q/vlan_dev.c
|
||
+++ b/net/8021q/vlan_dev.c
|
||
@@ -525,6 +525,26 @@ static const struct header_ops vlan_header_ops = {
|
||
.parse = eth_header_parse,
|
||
};
|
||
|
||
+static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev,
|
||
+ unsigned short type,
|
||
+ const void *daddr, const void *saddr,
|
||
+ unsigned int len)
|
||
+{
|
||
+ struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
|
||
+ struct net_device *real_dev = vlan->real_dev;
|
||
+
|
||
+ if (saddr == NULL)
|
||
+ saddr = dev->dev_addr;
|
||
+
|
||
+ return dev_hard_header(skb, real_dev, type, daddr, saddr, len);
|
||
+}
|
||
+
|
||
+static const struct header_ops vlan_passthru_header_ops = {
|
||
+ .create = vlan_passthru_hard_header,
|
||
+ .rebuild = dev_rebuild_header,
|
||
+ .parse = eth_header_parse,
|
||
+};
|
||
+
|
||
static const struct net_device_ops vlan_netdev_ops;
|
||
|
||
static int vlan_dev_init(struct net_device *dev)
|
||
@@ -564,7 +584,7 @@ static int vlan_dev_init(struct net_device *dev)
|
||
|
||
dev->needed_headroom = real_dev->needed_headroom;
|
||
if (real_dev->features & NETIF_F_HW_VLAN_TX) {
|
||
- dev->header_ops = real_dev->header_ops;
|
||
+ dev->header_ops = &vlan_passthru_header_ops;
|
||
dev->hard_header_len = real_dev->hard_header_len;
|
||
} else {
|
||
dev->header_ops = &vlan_header_ops;
|
||
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
|
||
index 5071136..7f046b4 100644
|
||
--- a/net/8021q/vlan_netlink.c
|
||
+++ b/net/8021q/vlan_netlink.c
|
||
@@ -152,7 +152,7 @@ static size_t vlan_get_size(const struct net_device *dev)
|
||
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
|
||
|
||
return nla_total_size(2) + /* IFLA_VLAN_ID */
|
||
- sizeof(struct ifla_vlan_flags) + /* IFLA_VLAN_FLAGS */
|
||
+ nla_total_size(sizeof(struct ifla_vlan_flags)) + /* IFLA_VLAN_FLAGS */
|
||
vlan_qos_map_size(vlan->nr_ingress_mappings) +
|
||
vlan_qos_map_size(vlan->nr_egress_mappings);
|
||
}
|
||
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
|
||
index 052d343..9f4fcc5 100644
|
||
--- a/net/9p/trans_virtio.c
|
||
+++ b/net/9p/trans_virtio.c
|
||
@@ -39,6 +39,7 @@
|
||
#include <linux/inet.h>
|
||
#include <linux/idr.h>
|
||
#include <linux/file.h>
|
||
+#include <linux/highmem.h>
|
||
#include <linux/slab.h>
|
||
#include <net/9p/9p.h>
|
||
#include <linux/parser.h>
|
||
@@ -325,7 +326,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
|
||
int count = nr_pages;
|
||
while (nr_pages) {
|
||
s = rest_of_page(data);
|
||
- pages[index++] = virt_to_page(data);
|
||
+ pages[index++] = kmap_to_page(data);
|
||
data += s;
|
||
nr_pages--;
|
||
}
|
||
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
|
||
index bfa9ab9..79aaac2 100644
|
||
--- a/net/appletalk/ddp.c
|
||
+++ b/net/appletalk/ddp.c
|
||
@@ -1494,8 +1494,6 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
|
||
goto drop;
|
||
|
||
/* Queue packet (standard) */
|
||
- skb->sk = sock;
|
||
-
|
||
if (sock_queue_rcv_skb(sock, skb) < 0)
|
||
goto drop;
|
||
|
||
@@ -1649,7 +1647,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
|
||
if (!skb)
|
||
goto out;
|
||
|
||
- skb->sk = sk;
|
||
skb_reserve(skb, ddp_dl->header_length);
|
||
skb_reserve(skb, dev->hard_header_len);
|
||
skb->dev = dev;
|
||
@@ -1740,7 +1737,6 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
|
||
size_t size, int flags)
|
||
{
|
||
struct sock *sk = sock->sk;
|
||
- struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
|
||
struct ddpehdr *ddp;
|
||
int copied = 0;
|
||
int offset = 0;
|
||
@@ -1769,14 +1765,13 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
|
||
}
|
||
err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
|
||
|
||
- if (!err) {
|
||
- if (sat) {
|
||
- sat->sat_family = AF_APPLETALK;
|
||
- sat->sat_port = ddp->deh_sport;
|
||
- sat->sat_addr.s_node = ddp->deh_snode;
|
||
- sat->sat_addr.s_net = ddp->deh_snet;
|
||
- }
|
||
- msg->msg_namelen = sizeof(*sat);
|
||
+ if (!err && msg->msg_name) {
|
||
+ struct sockaddr_at *sat = msg->msg_name;
|
||
+ sat->sat_family = AF_APPLETALK;
|
||
+ sat->sat_port = ddp->deh_sport;
|
||
+ sat->sat_addr.s_node = ddp->deh_snode;
|
||
+ sat->sat_addr.s_net = ddp->deh_snet;
|
||
+ msg->msg_namelen = sizeof(*sat);
|
||
}
|
||
|
||
skb_free_datagram(sk, skb); /* Free the datagram. */
|
||
diff --git a/net/atm/common.c b/net/atm/common.c
|
||
index f0a9b7e..0c0ad93 100644
|
||
--- a/net/atm/common.c
|
||
+++ b/net/atm/common.c
|
||
@@ -520,8 +520,6 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
|
||
struct sk_buff *skb;
|
||
int copied, error = -EINVAL;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
if (sock->state != SS_CONNECTED)
|
||
return -ENOTCONN;
|
||
|
||
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
|
||
index 68b3992..ca1820c 100644
|
||
--- a/net/ax25/af_ax25.c
|
||
+++ b/net/ax25/af_ax25.c
|
||
@@ -1640,11 +1640,11 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
|
||
skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
|
||
|
||
- if (msg->msg_namelen != 0) {
|
||
- struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
|
||
+ if (msg->msg_name) {
|
||
ax25_digi digi;
|
||
ax25_address src;
|
||
const unsigned char *mac = skb_mac_header(skb);
|
||
+ struct sockaddr_ax25 *sax = msg->msg_name;
|
||
|
||
memset(sax, 0, sizeof(struct full_sockaddr_ax25));
|
||
ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL,
|
||
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
|
||
index 219df5c..7f260fc 100644
|
||
--- a/net/bluetooth/af_bluetooth.c
|
||
+++ b/net/bluetooth/af_bluetooth.c
|
||
@@ -349,8 +349,6 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (flags & MSG_OOB)
|
||
return -EOPNOTSUPP;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
BT_DBG("sk %p size %zu", sk, size);
|
||
|
||
lock_sock(sk);
|
||
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
|
||
index 550f601..95ccb21 100644
|
||
--- a/net/bluetooth/hci_sock.c
|
||
+++ b/net/bluetooth/hci_sock.c
|
||
@@ -499,8 +499,6 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (!skb)
|
||
return err;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
copied = skb->len;
|
||
if (len < copied) {
|
||
msg->msg_flags |= MSG_TRUNC;
|
||
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
|
||
index e1144e1..ff44f5f 100644
|
||
--- a/net/bridge/br_if.c
|
||
+++ b/net/bridge/br_if.c
|
||
@@ -170,6 +170,8 @@ void br_dev_delete(struct net_device *dev, struct list_head *head)
|
||
del_nbp(p);
|
||
}
|
||
|
||
+ br_fdb_delete_by_port(br, NULL, 1);
|
||
+
|
||
del_timer_sync(&br->gc_timer);
|
||
|
||
br_sysfs_delbr(br->dev);
|
||
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
|
||
index ca670d9..0b870d7 100644
|
||
--- a/net/bridge/br_multicast.c
|
||
+++ b/net/bridge/br_multicast.c
|
||
@@ -1138,6 +1138,12 @@ static int br_ip6_multicast_query(struct net_bridge *br,
|
||
|
||
br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
|
||
|
||
+ /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
|
||
+ if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
|
||
+ err = -EINVAL;
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
if (skb->len == sizeof(*mld)) {
|
||
if (!pskb_may_pull(skb, sizeof(*mld))) {
|
||
err = -EINVAL;
|
||
@@ -1744,7 +1750,7 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
|
||
u32 old;
|
||
struct net_bridge_mdb_htable *mdb;
|
||
|
||
- spin_lock(&br->multicast_lock);
|
||
+ spin_lock_bh(&br->multicast_lock);
|
||
if (!netif_running(br->dev))
|
||
goto unlock;
|
||
|
||
@@ -1776,7 +1782,7 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
|
||
}
|
||
|
||
unlock:
|
||
- spin_unlock(&br->multicast_lock);
|
||
+ spin_unlock_bh(&br->multicast_lock);
|
||
|
||
return err;
|
||
}
|
||
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
|
||
index f774796..2f100cc 100644
|
||
--- a/net/bridge/br_stp_if.c
|
||
+++ b/net/bridge/br_stp_if.c
|
||
@@ -134,7 +134,7 @@ static void br_stp_start(struct net_bridge *br)
|
||
|
||
if (br->bridge_forward_delay < BR_MIN_FORWARD_DELAY)
|
||
__br_set_forward_delay(br, BR_MIN_FORWARD_DELAY);
|
||
- else if (br->bridge_forward_delay < BR_MAX_FORWARD_DELAY)
|
||
+ else if (br->bridge_forward_delay > BR_MAX_FORWARD_DELAY)
|
||
__br_set_forward_delay(br, BR_MAX_FORWARD_DELAY);
|
||
|
||
if (r == 0) {
|
||
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
|
||
index 5fe2ff3..f381fa1 100644
|
||
--- a/net/bridge/netfilter/ebtables.c
|
||
+++ b/net/bridge/netfilter/ebtables.c
|
||
@@ -1044,10 +1044,9 @@ static int do_replace_finish(struct net *net, struct ebt_replace *repl,
|
||
if (repl->num_counters &&
|
||
copy_to_user(repl->counters, counterstmp,
|
||
repl->num_counters * sizeof(struct ebt_counter))) {
|
||
- ret = -EFAULT;
|
||
+ /* Silent error, can't fail, new table is already in place */
|
||
+ net_warn_ratelimited("ebtables: counters copy to user failed while replacing table\n");
|
||
}
|
||
- else
|
||
- ret = 0;
|
||
|
||
/* decrease module count and free resources */
|
||
EBT_ENTRY_ITERATE(table->entries, table->entries_size,
|
||
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
|
||
index 87e73b0..cce77b2 100644
|
||
--- a/net/caif/caif_socket.c
|
||
+++ b/net/caif/caif_socket.c
|
||
@@ -287,8 +287,6 @@ static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (m->msg_flags&MSG_OOB)
|
||
goto read_error;
|
||
|
||
- m->msg_namelen = 0;
|
||
-
|
||
skb = skb_recv_datagram(sk, flags, 0 , &ret);
|
||
if (!skb)
|
||
goto read_error;
|
||
@@ -362,8 +360,6 @@ static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (flags&MSG_OOB)
|
||
goto out;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
/*
|
||
* Lock the socket to prevent queue disordering
|
||
* while sleeps in memcpy_tomsg
|
||
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
|
||
index 96238ba..de6662b 100644
|
||
--- a/net/ceph/auth_x.c
|
||
+++ b/net/ceph/auth_x.c
|
||
@@ -13,8 +13,6 @@
|
||
#include "auth_x.h"
|
||
#include "auth_x_protocol.h"
|
||
|
||
-#define TEMP_TICKET_BUF_LEN 256
|
||
-
|
||
static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed);
|
||
|
||
static int ceph_x_is_authenticated(struct ceph_auth_client *ac)
|
||
@@ -64,7 +62,7 @@ static int ceph_x_encrypt(struct ceph_crypto_key *secret,
|
||
}
|
||
|
||
static int ceph_x_decrypt(struct ceph_crypto_key *secret,
|
||
- void **p, void *end, void *obuf, size_t olen)
|
||
+ void **p, void *end, void **obuf, size_t olen)
|
||
{
|
||
struct ceph_x_encrypt_header head;
|
||
size_t head_len = sizeof(head);
|
||
@@ -75,8 +73,14 @@ static int ceph_x_decrypt(struct ceph_crypto_key *secret,
|
||
return -EINVAL;
|
||
|
||
dout("ceph_x_decrypt len %d\n", len);
|
||
- ret = ceph_decrypt2(secret, &head, &head_len, obuf, &olen,
|
||
- *p, len);
|
||
+ if (*obuf == NULL) {
|
||
+ *obuf = kmalloc(len, GFP_NOFS);
|
||
+ if (!*obuf)
|
||
+ return -ENOMEM;
|
||
+ olen = len;
|
||
+ }
|
||
+
|
||
+ ret = ceph_decrypt2(secret, &head, &head_len, *obuf, &olen, *p, len);
|
||
if (ret)
|
||
return ret;
|
||
if (head.struct_v != 1 || le64_to_cpu(head.magic) != CEPHX_ENC_MAGIC)
|
||
@@ -129,139 +133,120 @@ static void remove_ticket_handler(struct ceph_auth_client *ac,
|
||
kfree(th);
|
||
}
|
||
|
||
-static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
|
||
- struct ceph_crypto_key *secret,
|
||
- void *buf, void *end)
|
||
+static int process_one_ticket(struct ceph_auth_client *ac,
|
||
+ struct ceph_crypto_key *secret,
|
||
+ void **p, void *end)
|
||
{
|
||
struct ceph_x_info *xi = ac->private;
|
||
- int num;
|
||
- void *p = buf;
|
||
+ int type;
|
||
+ u8 tkt_struct_v, blob_struct_v;
|
||
+ struct ceph_x_ticket_handler *th;
|
||
+ void *dbuf = NULL;
|
||
+ void *dp, *dend;
|
||
+ int dlen;
|
||
+ char is_enc;
|
||
+ struct timespec validity;
|
||
+ struct ceph_crypto_key old_key;
|
||
+ void *ticket_buf = NULL;
|
||
+ void *tp, *tpend;
|
||
+ struct ceph_timespec new_validity;
|
||
+ struct ceph_crypto_key new_session_key;
|
||
+ struct ceph_buffer *new_ticket_blob;
|
||
+ unsigned long new_expires, new_renew_after;
|
||
+ u64 new_secret_id;
|
||
int ret;
|
||
- char *dbuf;
|
||
- char *ticket_buf;
|
||
- u8 reply_struct_v;
|
||
|
||
- dbuf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS);
|
||
- if (!dbuf)
|
||
- return -ENOMEM;
|
||
+ ceph_decode_need(p, end, sizeof(u32) + 1, bad);
|
||
|
||
- ret = -ENOMEM;
|
||
- ticket_buf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS);
|
||
- if (!ticket_buf)
|
||
- goto out_dbuf;
|
||
+ type = ceph_decode_32(p);
|
||
+ dout(" ticket type %d %s\n", type, ceph_entity_type_name(type));
|
||
|
||
- ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
|
||
- reply_struct_v = ceph_decode_8(&p);
|
||
- if (reply_struct_v != 1)
|
||
+ tkt_struct_v = ceph_decode_8(p);
|
||
+ if (tkt_struct_v != 1)
|
||
goto bad;
|
||
- num = ceph_decode_32(&p);
|
||
- dout("%d tickets\n", num);
|
||
- while (num--) {
|
||
- int type;
|
||
- u8 tkt_struct_v, blob_struct_v;
|
||
- struct ceph_x_ticket_handler *th;
|
||
- void *dp, *dend;
|
||
- int dlen;
|
||
- char is_enc;
|
||
- struct timespec validity;
|
||
- struct ceph_crypto_key old_key;
|
||
- void *tp, *tpend;
|
||
- struct ceph_timespec new_validity;
|
||
- struct ceph_crypto_key new_session_key;
|
||
- struct ceph_buffer *new_ticket_blob;
|
||
- unsigned long new_expires, new_renew_after;
|
||
- u64 new_secret_id;
|
||
-
|
||
- ceph_decode_need(&p, end, sizeof(u32) + 1, bad);
|
||
-
|
||
- type = ceph_decode_32(&p);
|
||
- dout(" ticket type %d %s\n", type, ceph_entity_type_name(type));
|
||
-
|
||
- tkt_struct_v = ceph_decode_8(&p);
|
||
- if (tkt_struct_v != 1)
|
||
- goto bad;
|
||
-
|
||
- th = get_ticket_handler(ac, type);
|
||
- if (IS_ERR(th)) {
|
||
- ret = PTR_ERR(th);
|
||
- goto out;
|
||
- }
|
||
|
||
- /* blob for me */
|
||
- dlen = ceph_x_decrypt(secret, &p, end, dbuf,
|
||
- TEMP_TICKET_BUF_LEN);
|
||
- if (dlen <= 0) {
|
||
- ret = dlen;
|
||
- goto out;
|
||
- }
|
||
- dout(" decrypted %d bytes\n", dlen);
|
||
- dend = dbuf + dlen;
|
||
- dp = dbuf;
|
||
+ th = get_ticket_handler(ac, type);
|
||
+ if (IS_ERR(th)) {
|
||
+ ret = PTR_ERR(th);
|
||
+ goto out;
|
||
+ }
|
||
|
||
- tkt_struct_v = ceph_decode_8(&dp);
|
||
- if (tkt_struct_v != 1)
|
||
- goto bad;
|
||
+ /* blob for me */
|
||
+ dlen = ceph_x_decrypt(secret, p, end, &dbuf, 0);
|
||
+ if (dlen <= 0) {
|
||
+ ret = dlen;
|
||
+ goto out;
|
||
+ }
|
||
+ dout(" decrypted %d bytes\n", dlen);
|
||
+ dp = dbuf;
|
||
+ dend = dp + dlen;
|
||
|
||
- memcpy(&old_key, &th->session_key, sizeof(old_key));
|
||
- ret = ceph_crypto_key_decode(&new_session_key, &dp, dend);
|
||
- if (ret)
|
||
- goto out;
|
||
+ tkt_struct_v = ceph_decode_8(&dp);
|
||
+ if (tkt_struct_v != 1)
|
||
+ goto bad;
|
||
|
||
- ceph_decode_copy(&dp, &new_validity, sizeof(new_validity));
|
||
- ceph_decode_timespec(&validity, &new_validity);
|
||
- new_expires = get_seconds() + validity.tv_sec;
|
||
- new_renew_after = new_expires - (validity.tv_sec / 4);
|
||
- dout(" expires=%lu renew_after=%lu\n", new_expires,
|
||
- new_renew_after);
|
||
+ memcpy(&old_key, &th->session_key, sizeof(old_key));
|
||
+ ret = ceph_crypto_key_decode(&new_session_key, &dp, dend);
|
||
+ if (ret)
|
||
+ goto out;
|
||
|
||
- /* ticket blob for service */
|
||
- ceph_decode_8_safe(&p, end, is_enc, bad);
|
||
- tp = ticket_buf;
|
||
- if (is_enc) {
|
||
- /* encrypted */
|
||
- dout(" encrypted ticket\n");
|
||
- dlen = ceph_x_decrypt(&old_key, &p, end, ticket_buf,
|
||
- TEMP_TICKET_BUF_LEN);
|
||
- if (dlen < 0) {
|
||
- ret = dlen;
|
||
- goto out;
|
||
- }
|
||
- dlen = ceph_decode_32(&tp);
|
||
- } else {
|
||
- /* unencrypted */
|
||
- ceph_decode_32_safe(&p, end, dlen, bad);
|
||
- ceph_decode_need(&p, end, dlen, bad);
|
||
- ceph_decode_copy(&p, ticket_buf, dlen);
|
||
+ ceph_decode_copy(&dp, &new_validity, sizeof(new_validity));
|
||
+ ceph_decode_timespec(&validity, &new_validity);
|
||
+ new_expires = get_seconds() + validity.tv_sec;
|
||
+ new_renew_after = new_expires - (validity.tv_sec / 4);
|
||
+ dout(" expires=%lu renew_after=%lu\n", new_expires,
|
||
+ new_renew_after);
|
||
+
|
||
+ /* ticket blob for service */
|
||
+ ceph_decode_8_safe(p, end, is_enc, bad);
|
||
+ if (is_enc) {
|
||
+ /* encrypted */
|
||
+ dout(" encrypted ticket\n");
|
||
+ dlen = ceph_x_decrypt(&old_key, p, end, &ticket_buf, 0);
|
||
+ if (dlen < 0) {
|
||
+ ret = dlen;
|
||
+ goto out;
|
||
}
|
||
- tpend = tp + dlen;
|
||
- dout(" ticket blob is %d bytes\n", dlen);
|
||
- ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad);
|
||
- blob_struct_v = ceph_decode_8(&tp);
|
||
- new_secret_id = ceph_decode_64(&tp);
|
||
- ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend);
|
||
- if (ret)
|
||
+ tp = ticket_buf;
|
||
+ dlen = ceph_decode_32(&tp);
|
||
+ } else {
|
||
+ /* unencrypted */
|
||
+ ceph_decode_32_safe(p, end, dlen, bad);
|
||
+ ticket_buf = kmalloc(dlen, GFP_NOFS);
|
||
+ if (!ticket_buf) {
|
||
+ ret = -ENOMEM;
|
||
goto out;
|
||
-
|
||
- /* all is well, update our ticket */
|
||
- ceph_crypto_key_destroy(&th->session_key);
|
||
- if (th->ticket_blob)
|
||
- ceph_buffer_put(th->ticket_blob);
|
||
- th->session_key = new_session_key;
|
||
- th->ticket_blob = new_ticket_blob;
|
||
- th->validity = new_validity;
|
||
- th->secret_id = new_secret_id;
|
||
- th->expires = new_expires;
|
||
- th->renew_after = new_renew_after;
|
||
- dout(" got ticket service %d (%s) secret_id %lld len %d\n",
|
||
- type, ceph_entity_type_name(type), th->secret_id,
|
||
- (int)th->ticket_blob->vec.iov_len);
|
||
- xi->have_keys |= th->service;
|
||
+ }
|
||
+ tp = ticket_buf;
|
||
+ ceph_decode_need(p, end, dlen, bad);
|
||
+ ceph_decode_copy(p, ticket_buf, dlen);
|
||
}
|
||
+ tpend = tp + dlen;
|
||
+ dout(" ticket blob is %d bytes\n", dlen);
|
||
+ ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad);
|
||
+ blob_struct_v = ceph_decode_8(&tp);
|
||
+ new_secret_id = ceph_decode_64(&tp);
|
||
+ ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend);
|
||
+ if (ret)
|
||
+ goto out;
|
||
+
|
||
+ /* all is well, update our ticket */
|
||
+ ceph_crypto_key_destroy(&th->session_key);
|
||
+ if (th->ticket_blob)
|
||
+ ceph_buffer_put(th->ticket_blob);
|
||
+ th->session_key = new_session_key;
|
||
+ th->ticket_blob = new_ticket_blob;
|
||
+ th->validity = new_validity;
|
||
+ th->secret_id = new_secret_id;
|
||
+ th->expires = new_expires;
|
||
+ th->renew_after = new_renew_after;
|
||
+ dout(" got ticket service %d (%s) secret_id %lld len %d\n",
|
||
+ type, ceph_entity_type_name(type), th->secret_id,
|
||
+ (int)th->ticket_blob->vec.iov_len);
|
||
+ xi->have_keys |= th->service;
|
||
|
||
- ret = 0;
|
||
out:
|
||
kfree(ticket_buf);
|
||
-out_dbuf:
|
||
kfree(dbuf);
|
||
return ret;
|
||
|
||
@@ -270,6 +255,34 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
|
||
goto out;
|
||
}
|
||
|
||
+static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
|
||
+ struct ceph_crypto_key *secret,
|
||
+ void *buf, void *end)
|
||
+{
|
||
+ void *p = buf;
|
||
+ u8 reply_struct_v;
|
||
+ u32 num;
|
||
+ int ret;
|
||
+
|
||
+ ceph_decode_8_safe(&p, end, reply_struct_v, bad);
|
||
+ if (reply_struct_v != 1)
|
||
+ return -EINVAL;
|
||
+
|
||
+ ceph_decode_32_safe(&p, end, num, bad);
|
||
+ dout("%d tickets\n", num);
|
||
+
|
||
+ while (num--) {
|
||
+ ret = process_one_ticket(ac, secret, &p, end);
|
||
+ if (ret)
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+
|
||
+bad:
|
||
+ return -EINVAL;
|
||
+}
|
||
+
|
||
static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
|
||
struct ceph_x_ticket_handler *th,
|
||
struct ceph_x_authorizer *au)
|
||
@@ -583,13 +596,14 @@ static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac,
|
||
struct ceph_x_ticket_handler *th;
|
||
int ret = 0;
|
||
struct ceph_x_authorize_reply reply;
|
||
+ void *preply = &reply;
|
||
void *p = au->reply_buf;
|
||
void *end = p + sizeof(au->reply_buf);
|
||
|
||
th = get_ticket_handler(ac, au->service);
|
||
if (IS_ERR(th))
|
||
return PTR_ERR(th);
|
||
- ret = ceph_x_decrypt(&th->session_key, &p, end, &reply, sizeof(reply));
|
||
+ ret = ceph_x_decrypt(&th->session_key, &p, end, &preply, sizeof(reply));
|
||
if (ret < 0)
|
||
return ret;
|
||
if (ret != sizeof(reply))
|
||
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
|
||
index 6765da3..bc293c0 100644
|
||
--- a/net/ceph/mon_client.c
|
||
+++ b/net/ceph/mon_client.c
|
||
@@ -1042,7 +1042,15 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
|
||
if (!m) {
|
||
pr_info("alloc_msg unknown type %d\n", type);
|
||
*skip = 1;
|
||
+ } else if (front_len > m->front_max) {
|
||
+ pr_warning("mon_alloc_msg front %d > prealloc %d (%u#%llu)\n",
|
||
+ front_len, m->front_max,
|
||
+ (unsigned int)con->peer_name.type,
|
||
+ le64_to_cpu(con->peer_name.num));
|
||
+ ceph_msg_put(m);
|
||
+ m = ceph_msg_new(type, front_len, GFP_NOFS, false);
|
||
}
|
||
+
|
||
return m;
|
||
}
|
||
|
||
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
|
||
index 8e3aa4d..835d81b 100644
|
||
--- a/net/ceph/osd_client.c
|
||
+++ b/net/ceph/osd_client.c
|
||
@@ -1269,14 +1269,17 @@ static void reset_changed_osds(struct ceph_osd_client *osdc)
|
||
*
|
||
* Caller should hold map_sem for read.
|
||
*/
|
||
-static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
|
||
+static void kick_requests(struct ceph_osd_client *osdc, bool force_resend,
|
||
+ bool force_resend_writes)
|
||
{
|
||
struct ceph_osd_request *req, *nreq;
|
||
struct rb_node *p;
|
||
int needmap = 0;
|
||
int err;
|
||
+ bool force_resend_req;
|
||
|
||
- dout("kick_requests %s\n", force_resend ? " (force resend)" : "");
|
||
+ dout("kick_requests %s %s\n", force_resend ? " (force resend)" : "",
|
||
+ force_resend_writes ? " (force resend writes)" : "");
|
||
mutex_lock(&osdc->request_mutex);
|
||
for (p = rb_first(&osdc->requests); p; ) {
|
||
req = rb_entry(p, struct ceph_osd_request, r_node);
|
||
@@ -1299,7 +1302,10 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
|
||
continue;
|
||
}
|
||
|
||
- err = __map_request(osdc, req, force_resend);
|
||
+ force_resend_req = force_resend ||
|
||
+ (force_resend_writes &&
|
||
+ req->r_flags & CEPH_OSD_FLAG_WRITE);
|
||
+ err = __map_request(osdc, req, force_resend_req);
|
||
if (err < 0)
|
||
continue; /* error */
|
||
if (req->r_osd == NULL) {
|
||
@@ -1319,7 +1325,8 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
|
||
r_linger_item) {
|
||
dout("linger req=%p req->r_osd=%p\n", req, req->r_osd);
|
||
|
||
- err = __map_request(osdc, req, force_resend);
|
||
+ err = __map_request(osdc, req,
|
||
+ force_resend || force_resend_writes);
|
||
dout("__map_request returned %d\n", err);
|
||
if (err == 0)
|
||
continue; /* no change and no osd was specified */
|
||
@@ -1361,6 +1368,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
|
||
struct ceph_osdmap *newmap = NULL, *oldmap;
|
||
int err;
|
||
struct ceph_fsid fsid;
|
||
+ bool was_full;
|
||
|
||
dout("handle_map have %u\n", osdc->osdmap ? osdc->osdmap->epoch : 0);
|
||
p = msg->front.iov_base;
|
||
@@ -1374,6 +1382,8 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
|
||
|
||
down_write(&osdc->map_sem);
|
||
|
||
+ was_full = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL);
|
||
+
|
||
/* incremental maps */
|
||
ceph_decode_32_safe(&p, end, nr_maps, bad);
|
||
dout(" %d inc maps\n", nr_maps);
|
||
@@ -1398,7 +1408,10 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
|
||
ceph_osdmap_destroy(osdc->osdmap);
|
||
osdc->osdmap = newmap;
|
||
}
|
||
- kick_requests(osdc, 0);
|
||
+ was_full = was_full ||
|
||
+ ceph_osdmap_flag(osdc->osdmap,
|
||
+ CEPH_OSDMAP_FULL);
|
||
+ kick_requests(osdc, 0, was_full);
|
||
} else {
|
||
dout("ignoring incremental map %u len %d\n",
|
||
epoch, maplen);
|
||
@@ -1441,7 +1454,10 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
|
||
skipped_map = 1;
|
||
ceph_osdmap_destroy(oldmap);
|
||
}
|
||
- kick_requests(osdc, skipped_map);
|
||
+ was_full = was_full ||
|
||
+ ceph_osdmap_flag(osdc->osdmap,
|
||
+ CEPH_OSDMAP_FULL);
|
||
+ kick_requests(osdc, skipped_map, was_full);
|
||
}
|
||
p += maplen;
|
||
nr_maps--;
|
||
@@ -1721,6 +1737,8 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
|
||
dout("osdc_start_request failed map, "
|
||
" will retry %lld\n", req->r_tid);
|
||
rc = 0;
|
||
+ } else {
|
||
+ __unregister_request(osdc, req);
|
||
}
|
||
goto out_unlock;
|
||
}
|
||
diff --git a/net/compat.c b/net/compat.c
|
||
index 93248dc..f7f82ba 100644
|
||
--- a/net/compat.c
|
||
+++ b/net/compat.c
|
||
@@ -71,6 +71,8 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg)
|
||
__get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
|
||
__get_user(kmsg->msg_flags, &umsg->msg_flags))
|
||
return -EFAULT;
|
||
+ if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
|
||
+ kmsg->msg_namelen = sizeof(struct sockaddr_storage);
|
||
kmsg->msg_name = compat_ptr(tmp1);
|
||
kmsg->msg_iov = compat_ptr(tmp2);
|
||
kmsg->msg_control = compat_ptr(tmp3);
|
||
@@ -83,7 +85,7 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
|
||
{
|
||
int tot_len;
|
||
|
||
- if (kern_msg->msg_namelen) {
|
||
+ if (kern_msg->msg_name && kern_msg->msg_namelen) {
|
||
if (mode == VERIFY_READ) {
|
||
int err = move_addr_to_kernel(kern_msg->msg_name,
|
||
kern_msg->msg_namelen,
|
||
@@ -92,8 +94,10 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
|
||
return err;
|
||
}
|
||
kern_msg->msg_name = kern_address;
|
||
- } else
|
||
+ } else {
|
||
kern_msg->msg_name = NULL;
|
||
+ kern_msg->msg_namelen = 0;
|
||
+ }
|
||
|
||
tot_len = iov_from_user_compat_to_kern(kern_iov,
|
||
(struct compat_iovec __user *)kern_msg->msg_iov,
|
||
@@ -778,21 +782,16 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
|
||
if (flags & MSG_CMSG_COMPAT)
|
||
return -EINVAL;
|
||
|
||
- if (COMPAT_USE_64BIT_TIME)
|
||
- return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
|
||
- flags | MSG_CMSG_COMPAT,
|
||
- (struct timespec *) timeout);
|
||
-
|
||
if (timeout == NULL)
|
||
return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
|
||
flags | MSG_CMSG_COMPAT, NULL);
|
||
|
||
- if (get_compat_timespec(&ktspec, timeout))
|
||
+ if (compat_get_timespec(&ktspec, timeout))
|
||
return -EFAULT;
|
||
|
||
datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
|
||
flags | MSG_CMSG_COMPAT, &ktspec);
|
||
- if (datagrams > 0 && put_compat_timespec(&ktspec, timeout))
|
||
+ if (datagrams > 0 && compat_put_timespec(&ktspec, timeout))
|
||
datagrams = -EFAULT;
|
||
|
||
return datagrams;
|
||
diff --git a/net/core/dev.c b/net/core/dev.c
|
||
index 937f7136..634f56d 100644
|
||
--- a/net/core/dev.c
|
||
+++ b/net/core/dev.c
|
||
@@ -3574,6 +3574,7 @@ static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
|
||
skb->vlan_tci = 0;
|
||
skb->dev = napi->dev;
|
||
skb->skb_iif = 0;
|
||
+ skb->truesize = SKB_TRUESIZE(skb_end_offset(skb));
|
||
|
||
napi->skb = skb;
|
||
}
|
||
@@ -4443,7 +4444,7 @@ static void dev_change_rx_flags(struct net_device *dev, int flags)
|
||
{
|
||
const struct net_device_ops *ops = dev->netdev_ops;
|
||
|
||
- if ((dev->flags & IFF_UP) && ops->ndo_change_rx_flags)
|
||
+ if (ops->ndo_change_rx_flags)
|
||
ops->ndo_change_rx_flags(dev, flags);
|
||
}
|
||
|
||
@@ -5545,13 +5546,8 @@ int register_netdevice(struct net_device *dev)
|
||
dev->features |= NETIF_F_SOFT_FEATURES;
|
||
dev->wanted_features = dev->features & dev->hw_features;
|
||
|
||
- /* Turn on no cache copy if HW is doing checksum */
|
||
if (!(dev->flags & IFF_LOOPBACK)) {
|
||
dev->hw_features |= NETIF_F_NOCACHE_COPY;
|
||
- if (dev->features & NETIF_F_ALL_CSUM) {
|
||
- dev->wanted_features |= NETIF_F_NOCACHE_COPY;
|
||
- dev->features |= NETIF_F_NOCACHE_COPY;
|
||
- }
|
||
}
|
||
|
||
/* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
|
||
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
|
||
index b856f87..1d9a529 100644
|
||
--- a/net/core/drop_monitor.c
|
||
+++ b/net/core/drop_monitor.c
|
||
@@ -61,7 +61,6 @@ static struct genl_family net_drop_monitor_family = {
|
||
.hdrsize = 0,
|
||
.name = "NET_DM",
|
||
.version = 2,
|
||
- .maxattr = NET_DM_CMD_MAX,
|
||
};
|
||
|
||
static DEFINE_PER_CPU(struct per_cpu_dm_data, dm_cpu_data);
|
||
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
|
||
index b17985f..3e4ca98 100644
|
||
--- a/net/core/fib_rules.c
|
||
+++ b/net/core/fib_rules.c
|
||
@@ -775,6 +775,13 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
|
||
attach_rules(&ops->rules_list, dev);
|
||
break;
|
||
|
||
+ case NETDEV_CHANGENAME:
|
||
+ list_for_each_entry(ops, &net->rules_ops, list) {
|
||
+ detach_rules(&ops->rules_list, dev);
|
||
+ attach_rules(&ops->rules_list, dev);
|
||
+ }
|
||
+ break;
|
||
+
|
||
case NETDEV_UNREGISTER:
|
||
list_for_each_entry(ops, &net->rules_ops, list)
|
||
detach_rules(&ops->rules_list, dev);
|
||
diff --git a/net/core/filter.c b/net/core/filter.c
|
||
index 491e2e1..21237ce 100644
|
||
--- a/net/core/filter.c
|
||
+++ b/net/core/filter.c
|
||
@@ -323,6 +323,8 @@ unsigned int sk_run_filter(const struct sk_buff *skb,
|
||
|
||
if (skb_is_nonlinear(skb))
|
||
return 0;
|
||
+ if (skb->len < sizeof(struct nlattr))
|
||
+ return 0;
|
||
if (A > skb->len - sizeof(struct nlattr))
|
||
return 0;
|
||
|
||
@@ -339,11 +341,13 @@ unsigned int sk_run_filter(const struct sk_buff *skb,
|
||
|
||
if (skb_is_nonlinear(skb))
|
||
return 0;
|
||
+ if (skb->len < sizeof(struct nlattr))
|
||
+ return 0;
|
||
if (A > skb->len - sizeof(struct nlattr))
|
||
return 0;
|
||
|
||
nla = (struct nlattr *)&skb->data[A];
|
||
- if (nla->nla_len > A - skb->len)
|
||
+ if (nla->nla_len > skb->len - A)
|
||
return 0;
|
||
|
||
nla = nla_find_nested(nla, X);
|
||
diff --git a/net/core/iovec.c b/net/core/iovec.c
|
||
index 7e7aeb0..d1628b7 100644
|
||
--- a/net/core/iovec.c
|
||
+++ b/net/core/iovec.c
|
||
@@ -39,7 +39,7 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a
|
||
{
|
||
int size, ct, err;
|
||
|
||
- if (m->msg_namelen) {
|
||
+ if (m->msg_name && m->msg_namelen) {
|
||
if (mode == VERIFY_READ) {
|
||
void __user *namep;
|
||
namep = (void __user __force *) m->msg_name;
|
||
@@ -51,6 +51,7 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a
|
||
m->msg_name = address;
|
||
} else {
|
||
m->msg_name = NULL;
|
||
+ m->msg_namelen = 0;
|
||
}
|
||
|
||
size = m->msg_iovlen * sizeof(struct iovec);
|
||
@@ -156,6 +157,10 @@ EXPORT_SYMBOL(memcpy_fromiovec);
|
||
int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
|
||
int offset, int len)
|
||
{
|
||
+ /* No data? Done! */
|
||
+ if (len == 0)
|
||
+ return 0;
|
||
+
|
||
/* Skip over the finished iovecs */
|
||
while (offset >= iov->iov_len) {
|
||
offset -= iov->iov_len;
|
||
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
|
||
index 35788d4..83d5a6a 100644
|
||
--- a/net/core/pktgen.c
|
||
+++ b/net/core/pktgen.c
|
||
@@ -2507,6 +2507,8 @@ static int process_ipsec(struct pktgen_dev *pkt_dev,
|
||
if (x) {
|
||
int ret;
|
||
__u8 *eth;
|
||
+ struct iphdr *iph;
|
||
+
|
||
nhead = x->props.header_len - skb_headroom(skb);
|
||
if (nhead > 0) {
|
||
ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
|
||
@@ -2528,6 +2530,11 @@ static int process_ipsec(struct pktgen_dev *pkt_dev,
|
||
eth = (__u8 *) skb_push(skb, ETH_HLEN);
|
||
memcpy(eth, pkt_dev->hh, 12);
|
||
*(u16 *) ð[12] = protocol;
|
||
+
|
||
+ /* Update IPv4 header len as well as checksum value */
|
||
+ iph = ip_hdr(skb);
|
||
+ iph->tot_len = htons(skb->len - ETH_HLEN);
|
||
+ ip_send_check(iph);
|
||
}
|
||
}
|
||
return 1;
|
||
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
|
||
index ba4f4a9..323733e 100644
|
||
--- a/net/core/rtnetlink.c
|
||
+++ b/net/core/rtnetlink.c
|
||
@@ -748,7 +748,8 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev,
|
||
return 0;
|
||
}
|
||
|
||
-static size_t rtnl_port_size(const struct net_device *dev)
|
||
+static size_t rtnl_port_size(const struct net_device *dev,
|
||
+ u32 ext_filter_mask)
|
||
{
|
||
size_t port_size = nla_total_size(4) /* PORT_VF */
|
||
+ nla_total_size(PORT_PROFILE_MAX) /* PORT_PROFILE */
|
||
@@ -764,7 +765,8 @@ static size_t rtnl_port_size(const struct net_device *dev)
|
||
size_t port_self_size = nla_total_size(sizeof(struct nlattr))
|
||
+ port_size;
|
||
|
||
- if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent)
|
||
+ if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent ||
|
||
+ !(ext_filter_mask & RTEXT_FILTER_VF))
|
||
return 0;
|
||
if (dev_num_vf(dev->dev.parent))
|
||
return port_self_size + vf_ports_size +
|
||
@@ -795,7 +797,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
|
||
+ nla_total_size(ext_filter_mask
|
||
& RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */
|
||
+ rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */
|
||
- + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
|
||
+ + rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
|
||
+ rtnl_link_get_size(dev) /* IFLA_LINKINFO */
|
||
+ rtnl_link_get_af_size(dev); /* IFLA_AF_SPEC */
|
||
}
|
||
@@ -855,11 +857,13 @@ static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev)
|
||
return 0;
|
||
}
|
||
|
||
-static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev)
|
||
+static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev,
|
||
+ u32 ext_filter_mask)
|
||
{
|
||
int err;
|
||
|
||
- if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent)
|
||
+ if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent ||
|
||
+ !(ext_filter_mask & RTEXT_FILTER_VF))
|
||
return 0;
|
||
|
||
err = rtnl_port_self_fill(skb, dev);
|
||
@@ -1006,7 +1010,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||
nla_nest_end(skb, vfinfo);
|
||
}
|
||
|
||
- if (rtnl_port_fill(skb, dev))
|
||
+ if (rtnl_port_fill(skb, dev, ext_filter_mask))
|
||
goto nla_put_failure;
|
||
|
||
if (dev->rtnl_link_ops) {
|
||
@@ -1061,6 +1065,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
||
struct hlist_node *node;
|
||
struct nlattr *tb[IFLA_MAX+1];
|
||
u32 ext_filter_mask = 0;
|
||
+ int err;
|
||
|
||
s_h = cb->args[0];
|
||
s_idx = cb->args[1];
|
||
@@ -1081,11 +1086,17 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
||
hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
|
||
if (idx < s_idx)
|
||
goto cont;
|
||
- if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
|
||
- NETLINK_CB(cb->skb).pid,
|
||
- cb->nlh->nlmsg_seq, 0,
|
||
- NLM_F_MULTI,
|
||
- ext_filter_mask) <= 0)
|
||
+ err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
|
||
+ NETLINK_CB(cb->skb).pid,
|
||
+ cb->nlh->nlmsg_seq, 0,
|
||
+ NLM_F_MULTI,
|
||
+ ext_filter_mask);
|
||
+ /* If we ran out of room on the first message,
|
||
+ * we're in trouble
|
||
+ */
|
||
+ WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
|
||
+
|
||
+ if (err <= 0)
|
||
goto out;
|
||
|
||
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
|
||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
|
||
index 4ca933f..771e325 100644
|
||
--- a/net/core/skbuff.c
|
||
+++ b/net/core/skbuff.c
|
||
@@ -45,6 +45,8 @@
|
||
#include <linux/in.h>
|
||
#include <linux/inet.h>
|
||
#include <linux/slab.h>
|
||
+#include <linux/tcp.h>
|
||
+#include <linux/udp.h>
|
||
#include <linux/netdevice.h>
|
||
#ifdef CONFIG_NET_CLS_ACT
|
||
#include <net/pkt_sched.h>
|
||
@@ -731,7 +733,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
|
||
skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
|
||
return 0;
|
||
}
|
||
-
|
||
+EXPORT_SYMBOL_GPL(skb_copy_ubufs);
|
||
|
||
/**
|
||
* skb_clone - duplicate an sk_buff
|
||
@@ -819,7 +821,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
|
||
struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
|
||
{
|
||
int headerlen = skb_headroom(skb);
|
||
- unsigned int size = (skb_end_pointer(skb) - skb->head) + skb->data_len;
|
||
+ unsigned int size = skb_end_offset(skb) + skb->data_len;
|
||
struct sk_buff *n = alloc_skb(size, gfp_mask);
|
||
|
||
if (!n)
|
||
@@ -920,7 +922,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
|
||
{
|
||
int i;
|
||
u8 *data;
|
||
- int size = nhead + (skb_end_pointer(skb) - skb->head) + ntail;
|
||
+ int size = nhead + skb_end_offset(skb) + ntail;
|
||
long off;
|
||
bool fastpath;
|
||
|
||
@@ -2719,14 +2721,13 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
|
||
if (unlikely(!nskb))
|
||
goto err;
|
||
|
||
- hsize = skb_end_pointer(nskb) - nskb->head;
|
||
+ hsize = skb_end_offset(nskb);
|
||
if (skb_cow_head(nskb, doffset + headroom)) {
|
||
kfree_skb(nskb);
|
||
goto err;
|
||
}
|
||
|
||
- nskb->truesize += skb_end_pointer(nskb) - nskb->head -
|
||
- hsize;
|
||
+ nskb->truesize += skb_end_offset(nskb) - hsize;
|
||
skb_release_head_state(nskb);
|
||
__skb_push(nskb, doffset);
|
||
} else {
|
||
@@ -2747,7 +2748,6 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
|
||
tail = nskb;
|
||
|
||
__copy_skb_header(nskb, skb);
|
||
- nskb->mac_len = skb->mac_len;
|
||
|
||
/* nskb and skb might have different headroom */
|
||
if (nskb->ip_summed == CHECKSUM_PARTIAL)
|
||
@@ -2757,6 +2757,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
|
||
skb_set_network_header(nskb, skb->mac_len);
|
||
nskb->transport_header = (nskb->network_header +
|
||
skb_network_header_len(skb));
|
||
+ skb_reset_mac_len(nskb);
|
||
skb_copy_from_linear_data(skb, nskb->data, doffset);
|
||
|
||
if (fskb != skb_shinfo(skb)->frag_list)
|
||
@@ -2776,6 +2777,9 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
|
||
skb_put(nskb, hsize), hsize);
|
||
|
||
while (pos < offset + len && i < nfrags) {
|
||
+ if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
|
||
+ goto err;
|
||
+
|
||
*frag = skb_shinfo(skb)->frags[i];
|
||
__skb_frag_ref(frag);
|
||
size = skb_frag_size(frag);
|
||
@@ -3281,3 +3285,28 @@ void __skb_warn_lro_forwarding(const struct sk_buff *skb)
|
||
" while LRO is enabled\n", skb->dev->name);
|
||
}
|
||
EXPORT_SYMBOL(__skb_warn_lro_forwarding);
|
||
+
|
||
+/**
|
||
+ * skb_gso_transport_seglen - Return length of individual segments of a gso packet
|
||
+ *
|
||
+ * @skb: GSO skb
|
||
+ *
|
||
+ * skb_gso_transport_seglen is used to determine the real size of the
|
||
+ * individual segments, including Layer4 headers (TCP/UDP).
|
||
+ *
|
||
+ * The MAC/L2 or network (IP, IPv6) headers are not accounted for.
|
||
+ */
|
||
+unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
|
||
+{
|
||
+ const struct skb_shared_info *shinfo = skb_shinfo(skb);
|
||
+
|
||
+ if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
|
||
+ return tcp_hdrlen(skb) + shinfo->gso_size;
|
||
+
|
||
+ /* UFO sets gso_size to the size of the fragmentation
|
||
+ * payload, i.e. the size of the L4 (UDP) header is already
|
||
+ * accounted for.
|
||
+ */
|
||
+ return shinfo->gso_size;
|
||
+}
|
||
+EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);
|
||
diff --git a/net/core/sock.c b/net/core/sock.c
|
||
index 561eb57..832cf04 100644
|
||
--- a/net/core/sock.c
|
||
+++ b/net/core/sock.c
|
||
@@ -795,7 +795,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
|
||
|
||
case SO_PEEK_OFF:
|
||
if (sock->ops->set_peek_off)
|
||
- sock->ops->set_peek_off(sk, val);
|
||
+ ret = sock->ops->set_peek_off(sk, val);
|
||
else
|
||
ret = -EOPNOTSUPP;
|
||
break;
|
||
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c
|
||
index c32be29..2022b46 100644
|
||
--- a/net/dns_resolver/dns_query.c
|
||
+++ b/net/dns_resolver/dns_query.c
|
||
@@ -150,7 +150,9 @@ int dns_query(const char *type, const char *name, size_t namelen,
|
||
if (!*_result)
|
||
goto put;
|
||
|
||
- memcpy(*_result, upayload->data, len + 1);
|
||
+ memcpy(*_result, upayload->data, len);
|
||
+ (*_result)[len] = '\0';
|
||
+
|
||
if (_expiry)
|
||
*_expiry = rkey->expiry;
|
||
|
||
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
|
||
index 840821b..ddbdceb 100644
|
||
--- a/net/ieee802154/6lowpan.c
|
||
+++ b/net/ieee802154/6lowpan.c
|
||
@@ -803,7 +803,7 @@ lowpan_process_data(struct sk_buff *skb)
|
||
* Traffic class carried in-line
|
||
* ECN + DSCP (1 byte), Flow Label is elided
|
||
*/
|
||
- case 1: /* 10b */
|
||
+ case 2: /* 10b */
|
||
if (!skb->len)
|
||
goto drop;
|
||
tmp = lowpan_fetch_skb_u8(skb);
|
||
@@ -816,7 +816,7 @@ lowpan_process_data(struct sk_buff *skb)
|
||
* Flow Label carried in-line
|
||
* ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
|
||
*/
|
||
- case 2: /* 01b */
|
||
+ case 1: /* 01b */
|
||
if (!skb->len)
|
||
goto drop;
|
||
tmp = lowpan_fetch_skb_u8(skb);
|
||
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
|
||
index 424fafb..ec07510 100644
|
||
--- a/net/ipv4/datagram.c
|
||
+++ b/net/ipv4/datagram.c
|
||
@@ -57,7 +57,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||
if (IS_ERR(rt)) {
|
||
err = PTR_ERR(rt);
|
||
if (err == -ENETUNREACH)
|
||
- IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
|
||
+ IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
|
||
goto out;
|
||
}
|
||
|
||
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
|
||
index 8861f91..8d244ea 100644
|
||
--- a/net/ipv4/fib_semantics.c
|
||
+++ b/net/ipv4/fib_semantics.c
|
||
@@ -751,13 +751,13 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
|
||
fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL);
|
||
if (fi == NULL)
|
||
goto failure;
|
||
+ fib_info_cnt++;
|
||
if (cfg->fc_mx) {
|
||
fi->fib_metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
|
||
if (!fi->fib_metrics)
|
||
goto failure;
|
||
} else
|
||
fi->fib_metrics = (u32 *) dst_default_metrics;
|
||
- fib_info_cnt++;
|
||
|
||
fi->fib_net = hold_net(net);
|
||
fi->fib_protocol = cfg->fc_protocol;
|
||
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
|
||
index c8e2699..3f0bb3b 100644
|
||
--- a/net/ipv4/igmp.c
|
||
+++ b/net/ipv4/igmp.c
|
||
@@ -1866,6 +1866,10 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
|
||
|
||
rtnl_lock();
|
||
in_dev = ip_mc_find_dev(net, imr);
|
||
+ if (!in_dev) {
|
||
+ ret = -ENODEV;
|
||
+ goto out;
|
||
+ }
|
||
ifindex = imr->imr_ifindex;
|
||
for (imlp = &inet->mc_list;
|
||
(iml = rtnl_dereference(*imlp)) != NULL;
|
||
@@ -1883,16 +1887,14 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
|
||
|
||
*imlp = iml->next_rcu;
|
||
|
||
- if (in_dev)
|
||
- ip_mc_dec_group(in_dev, group);
|
||
+ ip_mc_dec_group(in_dev, group);
|
||
rtnl_unlock();
|
||
/* decrease mem now to avoid the memleak warning */
|
||
atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
|
||
kfree_rcu(iml, rcu);
|
||
return 0;
|
||
}
|
||
- if (!in_dev)
|
||
- ret = -ENODEV;
|
||
+out:
|
||
rtnl_unlock();
|
||
return ret;
|
||
}
|
||
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
|
||
index d7b862a..8cb3091c8 100644
|
||
--- a/net/ipv4/inet_diag.c
|
||
+++ b/net/ipv4/inet_diag.c
|
||
@@ -110,6 +110,10 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
|
||
|
||
r->id.idiag_sport = inet->inet_sport;
|
||
r->id.idiag_dport = inet->inet_dport;
|
||
+
|
||
+ memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src));
|
||
+ memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst));
|
||
+
|
||
r->id.idiag_src[0] = inet->inet_rcv_saddr;
|
||
r->id.idiag_dst[0] = inet->inet_daddr;
|
||
|
||
@@ -227,12 +231,19 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
|
||
|
||
r->idiag_family = tw->tw_family;
|
||
r->idiag_retrans = 0;
|
||
+
|
||
r->id.idiag_if = tw->tw_bound_dev_if;
|
||
sock_diag_save_cookie(tw, r->id.idiag_cookie);
|
||
+
|
||
r->id.idiag_sport = tw->tw_sport;
|
||
r->id.idiag_dport = tw->tw_dport;
|
||
+
|
||
+ memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src));
|
||
+ memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst));
|
||
+
|
||
r->id.idiag_src[0] = tw->tw_rcv_saddr;
|
||
r->id.idiag_dst[0] = tw->tw_daddr;
|
||
+
|
||
r->idiag_state = tw->tw_substate;
|
||
r->idiag_timer = 3;
|
||
r->idiag_expires = DIV_ROUND_UP(tmo * 1000, HZ);
|
||
@@ -714,8 +725,13 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
|
||
|
||
r->id.idiag_sport = inet->inet_sport;
|
||
r->id.idiag_dport = ireq->rmt_port;
|
||
+
|
||
+ memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src));
|
||
+ memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst));
|
||
+
|
||
r->id.idiag_src[0] = ireq->loc_addr;
|
||
r->id.idiag_dst[0] = ireq->rmt_addr;
|
||
+
|
||
r->idiag_expires = jiffies_to_msecs(tmo);
|
||
r->idiag_rqueue = 0;
|
||
r->idiag_wqueue = 0;
|
||
@@ -925,7 +941,7 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
|
||
++num;
|
||
}
|
||
|
||
- if (r->idiag_states & TCPF_TIME_WAIT) {
|
||
+ if (r->idiag_states & (TCPF_TIME_WAIT | TCPF_FIN_WAIT2)) {
|
||
struct inet_timewait_sock *tw;
|
||
|
||
inet_twsk_for_each(tw, node,
|
||
@@ -933,6 +949,8 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
|
||
|
||
if (num < s_num)
|
||
goto next_dying;
|
||
+ if (!(r->idiag_states & (1 << tw->tw_substate)))
|
||
+ goto next_dying;
|
||
if (r->sdiag_family != AF_UNSPEC &&
|
||
tw->tw_family != r->sdiag_family)
|
||
goto next_dying;
|
||
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
|
||
index 984ec65..4afcf31 100644
|
||
--- a/net/ipv4/inet_hashtables.c
|
||
+++ b/net/ipv4/inet_hashtables.c
|
||
@@ -268,7 +268,7 @@ struct sock * __inet_lookup_established(struct net *net,
|
||
}
|
||
if (unlikely(!INET_TW_MATCH(sk, net, hash, acookie,
|
||
saddr, daddr, ports, dif))) {
|
||
- sock_put(sk);
|
||
+ inet_twsk_put(inet_twsk(sk));
|
||
goto begintw;
|
||
}
|
||
goto out;
|
||
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
|
||
index b69a370..5235417 100644
|
||
--- a/net/ipv4/ip_options.c
|
||
+++ b/net/ipv4/ip_options.c
|
||
@@ -279,6 +279,10 @@ int ip_options_compile(struct net *net,
|
||
optptr++;
|
||
continue;
|
||
}
|
||
+ if (unlikely(l < 2)) {
|
||
+ pp_ptr = optptr;
|
||
+ goto error;
|
||
+ }
|
||
optlen = optptr[1];
|
||
if (optlen<2 || optlen>l) {
|
||
pp_ptr = optptr;
|
||
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
|
||
index 45bdd7b..2900e71 100644
|
||
--- a/net/ipv4/ip_output.c
|
||
+++ b/net/ipv4/ip_output.c
|
||
@@ -846,7 +846,7 @@ static int __ip_append_data(struct sock *sk,
|
||
csummode = CHECKSUM_PARTIAL;
|
||
|
||
cork->length += length;
|
||
- if (((length > mtu) || (skb && skb_is_gso(skb))) &&
|
||
+ if (((length > mtu) || (skb && skb_has_frags(skb))) &&
|
||
(sk->sk_protocol == IPPROTO_UDP) &&
|
||
(rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len) {
|
||
err = ip_ufo_append_data(sk, queue, getfrag, from, length,
|
||
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
|
||
index d2f6348..4901326 100644
|
||
--- a/net/ipv4/ipip.c
|
||
+++ b/net/ipv4/ipip.c
|
||
@@ -908,4 +908,5 @@ static void __exit ipip_fini(void)
|
||
module_init(ipip_init);
|
||
module_exit(ipip_fini);
|
||
MODULE_LICENSE("GPL");
|
||
+MODULE_ALIAS_RTNL_LINK("ipip");
|
||
MODULE_ALIAS_NETDEV("tunl0");
|
||
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
|
||
index a0b7166..94cd1ef 100644
|
||
--- a/net/ipv4/ipmr.c
|
||
+++ b/net/ipv4/ipmr.c
|
||
@@ -154,9 +154,12 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
|
||
static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
|
||
struct mr_table **mrt)
|
||
{
|
||
- struct ipmr_result res;
|
||
- struct fib_lookup_arg arg = { .result = &res, };
|
||
int err;
|
||
+ struct ipmr_result res;
|
||
+ struct fib_lookup_arg arg = {
|
||
+ .result = &res,
|
||
+ .flags = FIB_LOOKUP_NOREF,
|
||
+ };
|
||
|
||
err = fib_rules_lookup(net->ipv4.mr_rules_ops,
|
||
flowi4_to_flowi(flp4), 0, &arg);
|
||
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
|
||
index cfaaf13..990f62c 100644
|
||
--- a/net/ipv4/netfilter/arp_tables.c
|
||
+++ b/net/ipv4/netfilter/arp_tables.c
|
||
@@ -1044,8 +1044,10 @@ static int __do_replace(struct net *net, const char *name,
|
||
|
||
xt_free_table_info(oldinfo);
|
||
if (copy_to_user(counters_ptr, counters,
|
||
- sizeof(struct xt_counters) * num_counters) != 0)
|
||
- ret = -EFAULT;
|
||
+ sizeof(struct xt_counters) * num_counters) != 0) {
|
||
+ /* Silent error, can't fail, new table is already in place */
|
||
+ net_warn_ratelimited("arptables: counters copy to user failed while replacing table\n");
|
||
+ }
|
||
vfree(counters);
|
||
xt_table_unlock(t);
|
||
return ret;
|
||
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
|
||
index ed1468a..d6eb463 100644
|
||
--- a/net/ipv4/netfilter/ip_tables.c
|
||
+++ b/net/ipv4/netfilter/ip_tables.c
|
||
@@ -1232,8 +1232,10 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
|
||
|
||
xt_free_table_info(oldinfo);
|
||
if (copy_to_user(counters_ptr, counters,
|
||
- sizeof(struct xt_counters) * num_counters) != 0)
|
||
- ret = -EFAULT;
|
||
+ sizeof(struct xt_counters) * num_counters) != 0) {
|
||
+ /* Silent error, can't fail, new table is already in place */
|
||
+ net_warn_ratelimited("iptables: counters copy to user failed while replacing table\n");
|
||
+ }
|
||
vfree(counters);
|
||
xt_table_unlock(t);
|
||
return ret;
|
||
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
|
||
index 9bb1b8a..010288f 100644
|
||
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
|
||
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
|
||
@@ -22,7 +22,6 @@
|
||
#endif
|
||
#include <net/netfilter/nf_conntrack_zones.h>
|
||
|
||
-/* Returns new sk_buff, or NULL */
|
||
static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
|
||
{
|
||
int err;
|
||
@@ -33,8 +32,10 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
|
||
err = ip_defrag(skb, user);
|
||
local_bh_enable();
|
||
|
||
- if (!err)
|
||
+ if (!err) {
|
||
ip_send_check(ip_hdr(skb));
|
||
+ skb->local_df = 1;
|
||
+ }
|
||
|
||
return err;
|
||
}
|
||
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
|
||
index 145dffd..bc374ad 100644
|
||
--- a/net/ipv4/ping.c
|
||
+++ b/net/ipv4/ping.c
|
||
@@ -795,7 +795,7 @@ int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||
err = PTR_ERR(rt);
|
||
rt = NULL;
|
||
if (err == -ENETUNREACH)
|
||
- IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
|
||
+ IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES);
|
||
goto out;
|
||
}
|
||
|
||
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
|
||
index 2de2ee7..d7a9925 100644
|
||
--- a/net/ipv4/route.c
|
||
+++ b/net/ipv4/route.c
|
||
@@ -151,6 +151,9 @@ static void ipv4_link_failure(struct sk_buff *skb);
|
||
static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
|
||
static int rt_garbage_collect(struct dst_ops *ops);
|
||
|
||
+static void __rt_garbage_collect(struct work_struct *w);
|
||
+static DECLARE_WORK(rt_gc_worker, __rt_garbage_collect);
|
||
+
|
||
static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
|
||
int how)
|
||
{
|
||
@@ -979,12 +982,13 @@ static void rt_emergency_hash_rebuild(struct net *net)
|
||
and when load increases it reduces to limit cache size.
|
||
*/
|
||
|
||
-static int rt_garbage_collect(struct dst_ops *ops)
|
||
+static void __do_rt_garbage_collect(int elasticity, int min_interval)
|
||
{
|
||
static unsigned long expire = RT_GC_TIMEOUT;
|
||
static unsigned long last_gc;
|
||
static int rover;
|
||
static int equilibrium;
|
||
+ static DEFINE_SPINLOCK(rt_gc_lock);
|
||
struct rtable *rth;
|
||
struct rtable __rcu **rthp;
|
||
unsigned long now = jiffies;
|
||
@@ -996,9 +1000,11 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
||
* do not make it too frequently.
|
||
*/
|
||
|
||
+ spin_lock_bh(&rt_gc_lock);
|
||
+
|
||
RT_CACHE_STAT_INC(gc_total);
|
||
|
||
- if (now - last_gc < ip_rt_gc_min_interval &&
|
||
+ if (now - last_gc < min_interval &&
|
||
entries < ip_rt_max_size) {
|
||
RT_CACHE_STAT_INC(gc_ignored);
|
||
goto out;
|
||
@@ -1006,7 +1012,7 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
||
|
||
entries = dst_entries_get_slow(&ipv4_dst_ops);
|
||
/* Calculate number of entries, which we want to expire now. */
|
||
- goal = entries - (ip_rt_gc_elasticity << rt_hash_log);
|
||
+ goal = entries - (elasticity << rt_hash_log);
|
||
if (goal <= 0) {
|
||
if (equilibrium < ipv4_dst_ops.gc_thresh)
|
||
equilibrium = ipv4_dst_ops.gc_thresh;
|
||
@@ -1023,7 +1029,7 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
||
equilibrium = entries - goal;
|
||
}
|
||
|
||
- if (now - last_gc >= ip_rt_gc_min_interval)
|
||
+ if (now - last_gc >= min_interval)
|
||
last_gc = now;
|
||
|
||
if (goal <= 0) {
|
||
@@ -1088,15 +1094,34 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
||
if (net_ratelimit())
|
||
pr_warn("dst cache overflow\n");
|
||
RT_CACHE_STAT_INC(gc_dst_overflow);
|
||
- return 1;
|
||
+ goto out;
|
||
|
||
work_done:
|
||
- expire += ip_rt_gc_min_interval;
|
||
+ expire += min_interval;
|
||
if (expire > ip_rt_gc_timeout ||
|
||
dst_entries_get_fast(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh ||
|
||
dst_entries_get_slow(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh)
|
||
expire = ip_rt_gc_timeout;
|
||
-out: return 0;
|
||
+out:
|
||
+ spin_unlock_bh(&rt_gc_lock);
|
||
+}
|
||
+
|
||
+static void __rt_garbage_collect(struct work_struct *w)
|
||
+{
|
||
+ __do_rt_garbage_collect(ip_rt_gc_elasticity, ip_rt_gc_min_interval);
|
||
+}
|
||
+
|
||
+static int rt_garbage_collect(struct dst_ops *ops)
|
||
+{
|
||
+ if (!work_pending(&rt_gc_worker))
|
||
+ schedule_work(&rt_gc_worker);
|
||
+
|
||
+ if (dst_entries_get_fast(&ipv4_dst_ops) >= ip_rt_max_size ||
|
||
+ dst_entries_get_slow(&ipv4_dst_ops) >= ip_rt_max_size) {
|
||
+ RT_CACHE_STAT_INC(gc_dst_overflow);
|
||
+ return 1;
|
||
+ }
|
||
+ return 0;
|
||
}
|
||
|
||
/*
|
||
@@ -1153,7 +1178,7 @@ static struct rtable *rt_intern_hash(unsigned hash, struct rtable *rt,
|
||
unsigned long now;
|
||
u32 min_score;
|
||
int chain_length;
|
||
- int attempts = !in_softirq();
|
||
+ int attempts = 1;
|
||
|
||
restart:
|
||
chain_length = 0;
|
||
@@ -1289,14 +1314,15 @@ static struct rtable *rt_intern_hash(unsigned hash, struct rtable *rt,
|
||
can be released. Try to shrink route cache,
|
||
it is most likely it holds some neighbour records.
|
||
*/
|
||
- if (attempts-- > 0) {
|
||
- int saved_elasticity = ip_rt_gc_elasticity;
|
||
- int saved_int = ip_rt_gc_min_interval;
|
||
- ip_rt_gc_elasticity = 1;
|
||
- ip_rt_gc_min_interval = 0;
|
||
- rt_garbage_collect(&ipv4_dst_ops);
|
||
- ip_rt_gc_min_interval = saved_int;
|
||
- ip_rt_gc_elasticity = saved_elasticity;
|
||
+ if (!in_softirq() && attempts-- > 0) {
|
||
+ static DEFINE_SPINLOCK(lock);
|
||
+
|
||
+ if (spin_trylock(&lock)) {
|
||
+ __do_rt_garbage_collect(1, 0);
|
||
+ spin_unlock(&lock);
|
||
+ } else {
|
||
+ spin_unlock_wait(&lock);
|
||
+ }
|
||
goto restart;
|
||
}
|
||
|
||
@@ -2133,7 +2159,7 @@ static int __mkroute_input(struct sk_buff *skb,
|
||
struct in_device *out_dev;
|
||
unsigned int flags = 0;
|
||
__be32 spec_dst;
|
||
- u32 itag;
|
||
+ u32 itag = 0;
|
||
|
||
/* get a working reference to the output device */
|
||
out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res));
|
||
@@ -2721,7 +2747,7 @@ static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4)
|
||
RT_SCOPE_LINK);
|
||
goto make_route;
|
||
}
|
||
- if (fl4->saddr) {
|
||
+ if (!fl4->saddr) {
|
||
if (ipv4_is_multicast(fl4->daddr))
|
||
fl4->saddr = inet_select_addr(dev_out, 0,
|
||
fl4->flowi4_scope);
|
||
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
|
||
index b6ae92a..894b7ce 100644
|
||
--- a/net/ipv4/tcp_cubic.c
|
||
+++ b/net/ipv4/tcp_cubic.c
|
||
@@ -408,7 +408,7 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us)
|
||
ratio -= ca->delayed_ack >> ACK_RATIO_SHIFT;
|
||
ratio += cnt;
|
||
|
||
- ca->delayed_ack = min(ratio, ACK_RATIO_LIMIT);
|
||
+ ca->delayed_ack = clamp(ratio, 1U, ACK_RATIO_LIMIT);
|
||
}
|
||
|
||
/* Some calls are for duplicates without timetamps */
|
||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
|
||
index 735d9bc..d09117c 100644
|
||
--- a/net/ipv4/tcp_input.c
|
||
+++ b/net/ipv4/tcp_input.c
|
||
@@ -1251,7 +1251,7 @@ static int tcp_check_dsack(struct sock *sk, const struct sk_buff *ack_skb,
|
||
}
|
||
|
||
/* D-SACK for already forgotten data... Do dumb counting. */
|
||
- if (dup_sack && tp->undo_marker && tp->undo_retrans &&
|
||
+ if (dup_sack && tp->undo_marker && tp->undo_retrans > 0 &&
|
||
!after(end_seq_0, prior_snd_una) &&
|
||
after(end_seq_0, tp->undo_marker))
|
||
tp->undo_retrans--;
|
||
@@ -1305,7 +1305,7 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
|
||
unsigned int new_len = (pkt_len / mss) * mss;
|
||
if (!in_sack && new_len < pkt_len) {
|
||
new_len += mss;
|
||
- if (new_len > skb->len)
|
||
+ if (new_len >= skb->len)
|
||
return 0;
|
||
}
|
||
pkt_len = new_len;
|
||
@@ -1329,7 +1329,7 @@ static u8 tcp_sacktag_one(struct sock *sk,
|
||
|
||
/* Account D-SACK for retransmitted packet. */
|
||
if (dup_sack && (sacked & TCPCB_RETRANS)) {
|
||
- if (tp->undo_marker && tp->undo_retrans &&
|
||
+ if (tp->undo_marker && tp->undo_retrans > 0 &&
|
||
after(end_seq, tp->undo_marker))
|
||
tp->undo_retrans--;
|
||
if (sacked & TCPCB_SACKED_ACKED)
|
||
@@ -1469,7 +1469,10 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
|
||
tp->lost_cnt_hint -= tcp_skb_pcount(prev);
|
||
}
|
||
|
||
- TCP_SKB_CB(skb)->tcp_flags |= TCP_SKB_CB(prev)->tcp_flags;
|
||
+ TCP_SKB_CB(prev)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags;
|
||
+ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
|
||
+ TCP_SKB_CB(prev)->end_seq++;
|
||
+
|
||
if (skb == tcp_highest_sack(sk))
|
||
tcp_advance_highest_sack(sk, skb);
|
||
|
||
@@ -2224,7 +2227,7 @@ static void tcp_clear_retrans_partial(struct tcp_sock *tp)
|
||
tp->lost_out = 0;
|
||
|
||
tp->undo_marker = 0;
|
||
- tp->undo_retrans = 0;
|
||
+ tp->undo_retrans = -1;
|
||
}
|
||
|
||
void tcp_clear_retrans(struct tcp_sock *tp)
|
||
@@ -3163,7 +3166,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
|
||
tp->high_seq = tp->snd_nxt;
|
||
tp->prior_ssthresh = 0;
|
||
tp->undo_marker = tp->snd_una;
|
||
- tp->undo_retrans = tp->retrans_out;
|
||
+ tp->undo_retrans = tp->retrans_out ? : -1;
|
||
|
||
if (icsk->icsk_ca_state < TCP_CA_CWR) {
|
||
if (!(flag & FLAG_ECE))
|
||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
|
||
index 8491530..680ce9c 100644
|
||
--- a/net/ipv4/tcp_ipv4.c
|
||
+++ b/net/ipv4/tcp_ipv4.c
|
||
@@ -176,7 +176,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||
if (IS_ERR(rt)) {
|
||
err = PTR_ERR(rt);
|
||
if (err == -ENETUNREACH)
|
||
- IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
|
||
+ IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
|
||
return err;
|
||
}
|
||
|
||
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
|
||
index 8634f14..521d637 100644
|
||
--- a/net/ipv4/tcp_output.c
|
||
+++ b/net/ipv4/tcp_output.c
|
||
@@ -932,6 +932,9 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
|
||
static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
|
||
unsigned int mss_now)
|
||
{
|
||
+ /* Make sure we own this skb before messing gso_size/gso_segs */
|
||
+ WARN_ON_ONCE(skb_cloned(skb));
|
||
+
|
||
if (skb->len <= mss_now || !sk_can_gso(sk) ||
|
||
skb->ip_summed == CHECKSUM_NONE) {
|
||
/* Avoid the costly divide in the normal
|
||
@@ -1013,9 +1016,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
|
||
if (nsize < 0)
|
||
nsize = 0;
|
||
|
||
- if (skb_cloned(skb) &&
|
||
- skb_is_nonlinear(skb) &&
|
||
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
|
||
+ if (skb_unclone(skb, GFP_ATOMIC))
|
||
return -ENOMEM;
|
||
|
||
/* Get a new skb... force flag on. */
|
||
@@ -2128,6 +2129,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
|
||
int oldpcount = tcp_skb_pcount(skb);
|
||
|
||
if (unlikely(oldpcount > 1)) {
|
||
+ if (skb_unclone(skb, GFP_ATOMIC))
|
||
+ return -ENOMEM;
|
||
tcp_init_tso_segs(sk, skb, cur_mss);
|
||
tcp_adjust_pcount(sk, skb, oldpcount - tcp_skb_pcount(skb));
|
||
}
|
||
@@ -2190,13 +2193,15 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
|
||
if (!tp->retrans_stamp)
|
||
tp->retrans_stamp = TCP_SKB_CB(skb)->when;
|
||
|
||
- tp->undo_retrans += tcp_skb_pcount(skb);
|
||
-
|
||
/* snd_nxt is stored to detect loss of retransmitted segment,
|
||
* see tcp_input.c tcp_sacktag_write_queue().
|
||
*/
|
||
TCP_SKB_CB(skb)->ack_seq = tp->snd_nxt;
|
||
}
|
||
+
|
||
+ if (tp->undo_retrans < 0)
|
||
+ tp->undo_retrans = 0;
|
||
+ tp->undo_retrans += tcp_skb_pcount(skb);
|
||
return err;
|
||
}
|
||
|
||
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
|
||
index 80fa2bf..c042e52 100644
|
||
--- a/net/ipv4/tcp_vegas.c
|
||
+++ b/net/ipv4/tcp_vegas.c
|
||
@@ -218,7 +218,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
|
||
* This is:
|
||
* (actual rate in segments) * baseRTT
|
||
*/
|
||
- target_cwnd = tp->snd_cwnd * vegas->baseRTT / rtt;
|
||
+ target_cwnd = (u64)tp->snd_cwnd * vegas->baseRTT;
|
||
+ do_div(target_cwnd, rtt);
|
||
|
||
/* Calculate the difference between the window we had,
|
||
* and the window we would like to have. This quantity
|
||
diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c
|
||
index ac43cd7..b4d1858 100644
|
||
--- a/net/ipv4/tcp_veno.c
|
||
+++ b/net/ipv4/tcp_veno.c
|
||
@@ -144,7 +144,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
|
||
|
||
rtt = veno->minrtt;
|
||
|
||
- target_cwnd = (tp->snd_cwnd * veno->basertt);
|
||
+ target_cwnd = (u64)tp->snd_cwnd * veno->basertt;
|
||
target_cwnd <<= V_PARAM_SHIFT;
|
||
do_div(target_cwnd, rtt);
|
||
|
||
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
|
||
index 5a5db88..e284f39 100644
|
||
--- a/net/ipv4/udp.c
|
||
+++ b/net/ipv4/udp.c
|
||
@@ -941,7 +941,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||
err = PTR_ERR(rt);
|
||
rt = NULL;
|
||
if (err == -ENETUNREACH)
|
||
- IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
|
||
+ IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES);
|
||
goto out;
|
||
}
|
||
|
||
@@ -1040,6 +1040,9 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset,
|
||
struct udp_sock *up = udp_sk(sk);
|
||
int ret;
|
||
|
||
+ if (flags & MSG_SENDPAGE_NOTLAST)
|
||
+ flags |= MSG_MORE;
|
||
+
|
||
if (!up->pending) {
|
||
struct msghdr msg = { .msg_flags = flags|MSG_MORE };
|
||
|
||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
|
||
index d1af0f3..019f5da 100644
|
||
--- a/net/ipv6/addrconf.c
|
||
+++ b/net/ipv6/addrconf.c
|
||
@@ -903,8 +903,11 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
|
||
* Lifetime is greater than REGEN_ADVANCE time units. In particular,
|
||
* an implementation must not create a temporary address with a zero
|
||
* Preferred Lifetime.
|
||
+ * Use age calculation as in addrconf_verify to avoid unnecessary
|
||
+ * temporary addresses being generated.
|
||
*/
|
||
- if (tmp_prefered_lft <= regen_advance) {
|
||
+ age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
|
||
+ if (tmp_prefered_lft <= regen_advance + age) {
|
||
in6_ifa_put(ifp);
|
||
in6_dev_put(idev);
|
||
ret = -1;
|
||
@@ -2507,8 +2510,18 @@ static void init_loopback(struct net_device *dev)
|
||
if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))
|
||
continue;
|
||
|
||
- if (sp_ifa->rt)
|
||
- continue;
|
||
+ if (sp_ifa->rt) {
|
||
+ /* This dst has been added to garbage list when
|
||
+ * lo device down, release this obsolete dst and
|
||
+ * reallocate a new router for ifa.
|
||
+ */
|
||
+ if (sp_ifa->rt->dst.obsolete > 0) {
|
||
+ dst_release(&sp_ifa->rt->dst);
|
||
+ sp_ifa->rt = NULL;
|
||
+ } else {
|
||
+ continue;
|
||
+ }
|
||
+ }
|
||
|
||
sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0);
|
||
|
||
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
|
||
index ae4d713..1ad0906 100644
|
||
--- a/net/ipv6/datagram.c
|
||
+++ b/net/ipv6/datagram.c
|
||
@@ -375,6 +375,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
|
||
if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
|
||
sin->sin6_family = AF_INET6;
|
||
sin->sin6_flowinfo = 0;
|
||
+ sin->sin6_port = 0;
|
||
sin->sin6_scope_id = 0;
|
||
if (skb->protocol == htons(ETH_P_IPV6)) {
|
||
sin->sin6_addr = ipv6_hdr(skb)->saddr;
|
||
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
|
||
index c906256..f8d431f 100644
|
||
--- a/net/ipv6/icmp.c
|
||
+++ b/net/ipv6/icmp.c
|
||
@@ -518,7 +518,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
|
||
np->tclass, NULL, &fl6, (struct rt6_info*)dst,
|
||
MSG_DONTWAIT, np->dontfrag);
|
||
if (err) {
|
||
- ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
|
||
+ ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
|
||
ip6_flush_pending_frames(sk);
|
||
} else {
|
||
err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
|
||
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
|
||
index 73f1a00..e38290b 100644
|
||
--- a/net/ipv6/inet6_hashtables.c
|
||
+++ b/net/ipv6/inet6_hashtables.c
|
||
@@ -110,7 +110,7 @@ struct sock *__inet6_lookup_established(struct net *net,
|
||
goto out;
|
||
}
|
||
if (!INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) {
|
||
- sock_put(sk);
|
||
+ inet_twsk_put(inet_twsk(sk));
|
||
goto begintw;
|
||
}
|
||
goto out;
|
||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
|
||
index f1bf290..a4f6f5f 100644
|
||
--- a/net/ipv6/ip6_output.c
|
||
+++ b/net/ipv6/ip6_output.c
|
||
@@ -144,8 +144,8 @@ static int ip6_finish_output2(struct sk_buff *skb)
|
||
return res;
|
||
}
|
||
rcu_read_unlock();
|
||
- IP6_INC_STATS_BH(dev_net(dst->dev),
|
||
- ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
|
||
+ IP6_INC_STATS(dev_net(dst->dev),
|
||
+ ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
|
||
kfree_skb(skb);
|
||
return -EINVAL;
|
||
}
|
||
@@ -601,7 +601,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
|
||
void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
|
||
{
|
||
static atomic_t ipv6_fragmentation_id;
|
||
- int old, new;
|
||
+ int ident;
|
||
|
||
if (rt && !(rt->dst.flags & DST_NOPEER)) {
|
||
struct inet_peer *peer;
|
||
@@ -614,13 +614,8 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
|
||
return;
|
||
}
|
||
}
|
||
- do {
|
||
- old = atomic_read(&ipv6_fragmentation_id);
|
||
- new = old + 1;
|
||
- if (!new)
|
||
- new = 1;
|
||
- } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old);
|
||
- fhdr->identification = htonl(new);
|
||
+ ident = atomic_inc_return(&ipv6_fragmentation_id);
|
||
+ fhdr->identification = htonl(ident);
|
||
}
|
||
|
||
int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
||
@@ -1184,21 +1179,19 @@ static void ip6_append_data_mtu(unsigned int *mtu,
|
||
unsigned int fragheaderlen,
|
||
struct sk_buff *skb,
|
||
struct rt6_info *rt,
|
||
- bool pmtuprobe)
|
||
+ unsigned int orig_mtu)
|
||
{
|
||
if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
|
||
if (skb == NULL) {
|
||
/* first fragment, reserve header_len */
|
||
- *mtu = *mtu - rt->dst.header_len;
|
||
+ *mtu = orig_mtu - rt->dst.header_len;
|
||
|
||
} else {
|
||
/*
|
||
* this fragment is not first, the headers
|
||
* space is regarded as data space.
|
||
*/
|
||
- *mtu = min(*mtu, pmtuprobe ?
|
||
- rt->dst.dev->mtu :
|
||
- dst_mtu(rt->dst.path));
|
||
+ *mtu = orig_mtu;
|
||
}
|
||
*maxfraglen = ((*mtu - fragheaderlen) & ~7)
|
||
+ fragheaderlen - sizeof(struct frag_hdr);
|
||
@@ -1215,7 +1208,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
|
||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||
struct inet_cork *cork;
|
||
struct sk_buff *skb, *skb_prev = NULL;
|
||
- unsigned int maxfraglen, fragheaderlen, mtu;
|
||
+ unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
|
||
int exthdrlen;
|
||
int dst_exthdrlen;
|
||
int hh_len;
|
||
@@ -1300,6 +1293,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
|
||
dst_exthdrlen = 0;
|
||
mtu = cork->fragsize;
|
||
}
|
||
+ orig_mtu = mtu;
|
||
|
||
hh_len = LL_RESERVED_SPACE(rt->dst.dev);
|
||
|
||
@@ -1346,7 +1340,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
|
||
skb = skb_peek_tail(&sk->sk_write_queue);
|
||
cork->length += length;
|
||
if (((length > mtu) ||
|
||
- (skb && skb_is_gso(skb))) &&
|
||
+ (skb && skb_has_frags(skb))) &&
|
||
(sk->sk_protocol == IPPROTO_UDP) &&
|
||
(rt->dst.dev->features & NETIF_F_UFO)) {
|
||
err = ip6_ufo_append_data(sk, getfrag, from, length,
|
||
@@ -1382,8 +1376,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
|
||
if (skb == NULL || skb_prev == NULL)
|
||
ip6_append_data_mtu(&mtu, &maxfraglen,
|
||
fragheaderlen, skb, rt,
|
||
- np->pmtudisc ==
|
||
- IPV6_PMTUDISC_PROBE);
|
||
+ orig_mtu);
|
||
|
||
skb_prev = skb;
|
||
|
||
@@ -1653,8 +1646,8 @@ int ip6_push_pending_frames(struct sock *sk)
|
||
if (proto == IPPROTO_ICMPV6) {
|
||
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
|
||
|
||
- ICMP6MSGOUT_INC_STATS_BH(net, idev, icmp6_hdr(skb)->icmp6_type);
|
||
- ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
|
||
+ ICMP6MSGOUT_INC_STATS(net, idev, icmp6_hdr(skb)->icmp6_type);
|
||
+ ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
|
||
}
|
||
|
||
err = ip6_local_out(skb);
|
||
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
|
||
index aa21da6..b876a2f 100644
|
||
--- a/net/ipv6/ip6_tunnel.c
|
||
+++ b/net/ipv6/ip6_tunnel.c
|
||
@@ -57,6 +57,7 @@
|
||
MODULE_AUTHOR("Ville Nuorvala");
|
||
MODULE_DESCRIPTION("IPv6 tunneling device");
|
||
MODULE_LICENSE("GPL");
|
||
+MODULE_ALIAS_RTNL_LINK("ip6tnl");
|
||
MODULE_ALIAS_NETDEV("ip6tnl0");
|
||
|
||
#ifdef IP6_TNL_DEBUG
|
||
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
|
||
index d5e4615..abe1f76 100644
|
||
--- a/net/ipv6/ip6mr.c
|
||
+++ b/net/ipv6/ip6mr.c
|
||
@@ -138,9 +138,12 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
|
||
static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
|
||
struct mr6_table **mrt)
|
||
{
|
||
- struct ip6mr_result res;
|
||
- struct fib_lookup_arg arg = { .result = &res, };
|
||
int err;
|
||
+ struct ip6mr_result res;
|
||
+ struct fib_lookup_arg arg = {
|
||
+ .result = &res,
|
||
+ .flags = FIB_LOOKUP_NOREF,
|
||
+ };
|
||
|
||
err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
|
||
flowi6_to_flowi(flp6), 0, &arg);
|
||
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
|
||
index 9728df5..e027bf2 100644
|
||
--- a/net/ipv6/mcast.c
|
||
+++ b/net/ipv6/mcast.c
|
||
@@ -1430,11 +1430,12 @@ static void mld_sendpack(struct sk_buff *skb)
|
||
dst_output);
|
||
out:
|
||
if (!err) {
|
||
- ICMP6MSGOUT_INC_STATS_BH(net, idev, ICMPV6_MLD2_REPORT);
|
||
- ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
|
||
- IP6_UPD_PO_STATS_BH(net, idev, IPSTATS_MIB_OUTMCAST, payload_len);
|
||
- } else
|
||
- IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS);
|
||
+ ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT);
|
||
+ ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
|
||
+ IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, payload_len);
|
||
+ } else {
|
||
+ IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
|
||
+ }
|
||
|
||
rcu_read_unlock();
|
||
return;
|
||
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
|
||
index c30a20c..d605f21 100644
|
||
--- a/net/ipv6/netfilter/ip6_tables.c
|
||
+++ b/net/ipv6/netfilter/ip6_tables.c
|
||
@@ -1241,8 +1241,10 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
|
||
|
||
xt_free_table_info(oldinfo);
|
||
if (copy_to_user(counters_ptr, counters,
|
||
- sizeof(struct xt_counters) * num_counters) != 0)
|
||
- ret = -EFAULT;
|
||
+ sizeof(struct xt_counters) * num_counters) != 0) {
|
||
+ /* Silent error, can't fail, new table is already in place */
|
||
+ net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n");
|
||
+ }
|
||
vfree(counters);
|
||
xt_table_unlock(t);
|
||
return ret;
|
||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
|
||
index beaa141..8b75eb1 100644
|
||
--- a/net/ipv6/route.c
|
||
+++ b/net/ipv6/route.c
|
||
@@ -815,7 +815,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
|
||
}
|
||
|
||
static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
|
||
- struct flowi6 *fl6, int flags)
|
||
+ struct flowi6 *fl6, int flags, bool input)
|
||
{
|
||
struct fib6_node *fn;
|
||
struct rt6_info *rt, *nrt;
|
||
@@ -823,8 +823,11 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
|
||
int attempts = 3;
|
||
int err;
|
||
int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;
|
||
+ int local = RTF_NONEXTHOP;
|
||
|
||
strict |= flags & RT6_LOOKUP_F_IFACE;
|
||
+ if (input)
|
||
+ local |= RTF_LOCAL;
|
||
|
||
relookup:
|
||
read_lock_bh(&table->tb6_lock);
|
||
@@ -844,7 +847,7 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
|
||
read_unlock_bh(&table->tb6_lock);
|
||
|
||
if (!dst_get_neighbour_noref_raw(&rt->dst) &&
|
||
- !(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_LOCAL)))
|
||
+ !(rt->rt6i_flags & local))
|
||
nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
|
||
else if (!(rt->dst.flags & DST_HOST))
|
||
nrt = rt6_alloc_clone(rt, &fl6->daddr);
|
||
@@ -888,7 +891,7 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
|
||
static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
|
||
struct flowi6 *fl6, int flags)
|
||
{
|
||
- return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
|
||
+ return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags, true);
|
||
}
|
||
|
||
static struct dst_entry *ip6_route_input_lookup(struct net *net,
|
||
@@ -921,7 +924,7 @@ void ip6_route_input(struct sk_buff *skb)
|
||
static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
|
||
struct flowi6 *fl6, int flags)
|
||
{
|
||
- return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
|
||
+ return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags, false);
|
||
}
|
||
|
||
struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
|
||
@@ -1295,7 +1298,7 @@ int ip6_route_add(struct fib6_config *cfg)
|
||
if (!table)
|
||
goto out;
|
||
|
||
- rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL, DST_NOCOUNT);
|
||
+ rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
|
||
|
||
if (!rt) {
|
||
err = -ENOMEM;
|
||
@@ -2098,15 +2101,11 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
|
||
{
|
||
struct net *net = dev_net(idev->dev);
|
||
struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,
|
||
- net->loopback_dev, 0);
|
||
+ net->loopback_dev, DST_NOCOUNT);
|
||
int err;
|
||
|
||
- if (!rt) {
|
||
- if (net_ratelimit())
|
||
- pr_warning("IPv6: Maximum number of routes reached,"
|
||
- " consider increasing route/max_size.\n");
|
||
+ if (!rt)
|
||
return ERR_PTR(-ENOMEM);
|
||
- }
|
||
|
||
in6_dev_hold(idev);
|
||
|
||
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
|
||
index c4ffd17..3f20ba4 100644
|
||
--- a/net/ipv6/sit.c
|
||
+++ b/net/ipv6/sit.c
|
||
@@ -1303,4 +1303,5 @@ static int __init sit_init(void)
|
||
module_init(sit_init);
|
||
module_exit(sit_cleanup);
|
||
MODULE_LICENSE("GPL");
|
||
+MODULE_ALIAS_RTNL_LINK("sit");
|
||
MODULE_ALIAS_NETDEV("sit0");
|
||
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
|
||
index 05af4a8..875d25b 100644
|
||
--- a/net/ipv6/udp.c
|
||
+++ b/net/ipv6/udp.c
|
||
@@ -1368,7 +1368,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
|
||
fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
|
||
fptr->nexthdr = nexthdr;
|
||
fptr->reserved = 0;
|
||
- ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
|
||
+ fptr->identification = skb_shinfo(skb)->ip6_frag_id;
|
||
|
||
/* Fragment the skb. ipv6 header and the remaining fields of the
|
||
* fragment header are updated in ipv6_gso_segment()
|
||
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
|
||
index 9680226..8c06a50 100644
|
||
--- a/net/ipx/af_ipx.c
|
||
+++ b/net/ipx/af_ipx.c
|
||
@@ -1835,8 +1835,6 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (skb->tstamp.tv64)
|
||
sk->sk_stamp = skb->tstamp;
|
||
|
||
- msg->msg_namelen = sizeof(*sipx);
|
||
-
|
||
if (sipx) {
|
||
sipx->sipx_family = AF_IPX;
|
||
sipx->sipx_port = ipx->ipx_source.sock;
|
||
@@ -1844,6 +1842,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
sipx->sipx_network = IPX_SKB_CB(skb)->ipx_source_net;
|
||
sipx->sipx_type = ipx->ipx_type;
|
||
sipx->sipx_zero = 0;
|
||
+ msg->msg_namelen = sizeof(*sipx);
|
||
}
|
||
rc = copied;
|
||
|
||
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
|
||
index bd25678..12218f7 100644
|
||
--- a/net/irda/af_irda.c
|
||
+++ b/net/irda/af_irda.c
|
||
@@ -1386,8 +1386,6 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
|
||
|
||
IRDA_DEBUG(4, "%s()\n", __func__);
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
|
||
flags & MSG_DONTWAIT, &err);
|
||
if (!skb)
|
||
@@ -1452,8 +1450,6 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
|
||
target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
|
||
timeo = sock_rcvtimeo(sk, noblock);
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
do {
|
||
int chunk;
|
||
struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue);
|
||
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
|
||
index 6492b29..1fe397a 100644
|
||
--- a/net/iucv/af_iucv.c
|
||
+++ b/net/iucv/af_iucv.c
|
||
@@ -1331,8 +1331,6 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
struct sk_buff *skb, *rskb, *cskb;
|
||
int err = 0;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
if ((sk->sk_state == IUCV_DISCONN) &&
|
||
skb_queue_empty(&iucv->backlog_skb_q) &&
|
||
skb_queue_empty(&sk->sk_receive_queue) &&
|
||
diff --git a/net/key/af_key.c b/net/key/af_key.c
|
||
index 42147b3..1afbbd8 100644
|
||
--- a/net/key/af_key.c
|
||
+++ b/net/key/af_key.c
|
||
@@ -3595,7 +3595,6 @@ static int pfkey_recvmsg(struct kiocb *kiocb,
|
||
if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
|
||
goto out;
|
||
|
||
- msg->msg_namelen = 0;
|
||
skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
|
||
if (skb == NULL)
|
||
goto out;
|
||
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
|
||
index 391f8f2..cf7821b7 100644
|
||
--- a/net/l2tp/l2tp_ppp.c
|
||
+++ b/net/l2tp/l2tp_ppp.c
|
||
@@ -200,8 +200,6 @@ static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (sk->sk_state & PPPOX_BOUND)
|
||
goto end;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
err = 0;
|
||
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
|
||
flags & MSG_DONTWAIT, &err);
|
||
@@ -357,7 +355,9 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
|
||
goto error_put_sess_tun;
|
||
}
|
||
|
||
+ local_bh_disable();
|
||
l2tp_xmit_skb(session, skb, session->hdr_len);
|
||
+ local_bh_enable();
|
||
|
||
sock_put(ps->tunnel_sock);
|
||
sock_put(sk);
|
||
@@ -432,7 +432,9 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
|
||
skb->data[0] = ppph[0];
|
||
skb->data[1] = ppph[1];
|
||
|
||
+ local_bh_disable();
|
||
l2tp_xmit_skb(session, skb, session->hdr_len);
|
||
+ local_bh_enable();
|
||
|
||
sock_put(sk_tun);
|
||
sock_put(sk);
|
||
@@ -770,9 +772,10 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
|
||
session->deref = pppol2tp_session_sock_put;
|
||
|
||
/* If PMTU discovery was enabled, use the MTU that was discovered */
|
||
- dst = sk_dst_get(sk);
|
||
+ dst = sk_dst_get(tunnel->sock);
|
||
if (dst != NULL) {
|
||
- u32 pmtu = dst_mtu(__sk_dst_get(sk));
|
||
+ u32 pmtu = dst_mtu(dst);
|
||
+
|
||
if (pmtu != 0)
|
||
session->mtu = session->mru = pmtu -
|
||
PPPOL2TP_HEADER_OVERHEAD;
|
||
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
|
||
index e4d2fbb..1c2dc50 100644
|
||
--- a/net/llc/af_llc.c
|
||
+++ b/net/llc/af_llc.c
|
||
@@ -716,13 +716,11 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
unsigned long cpu_flags;
|
||
size_t copied = 0;
|
||
u32 peek_seq = 0;
|
||
- u32 *seq;
|
||
+ u32 *seq, skb_len;
|
||
unsigned long used;
|
||
int target; /* Read at least this many bytes */
|
||
long timeo;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
lock_sock(sk);
|
||
copied = -ENOTCONN;
|
||
if (unlikely(sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN))
|
||
@@ -816,6 +814,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
}
|
||
continue;
|
||
found_ok_skb:
|
||
+ skb_len = skb->len;
|
||
/* Ok so how much can we use? */
|
||
used = skb->len - offset;
|
||
if (len < used)
|
||
@@ -848,7 +847,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
}
|
||
|
||
/* Partial read */
|
||
- if (used + offset < skb->len)
|
||
+ if (used + offset < skb_len)
|
||
continue;
|
||
} while (len > 0);
|
||
|
||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
|
||
index 30f99c3..d5404cc 100644
|
||
--- a/net/mac80211/debugfs_netdev.c
|
||
+++ b/net/mac80211/debugfs_netdev.c
|
||
@@ -33,8 +33,7 @@ static ssize_t ieee80211_if_read(
|
||
ssize_t ret = -EINVAL;
|
||
|
||
read_lock(&dev_base_lock);
|
||
- if (sdata->dev->reg_state == NETREG_REGISTERED)
|
||
- ret = (*format)(sdata, buf, sizeof(buf));
|
||
+ ret = (*format)(sdata, buf, sizeof(buf));
|
||
read_unlock(&dev_base_lock);
|
||
|
||
if (ret >= 0)
|
||
@@ -61,8 +60,7 @@ static ssize_t ieee80211_if_write(
|
||
|
||
ret = -ENODEV;
|
||
rtnl_lock();
|
||
- if (sdata->dev->reg_state == NETREG_REGISTERED)
|
||
- ret = (*write)(sdata, buf, count);
|
||
+ ret = (*write)(sdata, buf, count);
|
||
rtnl_unlock();
|
||
|
||
return ret;
|
||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
|
||
index 75896c8..728fa77 100644
|
||
--- a/net/mac80211/ieee80211_i.h
|
||
+++ b/net/mac80211/ieee80211_i.h
|
||
@@ -790,12 +790,15 @@ struct tpt_led_trigger {
|
||
* that the scan completed.
|
||
* @SCAN_ABORTED: Set for our scan work function when the driver reported
|
||
* a scan complete for an aborted scan.
|
||
+ * @SCAN_HW_CANCELLED: Set for our scan work function when the scan is being
|
||
+ * cancelled.
|
||
*/
|
||
enum {
|
||
SCAN_SW_SCANNING,
|
||
SCAN_HW_SCANNING,
|
||
SCAN_COMPLETED,
|
||
SCAN_ABORTED,
|
||
+ SCAN_HW_CANCELLED,
|
||
};
|
||
|
||
/**
|
||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
|
||
index 067aa2a..f5ed863 100644
|
||
--- a/net/mac80211/rx.c
|
||
+++ b/net/mac80211/rx.c
|
||
@@ -763,7 +763,8 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
|
||
u16 sc;
|
||
u8 tid, ack_policy;
|
||
|
||
- if (!ieee80211_is_data_qos(hdr->frame_control))
|
||
+ if (!ieee80211_is_data_qos(hdr->frame_control) ||
|
||
+ is_multicast_ether_addr(hdr->addr1))
|
||
goto dont_reorder;
|
||
|
||
/*
|
||
@@ -2827,6 +2828,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||
case NL80211_IFTYPE_ADHOC:
|
||
if (!bssid)
|
||
return 0;
|
||
+ if (compare_ether_addr(sdata->vif.addr, hdr->addr2) == 0 ||
|
||
+ compare_ether_addr(sdata->u.ibss.bssid, hdr->addr2) == 0)
|
||
+ return 0;
|
||
if (ieee80211_is_beacon(hdr->frame_control)) {
|
||
return 1;
|
||
}
|
||
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
|
||
index bcc57f9..9520749 100644
|
||
--- a/net/mac80211/scan.c
|
||
+++ b/net/mac80211/scan.c
|
||
@@ -259,6 +259,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
|
||
enum ieee80211_band band;
|
||
int i, ielen, n_chans;
|
||
|
||
+ if (test_bit(SCAN_HW_CANCELLED, &local->scanning))
|
||
+ return false;
|
||
+
|
||
do {
|
||
if (local->hw_scan_band == IEEE80211_NUM_BANDS)
|
||
return false;
|
||
@@ -844,7 +847,23 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
|
||
if (!local->scan_req)
|
||
goto out;
|
||
|
||
+ /*
|
||
+ * We have a scan running and the driver already reported completion,
|
||
+ * but the worker hasn't run yet or is stuck on the mutex - mark it as
|
||
+ * cancelled.
|
||
+ */
|
||
+ if (test_bit(SCAN_HW_SCANNING, &local->scanning) &&
|
||
+ test_bit(SCAN_COMPLETED, &local->scanning)) {
|
||
+ set_bit(SCAN_HW_CANCELLED, &local->scanning);
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
|
||
+ /*
|
||
+ * Make sure that __ieee80211_scan_completed doesn't trigger a
|
||
+ * scan on another band.
|
||
+ */
|
||
+ set_bit(SCAN_HW_CANCELLED, &local->scanning);
|
||
if (local->ops->cancel_hw_scan)
|
||
drv_cancel_hw_scan(local, local->scan_sdata);
|
||
goto out;
|
||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
|
||
index e2e0e0b..569eb2c 100644
|
||
--- a/net/mac80211/sta_info.c
|
||
+++ b/net/mac80211/sta_info.c
|
||
@@ -242,6 +242,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||
return NULL;
|
||
|
||
spin_lock_init(&sta->lock);
|
||
+ spin_lock_init(&sta->ps_lock);
|
||
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
|
||
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
|
||
mutex_init(&sta->ampdu_mlme.mtx);
|
||
@@ -971,6 +972,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||
|
||
skb_queue_head_init(&pending);
|
||
|
||
+ /* sync with ieee80211_tx_h_unicast_ps_buf */
|
||
+ spin_lock(&sta->ps_lock);
|
||
/* Send all buffered frames to the station */
|
||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||
int count = skb_queue_len(&pending), tmp;
|
||
@@ -990,6 +993,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||
}
|
||
|
||
ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
|
||
+ spin_unlock(&sta->ps_lock);
|
||
|
||
local->total_ps_buffered -= buffered;
|
||
|
||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
|
||
index ab05768..249f4d0 100644
|
||
--- a/net/mac80211/sta_info.h
|
||
+++ b/net/mac80211/sta_info.h
|
||
@@ -227,6 +227,7 @@ struct sta_ampdu_mlme {
|
||
* @drv_unblock_wk: used for driver PS unblocking
|
||
* @listen_interval: listen interval of this station, when we're acting as AP
|
||
* @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
|
||
+ * @ps_lock: used for powersave (when mac80211 is the AP) related locking
|
||
* @ps_tx_buf: buffers (per AC) of frames to transmit to this station
|
||
* when it leaves power saving state or polls
|
||
* @tx_filtered: buffers (per AC) of frames we already tried to
|
||
@@ -297,10 +298,8 @@ struct sta_info {
|
||
/* use the accessors defined below */
|
||
unsigned long _flags;
|
||
|
||
- /*
|
||
- * STA powersave frame queues, no more than the internal
|
||
- * locking required.
|
||
- */
|
||
+ /* STA powersave lock and frame queues */
|
||
+ spinlock_t ps_lock;
|
||
struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
|
||
struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
|
||
unsigned long driver_buffered_tids;
|
||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
|
||
index 47b117f..9e88897 100644
|
||
--- a/net/mac80211/status.c
|
||
+++ b/net/mac80211/status.c
|
||
@@ -183,6 +183,9 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
|
||
struct ieee80211_local *local = sta->local;
|
||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||
|
||
+ if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
|
||
+ sta->last_rx = jiffies;
|
||
+
|
||
if (ieee80211_is_data_qos(mgmt->frame_control)) {
|
||
struct ieee80211_hdr *hdr = (void *) skb->data;
|
||
u8 *qc = ieee80211_get_qos_ctl(hdr);
|
||
@@ -429,7 +432,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||
IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
|
||
IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
|
||
|
||
- ieee80211_set_bar_pending(sta, tid, ssn);
|
||
+ if (local->hw.flags &
|
||
+ IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL)
|
||
+ ieee80211_stop_tx_ba_session(&sta->sta, tid);
|
||
+ else
|
||
+ ieee80211_set_bar_pending(sta, tid, ssn);
|
||
}
|
||
}
|
||
|
||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
|
||
index eace766..b7fc3dd 100644
|
||
--- a/net/mac80211/tx.c
|
||
+++ b/net/mac80211/tx.c
|
||
@@ -471,6 +471,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
|
||
purge_old_ps_buffers(tx->local);
|
||
+
|
||
+ /* sync with ieee80211_sta_ps_deliver_wakeup */
|
||
+ spin_lock(&sta->ps_lock);
|
||
+ /*
|
||
+ * STA woke up the meantime and all the frames on ps_tx_buf have
|
||
+ * been queued to pending queue. No reordering can happen, go
|
||
+ * ahead and Tx the packet.
|
||
+ */
|
||
+ if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
|
||
+ !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
|
||
+ spin_unlock(&sta->ps_lock);
|
||
+ return TX_CONTINUE;
|
||
+ }
|
||
+
|
||
if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
|
||
struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
|
||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||
@@ -487,6 +501,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
||
info->control.vif = &tx->sdata->vif;
|
||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||
skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
|
||
+ spin_unlock(&sta->ps_lock);
|
||
|
||
if (!timer_pending(&local->sta_cleanup))
|
||
mod_timer(&local->sta_cleanup,
|
||
@@ -907,7 +922,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx,
|
||
}
|
||
|
||
/* adjust first fragment's length */
|
||
- skb->len = hdrlen + per_fragm;
|
||
+ skb_trim(skb, hdrlen + per_fragm);
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
|
||
index 93faf6a..4a8c55b 100644
|
||
--- a/net/netfilter/nf_conntrack_sip.c
|
||
+++ b/net/netfilter/nf_conntrack_sip.c
|
||
@@ -1468,7 +1468,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
|
||
|
||
msglen = origlen = end - dptr;
|
||
if (msglen > datalen)
|
||
- return NF_DROP;
|
||
+ return NF_ACCEPT;
|
||
|
||
ret = process_sip_msg(skb, ct, dataoff, &dptr, &msglen);
|
||
if (ret != NF_ACCEPT)
|
||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
|
||
index 5155386..fc40cb3 100644
|
||
--- a/net/netlink/af_netlink.c
|
||
+++ b/net/netlink/af_netlink.c
|
||
@@ -1446,8 +1446,6 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
|
||
}
|
||
#endif
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
copied = data_skb->len;
|
||
if (len < copied) {
|
||
msg->msg_flags |= MSG_TRUNC;
|
||
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
|
||
index 7ed9b1d..dcf6791 100644
|
||
--- a/net/netrom/af_netrom.c
|
||
+++ b/net/netrom/af_netrom.c
|
||
@@ -1181,10 +1181,9 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
sax->sax25_family = AF_NETROM;
|
||
skb_copy_from_linear_data_offset(skb, 7, sax->sax25_call.ax25_call,
|
||
AX25_ADDR_LEN);
|
||
+ msg->msg_namelen = sizeof(*sax);
|
||
}
|
||
|
||
- msg->msg_namelen = sizeof(*sax);
|
||
-
|
||
skb_free_datagram(sk, skb);
|
||
|
||
release_sock(sk);
|
||
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
|
||
index e879dce..44835ce 100644
|
||
--- a/net/nfc/rawsock.c
|
||
+++ b/net/nfc/rawsock.c
|
||
@@ -235,8 +235,6 @@ static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (!skb)
|
||
return rc;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
copied = skb->len;
|
||
if (len < copied) {
|
||
msg->msg_flags |= MSG_TRUNC;
|
||
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
|
||
index 04279cc..030bd3f 100644
|
||
--- a/net/packet/af_packet.c
|
||
+++ b/net/packet/af_packet.c
|
||
@@ -294,6 +294,7 @@ struct packet_sock {
|
||
unsigned int tp_reserve;
|
||
unsigned int tp_loss:1;
|
||
unsigned int tp_tstamp;
|
||
+ struct net_device __rcu *cached_dev;
|
||
struct packet_type prot_hook ____cacheline_aligned_in_smp;
|
||
};
|
||
|
||
@@ -349,11 +350,15 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po);
|
||
static void register_prot_hook(struct sock *sk)
|
||
{
|
||
struct packet_sock *po = pkt_sk(sk);
|
||
+
|
||
if (!po->running) {
|
||
- if (po->fanout)
|
||
+ if (po->fanout) {
|
||
__fanout_link(sk, po);
|
||
- else
|
||
+ } else {
|
||
dev_add_pack(&po->prot_hook);
|
||
+ rcu_assign_pointer(po->cached_dev, po->prot_hook.dev);
|
||
+ }
|
||
+
|
||
sock_hold(sk);
|
||
po->running = 1;
|
||
}
|
||
@@ -371,10 +376,13 @@ static void __unregister_prot_hook(struct sock *sk, bool sync)
|
||
struct packet_sock *po = pkt_sk(sk);
|
||
|
||
po->running = 0;
|
||
- if (po->fanout)
|
||
+ if (po->fanout) {
|
||
__fanout_unlink(sk, po);
|
||
- else
|
||
+ } else {
|
||
__dev_remove_pack(&po->prot_hook);
|
||
+ RCU_INIT_POINTER(po->cached_dev, NULL);
|
||
+ }
|
||
+
|
||
__sock_put(sk);
|
||
|
||
if (sync) {
|
||
@@ -496,9 +504,9 @@ static void prb_shutdown_retire_blk_timer(struct packet_sock *po,
|
||
|
||
pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc;
|
||
|
||
- spin_lock(&rb_queue->lock);
|
||
+ spin_lock_bh(&rb_queue->lock);
|
||
pkc->delete_blk_timer = 1;
|
||
- spin_unlock(&rb_queue->lock);
|
||
+ spin_unlock_bh(&rb_queue->lock);
|
||
|
||
prb_del_retire_blk_timer(pkc);
|
||
}
|
||
@@ -2044,12 +2052,24 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
|
||
return tp_len;
|
||
}
|
||
|
||
+static struct net_device *packet_cached_dev_get(struct packet_sock *po)
|
||
+{
|
||
+ struct net_device *dev;
|
||
+
|
||
+ rcu_read_lock();
|
||
+ dev = rcu_dereference(po->cached_dev);
|
||
+ if (dev)
|
||
+ dev_hold(dev);
|
||
+ rcu_read_unlock();
|
||
+
|
||
+ return dev;
|
||
+}
|
||
+
|
||
static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
|
||
{
|
||
struct sk_buff *skb;
|
||
struct net_device *dev;
|
||
__be16 proto;
|
||
- bool need_rls_dev = false;
|
||
int err, reserve = 0;
|
||
void *ph;
|
||
struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name;
|
||
@@ -2063,7 +2083,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
|
||
|
||
err = -EBUSY;
|
||
if (saddr == NULL) {
|
||
- dev = po->prot_hook.dev;
|
||
+ dev = packet_cached_dev_get(po);
|
||
proto = po->num;
|
||
addr = NULL;
|
||
} else {
|
||
@@ -2077,19 +2097,17 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
|
||
proto = saddr->sll_protocol;
|
||
addr = saddr->sll_addr;
|
||
dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex);
|
||
- need_rls_dev = true;
|
||
}
|
||
|
||
err = -ENXIO;
|
||
if (unlikely(dev == NULL))
|
||
goto out;
|
||
-
|
||
- reserve = dev->hard_header_len;
|
||
-
|
||
err = -ENETDOWN;
|
||
if (unlikely(!(dev->flags & IFF_UP)))
|
||
goto out_put;
|
||
|
||
+ reserve = dev->hard_header_len;
|
||
+
|
||
size_max = po->tx_ring.frame_size
|
||
- (po->tp_hdrlen - sizeof(struct sockaddr_ll));
|
||
|
||
@@ -2166,8 +2184,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
|
||
__packet_set_status(po, ph, status);
|
||
kfree_skb(skb);
|
||
out_put:
|
||
- if (need_rls_dev)
|
||
- dev_put(dev);
|
||
+ dev_put(dev);
|
||
out:
|
||
mutex_unlock(&po->pg_vec_lock);
|
||
return err;
|
||
@@ -2205,7 +2222,6 @@ static int packet_snd(struct socket *sock,
|
||
struct sk_buff *skb;
|
||
struct net_device *dev;
|
||
__be16 proto;
|
||
- bool need_rls_dev = false;
|
||
unsigned char *addr;
|
||
int err, reserve = 0;
|
||
struct virtio_net_hdr vnet_hdr = { 0 };
|
||
@@ -2221,7 +2237,7 @@ static int packet_snd(struct socket *sock,
|
||
*/
|
||
|
||
if (saddr == NULL) {
|
||
- dev = po->prot_hook.dev;
|
||
+ dev = packet_cached_dev_get(po);
|
||
proto = po->num;
|
||
addr = NULL;
|
||
} else {
|
||
@@ -2233,19 +2249,17 @@ static int packet_snd(struct socket *sock,
|
||
proto = saddr->sll_protocol;
|
||
addr = saddr->sll_addr;
|
||
dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex);
|
||
- need_rls_dev = true;
|
||
}
|
||
|
||
err = -ENXIO;
|
||
- if (dev == NULL)
|
||
+ if (unlikely(dev == NULL))
|
||
goto out_unlock;
|
||
- if (sock->type == SOCK_RAW)
|
||
- reserve = dev->hard_header_len;
|
||
-
|
||
err = -ENETDOWN;
|
||
- if (!(dev->flags & IFF_UP))
|
||
+ if (unlikely(!(dev->flags & IFF_UP)))
|
||
goto out_unlock;
|
||
|
||
+ if (sock->type == SOCK_RAW)
|
||
+ reserve = dev->hard_header_len;
|
||
if (po->has_vnet_hdr) {
|
||
vnet_hdr_len = sizeof(vnet_hdr);
|
||
|
||
@@ -2378,15 +2392,14 @@ static int packet_snd(struct socket *sock,
|
||
if (err > 0 && (err = net_xmit_errno(err)) != 0)
|
||
goto out_unlock;
|
||
|
||
- if (need_rls_dev)
|
||
- dev_put(dev);
|
||
+ dev_put(dev);
|
||
|
||
return len;
|
||
|
||
out_free:
|
||
kfree_skb(skb);
|
||
out_unlock:
|
||
- if (dev && need_rls_dev)
|
||
+ if (dev)
|
||
dev_put(dev);
|
||
out:
|
||
return err;
|
||
@@ -2603,6 +2616,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
|
||
po = pkt_sk(sk);
|
||
sk->sk_family = PF_PACKET;
|
||
po->num = proto;
|
||
+ RCU_INIT_POINTER(po->cached_dev, NULL);
|
||
|
||
sk->sk_destruct = packet_sock_destruct;
|
||
sk_refcnt_debug_inc(sk);
|
||
@@ -2691,7 +2705,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
struct sock *sk = sock->sk;
|
||
struct sk_buff *skb;
|
||
int copied, err;
|
||
- struct sockaddr_ll *sll;
|
||
int vnet_hdr_len = 0;
|
||
|
||
err = -EINVAL;
|
||
@@ -2774,22 +2787,10 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
goto out_free;
|
||
}
|
||
|
||
- /*
|
||
- * If the address length field is there to be filled in, we fill
|
||
- * it in now.
|
||
+ /* You lose any data beyond the buffer you gave. If it worries
|
||
+ * a user program they can ask the device for its MTU
|
||
+ * anyway.
|
||
*/
|
||
-
|
||
- sll = &PACKET_SKB_CB(skb)->sa.ll;
|
||
- if (sock->type == SOCK_PACKET)
|
||
- msg->msg_namelen = sizeof(struct sockaddr_pkt);
|
||
- else
|
||
- msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr);
|
||
-
|
||
- /*
|
||
- * You lose any data beyond the buffer you gave. If it worries a
|
||
- * user program they can ask the device for its MTU anyway.
|
||
- */
|
||
-
|
||
copied = skb->len;
|
||
if (copied > len) {
|
||
copied = len;
|
||
@@ -2802,9 +2803,20 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
|
||
sock_recv_ts_and_drops(msg, sk, skb);
|
||
|
||
- if (msg->msg_name)
|
||
+ if (msg->msg_name) {
|
||
+ /* If the address length field is there to be filled
|
||
+ * in, we fill it in now.
|
||
+ */
|
||
+ if (sock->type == SOCK_PACKET) {
|
||
+ msg->msg_namelen = sizeof(struct sockaddr_pkt);
|
||
+ } else {
|
||
+ struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll;
|
||
+ msg->msg_namelen = sll->sll_halen +
|
||
+ offsetof(struct sockaddr_ll, sll_addr);
|
||
+ }
|
||
memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
|
||
msg->msg_namelen);
|
||
+ }
|
||
|
||
if (pkt_sk(sk)->auxdata) {
|
||
struct tpacket_auxdata aux;
|
||
diff --git a/net/rds/ib.c b/net/rds/ib.c
|
||
index b4c8b00..ba2dffe 100644
|
||
--- a/net/rds/ib.c
|
||
+++ b/net/rds/ib.c
|
||
@@ -338,7 +338,8 @@ static int rds_ib_laddr_check(__be32 addr)
|
||
ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin);
|
||
/* due to this, we will claim to support iWARP devices unless we
|
||
check node_type. */
|
||
- if (ret || cm_id->device->node_type != RDMA_NODE_IB_CA)
|
||
+ if (ret || !cm_id->device ||
|
||
+ cm_id->device->node_type != RDMA_NODE_IB_CA)
|
||
ret = -EADDRNOTAVAIL;
|
||
|
||
rdsdebug("addr %pI4 ret %d node type %d\n",
|
||
diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c
|
||
index e590949..37be6e2 100644
|
||
--- a/net/rds/ib_send.c
|
||
+++ b/net/rds/ib_send.c
|
||
@@ -552,9 +552,8 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
|
||
&& rm->m_inc.i_hdr.h_flags & RDS_FLAG_CONG_BITMAP) {
|
||
rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
|
||
scat = &rm->data.op_sg[sg];
|
||
- ret = sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
|
||
- ret = min_t(int, ret, scat->length - conn->c_xmit_data_off);
|
||
- return ret;
|
||
+ ret = max_t(int, RDS_CONG_MAP_BYTES, scat->length);
|
||
+ return sizeof(struct rds_header) + ret;
|
||
}
|
||
|
||
/* FIXME we may overallocate here */
|
||
diff --git a/net/rds/iw.c b/net/rds/iw.c
|
||
index 7826d46..5899356 100644
|
||
--- a/net/rds/iw.c
|
||
+++ b/net/rds/iw.c
|
||
@@ -239,7 +239,8 @@ static int rds_iw_laddr_check(__be32 addr)
|
||
ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin);
|
||
/* due to this, we will claim to support IB devices unless we
|
||
check node_type. */
|
||
- if (ret || cm_id->device->node_type != RDMA_NODE_RNIC)
|
||
+ if (ret || !cm_id->device ||
|
||
+ cm_id->device->node_type != RDMA_NODE_RNIC)
|
||
ret = -EADDRNOTAVAIL;
|
||
|
||
rdsdebug("addr %pI4 ret %d node type %d\n",
|
||
diff --git a/net/rds/recv.c b/net/rds/recv.c
|
||
index 9f0f17c..de339b2 100644
|
||
--- a/net/rds/recv.c
|
||
+++ b/net/rds/recv.c
|
||
@@ -410,8 +410,6 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
|
||
|
||
rdsdebug("size %zu flags 0x%x timeo %ld\n", size, msg_flags, timeo);
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
if (msg_flags & MSG_OOB)
|
||
goto out;
|
||
|
||
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
|
||
index 7f645d1..bde7d69 100644
|
||
--- a/net/rose/af_rose.c
|
||
+++ b/net/rose/af_rose.c
|
||
@@ -1220,7 +1220,6 @@ static int rose_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
{
|
||
struct sock *sk = sock->sk;
|
||
struct rose_sock *rose = rose_sk(sk);
|
||
- struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name;
|
||
size_t copied;
|
||
unsigned char *asmptr;
|
||
struct sk_buff *skb;
|
||
@@ -1256,24 +1255,19 @@ static int rose_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
|
||
skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
|
||
|
||
- if (srose != NULL) {
|
||
- memset(srose, 0, msg->msg_namelen);
|
||
+ if (msg->msg_name) {
|
||
+ struct sockaddr_rose *srose;
|
||
+ struct full_sockaddr_rose *full_srose = msg->msg_name;
|
||
+
|
||
+ memset(msg->msg_name, 0, sizeof(struct full_sockaddr_rose));
|
||
+ srose = msg->msg_name;
|
||
srose->srose_family = AF_ROSE;
|
||
srose->srose_addr = rose->dest_addr;
|
||
srose->srose_call = rose->dest_call;
|
||
srose->srose_ndigis = rose->dest_ndigis;
|
||
- if (msg->msg_namelen >= sizeof(struct full_sockaddr_rose)) {
|
||
- struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)msg->msg_name;
|
||
- for (n = 0 ; n < rose->dest_ndigis ; n++)
|
||
- full_srose->srose_digis[n] = rose->dest_digis[n];
|
||
- msg->msg_namelen = sizeof(struct full_sockaddr_rose);
|
||
- } else {
|
||
- if (rose->dest_ndigis >= 1) {
|
||
- srose->srose_ndigis = 1;
|
||
- srose->srose_digi = rose->dest_digis[0];
|
||
- }
|
||
- msg->msg_namelen = sizeof(struct sockaddr_rose);
|
||
- }
|
||
+ for (n = 0 ; n < rose->dest_ndigis ; n++)
|
||
+ full_srose->srose_digis[n] = rose->dest_digis[n];
|
||
+ msg->msg_namelen = sizeof(struct full_sockaddr_rose);
|
||
}
|
||
|
||
skb_free_datagram(sk, skb);
|
||
diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c
|
||
index 4b48687..898492a 100644
|
||
--- a/net/rxrpc/ar-recvmsg.c
|
||
+++ b/net/rxrpc/ar-recvmsg.c
|
||
@@ -143,10 +143,13 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
|
||
/* copy the peer address and timestamp */
|
||
if (!continue_call) {
|
||
- if (msg->msg_name && msg->msg_namelen > 0)
|
||
+ if (msg->msg_name) {
|
||
+ size_t len =
|
||
+ sizeof(call->conn->trans->peer->srx);
|
||
memcpy(msg->msg_name,
|
||
- &call->conn->trans->peer->srx,
|
||
- sizeof(call->conn->trans->peer->srx));
|
||
+ &call->conn->trans->peer->srx, len);
|
||
+ msg->msg_namelen = len;
|
||
+ }
|
||
sock_recv_ts_and_drops(msg, &rx->sk, skb);
|
||
}
|
||
|
||
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
|
||
index e051398..d067ed1 100644
|
||
--- a/net/sched/act_mirred.c
|
||
+++ b/net/sched/act_mirred.c
|
||
@@ -201,13 +201,12 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
|
||
out:
|
||
if (err) {
|
||
m->tcf_qstats.overlimits++;
|
||
- /* should we be asking for packet to be dropped?
|
||
- * may make sense for redirect case only
|
||
- */
|
||
- retval = TC_ACT_SHOT;
|
||
- } else {
|
||
+ if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
|
||
+ retval = TC_ACT_SHOT;
|
||
+ else
|
||
+ retval = m->tcf_action;
|
||
+ } else
|
||
retval = m->tcf_action;
|
||
- }
|
||
spin_unlock(&m->tcf_lock);
|
||
|
||
return retval;
|
||
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
|
||
index 3c04692..da54d29 100644
|
||
--- a/net/sctp/associola.c
|
||
+++ b/net/sctp/associola.c
|
||
@@ -389,7 +389,7 @@ void sctp_association_free(struct sctp_association *asoc)
|
||
/* Only real associations count against the endpoint, so
|
||
* don't bother for if this is a temporary association.
|
||
*/
|
||
- if (!asoc->temp) {
|
||
+ if (!list_empty(&asoc->asocs)) {
|
||
list_del(&asoc->asocs);
|
||
|
||
/* Decrement the backlog value for a TCP-style listening
|
||
@@ -1188,6 +1188,7 @@ void sctp_assoc_update(struct sctp_association *asoc,
|
||
asoc->c = new->c;
|
||
asoc->peer.rwnd = new->peer.rwnd;
|
||
asoc->peer.sack_needed = new->peer.sack_needed;
|
||
+ asoc->peer.auth_capable = new->peer.auth_capable;
|
||
asoc->peer.i = new->peer.i;
|
||
sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
|
||
asoc->peer.i.initial_tsn, GFP_ATOMIC);
|
||
diff --git a/net/sctp/output.c b/net/sctp/output.c
|
||
index 32ba8d0..5bd9aa9 100644
|
||
--- a/net/sctp/output.c
|
||
+++ b/net/sctp/output.c
|
||
@@ -518,7 +518,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
|
||
* by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
|
||
*/
|
||
if (!sctp_checksum_disable) {
|
||
- if (!(dst->dev->features & NETIF_F_SCTP_CSUM)) {
|
||
+ if (!(dst->dev->features & NETIF_F_SCTP_CSUM) ||
|
||
+ (dst_xfrm(dst) != NULL) || packet->ipfragok) {
|
||
__u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len);
|
||
|
||
/* 3) Put the resultant value into the checksum field in the
|
||
@@ -586,7 +587,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
|
||
return err;
|
||
no_route:
|
||
kfree_skb(nskb);
|
||
- IP_INC_STATS_BH(&init_net, IPSTATS_MIB_OUTNOROUTES);
|
||
+ IP_INC_STATS(&init_net, IPSTATS_MIB_OUTNOROUTES);
|
||
|
||
/* FIXME: Returning the 'err' will effect all the associations
|
||
* associated with a socket, although only one of the paths of the
|
||
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
|
||
index a85eeeb..adb0287 100644
|
||
--- a/net/sctp/sm_make_chunk.c
|
||
+++ b/net/sctp/sm_make_chunk.c
|
||
@@ -1366,8 +1366,8 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
|
||
BUG_ON(!list_empty(&chunk->list));
|
||
list_del_init(&chunk->transmitted_list);
|
||
|
||
- /* Free the chunk skb data and the SCTP_chunk stub itself. */
|
||
- dev_kfree_skb(chunk->skb);
|
||
+ consume_skb(chunk->skb);
|
||
+ consume_skb(chunk->auth_chunk);
|
||
|
||
SCTP_DBG_OBJCNT_DEC(chunk);
|
||
kmem_cache_free(sctp_chunk_cachep, chunk);
|
||
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
|
||
index cb1c430..5ac33b6 100644
|
||
--- a/net/sctp/sm_statefuns.c
|
||
+++ b/net/sctp/sm_statefuns.c
|
||
@@ -747,6 +747,12 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
|
||
struct sctp_chunk auth;
|
||
sctp_ierror_t ret;
|
||
|
||
+ /* Make sure that we and the peer are AUTH capable */
|
||
+ if (!sctp_auth_enable || !new_asoc->peer.auth_capable) {
|
||
+ sctp_association_free(new_asoc);
|
||
+ return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
|
||
+ }
|
||
+
|
||
/* set-up our fake chunk so that we can process it */
|
||
auth.skb = chunk->auth_chunk;
|
||
auth.asoc = chunk->asoc;
|
||
@@ -757,10 +763,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
|
||
auth.transport = chunk->transport;
|
||
|
||
ret = sctp_sf_authenticate(ep, new_asoc, type, &auth);
|
||
-
|
||
- /* We can now safely free the auth_chunk clone */
|
||
- kfree_skb(chunk->auth_chunk);
|
||
-
|
||
if (ret != SCTP_IERROR_NO_ERROR) {
|
||
sctp_association_free(new_asoc);
|
||
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
|
||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
|
||
index e9e50ca..0c0bd2f 100644
|
||
--- a/net/sctp/socket.c
|
||
+++ b/net/sctp/socket.c
|
||
@@ -70,6 +70,7 @@
|
||
#include <linux/init.h>
|
||
#include <linux/crypto.h>
|
||
#include <linux/slab.h>
|
||
+#include <linux/compat.h>
|
||
|
||
#include <net/ip.h>
|
||
#include <net/icmp.h>
|
||
@@ -1376,11 +1377,19 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
|
||
/*
|
||
* New (hopefully final) interface for the API.
|
||
* We use the sctp_getaddrs_old structure so that use-space library
|
||
- * can avoid any unnecessary allocations. The only defferent part
|
||
+ * can avoid any unnecessary allocations. The only different part
|
||
* is that we store the actual length of the address buffer into the
|
||
- * addrs_num structure member. That way we can re-use the existing
|
||
+ * addrs_num structure member. That way we can re-use the existing
|
||
* code.
|
||
*/
|
||
+#ifdef CONFIG_COMPAT
|
||
+struct compat_sctp_getaddrs_old {
|
||
+ sctp_assoc_t assoc_id;
|
||
+ s32 addr_num;
|
||
+ compat_uptr_t addrs; /* struct sockaddr * */
|
||
+};
|
||
+#endif
|
||
+
|
||
SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len,
|
||
char __user *optval,
|
||
int __user *optlen)
|
||
@@ -1389,16 +1398,30 @@ SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len,
|
||
sctp_assoc_t assoc_id = 0;
|
||
int err = 0;
|
||
|
||
- if (len < sizeof(param))
|
||
- return -EINVAL;
|
||
+#ifdef CONFIG_COMPAT
|
||
+ if (is_compat_task()) {
|
||
+ struct compat_sctp_getaddrs_old param32;
|
||
|
||
- if (copy_from_user(¶m, optval, sizeof(param)))
|
||
- return -EFAULT;
|
||
+ if (len < sizeof(param32))
|
||
+ return -EINVAL;
|
||
+ if (copy_from_user(¶m32, optval, sizeof(param32)))
|
||
+ return -EFAULT;
|
||
|
||
- err = __sctp_setsockopt_connectx(sk,
|
||
- (struct sockaddr __user *)param.addrs,
|
||
- param.addr_num, &assoc_id);
|
||
+ param.assoc_id = param32.assoc_id;
|
||
+ param.addr_num = param32.addr_num;
|
||
+ param.addrs = compat_ptr(param32.addrs);
|
||
+ } else
|
||
+#endif
|
||
+ {
|
||
+ if (len < sizeof(param))
|
||
+ return -EINVAL;
|
||
+ if (copy_from_user(¶m, optval, sizeof(param)))
|
||
+ return -EFAULT;
|
||
+ }
|
||
|
||
+ err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *)
|
||
+ param.addrs, param.addr_num,
|
||
+ &assoc_id);
|
||
if (err == 0 || err == -EINPROGRESS) {
|
||
if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
|
||
return -EFAULT;
|
||
@@ -6346,6 +6369,46 @@ static void __sctp_write_space(struct sctp_association *asoc)
|
||
}
|
||
}
|
||
|
||
+static void sctp_wake_up_waiters(struct sock *sk,
|
||
+ struct sctp_association *asoc)
|
||
+{
|
||
+ struct sctp_association *tmp = asoc;
|
||
+
|
||
+ /* We do accounting for the sndbuf space per association,
|
||
+ * so we only need to wake our own association.
|
||
+ */
|
||
+ if (asoc->ep->sndbuf_policy)
|
||
+ return __sctp_write_space(asoc);
|
||
+
|
||
+ /* If association goes down and is just flushing its
|
||
+ * outq, then just normally notify others.
|
||
+ */
|
||
+ if (asoc->base.dead)
|
||
+ return sctp_write_space(sk);
|
||
+
|
||
+ /* Accounting for the sndbuf space is per socket, so we
|
||
+ * need to wake up others, try to be fair and in case of
|
||
+ * other associations, let them have a go first instead
|
||
+ * of just doing a sctp_write_space() call.
|
||
+ *
|
||
+ * Note that we reach sctp_wake_up_waiters() only when
|
||
+ * associations free up queued chunks, thus we are under
|
||
+ * lock and the list of associations on a socket is
|
||
+ * guaranteed not to change.
|
||
+ */
|
||
+ for (tmp = list_next_entry(tmp, asocs); 1;
|
||
+ tmp = list_next_entry(tmp, asocs)) {
|
||
+ /* Manually skip the head element. */
|
||
+ if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs))
|
||
+ continue;
|
||
+ /* Wake up association. */
|
||
+ __sctp_write_space(tmp);
|
||
+ /* We've reached the end. */
|
||
+ if (tmp == asoc)
|
||
+ break;
|
||
+ }
|
||
+}
|
||
+
|
||
/* Do accounting for the sndbuf space.
|
||
* Decrement the used sndbuf space of the corresponding association by the
|
||
* data size which was just transmitted(freed).
|
||
@@ -6373,7 +6436,7 @@ static void sctp_wfree(struct sk_buff *skb)
|
||
sk_mem_uncharge(sk, skb->truesize);
|
||
|
||
sock_wfree(skb);
|
||
- __sctp_write_space(asoc);
|
||
+ sctp_wake_up_waiters(sk, asoc);
|
||
|
||
sctp_association_put(asoc);
|
||
}
|
||
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
|
||
index 8a84017..57da447 100644
|
||
--- a/net/sctp/ulpevent.c
|
||
+++ b/net/sctp/ulpevent.c
|
||
@@ -373,9 +373,10 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
|
||
* specification [SCTP] and any extensions for a list of possible
|
||
* error formats.
|
||
*/
|
||
-struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
|
||
- const struct sctp_association *asoc, struct sctp_chunk *chunk,
|
||
- __u16 flags, gfp_t gfp)
|
||
+struct sctp_ulpevent *
|
||
+sctp_ulpevent_make_remote_error(const struct sctp_association *asoc,
|
||
+ struct sctp_chunk *chunk, __u16 flags,
|
||
+ gfp_t gfp)
|
||
{
|
||
struct sctp_ulpevent *event;
|
||
struct sctp_remote_error *sre;
|
||
@@ -394,8 +395,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
|
||
/* Copy the skb to a new skb with room for us to prepend
|
||
* notification with.
|
||
*/
|
||
- skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error),
|
||
- 0, gfp);
|
||
+ skb = skb_copy_expand(chunk->skb, sizeof(*sre), 0, gfp);
|
||
|
||
/* Pull off the rest of the cause TLV from the chunk. */
|
||
skb_pull(chunk->skb, elen);
|
||
@@ -406,62 +406,21 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
|
||
event = sctp_skb2event(skb);
|
||
sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
|
||
|
||
- sre = (struct sctp_remote_error *)
|
||
- skb_push(skb, sizeof(struct sctp_remote_error));
|
||
+ sre = (struct sctp_remote_error *) skb_push(skb, sizeof(*sre));
|
||
|
||
/* Trim the buffer to the right length. */
|
||
- skb_trim(skb, sizeof(struct sctp_remote_error) + elen);
|
||
+ skb_trim(skb, sizeof(*sre) + elen);
|
||
|
||
- /* Socket Extensions for SCTP
|
||
- * 5.3.1.3 SCTP_REMOTE_ERROR
|
||
- *
|
||
- * sre_type:
|
||
- * It should be SCTP_REMOTE_ERROR.
|
||
- */
|
||
+ /* RFC6458, Section 6.1.3. SCTP_REMOTE_ERROR */
|
||
+ memset(sre, 0, sizeof(*sre));
|
||
sre->sre_type = SCTP_REMOTE_ERROR;
|
||
-
|
||
- /*
|
||
- * Socket Extensions for SCTP
|
||
- * 5.3.1.3 SCTP_REMOTE_ERROR
|
||
- *
|
||
- * sre_flags: 16 bits (unsigned integer)
|
||
- * Currently unused.
|
||
- */
|
||
sre->sre_flags = 0;
|
||
-
|
||
- /* Socket Extensions for SCTP
|
||
- * 5.3.1.3 SCTP_REMOTE_ERROR
|
||
- *
|
||
- * sre_length: sizeof (__u32)
|
||
- *
|
||
- * This field is the total length of the notification data,
|
||
- * including the notification header.
|
||
- */
|
||
sre->sre_length = skb->len;
|
||
-
|
||
- /* Socket Extensions for SCTP
|
||
- * 5.3.1.3 SCTP_REMOTE_ERROR
|
||
- *
|
||
- * sre_error: 16 bits (unsigned integer)
|
||
- * This value represents one of the Operational Error causes defined in
|
||
- * the SCTP specification, in network byte order.
|
||
- */
|
||
sre->sre_error = cause;
|
||
-
|
||
- /* Socket Extensions for SCTP
|
||
- * 5.3.1.3 SCTP_REMOTE_ERROR
|
||
- *
|
||
- * sre_assoc_id: sizeof (sctp_assoc_t)
|
||
- *
|
||
- * The association id field, holds the identifier for the association.
|
||
- * All notifications for a given association have the same association
|
||
- * identifier. For TCP style socket, this field is ignored.
|
||
- */
|
||
sctp_ulpevent_set_owner(event, asoc);
|
||
sre->sre_assoc_id = sctp_assoc2id(asoc);
|
||
|
||
return event;
|
||
-
|
||
fail:
|
||
return NULL;
|
||
}
|
||
@@ -904,7 +863,9 @@ __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event)
|
||
return notification->sn_header.sn_type;
|
||
}
|
||
|
||
-/* Copy out the sndrcvinfo into a msghdr. */
|
||
+/* RFC6458, Section 5.3.2. SCTP Header Information Structure
|
||
+ * (SCTP_SNDRCV, DEPRECATED)
|
||
+ */
|
||
void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
|
||
struct msghdr *msghdr)
|
||
{
|
||
@@ -913,74 +874,21 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
|
||
if (sctp_ulpevent_is_notification(event))
|
||
return;
|
||
|
||
- /* Sockets API Extensions for SCTP
|
||
- * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
|
||
- *
|
||
- * sinfo_stream: 16 bits (unsigned integer)
|
||
- *
|
||
- * For recvmsg() the SCTP stack places the message's stream number in
|
||
- * this value.
|
||
- */
|
||
+ memset(&sinfo, 0, sizeof(sinfo));
|
||
sinfo.sinfo_stream = event->stream;
|
||
- /* sinfo_ssn: 16 bits (unsigned integer)
|
||
- *
|
||
- * For recvmsg() this value contains the stream sequence number that
|
||
- * the remote endpoint placed in the DATA chunk. For fragmented
|
||
- * messages this is the same number for all deliveries of the message
|
||
- * (if more than one recvmsg() is needed to read the message).
|
||
- */
|
||
sinfo.sinfo_ssn = event->ssn;
|
||
- /* sinfo_ppid: 32 bits (unsigned integer)
|
||
- *
|
||
- * In recvmsg() this value is
|
||
- * the same information that was passed by the upper layer in the peer
|
||
- * application. Please note that byte order issues are NOT accounted
|
||
- * for and this information is passed opaquely by the SCTP stack from
|
||
- * one end to the other.
|
||
- */
|
||
sinfo.sinfo_ppid = event->ppid;
|
||
- /* sinfo_flags: 16 bits (unsigned integer)
|
||
- *
|
||
- * This field may contain any of the following flags and is composed of
|
||
- * a bitwise OR of these values.
|
||
- *
|
||
- * recvmsg() flags:
|
||
- *
|
||
- * SCTP_UNORDERED - This flag is present when the message was sent
|
||
- * non-ordered.
|
||
- */
|
||
sinfo.sinfo_flags = event->flags;
|
||
- /* sinfo_tsn: 32 bit (unsigned integer)
|
||
- *
|
||
- * For the receiving side, this field holds a TSN that was
|
||
- * assigned to one of the SCTP Data Chunks.
|
||
- */
|
||
sinfo.sinfo_tsn = event->tsn;
|
||
- /* sinfo_cumtsn: 32 bit (unsigned integer)
|
||
- *
|
||
- * This field will hold the current cumulative TSN as
|
||
- * known by the underlying SCTP layer. Note this field is
|
||
- * ignored when sending and only valid for a receive
|
||
- * operation when sinfo_flags are set to SCTP_UNORDERED.
|
||
- */
|
||
sinfo.sinfo_cumtsn = event->cumtsn;
|
||
- /* sinfo_assoc_id: sizeof (sctp_assoc_t)
|
||
- *
|
||
- * The association handle field, sinfo_assoc_id, holds the identifier
|
||
- * for the association announced in the COMMUNICATION_UP notification.
|
||
- * All notifications for a given association have the same identifier.
|
||
- * Ignored for one-to-one style sockets.
|
||
- */
|
||
sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc);
|
||
-
|
||
- /* context value that is set via SCTP_CONTEXT socket option. */
|
||
+ /* Context value that is set via SCTP_CONTEXT socket option. */
|
||
sinfo.sinfo_context = event->asoc->default_rcv_context;
|
||
-
|
||
/* These fields are not used while receiving. */
|
||
sinfo.sinfo_timetolive = 0;
|
||
|
||
put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
|
||
- sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
|
||
+ sizeof(sinfo), &sinfo);
|
||
}
|
||
|
||
/* Do accounting for bytes received and hold a reference to the association
|
||
diff --git a/net/socket.c b/net/socket.c
|
||
index 45fcf07..7e13992 100644
|
||
--- a/net/socket.c
|
||
+++ b/net/socket.c
|
||
@@ -225,12 +225,13 @@ static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen,
|
||
int err;
|
||
int len;
|
||
|
||
+ BUG_ON(klen > sizeof(struct sockaddr_storage));
|
||
err = get_user(len, ulen);
|
||
if (err)
|
||
return err;
|
||
if (len > klen)
|
||
len = klen;
|
||
- if (len < 0 || len > sizeof(struct sockaddr_storage))
|
||
+ if (len < 0)
|
||
return -EINVAL;
|
||
if (len) {
|
||
if (audit_sockaddr(klen, kaddr))
|
||
@@ -1795,8 +1796,10 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
|
||
msg.msg_iov = &iov;
|
||
iov.iov_len = size;
|
||
iov.iov_base = ubuf;
|
||
- msg.msg_name = (struct sockaddr *)&address;
|
||
- msg.msg_namelen = sizeof(address);
|
||
+ /* Save some cycles and don't copy the address if not needed */
|
||
+ msg.msg_name = addr ? (struct sockaddr *)&address : NULL;
|
||
+ /* We assume all kernel code knows the size of sockaddr_storage */
|
||
+ msg.msg_namelen = 0;
|
||
if (sock->file->f_flags & O_NONBLOCK)
|
||
flags |= MSG_DONTWAIT;
|
||
err = sock_recvmsg(sock, &msg, size, flags);
|
||
@@ -1920,6 +1923,20 @@ struct used_address {
|
||
unsigned int name_len;
|
||
};
|
||
|
||
+static int copy_msghdr_from_user(struct msghdr *kmsg,
|
||
+ struct msghdr __user *umsg)
|
||
+{
|
||
+ if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
|
||
+ return -EFAULT;
|
||
+
|
||
+ if (kmsg->msg_namelen < 0)
|
||
+ return -EINVAL;
|
||
+
|
||
+ if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
|
||
+ kmsg->msg_namelen = sizeof(struct sockaddr_storage);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
|
||
struct msghdr *msg_sys, unsigned flags,
|
||
struct used_address *used_address)
|
||
@@ -1938,8 +1955,11 @@ static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
|
||
if (MSG_CMSG_COMPAT & flags) {
|
||
if (get_compat_msghdr(msg_sys, msg_compat))
|
||
return -EFAULT;
|
||
- } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
|
||
- return -EFAULT;
|
||
+ } else {
|
||
+ err = copy_msghdr_from_user(msg_sys, msg);
|
||
+ if (err)
|
||
+ return err;
|
||
+ }
|
||
|
||
/* do not move before msg_sys is valid */
|
||
err = -EMSGSIZE;
|
||
@@ -2150,8 +2170,11 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
|
||
if (MSG_CMSG_COMPAT & flags) {
|
||
if (get_compat_msghdr(msg_sys, msg_compat))
|
||
return -EFAULT;
|
||
- } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
|
||
- return -EFAULT;
|
||
+ } else {
|
||
+ err = copy_msghdr_from_user(msg_sys, msg);
|
||
+ if (err)
|
||
+ return err;
|
||
+ }
|
||
|
||
err = -EMSGSIZE;
|
||
if (msg_sys->msg_iovlen > UIO_MAXIOV)
|
||
@@ -2166,16 +2189,14 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
|
||
goto out;
|
||
}
|
||
|
||
- /*
|
||
- * Save the user-mode address (verify_iovec will change the
|
||
- * kernel msghdr to use the kernel address space)
|
||
+ /* Save the user-mode address (verify_iovec will change the
|
||
+ * kernel msghdr to use the kernel address space)
|
||
*/
|
||
-
|
||
uaddr = (__force void __user *)msg_sys->msg_name;
|
||
uaddr_len = COMPAT_NAMELEN(msg);
|
||
- if (MSG_CMSG_COMPAT & flags) {
|
||
+ if (MSG_CMSG_COMPAT & flags)
|
||
err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
|
||
- } else
|
||
+ else
|
||
err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
|
||
if (err < 0)
|
||
goto out_freeiov;
|
||
@@ -2184,6 +2205,9 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
|
||
cmsg_ptr = (unsigned long)msg_sys->msg_control;
|
||
msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
|
||
|
||
+ /* We assume all kernel code knows the size of sockaddr_storage */
|
||
+ msg_sys->msg_namelen = 0;
|
||
+
|
||
if (sock->file->f_flags & O_NONBLOCK)
|
||
flags |= MSG_DONTWAIT;
|
||
err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys,
|
||
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
|
||
index a28a211..0658fb9 100644
|
||
--- a/net/sunrpc/clnt.c
|
||
+++ b/net/sunrpc/clnt.c
|
||
@@ -1331,13 +1331,18 @@ call_refreshresult(struct rpc_task *task)
|
||
task->tk_action = call_refresh;
|
||
switch (status) {
|
||
case 0:
|
||
- if (rpcauth_uptodatecred(task))
|
||
+ if (rpcauth_uptodatecred(task)) {
|
||
task->tk_action = call_allocate;
|
||
- return;
|
||
+ return;
|
||
+ }
|
||
+ /* Use rate-limiting and a max number of retries if refresh
|
||
+ * had status 0 but failed to update the cred.
|
||
+ */
|
||
case -ETIMEDOUT:
|
||
rpc_delay(task, 3*HZ);
|
||
case -EAGAIN:
|
||
status = -EACCES;
|
||
+ case -EKEYEXPIRED:
|
||
if (!task->tk_cred_retry)
|
||
break;
|
||
task->tk_cred_retry--;
|
||
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
|
||
index 202db75..b50336b 100644
|
||
--- a/net/sunrpc/sched.c
|
||
+++ b/net/sunrpc/sched.c
|
||
@@ -302,13 +302,20 @@ EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task);
|
||
/*
|
||
* Make an RPC task runnable.
|
||
*
|
||
- * Note: If the task is ASYNC, this must be called with
|
||
- * the spinlock held to protect the wait queue operation.
|
||
+ * Note: If the task is ASYNC, and is being made runnable after sitting on an
|
||
+ * rpc_wait_queue, this must be called with the queue spinlock held to protect
|
||
+ * the wait queue operation.
|
||
+ * Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(),
|
||
+ * which is needed to ensure that __rpc_execute() doesn't loop (due to the
|
||
+ * lockless RPC_IS_QUEUED() test) before we've had a chance to test
|
||
+ * the RPC_TASK_RUNNING flag.
|
||
*/
|
||
static void rpc_make_runnable(struct rpc_task *task)
|
||
{
|
||
+ bool need_wakeup = !rpc_test_and_set_running(task);
|
||
+
|
||
rpc_clear_queued(task);
|
||
- if (rpc_test_and_set_running(task))
|
||
+ if (!need_wakeup)
|
||
return;
|
||
if (RPC_IS_ASYNC(task)) {
|
||
INIT_WORK(&task->u.tk_work, rpc_async_schedule);
|
||
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
|
||
index f190ea9..4c23cfc 100644
|
||
--- a/net/sunrpc/svcsock.c
|
||
+++ b/net/sunrpc/svcsock.c
|
||
@@ -1441,6 +1441,22 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
|
||
return svsk;
|
||
}
|
||
|
||
+bool svc_alien_sock(struct net *net, int fd)
|
||
+{
|
||
+ int err;
|
||
+ struct socket *sock = sockfd_lookup(fd, &err);
|
||
+ bool ret = false;
|
||
+
|
||
+ if (!sock)
|
||
+ goto out;
|
||
+ if (sock_net(sock->sk) != net)
|
||
+ ret = true;
|
||
+ sockfd_put(sock);
|
||
+out:
|
||
+ return ret;
|
||
+}
|
||
+EXPORT_SYMBOL_GPL(svc_alien_sock);
|
||
+
|
||
/**
|
||
* svc_addsock - add a listener socket to an RPC service
|
||
* @serv: pointer to RPC service to which to add a new listener
|
||
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
|
||
index 79064471..31275e5 100644
|
||
--- a/net/sunrpc/xprtsock.c
|
||
+++ b/net/sunrpc/xprtsock.c
|
||
@@ -390,8 +390,10 @@ static int xs_send_kvec(struct socket *sock, struct sockaddr *addr, int addrlen,
|
||
return kernel_sendmsg(sock, &msg, NULL, 0, 0);
|
||
}
|
||
|
||
-static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned int base, int more)
|
||
+static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned int base, int more, bool zerocopy)
|
||
{
|
||
+ ssize_t (*do_sendpage)(struct socket *sock, struct page *page,
|
||
+ int offset, size_t size, int flags);
|
||
struct page **ppage;
|
||
unsigned int remainder;
|
||
int err, sent = 0;
|
||
@@ -400,6 +402,9 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i
|
||
base += xdr->page_base;
|
||
ppage = xdr->pages + (base >> PAGE_SHIFT);
|
||
base &= ~PAGE_MASK;
|
||
+ do_sendpage = sock->ops->sendpage;
|
||
+ if (!zerocopy)
|
||
+ do_sendpage = sock_no_sendpage;
|
||
for(;;) {
|
||
unsigned int len = min_t(unsigned int, PAGE_SIZE - base, remainder);
|
||
int flags = XS_SENDMSG_FLAGS;
|
||
@@ -407,7 +412,7 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i
|
||
remainder -= len;
|
||
if (remainder != 0 || more)
|
||
flags |= MSG_MORE;
|
||
- err = sock->ops->sendpage(sock, *ppage, base, len, flags);
|
||
+ err = do_sendpage(sock, *ppage, base, len, flags);
|
||
if (remainder == 0 || err != len)
|
||
break;
|
||
sent += err;
|
||
@@ -428,9 +433,10 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i
|
||
* @addrlen: UDP only -- length of destination address
|
||
* @xdr: buffer containing this request
|
||
* @base: starting position in the buffer
|
||
+ * @zerocopy: true if it is safe to use sendpage()
|
||
*
|
||
*/
|
||
-static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base)
|
||
+static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, bool zerocopy)
|
||
{
|
||
unsigned int remainder = xdr->len - base;
|
||
int err, sent = 0;
|
||
@@ -458,7 +464,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
|
||
if (base < xdr->page_len) {
|
||
unsigned int len = xdr->page_len - base;
|
||
remainder -= len;
|
||
- err = xs_send_pagedata(sock, xdr, base, remainder != 0);
|
||
+ err = xs_send_pagedata(sock, xdr, base, remainder != 0, zerocopy);
|
||
if (remainder == 0 || err != len)
|
||
goto out;
|
||
sent += err;
|
||
@@ -495,6 +501,7 @@ static int xs_nospace(struct rpc_task *task)
|
||
struct rpc_rqst *req = task->tk_rqstp;
|
||
struct rpc_xprt *xprt = req->rq_xprt;
|
||
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
|
||
+ struct sock *sk = transport->inet;
|
||
int ret = -EAGAIN;
|
||
|
||
dprintk("RPC: %5u xmit incomplete (%u left of %u)\n",
|
||
@@ -512,7 +519,7 @@ static int xs_nospace(struct rpc_task *task)
|
||
* window size
|
||
*/
|
||
set_bit(SOCK_NOSPACE, &transport->sock->flags);
|
||
- transport->inet->sk_write_pending++;
|
||
+ sk->sk_write_pending++;
|
||
/* ...and wait for more buffer space */
|
||
xprt_wait_for_buffer_space(task, xs_nospace_callback);
|
||
}
|
||
@@ -522,6 +529,9 @@ static int xs_nospace(struct rpc_task *task)
|
||
}
|
||
|
||
spin_unlock_bh(&xprt->transport_lock);
|
||
+
|
||
+ /* Race breaker in case memory is freed before above code is called */
|
||
+ sk->sk_write_space(sk);
|
||
return ret;
|
||
}
|
||
|
||
@@ -561,7 +571,7 @@ static int xs_local_send_request(struct rpc_task *task)
|
||
req->rq_svec->iov_base, req->rq_svec->iov_len);
|
||
|
||
status = xs_sendpages(transport->sock, NULL, 0,
|
||
- xdr, req->rq_bytes_sent);
|
||
+ xdr, req->rq_bytes_sent, true);
|
||
dprintk("RPC: %s(%u) = %d\n",
|
||
__func__, xdr->len - req->rq_bytes_sent, status);
|
||
if (likely(status >= 0)) {
|
||
@@ -617,7 +627,7 @@ static int xs_udp_send_request(struct rpc_task *task)
|
||
status = xs_sendpages(transport->sock,
|
||
xs_addr(xprt),
|
||
xprt->addrlen, xdr,
|
||
- req->rq_bytes_sent);
|
||
+ req->rq_bytes_sent, true);
|
||
|
||
dprintk("RPC: xs_udp_send_request(%u) = %d\n",
|
||
xdr->len - req->rq_bytes_sent, status);
|
||
@@ -688,6 +698,7 @@ static int xs_tcp_send_request(struct rpc_task *task)
|
||
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;
|
||
+ bool zerocopy = true;
|
||
int status;
|
||
|
||
xs_encode_stream_record_marker(&req->rq_snd_buf);
|
||
@@ -695,13 +706,20 @@ static int xs_tcp_send_request(struct rpc_task *task)
|
||
xs_pktdump("packet data:",
|
||
req->rq_svec->iov_base,
|
||
req->rq_svec->iov_len);
|
||
+ /* Don't use zero copy if this is a resend. If the RPC call
|
||
+ * completes while the socket holds a reference to the pages,
|
||
+ * then we may end up resending corrupted data.
|
||
+ */
|
||
+ if (task->tk_flags & RPC_TASK_SENT)
|
||
+ zerocopy = false;
|
||
|
||
/* Continue transmitting the packet/record. We must be careful
|
||
* to cope with writespace callbacks arriving _after_ we have
|
||
* called sendmsg(). */
|
||
while (1) {
|
||
status = xs_sendpages(transport->sock,
|
||
- NULL, 0, xdr, req->rq_bytes_sent);
|
||
+ NULL, 0, xdr, req->rq_bytes_sent,
|
||
+ zerocopy);
|
||
|
||
dprintk("RPC: xs_tcp_send_request(%u) = %d\n",
|
||
xdr->len - req->rq_bytes_sent, status);
|
||
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
|
||
index e00441a2..9495be3 100644
|
||
--- a/net/tipc/bcast.c
|
||
+++ b/net/tipc/bcast.c
|
||
@@ -541,6 +541,7 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
|
||
|
||
buf = node->bclink.deferred_head;
|
||
node->bclink.deferred_head = buf->next;
|
||
+ buf->next = NULL;
|
||
node->bclink.deferred_size--;
|
||
goto receive;
|
||
}
|
||
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
|
||
index 1441ab7..64b8470 100644
|
||
--- a/net/tipc/socket.c
|
||
+++ b/net/tipc/socket.c
|
||
@@ -949,9 +949,6 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,
|
||
goto exit;
|
||
}
|
||
|
||
- /* will be updated in set_orig_addr() if needed */
|
||
- m->msg_namelen = 0;
|
||
-
|
||
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
||
restart:
|
||
|
||
@@ -1078,9 +1075,6 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
|
||
goto exit;
|
||
}
|
||
|
||
- /* will be updated in set_orig_addr() if needed */
|
||
- m->msg_namelen = 0;
|
||
-
|
||
target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
|
||
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
||
restart:
|
||
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
|
||
index 3d13254..3ba95aa 100644
|
||
--- a/net/unix/af_unix.c
|
||
+++ b/net/unix/af_unix.c
|
||
@@ -525,13 +525,17 @@ static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,
|
||
static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *,
|
||
struct msghdr *, size_t, int);
|
||
|
||
-static void unix_set_peek_off(struct sock *sk, int val)
|
||
+static int unix_set_peek_off(struct sock *sk, int val)
|
||
{
|
||
struct unix_sock *u = unix_sk(sk);
|
||
|
||
- mutex_lock(&u->readlock);
|
||
+ if (mutex_lock_interruptible(&u->readlock))
|
||
+ return -EINTR;
|
||
+
|
||
sk->sk_peek_off = val;
|
||
mutex_unlock(&u->readlock);
|
||
+
|
||
+ return 0;
|
||
}
|
||
|
||
|
||
@@ -709,7 +713,9 @@ static int unix_autobind(struct socket *sock)
|
||
int err;
|
||
unsigned int retries = 0;
|
||
|
||
- mutex_lock(&u->readlock);
|
||
+ err = mutex_lock_interruptible(&u->readlock);
|
||
+ if (err)
|
||
+ return err;
|
||
|
||
err = 0;
|
||
if (u->addr)
|
||
@@ -842,7 +848,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||
goto out;
|
||
addr_len = err;
|
||
|
||
- mutex_lock(&u->readlock);
|
||
+ err = mutex_lock_interruptible(&u->readlock);
|
||
+ if (err)
|
||
+ goto out;
|
||
|
||
err = -EINVAL;
|
||
if (u->addr)
|
||
@@ -1248,6 +1256,15 @@ static int unix_socketpair(struct socket *socka, struct socket *sockb)
|
||
return 0;
|
||
}
|
||
|
||
+static void unix_sock_inherit_flags(const struct socket *old,
|
||
+ struct socket *new)
|
||
+{
|
||
+ if (test_bit(SOCK_PASSCRED, &old->flags))
|
||
+ set_bit(SOCK_PASSCRED, &new->flags);
|
||
+ if (test_bit(SOCK_PASSSEC, &old->flags))
|
||
+ set_bit(SOCK_PASSSEC, &new->flags);
|
||
+}
|
||
+
|
||
static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
|
||
{
|
||
struct sock *sk = sock->sk;
|
||
@@ -1282,6 +1299,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
|
||
/* attach accepted sock to socket */
|
||
unix_state_lock(tsk);
|
||
newsock->state = SS_CONNECTED;
|
||
+ unix_sock_inherit_flags(sock, newsock);
|
||
sock_graft(tsk, newsock);
|
||
unix_state_unlock(tsk);
|
||
return 0;
|
||
@@ -1746,7 +1764,6 @@ static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
|
||
{
|
||
struct unix_sock *u = unix_sk(sk);
|
||
|
||
- msg->msg_namelen = 0;
|
||
if (u->addr) {
|
||
msg->msg_namelen = u->addr->len;
|
||
memcpy(msg->msg_name, u->addr->name, u->addr->len);
|
||
@@ -1770,11 +1787,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (flags&MSG_OOB)
|
||
goto out;
|
||
|
||
- msg->msg_namelen = 0;
|
||
-
|
||
err = mutex_lock_interruptible(&u->readlock);
|
||
- if (err) {
|
||
- err = sock_intr_errno(sock_rcvtimeo(sk, noblock));
|
||
+ if (unlikely(err)) {
|
||
+ /* recvmsg() in non blocking mode is supposed to return -EAGAIN
|
||
+ * sk_rcvtimeo is not honored by mutex_lock_interruptible()
|
||
+ */
|
||
+ err = noblock ? -EAGAIN : -ERESTARTSYS;
|
||
goto out;
|
||
}
|
||
|
||
@@ -1896,6 +1914,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
struct unix_sock *u = unix_sk(sk);
|
||
struct sockaddr_un *sunaddr = msg->msg_name;
|
||
int copied = 0;
|
||
+ int noblock = flags & MSG_DONTWAIT;
|
||
int check_creds = 0;
|
||
int target;
|
||
int err = 0;
|
||
@@ -1911,9 +1930,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
goto out;
|
||
|
||
target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
|
||
- timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
|
||
-
|
||
- msg->msg_namelen = 0;
|
||
+ timeo = sock_rcvtimeo(sk, noblock);
|
||
|
||
/* Lock the socket to prevent queue disordering
|
||
* while sleeps in memcpy_tomsg
|
||
@@ -1925,8 +1942,11 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
}
|
||
|
||
err = mutex_lock_interruptible(&u->readlock);
|
||
- if (err) {
|
||
- err = sock_intr_errno(timeo);
|
||
+ if (unlikely(err)) {
|
||
+ /* recvmsg() in non blocking mode is supposed to return -EAGAIN
|
||
+ * sk_rcvtimeo is not honored by mutex_lock_interruptible()
|
||
+ */
|
||
+ err = noblock ? -EAGAIN : -ERESTARTSYS;
|
||
goto out;
|
||
}
|
||
|
||
diff --git a/net/unix/diag.c b/net/unix/diag.c
|
||
index f0486ae..2656840 100644
|
||
--- a/net/unix/diag.c
|
||
+++ b/net/unix/diag.c
|
||
@@ -134,6 +134,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
|
||
rep->udiag_family = AF_UNIX;
|
||
rep->udiag_type = sk->sk_type;
|
||
rep->udiag_state = sk->sk_state;
|
||
+ rep->pad = 0;
|
||
rep->udiag_ino = sk_ino;
|
||
sock_diag_save_cookie(sk, rep->udiag_cookie);
|
||
|
||
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c
|
||
index c4ad795..60549a4 100644
|
||
--- a/net/wireless/radiotap.c
|
||
+++ b/net/wireless/radiotap.c
|
||
@@ -95,6 +95,10 @@ int ieee80211_radiotap_iterator_init(
|
||
struct ieee80211_radiotap_header *radiotap_header,
|
||
int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
|
||
{
|
||
+ /* check the radiotap header can actually be present */
|
||
+ if (max_length < sizeof(struct ieee80211_radiotap_header))
|
||
+ return -EINVAL;
|
||
+
|
||
/* Linux only supports version 0 radiotap format */
|
||
if (radiotap_header->it_version)
|
||
return -EINVAL;
|
||
@@ -118,6 +122,10 @@ int ieee80211_radiotap_iterator_init(
|
||
/* find payload start allowing for extended bitmap(s) */
|
||
|
||
if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) {
|
||
+ if ((unsigned long)iterator->_arg -
|
||
+ (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
|
||
+ (unsigned long)iterator->_max_length)
|
||
+ return -EINVAL;
|
||
while (get_unaligned_le32(iterator->_arg) &
|
||
(1 << IEEE80211_RADIOTAP_EXT)) {
|
||
iterator->_arg += sizeof(uint32_t);
|
||
@@ -129,7 +137,8 @@ int ieee80211_radiotap_iterator_init(
|
||
*/
|
||
|
||
if ((unsigned long)iterator->_arg -
|
||
- (unsigned long)iterator->_rtheader >
|
||
+ (unsigned long)iterator->_rtheader +
|
||
+ sizeof(uint32_t) >
|
||
(unsigned long)iterator->_max_length)
|
||
return -EINVAL;
|
||
}
|
||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
|
||
index 94c06df..53f9e72 100644
|
||
--- a/net/wireless/sme.c
|
||
+++ b/net/wireless/sme.c
|
||
@@ -257,6 +257,9 @@ void cfg80211_conn_work(struct work_struct *work)
|
||
mutex_lock(&rdev->devlist_mtx);
|
||
|
||
list_for_each_entry(wdev, &rdev->netdev_list, list) {
|
||
+ if (!wdev->netdev)
|
||
+ continue;
|
||
+
|
||
wdev_lock(wdev);
|
||
if (!netif_running(wdev->netdev)) {
|
||
wdev_unlock(wdev);
|
||
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
|
||
index b943e3e..92aed9e 100644
|
||
--- a/net/x25/af_x25.c
|
||
+++ b/net/x25/af_x25.c
|
||
@@ -1343,10 +1343,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||
if (sx25) {
|
||
sx25->sx25_family = AF_X25;
|
||
sx25->sx25_addr = x25->dest_addr;
|
||
+ msg->msg_namelen = sizeof(*sx25);
|
||
}
|
||
|
||
- msg->msg_namelen = sizeof(struct sockaddr_x25);
|
||
-
|
||
x25_check_rbuf(sk);
|
||
rc = copied;
|
||
out_free_dgram:
|
||
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
|
||
index f527f4f..dcaaaa90 100644
|
||
--- a/scripts/mod/file2alias.c
|
||
+++ b/scripts/mod/file2alias.c
|
||
@@ -186,8 +186,8 @@ static void do_usb_entry(struct usb_device_id *id,
|
||
range_lo < 0x9 ? "[%X-9" : "[%X",
|
||
range_lo);
|
||
sprintf(alias + strlen(alias),
|
||
- range_hi > 0xA ? "a-%X]" : "%X]",
|
||
- range_lo);
|
||
+ range_hi > 0xA ? "A-%X]" : "%X]",
|
||
+ range_hi);
|
||
}
|
||
}
|
||
if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1))
|
||
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
|
||
index 78b70d8..3187684 100644
|
||
--- a/scripts/mod/modpost.c
|
||
+++ b/scripts/mod/modpost.c
|
||
@@ -571,12 +571,16 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
|
||
if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 ||
|
||
strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 ||
|
||
strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 ||
|
||
- strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0)
|
||
+ strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 ||
|
||
+ strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
|
||
+ strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
|
||
return 1;
|
||
if (info->hdr->e_machine == EM_PPC64)
|
||
/* Special register function linked on all modules during final link of .ko */
|
||
if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 ||
|
||
- strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0)
|
||
+ strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 ||
|
||
+ strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
|
||
+ strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
|
||
return 1;
|
||
/* Do not ignore this symbol */
|
||
return 0;
|
||
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
|
||
index eee5f8e..ed7ccdc 100644
|
||
--- a/scripts/package/builddeb
|
||
+++ b/scripts/package/builddeb
|
||
@@ -62,7 +62,7 @@ create_package() {
|
||
fi
|
||
|
||
# Create the package
|
||
- dpkg-gencontrol -isp $forcearch -p$pname -P"$pdir"
|
||
+ dpkg-gencontrol -isp $forcearch -Vkernel:debarch="${debarch:-$(dpkg --print-architecture)}" -p$pname -P"$pdir"
|
||
dpkg --build "$pdir" ..
|
||
}
|
||
|
||
@@ -252,15 +252,14 @@ mkdir -p "$destdir"
|
||
(cd $objtree; tar -c -f - -T "$objtree/debian/hdrobjfiles") | (cd $destdir; tar -xf -)
|
||
ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build"
|
||
rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles"
|
||
-arch=$(dpkg --print-architecture)
|
||
|
||
cat <<EOF >> debian/control
|
||
|
||
Package: $kernel_headers_packagename
|
||
Provides: linux-headers, linux-headers-2.6
|
||
-Architecture: $arch
|
||
-Description: Linux kernel headers for $KERNELRELEASE on $arch
|
||
- This package provides kernel header files for $KERNELRELEASE on $arch
|
||
+Architecture: any
|
||
+Description: Linux kernel headers for $KERNELRELEASE on \${kernel:debarch}
|
||
+ This package provides kernel header files for $KERNELRELEASE on \${kernel:debarch}
|
||
.
|
||
This is useful for people who need to build external modules
|
||
EOF
|
||
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
|
||
index 54e35c1..5e29610 100644
|
||
--- a/scripts/recordmcount.h
|
||
+++ b/scripts/recordmcount.h
|
||
@@ -163,11 +163,11 @@ static int mcount_adjust = 0;
|
||
|
||
static int MIPS_is_fake_mcount(Elf_Rel const *rp)
|
||
{
|
||
- static Elf_Addr old_r_offset;
|
||
+ static Elf_Addr old_r_offset = ~(Elf_Addr)0;
|
||
Elf_Addr current_r_offset = _w(rp->r_offset);
|
||
int is_fake;
|
||
|
||
- is_fake = old_r_offset &&
|
||
+ is_fake = (old_r_offset != ~(Elf_Addr)0) &&
|
||
(current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET);
|
||
old_r_offset = current_r_offset;
|
||
|
||
diff --git a/scripts/tags.sh b/scripts/tags.sh
|
||
index cf7b12f..246e4f6 100755
|
||
--- a/scripts/tags.sh
|
||
+++ b/scripts/tags.sh
|
||
@@ -153,7 +153,10 @@ exuberant()
|
||
--regex-c++='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/' \
|
||
--regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \
|
||
--regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
|
||
- --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/'
|
||
+ --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/'\
|
||
+ --regex-c++='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/' \
|
||
+ --regex-c++='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/' \
|
||
+ --regex-c++='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/'
|
||
|
||
all_kconfigs | xargs $1 -a \
|
||
--langdef=kconfig --language-force=kconfig \
|
||
@@ -195,7 +198,10 @@ emacs()
|
||
--regex='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/' \
|
||
--regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \
|
||
--regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
|
||
- --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/'
|
||
+ --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/'\
|
||
+ --regex='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/' \
|
||
+ --regex='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/' \
|
||
+ --regex='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/'
|
||
|
||
all_kconfigs | xargs $1 -a \
|
||
--regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
|
||
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
|
||
index 8901501..c487715 100644
|
||
--- a/security/integrity/evm/evm_main.c
|
||
+++ b/security/integrity/evm/evm_main.c
|
||
@@ -271,12 +271,20 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
||
* @xattr_value: pointer to the new extended attribute value
|
||
* @xattr_value_len: pointer to the new extended attribute value length
|
||
*
|
||
- * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that
|
||
- * the current value is valid.
|
||
+ * Before allowing the 'security.evm' protected xattr to be updated,
|
||
+ * verify the existing value is valid. As only the kernel should have
|
||
+ * access to the EVM encrypted key needed to calculate the HMAC, prevent
|
||
+ * userspace from writing HMAC value. Writing 'security.evm' requires
|
||
+ * requires CAP_SYS_ADMIN privileges.
|
||
*/
|
||
int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
||
const void *xattr_value, size_t xattr_value_len)
|
||
{
|
||
+ const struct evm_ima_xattr_data *xattr_data = xattr_value;
|
||
+
|
||
+ if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0)
|
||
+ && (xattr_data->type == EVM_XATTR_HMAC))
|
||
+ return -EPERM;
|
||
return evm_protect_xattr(dentry, xattr_name, xattr_value,
|
||
xattr_value_len);
|
||
}
|
||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
|
||
index d8edff2..d6aab27 100644
|
||
--- a/security/integrity/ima/ima_policy.c
|
||
+++ b/security/integrity/ima/ima_policy.c
|
||
@@ -62,7 +62,6 @@ static struct ima_measure_rule_entry default_rules[] = {
|
||
{.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
|
||
{.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
|
||
{.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
|
||
- {.action = DONT_MEASURE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC},
|
||
{.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
|
||
{.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
|
||
{.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
|
||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
|
||
index 102a833..8ca7b07 100644
|
||
--- a/security/selinux/hooks.c
|
||
+++ b/security/selinux/hooks.c
|
||
@@ -52,6 +52,7 @@
|
||
#include <net/icmp.h>
|
||
#include <net/ip.h> /* for local_port_range[] */
|
||
#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
|
||
+#include <net/inet_connection_sock.h>
|
||
#include <net/net_namespace.h>
|
||
#include <net/netlabel.h>
|
||
#include <linux/uaccess.h>
|
||
@@ -1332,15 +1333,33 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
|
||
isec->sid = sbsec->sid;
|
||
|
||
if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
|
||
- if (opt_dentry) {
|
||
- isec->sclass = inode_mode_to_security_class(inode->i_mode);
|
||
- rc = selinux_proc_get_sid(opt_dentry,
|
||
- isec->sclass,
|
||
- &sid);
|
||
- if (rc)
|
||
- goto out_unlock;
|
||
- isec->sid = sid;
|
||
- }
|
||
+ /* We must have a dentry to determine the label on
|
||
+ * procfs inodes */
|
||
+ if (opt_dentry)
|
||
+ /* Called from d_instantiate or
|
||
+ * d_splice_alias. */
|
||
+ dentry = dget(opt_dentry);
|
||
+ else
|
||
+ /* Called from selinux_complete_init, try to
|
||
+ * find a dentry. */
|
||
+ dentry = d_find_alias(inode);
|
||
+ /*
|
||
+ * This can be hit on boot when a file is accessed
|
||
+ * before the policy is loaded. When we load policy we
|
||
+ * may find inodes that have no dentry on the
|
||
+ * sbsec->isec_head list. No reason to complain as
|
||
+ * these will get fixed up the next time we go through
|
||
+ * inode_doinit() with a dentry, before these inodes
|
||
+ * could be used again by userspace.
|
||
+ */
|
||
+ if (!dentry)
|
||
+ goto out_unlock;
|
||
+ isec->sclass = inode_mode_to_security_class(inode->i_mode);
|
||
+ rc = selinux_proc_get_sid(dentry, isec->sclass, &sid);
|
||
+ dput(dentry);
|
||
+ if (rc)
|
||
+ goto out_unlock;
|
||
+ isec->sid = sid;
|
||
}
|
||
break;
|
||
}
|
||
@@ -3866,7 +3885,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
|
||
u32 nlbl_sid;
|
||
u32 nlbl_type;
|
||
|
||
- selinux_skb_xfrm_sid(skb, &xfrm_sid);
|
||
+ selinux_xfrm_skb_sid(skb, &xfrm_sid);
|
||
selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
|
||
|
||
err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
|
||
@@ -3880,6 +3899,30 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
|
||
return 0;
|
||
}
|
||
|
||
+/**
|
||
+ * selinux_conn_sid - Determine the child socket label for a connection
|
||
+ * @sk_sid: the parent socket's SID
|
||
+ * @skb_sid: the packet's SID
|
||
+ * @conn_sid: the resulting connection SID
|
||
+ *
|
||
+ * If @skb_sid is valid then the user:role:type information from @sk_sid is
|
||
+ * combined with the MLS information from @skb_sid in order to create
|
||
+ * @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy
|
||
+ * of @sk_sid. Returns zero on success, negative values on failure.
|
||
+ *
|
||
+ */
|
||
+static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
|
||
+{
|
||
+ int err = 0;
|
||
+
|
||
+ if (skb_sid != SECSID_NULL)
|
||
+ err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid);
|
||
+ else
|
||
+ *conn_sid = sk_sid;
|
||
+
|
||
+ return err;
|
||
+}
|
||
+
|
||
/* socket security operations */
|
||
|
||
static int socket_sockcreate_sid(const struct task_security_struct *tsec,
|
||
@@ -4367,8 +4410,10 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||
}
|
||
err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
|
||
PEER__RECV, &ad);
|
||
- if (err)
|
||
+ if (err) {
|
||
selinux_netlbl_err(skb, err, 0);
|
||
+ return err;
|
||
+ }
|
||
}
|
||
|
||
if (secmark_active) {
|
||
@@ -4506,7 +4551,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||
struct sk_security_struct *sksec = sk->sk_security;
|
||
int err;
|
||
u16 family = sk->sk_family;
|
||
- u32 newsid;
|
||
+ u32 connsid;
|
||
u32 peersid;
|
||
|
||
/* handle mapped IPv4 packets arriving via IPv6 sockets */
|
||
@@ -4516,16 +4561,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||
err = selinux_skb_peerlbl_sid(skb, family, &peersid);
|
||
if (err)
|
||
return err;
|
||
- if (peersid == SECSID_NULL) {
|
||
- req->secid = sksec->sid;
|
||
- req->peer_secid = SECSID_NULL;
|
||
- } else {
|
||
- err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
|
||
- if (err)
|
||
- return err;
|
||
- req->secid = newsid;
|
||
- req->peer_secid = peersid;
|
||
- }
|
||
+ err = selinux_conn_sid(sksec->sid, peersid, &connsid);
|
||
+ if (err)
|
||
+ return err;
|
||
+ req->secid = connsid;
|
||
+ req->peer_secid = peersid;
|
||
|
||
return selinux_netlbl_inet_conn_request(req, family);
|
||
}
|
||
@@ -4757,6 +4797,7 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum,
|
||
static unsigned int selinux_ip_output(struct sk_buff *skb,
|
||
u16 family)
|
||
{
|
||
+ struct sock *sk;
|
||
u32 sid;
|
||
|
||
if (!netlbl_enabled())
|
||
@@ -4765,8 +4806,27 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
|
||
/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
|
||
* because we want to make sure we apply the necessary labeling
|
||
* before IPsec is applied so we can leverage AH protection */
|
||
- if (skb->sk) {
|
||
- struct sk_security_struct *sksec = skb->sk->sk_security;
|
||
+ sk = skb->sk;
|
||
+ if (sk) {
|
||
+ struct sk_security_struct *sksec;
|
||
+
|
||
+ if (sk->sk_state == TCP_LISTEN)
|
||
+ /* if the socket is the listening state then this
|
||
+ * packet is a SYN-ACK packet which means it needs to
|
||
+ * be labeled based on the connection/request_sock and
|
||
+ * not the parent socket. unfortunately, we can't
|
||
+ * lookup the request_sock yet as it isn't queued on
|
||
+ * the parent socket until after the SYN-ACK is sent.
|
||
+ * the "solution" is to simply pass the packet as-is
|
||
+ * as any IP option based labeling should be copied
|
||
+ * from the initial connection request (in the IP
|
||
+ * layer). it is far from ideal, but until we get a
|
||
+ * security label in the packet itself this is the
|
||
+ * best we can do. */
|
||
+ return NF_ACCEPT;
|
||
+
|
||
+ /* standard practice, label using the parent socket */
|
||
+ sksec = sk->sk_security;
|
||
sid = sksec->sid;
|
||
} else
|
||
sid = SECINITSID_KERNEL;
|
||
@@ -4839,27 +4899,37 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
||
* as fast and as clean as possible. */
|
||
if (!selinux_policycap_netpeer)
|
||
return selinux_ip_postroute_compat(skb, ifindex, family);
|
||
+
|
||
+ secmark_active = selinux_secmark_enabled();
|
||
+ peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
|
||
+ if (!secmark_active && !peerlbl_active)
|
||
+ return NF_ACCEPT;
|
||
+
|
||
+ sk = skb->sk;
|
||
+
|
||
#ifdef CONFIG_XFRM
|
||
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
|
||
* packet transformation so allow the packet to pass without any checks
|
||
* since we'll have another chance to perform access control checks
|
||
* when the packet is on it's final way out.
|
||
* NOTE: there appear to be some IPv6 multicast cases where skb->dst
|
||
- * is NULL, in this case go ahead and apply access control. */
|
||
- if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
|
||
+ * is NULL, in this case go ahead and apply access control.
|
||
+ * is NULL, in this case go ahead and apply access control.
|
||
+ * NOTE: if this is a local socket (skb->sk != NULL) that is in the
|
||
+ * TCP listening state we cannot wait until the XFRM processing
|
||
+ * is done as we will miss out on the SA label if we do;
|
||
+ * unfortunately, this means more work, but it is only once per
|
||
+ * connection. */
|
||
+ if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
|
||
+ !(sk != NULL && sk->sk_state == TCP_LISTEN))
|
||
return NF_ACCEPT;
|
||
#endif
|
||
- secmark_active = selinux_secmark_enabled();
|
||
- peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
|
||
- if (!secmark_active && !peerlbl_active)
|
||
- return NF_ACCEPT;
|
||
|
||
- /* if the packet is being forwarded then get the peer label from the
|
||
- * packet itself; otherwise check to see if it is from a local
|
||
- * application or the kernel, if from an application get the peer label
|
||
- * from the sending socket, otherwise use the kernel's sid */
|
||
- sk = skb->sk;
|
||
if (sk == NULL) {
|
||
+ /* Without an associated socket the packet is either coming
|
||
+ * from the kernel or it is being forwarded; check the packet
|
||
+ * to determine which and if the packet is being forwarded
|
||
+ * query the packet directly to determine the security label. */
|
||
if (skb->skb_iif) {
|
||
secmark_perm = PACKET__FORWARD_OUT;
|
||
if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
|
||
@@ -4868,7 +4938,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
||
secmark_perm = PACKET__SEND;
|
||
peer_sid = SECINITSID_KERNEL;
|
||
}
|
||
+ } else if (sk->sk_state == TCP_LISTEN) {
|
||
+ /* Locally generated packet but the associated socket is in the
|
||
+ * listening state which means this is a SYN-ACK packet. In
|
||
+ * this particular case the correct security label is assigned
|
||
+ * to the connection/request_sock but unfortunately we can't
|
||
+ * query the request_sock as it isn't queued on the parent
|
||
+ * socket until after the SYN-ACK packet is sent; the only
|
||
+ * viable choice is to regenerate the label like we do in
|
||
+ * selinux_inet_conn_request(). See also selinux_ip_output()
|
||
+ * for similar problems. */
|
||
+ u32 skb_sid;
|
||
+ struct sk_security_struct *sksec = sk->sk_security;
|
||
+ if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
|
||
+ return NF_DROP;
|
||
+ /* At this point, if the returned skb peerlbl is SECSID_NULL
|
||
+ * and the packet has been through at least one XFRM
|
||
+ * transformation then we must be dealing with the "final"
|
||
+ * form of labeled IPsec packet; since we've already applied
|
||
+ * all of our access controls on this packet we can safely
|
||
+ * pass the packet. */
|
||
+ if (skb_sid == SECSID_NULL) {
|
||
+ switch (family) {
|
||
+ case PF_INET:
|
||
+ if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
|
||
+ return NF_ACCEPT;
|
||
+ break;
|
||
+ case PF_INET6:
|
||
+ if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
|
||
+ return NF_ACCEPT;
|
||
+ default:
|
||
+ return NF_DROP_ERR(-ECONNREFUSED);
|
||
+ }
|
||
+ }
|
||
+ if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
|
||
+ return NF_DROP;
|
||
+ secmark_perm = PACKET__SEND;
|
||
} else {
|
||
+ /* Locally generated packet, fetch the security label from the
|
||
+ * associated socket. */
|
||
struct sk_security_struct *sksec = sk->sk_security;
|
||
peer_sid = sksec->sid;
|
||
secmark_perm = PACKET__SEND;
|
||
@@ -5536,11 +5644,11 @@ static int selinux_setprocattr(struct task_struct *p,
|
||
/* Check for ptracing, and update the task SID if ok.
|
||
Otherwise, leave SID unchanged and fail. */
|
||
ptsid = 0;
|
||
- task_lock(p);
|
||
+ rcu_read_lock();
|
||
tracer = ptrace_parent(p);
|
||
if (tracer)
|
||
ptsid = task_sid(tracer);
|
||
- task_unlock(p);
|
||
+ rcu_read_unlock();
|
||
|
||
if (tracer) {
|
||
error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
|
||
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
|
||
index c220f31..d1c980ce 100644
|
||
--- a/security/selinux/include/xfrm.h
|
||
+++ b/security/selinux/include/xfrm.h
|
||
@@ -47,6 +47,7 @@ int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
|
||
int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
|
||
struct common_audit_data *ad, u8 proto);
|
||
int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
|
||
+int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid);
|
||
|
||
static inline void selinux_xfrm_notify_policyload(void)
|
||
{
|
||
@@ -79,12 +80,12 @@ static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int
|
||
static inline void selinux_xfrm_notify_policyload(void)
|
||
{
|
||
}
|
||
-#endif
|
||
|
||
-static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid)
|
||
+static inline int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid)
|
||
{
|
||
- int err = selinux_xfrm_decode_session(skb, sid, 0);
|
||
- BUG_ON(err);
|
||
+ *sid = SECSID_NULL;
|
||
+ return 0;
|
||
}
|
||
+#endif
|
||
|
||
#endif /* _SELINUX_XFRM_H_ */
|
||
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
|
||
index da4b8b2..6235d05 100644
|
||
--- a/security/selinux/netlabel.c
|
||
+++ b/security/selinux/netlabel.c
|
||
@@ -442,8 +442,7 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
|
||
sksec->nlbl_state != NLBL_CONNLABELED)
|
||
return 0;
|
||
|
||
- local_bh_disable();
|
||
- bh_lock_sock_nested(sk);
|
||
+ lock_sock(sk);
|
||
|
||
/* connected sockets are allowed to disconnect when the address family
|
||
* is set to AF_UNSPEC, if that is what is happening we want to reset
|
||
@@ -464,7 +463,6 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
|
||
sksec->nlbl_state = NLBL_CONNLABELED;
|
||
|
||
socket_connect_return:
|
||
- bh_unlock_sock(sk);
|
||
- local_bh_enable();
|
||
+ release_sock(sk);
|
||
return rc;
|
||
}
|
||
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
|
||
index a7f61d5..23e9cba 100644
|
||
--- a/security/selinux/ss/policydb.c
|
||
+++ b/security/selinux/ss/policydb.c
|
||
@@ -1914,7 +1914,19 @@ static int filename_trans_read(struct policydb *p, void *fp)
|
||
if (rc)
|
||
goto out;
|
||
|
||
- hashtab_insert(p->filename_trans, ft, otype);
|
||
+ rc = hashtab_insert(p->filename_trans, ft, otype);
|
||
+ if (rc) {
|
||
+ /*
|
||
+ * Do not return -EEXIST to the caller, or the system
|
||
+ * will not boot.
|
||
+ */
|
||
+ if (rc != -EEXIST)
|
||
+ goto out;
|
||
+ /* But free memory to avoid memory leak. */
|
||
+ kfree(ft);
|
||
+ kfree(name);
|
||
+ kfree(otype);
|
||
+ }
|
||
}
|
||
hash_eval(p->filename_trans, "filenametr");
|
||
return 0;
|
||
@@ -3202,10 +3214,10 @@ static int filename_write_helper(void *key, void *data, void *ptr)
|
||
if (rc)
|
||
return rc;
|
||
|
||
- buf[0] = ft->stype;
|
||
- buf[1] = ft->ttype;
|
||
- buf[2] = ft->tclass;
|
||
- buf[3] = otype->otype;
|
||
+ buf[0] = cpu_to_le32(ft->stype);
|
||
+ buf[1] = cpu_to_le32(ft->ttype);
|
||
+ buf[2] = cpu_to_le32(ft->tclass);
|
||
+ buf[3] = cpu_to_le32(otype->otype);
|
||
|
||
rc = put_entry(buf, sizeof(u32), 4, fp);
|
||
if (rc)
|
||
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
|
||
index 8ab2951..1552b91 100644
|
||
--- a/security/selinux/xfrm.c
|
||
+++ b/security/selinux/xfrm.c
|
||
@@ -152,21 +152,13 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *
|
||
return rc;
|
||
}
|
||
|
||
-/*
|
||
- * LSM hook implementation that checks and/or returns the xfrm sid for the
|
||
- * incoming packet.
|
||
- */
|
||
-
|
||
-int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
|
||
+static int selinux_xfrm_skb_sid_ingress(struct sk_buff *skb,
|
||
+ u32 *sid, int ckall)
|
||
{
|
||
- struct sec_path *sp;
|
||
+ struct sec_path *sp = skb->sp;
|
||
|
||
*sid = SECSID_NULL;
|
||
|
||
- if (skb == NULL)
|
||
- return 0;
|
||
-
|
||
- sp = skb->sp;
|
||
if (sp) {
|
||
int i, sid_set = 0;
|
||
|
||
@@ -190,6 +182,45 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
|
||
return 0;
|
||
}
|
||
|
||
+static u32 selinux_xfrm_skb_sid_egress(struct sk_buff *skb)
|
||
+{
|
||
+ struct dst_entry *dst = skb_dst(skb);
|
||
+ struct xfrm_state *x;
|
||
+
|
||
+ if (dst == NULL)
|
||
+ return SECSID_NULL;
|
||
+ x = dst->xfrm;
|
||
+ if (x == NULL || !selinux_authorizable_xfrm(x))
|
||
+ return SECSID_NULL;
|
||
+
|
||
+ return x->security->ctx_sid;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * LSM hook implementation that checks and/or returns the xfrm sid for the
|
||
+ * incoming packet.
|
||
+ */
|
||
+
|
||
+int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
|
||
+{
|
||
+ if (skb == NULL) {
|
||
+ *sid = SECSID_NULL;
|
||
+ return 0;
|
||
+ }
|
||
+ return selinux_xfrm_skb_sid_ingress(skb, sid, ckall);
|
||
+}
|
||
+
|
||
+int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid)
|
||
+{
|
||
+ int rc;
|
||
+
|
||
+ rc = selinux_xfrm_skb_sid_ingress(skb, sid, 0);
|
||
+ if (rc == 0 && *sid == SECSID_NULL)
|
||
+ *sid = selinux_xfrm_skb_sid_egress(skb);
|
||
+
|
||
+ return rc;
|
||
+}
|
||
+
|
||
/*
|
||
* Security blob allocation for xfrm_policy and xfrm_state
|
||
* CTX does not have a meaningful value on input
|
||
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c
|
||
index 76e0d56..823359e 100644
|
||
--- a/sound/arm/pxa2xx-pcm-lib.c
|
||
+++ b/sound/arm/pxa2xx-pcm-lib.c
|
||
@@ -166,7 +166,9 @@ void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
|
||
} else {
|
||
printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
|
||
rtd->params->name, dma_ch, dcsr);
|
||
+ snd_pcm_stream_lock(substream);
|
||
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
|
||
+ snd_pcm_stream_unlock(substream);
|
||
}
|
||
}
|
||
EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);
|
||
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
|
||
index d3ebdc5..a380a72 100644
|
||
--- a/sound/core/compress_offload.c
|
||
+++ b/sound/core/compress_offload.c
|
||
@@ -133,7 +133,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
|
||
kfree(data);
|
||
}
|
||
snd_card_unref(compr->card);
|
||
- return 0;
|
||
+ return ret;
|
||
}
|
||
|
||
static int snd_compr_free(struct inode *inode, struct file *f)
|
||
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
|
||
index 04caf6b..393799f 100644
|
||
--- a/sound/core/pcm_lib.c
|
||
+++ b/sound/core/pcm_lib.c
|
||
@@ -1762,14 +1762,16 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
|
||
{
|
||
struct snd_pcm_hw_params *params = arg;
|
||
snd_pcm_format_t format;
|
||
- int channels, width;
|
||
+ int channels;
|
||
+ ssize_t frame_size;
|
||
|
||
params->fifo_size = substream->runtime->hw.fifo_size;
|
||
if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) {
|
||
format = params_format(params);
|
||
channels = params_channels(params);
|
||
- width = snd_pcm_format_physical_width(format);
|
||
- params->fifo_size /= width * channels;
|
||
+ frame_size = snd_pcm_format_size(format, channels);
|
||
+ if (frame_size > 0)
|
||
+ params->fifo_size /= (unsigned)frame_size;
|
||
}
|
||
return 0;
|
||
}
|
||
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
|
||
index a919c35..8da43ef 100644
|
||
--- a/sound/drivers/aloop.c
|
||
+++ b/sound/drivers/aloop.c
|
||
@@ -287,12 +287,14 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
|
||
loopback_active_notify(dpcm);
|
||
break;
|
||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||
spin_lock(&cable->lock);
|
||
cable->pause |= stream;
|
||
spin_unlock(&cable->lock);
|
||
loopback_timer_stop(dpcm);
|
||
break;
|
||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||
spin_lock(&cable->lock);
|
||
dpcm->last_jiffies = jiffies;
|
||
cable->pause &= ~stream;
|
||
@@ -552,7 +554,8 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
|
||
static struct snd_pcm_hardware loopback_pcm_hardware =
|
||
{
|
||
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
|
||
- SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
|
||
+ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE |
|
||
+ SNDRV_PCM_INFO_RESUME),
|
||
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
|
||
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
|
||
SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
|
||
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
|
||
index 99704e6..7ab6741 100644
|
||
--- a/sound/drivers/pcsp/pcsp.c
|
||
+++ b/sound/drivers/pcsp/pcsp.c
|
||
@@ -187,8 +187,8 @@ static int __devinit pcsp_probe(struct platform_device *dev)
|
||
static int __devexit pcsp_remove(struct platform_device *dev)
|
||
{
|
||
struct snd_pcsp *chip = platform_get_drvdata(dev);
|
||
- alsa_card_pcsp_exit(chip);
|
||
pcspkr_input_remove(chip->input_dev);
|
||
+ alsa_card_pcsp_exit(chip);
|
||
platform_set_drvdata(dev, NULL);
|
||
return 0;
|
||
}
|
||
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
|
||
index cef813d..ed726d1 100644
|
||
--- a/sound/i2c/other/ak4xxx-adda.c
|
||
+++ b/sound/i2c/other/ak4xxx-adda.c
|
||
@@ -571,7 +571,7 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
|
||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||
int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
|
||
const char **input_names;
|
||
- int num_names, idx;
|
||
+ unsigned int num_names, idx;
|
||
|
||
num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
|
||
if (!num_names)
|
||
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
|
||
index 29cc8e1..a7d6a52 100644
|
||
--- a/sound/isa/msnd/msnd_pinnacle.c
|
||
+++ b/sound/isa/msnd/msnd_pinnacle.c
|
||
@@ -73,9 +73,11 @@
|
||
#ifdef MSND_CLASSIC
|
||
# include "msnd_classic.h"
|
||
# define LOGNAME "msnd_classic"
|
||
+# define DEV_NAME "msnd-classic"
|
||
#else
|
||
# include "msnd_pinnacle.h"
|
||
# define LOGNAME "snd_msnd_pinnacle"
|
||
+# define DEV_NAME "msnd-pinnacle"
|
||
#endif
|
||
|
||
static void __devinit set_default_audio_parameters(struct snd_msnd *chip)
|
||
@@ -1068,8 +1070,6 @@ static int __devexit snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
|
||
return 0;
|
||
}
|
||
|
||
-#define DEV_NAME "msnd-pinnacle"
|
||
-
|
||
static struct isa_driver snd_msnd_driver = {
|
||
.match = snd_msnd_isa_match,
|
||
.probe = snd_msnd_isa_probe,
|
||
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
|
||
index 5ca0939..cb53e8d 100644
|
||
--- a/sound/pci/Kconfig
|
||
+++ b/sound/pci/Kconfig
|
||
@@ -30,6 +30,7 @@ config SND_ALS300
|
||
select SND_PCM
|
||
select SND_AC97_CODEC
|
||
select SND_OPL3_LIB
|
||
+ select ZONE_DMA
|
||
help
|
||
Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+
|
||
|
||
@@ -54,6 +55,7 @@ config SND_ALI5451
|
||
tristate "ALi M5451 PCI Audio Controller"
|
||
select SND_MPU401_UART
|
||
select SND_AC97_CODEC
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for the integrated AC97 sound
|
||
device on motherboards using the ALi M5451 Audio Controller
|
||
@@ -158,6 +160,7 @@ config SND_AZT3328
|
||
select SND_PCM
|
||
select SND_RAWMIDI
|
||
select SND_AC97_CODEC
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for Aztech AZF3328 (PCI168)
|
||
soundcards.
|
||
@@ -463,6 +466,7 @@ config SND_EMU10K1
|
||
select SND_HWDEP
|
||
select SND_RAWMIDI
|
||
select SND_AC97_CODEC
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y to include support for Sound Blaster PCI 512, Live!,
|
||
Audigy and E-mu APS (partially supported) soundcards.
|
||
@@ -478,6 +482,7 @@ config SND_EMU10K1X
|
||
tristate "Emu10k1X (Dell OEM Version)"
|
||
select SND_AC97_CODEC
|
||
select SND_RAWMIDI
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for the Dell OEM version of the
|
||
Sound Blaster Live!.
|
||
@@ -511,6 +516,7 @@ config SND_ES1938
|
||
select SND_OPL3_LIB
|
||
select SND_MPU401_UART
|
||
select SND_AC97_CODEC
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for soundcards based on ESS Solo-1
|
||
(ES1938, ES1946, ES1969) chips.
|
||
@@ -522,6 +528,7 @@ config SND_ES1968
|
||
tristate "ESS ES1968/1978 (Maestro-1/2/2E)"
|
||
select SND_MPU401_UART
|
||
select SND_AC97_CODEC
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for soundcards based on ESS Maestro
|
||
1/2/2E chips.
|
||
@@ -602,6 +609,7 @@ config SND_ICE1712
|
||
select SND_MPU401_UART
|
||
select SND_AC97_CODEC
|
||
select BITREVERSE
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for soundcards based on the
|
||
ICE1712 (Envy24) chip.
|
||
@@ -688,6 +696,7 @@ config SND_LX6464ES
|
||
config SND_MAESTRO3
|
||
tristate "ESS Allegro/Maestro3"
|
||
select SND_AC97_CODEC
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for soundcards based on ESS Maestro 3
|
||
(Allegro) chips.
|
||
@@ -782,6 +791,7 @@ config SND_SIS7019
|
||
tristate "SiS 7019 Audio Accelerator"
|
||
depends on X86 && !X86_64
|
||
select SND_AC97_CODEC
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for the SiS 7019 Audio Accelerator.
|
||
|
||
@@ -793,6 +803,7 @@ config SND_SONICVIBES
|
||
select SND_OPL3_LIB
|
||
select SND_MPU401_UART
|
||
select SND_AC97_CODEC
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for soundcards based on the S3
|
||
SonicVibes chip.
|
||
@@ -804,6 +815,7 @@ config SND_TRIDENT
|
||
tristate "Trident 4D-Wave DX/NX; SiS 7018"
|
||
select SND_MPU401_UART
|
||
select SND_AC97_CODEC
|
||
+ select ZONE_DMA
|
||
help
|
||
Say Y here to include support for soundcards based on Trident
|
||
4D-Wave DX/NX or SiS 7018 chips.
|
||
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
|
||
index 04b1d7c..1a49aca 100644
|
||
--- a/sound/pci/asihpi/asihpi.c
|
||
+++ b/sound/pci/asihpi/asihpi.c
|
||
@@ -769,7 +769,10 @@ static void snd_card_asihpi_timer_function(unsigned long data)
|
||
s->number);
|
||
ds->drained_count++;
|
||
if (ds->drained_count > 20) {
|
||
+ unsigned long flags;
|
||
+ snd_pcm_stream_lock_irqsave(s, flags);
|
||
snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
|
||
+ snd_pcm_stream_unlock_irqrestore(s, flags);
|
||
continue;
|
||
}
|
||
} else {
|
||
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
|
||
index 590682f..0c48216 100644
|
||
--- a/sound/pci/atiixp.c
|
||
+++ b/sound/pci/atiixp.c
|
||
@@ -688,7 +688,9 @@ static void snd_atiixp_xrun_dma(struct atiixp *chip, struct atiixp_dma *dma)
|
||
if (! dma->substream || ! dma->running)
|
||
return;
|
||
snd_printdd("atiixp: XRUN detected (DMA %d)\n", dma->ops->type);
|
||
+ snd_pcm_stream_lock(dma->substream);
|
||
snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
|
||
+ snd_pcm_stream_unlock(dma->substream);
|
||
}
|
||
|
||
/*
|
||
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
|
||
index 524d35f..94d6e9b 100644
|
||
--- a/sound/pci/atiixp_modem.c
|
||
+++ b/sound/pci/atiixp_modem.c
|
||
@@ -638,7 +638,9 @@ static void snd_atiixp_xrun_dma(struct atiixp_modem *chip,
|
||
if (! dma->substream || ! dma->running)
|
||
return;
|
||
snd_printdd("atiixp-modem: XRUN detected (DMA %d)\n", dma->ops->type);
|
||
+ snd_pcm_stream_lock(dma->substream);
|
||
snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
|
||
+ snd_pcm_stream_unlock(dma->substream);
|
||
}
|
||
|
||
/*
|
||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
|
||
index e6083c1..33e538f 100644
|
||
--- a/sound/pci/hda/hda_intel.c
|
||
+++ b/sound/pci/hda/hda_intel.c
|
||
@@ -582,29 +582,43 @@ static char *driver_short_names[] __devinitdata = {
|
||
#define get_azx_dev(substream) (substream->runtime->private_data)
|
||
|
||
#ifdef CONFIG_X86
|
||
-static void __mark_pages_wc(struct azx *chip, void *addr, size_t size, bool on)
|
||
+static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
|
||
{
|
||
+ int pages;
|
||
+
|
||
if (azx_snoop(chip))
|
||
return;
|
||
- if (addr && size) {
|
||
- int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||
+ if (!dmab || !dmab->area || !dmab->bytes)
|
||
+ return;
|
||
+
|
||
+#ifdef CONFIG_SND_DMA_SGBUF
|
||
+ if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
|
||
+ struct snd_sg_buf *sgbuf = dmab->private_data;
|
||
if (on)
|
||
- set_memory_wc((unsigned long)addr, pages);
|
||
+ set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
|
||
else
|
||
- set_memory_wb((unsigned long)addr, pages);
|
||
+ set_pages_array_wb(sgbuf->page_table, sgbuf->pages);
|
||
+ return;
|
||
}
|
||
+#endif
|
||
+
|
||
+ pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||
+ if (on)
|
||
+ set_memory_wc((unsigned long)dmab->area, pages);
|
||
+ else
|
||
+ set_memory_wb((unsigned long)dmab->area, pages);
|
||
}
|
||
|
||
static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
|
||
bool on)
|
||
{
|
||
- __mark_pages_wc(chip, buf->area, buf->bytes, on);
|
||
+ __mark_pages_wc(chip, buf, on);
|
||
}
|
||
static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
|
||
- struct snd_pcm_runtime *runtime, bool on)
|
||
+ struct snd_pcm_substream *substream, bool on)
|
||
{
|
||
if (azx_dev->wc_marked != on) {
|
||
- __mark_pages_wc(chip, runtime->dma_area, runtime->dma_bytes, on);
|
||
+ __mark_pages_wc(chip, substream->runtime->dma_buffer_p, on);
|
||
azx_dev->wc_marked = on;
|
||
}
|
||
}
|
||
@@ -615,7 +629,7 @@ static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
|
||
{
|
||
}
|
||
static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
|
||
- struct snd_pcm_runtime *runtime, bool on)
|
||
+ struct snd_pcm_substream *substream, bool on)
|
||
{
|
||
}
|
||
#endif
|
||
@@ -1772,11 +1786,10 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||
{
|
||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||
struct azx *chip = apcm->chip;
|
||
- struct snd_pcm_runtime *runtime = substream->runtime;
|
||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||
int ret;
|
||
|
||
- mark_runtime_wc(chip, azx_dev, runtime, false);
|
||
+ mark_runtime_wc(chip, azx_dev, substream, false);
|
||
azx_dev->bufsize = 0;
|
||
azx_dev->period_bytes = 0;
|
||
azx_dev->format_val = 0;
|
||
@@ -1784,7 +1797,7 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||
params_buffer_bytes(hw_params));
|
||
if (ret < 0)
|
||
return ret;
|
||
- mark_runtime_wc(chip, azx_dev, runtime, true);
|
||
+ mark_runtime_wc(chip, azx_dev, substream, true);
|
||
return ret;
|
||
}
|
||
|
||
@@ -1793,7 +1806,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
|
||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||
struct azx *chip = apcm->chip;
|
||
- struct snd_pcm_runtime *runtime = substream->runtime;
|
||
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
||
|
||
/* reset BDL address */
|
||
@@ -1806,7 +1818,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
|
||
|
||
snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
|
||
|
||
- mark_runtime_wc(chip, azx_dev, runtime, false);
|
||
+ mark_runtime_wc(chip, azx_dev, substream, false);
|
||
return snd_pcm_lib_free_pages(substream);
|
||
}
|
||
|
||
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
|
||
index 033c4c5..20cfc5b 100644
|
||
--- a/sound/pci/hda/patch_conexant.c
|
||
+++ b/sound/pci/hda/patch_conexant.c
|
||
@@ -141,6 +141,7 @@ struct conexant_spec {
|
||
unsigned int hp_laptop:1;
|
||
unsigned int asus:1;
|
||
unsigned int pin_eapd_ctrls:1;
|
||
+ unsigned int fixup_stereo_dmic:1;
|
||
|
||
unsigned int adc_switching:1;
|
||
|
||
@@ -548,24 +549,12 @@ static int conexant_build_controls(struct hda_codec *codec)
|
||
return 0;
|
||
}
|
||
|
||
-#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||
-static int conexant_suspend(struct hda_codec *codec, pm_message_t state)
|
||
-{
|
||
- snd_hda_shutup_pins(codec);
|
||
- return 0;
|
||
-}
|
||
-#endif
|
||
-
|
||
static const struct hda_codec_ops conexant_patch_ops = {
|
||
.build_controls = conexant_build_controls,
|
||
.build_pcms = conexant_build_pcms,
|
||
.init = conexant_init,
|
||
.free = conexant_free,
|
||
.set_power_state = conexant_set_power,
|
||
-#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||
- .suspend = conexant_suspend,
|
||
-#endif
|
||
- .reboot_notify = snd_hda_shutup_pins,
|
||
};
|
||
|
||
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
||
@@ -4083,9 +4072,9 @@ static int cx_auto_init(struct hda_codec *codec)
|
||
|
||
static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
|
||
const char *dir, int cidx,
|
||
- hda_nid_t nid, int hda_dir, int amp_idx)
|
||
+ hda_nid_t nid, int hda_dir, int amp_idx, int chs)
|
||
{
|
||
- static char name[32];
|
||
+ static char name[44];
|
||
static struct snd_kcontrol_new knew[] = {
|
||
HDA_CODEC_VOLUME(name, 0, 0, 0),
|
||
HDA_CODEC_MUTE(name, 0, 0, 0),
|
||
@@ -4095,7 +4084,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
|
||
|
||
for (i = 0; i < 2; i++) {
|
||
struct snd_kcontrol *kctl;
|
||
- knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
|
||
+ knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx,
|
||
hda_dir);
|
||
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
|
||
knew[i].index = cidx;
|
||
@@ -4114,7 +4103,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
|
||
}
|
||
|
||
#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \
|
||
- cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
|
||
+ cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3)
|
||
|
||
#define cx_auto_add_pb_volume(codec, nid, str, idx) \
|
||
cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
|
||
@@ -4184,6 +4173,36 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
|
||
return 0;
|
||
}
|
||
|
||
+/* Returns zero if this is a normal stereo channel, and non-zero if it should
|
||
+ be split in two independent channels.
|
||
+ dest_label must be at least 44 characters. */
|
||
+static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label,
|
||
+ char *dest_label, int nid)
|
||
+{
|
||
+ struct conexant_spec *spec = codec->spec;
|
||
+ int i;
|
||
+
|
||
+ if (!spec->fixup_stereo_dmic)
|
||
+ return 0;
|
||
+
|
||
+ for (i = 0; i < AUTO_CFG_MAX_INS; i++) {
|
||
+ int def_conf;
|
||
+ if (spec->autocfg.inputs[i].pin != nid)
|
||
+ continue;
|
||
+
|
||
+ if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC)
|
||
+ return 0;
|
||
+ def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||
+ if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT)
|
||
+ return 0;
|
||
+
|
||
+ /* Finally found the inverted internal mic! */
|
||
+ snprintf(dest_label, 44, "Inverted %s", label);
|
||
+ return 1;
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
|
||
const char *label, const char *pfx,
|
||
int cidx)
|
||
@@ -4192,14 +4211,25 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
|
||
int i;
|
||
|
||
for (i = 0; i < spec->num_adc_nids; i++) {
|
||
+ char rightch_label[44];
|
||
hda_nid_t adc_nid = spec->adc_nids[i];
|
||
int idx = get_input_connection(codec, adc_nid, nid);
|
||
if (idx < 0)
|
||
continue;
|
||
if (codec->single_adc_amp)
|
||
idx = 0;
|
||
+
|
||
+ if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
|
||
+ /* Make two independent kcontrols for left and right */
|
||
+ int err = cx_auto_add_volume_idx(codec, label, pfx,
|
||
+ cidx, adc_nid, HDA_INPUT, idx, 1);
|
||
+ if (err < 0)
|
||
+ return err;
|
||
+ return cx_auto_add_volume_idx(codec, rightch_label, pfx,
|
||
+ cidx, adc_nid, HDA_INPUT, idx, 2);
|
||
+ }
|
||
return cx_auto_add_volume_idx(codec, label, pfx,
|
||
- cidx, adc_nid, HDA_INPUT, idx);
|
||
+ cidx, adc_nid, HDA_INPUT, idx, 3);
|
||
}
|
||
return 0;
|
||
}
|
||
@@ -4212,9 +4242,19 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
|
||
int i, con;
|
||
|
||
nid = spec->imux_info[idx].pin;
|
||
- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
|
||
+ if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
|
||
+ char rightch_label[44];
|
||
+ if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
|
||
+ int err = cx_auto_add_volume_idx(codec, label, " Boost",
|
||
+ cidx, nid, HDA_INPUT, 0, 1);
|
||
+ if (err < 0)
|
||
+ return err;
|
||
+ return cx_auto_add_volume_idx(codec, rightch_label, " Boost",
|
||
+ cidx, nid, HDA_INPUT, 0, 2);
|
||
+ }
|
||
return cx_auto_add_volume(codec, label, " Boost", cidx,
|
||
nid, HDA_INPUT);
|
||
+ }
|
||
con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
|
||
&mux, false, 0);
|
||
if (con < 0)
|
||
@@ -4360,10 +4400,6 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
|
||
.init = cx_auto_init,
|
||
.free = conexant_free,
|
||
.unsol_event = cx_auto_unsol_event,
|
||
-#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||
- .suspend = conexant_suspend,
|
||
-#endif
|
||
- .reboot_notify = snd_hda_shutup_pins,
|
||
};
|
||
|
||
/*
|
||
@@ -4381,23 +4417,33 @@ static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg)
|
||
|
||
}
|
||
|
||
-static void apply_pin_fixup(struct hda_codec *codec,
|
||
+enum {
|
||
+ CXT_PINCFG_LENOVO_X200,
|
||
+ CXT_PINCFG_LENOVO_TP410,
|
||
+ CXT_FIXUP_STEREO_DMIC
|
||
+};
|
||
+
|
||
+static void apply_fixup(struct hda_codec *codec,
|
||
const struct snd_pci_quirk *quirk,
|
||
const struct cxt_pincfg **table)
|
||
{
|
||
+ struct conexant_spec *spec = codec->spec;
|
||
+
|
||
quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
|
||
- if (quirk) {
|
||
+ if (!quirk)
|
||
+ return;
|
||
+ if (table[quirk->value]) {
|
||
snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n",
|
||
quirk->name);
|
||
apply_pincfg(codec, table[quirk->value]);
|
||
}
|
||
+ if (quirk->value == CXT_FIXUP_STEREO_DMIC) {
|
||
+ snd_printdd(KERN_INFO "hda_codec: applying internal mic workaround for %s\n",
|
||
+ quirk->name);
|
||
+ spec->fixup_stereo_dmic = 1;
|
||
+ }
|
||
}
|
||
|
||
-enum {
|
||
- CXT_PINCFG_LENOVO_X200,
|
||
- CXT_PINCFG_LENOVO_TP410,
|
||
-};
|
||
-
|
||
/* ThinkPad X200 & co with cxt5051 */
|
||
static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
|
||
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
|
||
@@ -4418,6 +4464,7 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_tp410[] = {
|
||
static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
|
||
[CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
|
||
[CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410,
|
||
+ [CXT_FIXUP_STEREO_DMIC] = NULL,
|
||
};
|
||
|
||
static const struct snd_pci_quirk cxt5051_fixups[] = {
|
||
@@ -4426,11 +4473,15 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
|
||
};
|
||
|
||
static const struct snd_pci_quirk cxt5066_fixups[] = {
|
||
+ SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
|
||
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
|
||
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
|
||
SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
|
||
SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
|
||
SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
|
||
+ SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
|
||
+ SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
|
||
+ SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
|
||
{}
|
||
};
|
||
|
||
@@ -4470,11 +4521,11 @@ static int patch_conexant_auto(struct hda_codec *codec)
|
||
case 0x14f15051:
|
||
add_cx5051_fake_mutes(codec);
|
||
codec->pin_amp_workaround = 1;
|
||
- apply_pin_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
|
||
+ apply_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
|
||
break;
|
||
default:
|
||
codec->pin_amp_workaround = 1;
|
||
- apply_pin_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
|
||
+ apply_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
|
||
}
|
||
|
||
/* Show mute-led control only on HP laptops
|
||
@@ -4555,6 +4606,20 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = {
|
||
.patch = patch_conexant_auto },
|
||
{ .id = 0x14f150b9, .name = "CX20665",
|
||
.patch = patch_conexant_auto },
|
||
+ { .id = 0x14f1510f, .name = "CX20751/2",
|
||
+ .patch = patch_conexant_auto },
|
||
+ { .id = 0x14f15110, .name = "CX20751/2",
|
||
+ .patch = patch_conexant_auto },
|
||
+ { .id = 0x14f15111, .name = "CX20753/4",
|
||
+ .patch = patch_conexant_auto },
|
||
+ { .id = 0x14f15113, .name = "CX20755",
|
||
+ .patch = patch_conexant_auto },
|
||
+ { .id = 0x14f15114, .name = "CX20756",
|
||
+ .patch = patch_conexant_auto },
|
||
+ { .id = 0x14f15115, .name = "CX20757",
|
||
+ .patch = patch_conexant_auto },
|
||
+ { .id = 0x14f151d7, .name = "CX20952",
|
||
+ .patch = patch_conexant_auto },
|
||
{} /* terminator */
|
||
};
|
||
|
||
@@ -4575,6 +4640,13 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab");
|
||
MODULE_ALIAS("snd-hda-codec-id:14f150ac");
|
||
MODULE_ALIAS("snd-hda-codec-id:14f150b8");
|
||
MODULE_ALIAS("snd-hda-codec-id:14f150b9");
|
||
+MODULE_ALIAS("snd-hda-codec-id:14f1510f");
|
||
+MODULE_ALIAS("snd-hda-codec-id:14f15110");
|
||
+MODULE_ALIAS("snd-hda-codec-id:14f15111");
|
||
+MODULE_ALIAS("snd-hda-codec-id:14f15113");
|
||
+MODULE_ALIAS("snd-hda-codec-id:14f15114");
|
||
+MODULE_ALIAS("snd-hda-codec-id:14f15115");
|
||
+MODULE_ALIAS("snd-hda-codec-id:14f151d7");
|
||
|
||
MODULE_LICENSE("GPL");
|
||
MODULE_DESCRIPTION("Conexant HD-audio codec");
|
||
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
|
||
index 02a6e3f..bd093a6 100644
|
||
--- a/sound/pci/hda/patch_hdmi.c
|
||
+++ b/sound/pci/hda/patch_hdmi.c
|
||
@@ -425,9 +425,11 @@ static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
|
||
if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
|
||
snd_hda_codec_write(codec, pin_nid, 0,
|
||
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
|
||
- /* Disable pin out until stream is active*/
|
||
+ /* Enable pin out: some machines with GM965 gets broken output when
|
||
+ * the pin is disabled or changed while using with HDMI
|
||
+ */
|
||
snd_hda_codec_write(codec, pin_nid, 0,
|
||
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
|
||
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||
}
|
||
|
||
static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
|
||
@@ -511,6 +513,17 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels)
|
||
}
|
||
}
|
||
|
||
+ if (!ca) {
|
||
+ /* if there was no match, select the regular ALSA channel
|
||
+ * allocation with the matching number of channels */
|
||
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
|
||
+ if (channels == channel_allocations[i].channels) {
|
||
+ ca = channel_allocations[i].ca_index;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
|
||
snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
|
||
ca, channels, buf);
|
||
@@ -908,7 +921,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
|
||
per_cvt->assigned = 1;
|
||
hinfo->nid = per_cvt->cvt_nid;
|
||
|
||
- snd_hda_codec_write(codec, per_pin->pin_nid, 0,
|
||
+ snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
|
||
AC_VERB_SET_CONNECT_SEL,
|
||
mux_idx);
|
||
snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
|
||
@@ -1152,17 +1165,11 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||
struct hdmi_spec *spec = codec->spec;
|
||
int pin_idx = hinfo_to_pin_index(spec, hinfo);
|
||
hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
|
||
- int pinctl;
|
||
|
||
hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
|
||
|
||
hdmi_setup_audio_infoframe(codec, pin_idx, substream);
|
||
|
||
- pinctl = snd_hda_codec_read(codec, pin_nid, 0,
|
||
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||
- snd_hda_codec_write(codec, pin_nid, 0,
|
||
- AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl | PIN_OUT);
|
||
-
|
||
return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
|
||
}
|
||
|
||
@@ -1174,7 +1181,6 @@ static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
||
int cvt_idx, pin_idx;
|
||
struct hdmi_spec_per_cvt *per_cvt;
|
||
struct hdmi_spec_per_pin *per_pin;
|
||
- int pinctl;
|
||
|
||
snd_hda_codec_cleanup_stream(codec, hinfo->nid);
|
||
|
||
@@ -1193,11 +1199,6 @@ static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
||
return -EINVAL;
|
||
per_pin = &spec->pins[pin_idx];
|
||
|
||
- pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
|
||
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||
- snd_hda_codec_write(codec, per_pin->pin_nid, 0,
|
||
- AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||
- pinctl & ~PIN_OUT);
|
||
snd_hda_spdif_ctls_unassign(codec, pin_idx);
|
||
}
|
||
|
||
@@ -1282,23 +1283,34 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
|
||
return 0;
|
||
}
|
||
|
||
-static int generic_hdmi_init(struct hda_codec *codec)
|
||
+static int generic_hdmi_init_per_pins(struct hda_codec *codec)
|
||
{
|
||
struct hdmi_spec *spec = codec->spec;
|
||
int pin_idx;
|
||
|
||
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
||
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
|
||
- hda_nid_t pin_nid = per_pin->pin_nid;
|
||
struct hdmi_eld *eld = &per_pin->sink_eld;
|
||
|
||
- hdmi_init_pin(codec, pin_nid);
|
||
- snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
|
||
-
|
||
per_pin->codec = codec;
|
||
INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
|
||
snd_hda_eld_proc_new(codec, eld, pin_idx);
|
||
}
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int generic_hdmi_init(struct hda_codec *codec)
|
||
+{
|
||
+ struct hdmi_spec *spec = codec->spec;
|
||
+ int pin_idx;
|
||
+
|
||
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
||
+ struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
|
||
+ hda_nid_t pin_nid = per_pin->pin_nid;
|
||
+
|
||
+ hdmi_init_pin(codec, pin_nid);
|
||
+ snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
|
||
+ }
|
||
snd_hda_jack_report_sync(codec);
|
||
return 0;
|
||
}
|
||
@@ -1343,6 +1355,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
|
||
return -EINVAL;
|
||
}
|
||
codec->patch_ops = generic_hdmi_patch_ops;
|
||
+ generic_hdmi_init_per_pins(codec);
|
||
|
||
init_channel_allocations();
|
||
|
||
@@ -1907,6 +1920,8 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
|
||
{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi },
|
||
{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_generic_hdmi },
|
||
{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_generic_hdmi },
|
||
+{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_generic_hdmi },
|
||
+{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_generic_hdmi },
|
||
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
|
||
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
|
||
{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
|
||
@@ -1953,6 +1968,8 @@ MODULE_ALIAS("snd-hda-codec-id:10de0041");
|
||
MODULE_ALIAS("snd-hda-codec-id:10de0042");
|
||
MODULE_ALIAS("snd-hda-codec-id:10de0043");
|
||
MODULE_ALIAS("snd-hda-codec-id:10de0044");
|
||
+MODULE_ALIAS("snd-hda-codec-id:10de0051");
|
||
+MODULE_ALIAS("snd-hda-codec-id:10de0060");
|
||
MODULE_ALIAS("snd-hda-codec-id:10de0067");
|
||
MODULE_ALIAS("snd-hda-codec-id:10de8001");
|
||
MODULE_ALIAS("snd-hda-codec-id:17e80047");
|
||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
||
index 33abb78..9461a00 100644
|
||
--- a/sound/pci/hda/patch_realtek.c
|
||
+++ b/sound/pci/hda/patch_realtek.c
|
||
@@ -458,6 +458,8 @@ static void alc_fix_pll(struct hda_codec *codec)
|
||
spec->pll_coef_idx);
|
||
val = snd_hda_codec_read(codec, spec->pll_nid, 0,
|
||
AC_VERB_GET_PROC_COEF, 0);
|
||
+ if (val == -1)
|
||
+ return;
|
||
snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
|
||
spec->pll_coef_idx);
|
||
snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
|
||
@@ -809,6 +811,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
|
||
case 0x10ec0885:
|
||
case 0x10ec0887:
|
||
/*case 0x10ec0889:*/ /* this causes an SPDIF problem */
|
||
+ case 0x10ec0900:
|
||
alc889_coef_init(codec);
|
||
break;
|
||
case 0x10ec0888:
|
||
@@ -4323,6 +4326,7 @@ static void alc_auto_init_std(struct hda_codec *codec)
|
||
|
||
static const struct snd_pci_quirk beep_white_list[] = {
|
||
SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
|
||
+ SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
|
||
SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
|
||
SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
|
||
SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
|
||
@@ -4950,12 +4954,10 @@ static const struct alc_fixup alc260_fixups[] = {
|
||
[ALC260_FIXUP_COEF] = {
|
||
.type = ALC_FIXUP_VERBS,
|
||
.v.verbs = (const struct hda_verb[]) {
|
||
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
|
||
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3040 },
|
||
+ { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
|
||
+ { 0x1a, AC_VERB_SET_PROC_COEF, 0x3040 },
|
||
{ }
|
||
},
|
||
- .chained = true,
|
||
- .chain_id = ALC260_FIXUP_HP_PIN_0F,
|
||
},
|
||
[ALC260_FIXUP_GPIO1] = {
|
||
.type = ALC_FIXUP_VERBS,
|
||
@@ -4970,8 +4972,8 @@ static const struct alc_fixup alc260_fixups[] = {
|
||
[ALC260_FIXUP_REPLACER] = {
|
||
.type = ALC_FIXUP_VERBS,
|
||
.v.verbs = (const struct hda_verb[]) {
|
||
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
|
||
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
|
||
+ { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
|
||
+ { 0x1a, AC_VERB_SET_PROC_COEF, 0x3050 },
|
||
{ }
|
||
},
|
||
.chained = true,
|
||
@@ -5515,6 +5517,7 @@ static int patch_alc882(struct hda_codec *codec)
|
||
switch (codec->vendor_id) {
|
||
case 0x10ec0882:
|
||
case 0x10ec0885:
|
||
+ case 0x10ec0900:
|
||
break;
|
||
default:
|
||
/* ALC883 and variants */
|
||
@@ -5844,6 +5847,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
|
||
static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
|
||
{
|
||
int val = alc_read_coef_idx(codec, 0x04);
|
||
+ if (val == -1)
|
||
+ return;
|
||
if (power_up)
|
||
val |= 1 << 11;
|
||
else
|
||
@@ -6274,27 +6279,30 @@ static void alc269_fill_coef(struct hda_codec *codec)
|
||
if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
|
||
val = alc_read_coef_idx(codec, 0x04);
|
||
/* Power up output pin */
|
||
- alc_write_coef_idx(codec, 0x04, val | (1<<11));
|
||
+ if (val != -1)
|
||
+ alc_write_coef_idx(codec, 0x04, val | (1<<11));
|
||
}
|
||
|
||
if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
|
||
val = alc_read_coef_idx(codec, 0xd);
|
||
- if ((val & 0x0c00) >> 10 != 0x1) {
|
||
+ if (val != -1 && (val & 0x0c00) >> 10 != 0x1) {
|
||
/* Capless ramp up clock control */
|
||
alc_write_coef_idx(codec, 0xd, val | (1<<10));
|
||
}
|
||
val = alc_read_coef_idx(codec, 0x17);
|
||
- if ((val & 0x01c0) >> 6 != 0x4) {
|
||
+ if (val != -1 && (val & 0x01c0) >> 6 != 0x4) {
|
||
/* Class D power on reset */
|
||
alc_write_coef_idx(codec, 0x17, val | (1<<7));
|
||
}
|
||
}
|
||
|
||
val = alc_read_coef_idx(codec, 0xd); /* Class D */
|
||
- alc_write_coef_idx(codec, 0xd, val | (1<<14));
|
||
+ if (val != -1)
|
||
+ alc_write_coef_idx(codec, 0xd, val | (1<<14));
|
||
|
||
val = alc_read_coef_idx(codec, 0x4); /* HP */
|
||
- alc_write_coef_idx(codec, 0x4, val | (1<<11));
|
||
+ if (val != -1)
|
||
+ alc_write_coef_idx(codec, 0x4, val | (1<<11));
|
||
}
|
||
|
||
/*
|
||
@@ -6833,6 +6841,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
|
||
SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
|
||
SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
|
||
SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_ASUS_MODE4),
|
||
+ SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_ASUS_MODE4),
|
||
SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
|
||
SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
|
||
SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
|
||
@@ -6968,6 +6977,7 @@ static int patch_alc662(struct hda_codec *codec)
|
||
case 0x10ec0272:
|
||
case 0x10ec0663:
|
||
case 0x10ec0665:
|
||
+ case 0x10ec0668:
|
||
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
|
||
break;
|
||
case 0x10ec0273:
|
||
@@ -7029,6 +7039,7 @@ static int patch_alc680(struct hda_codec *codec)
|
||
*/
|
||
static const struct hda_codec_preset snd_hda_preset_realtek[] = {
|
||
{ .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
|
||
+ { .id = 0x10ec0231, .name = "ALC231", .patch = patch_alc269 },
|
||
{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
|
||
{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
|
||
{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
|
||
@@ -7060,6 +7071,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
|
||
{ .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
|
||
{ .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 },
|
||
{ .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
|
||
+ { .id = 0x10ec0867, .name = "ALC891", .patch = patch_alc882 },
|
||
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
|
||
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
|
||
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
|
||
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
|
||
index 08c7f3a..8fd8ecf 100644
|
||
--- a/sound/pci/ice1712/ice1712.c
|
||
+++ b/sound/pci/ice1712/ice1712.c
|
||
@@ -686,9 +686,10 @@ static snd_pcm_uframes_t snd_ice1712_playback_pointer(struct snd_pcm_substream *
|
||
if (!(snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL) & 1))
|
||
return 0;
|
||
ptr = runtime->buffer_size - inw(ice->ddma_port + 4);
|
||
+ ptr = bytes_to_frames(substream->runtime, ptr);
|
||
if (ptr == runtime->buffer_size)
|
||
ptr = 0;
|
||
- return bytes_to_frames(substream->runtime, ptr);
|
||
+ return ptr;
|
||
}
|
||
|
||
static snd_pcm_uframes_t snd_ice1712_playback_ds_pointer(struct snd_pcm_substream *substream)
|
||
@@ -705,9 +706,10 @@ static snd_pcm_uframes_t snd_ice1712_playback_ds_pointer(struct snd_pcm_substrea
|
||
addr = ICE1712_DSC_ADDR0;
|
||
ptr = snd_ice1712_ds_read(ice, substream->number * 2, addr) -
|
||
ice->playback_con_virt_addr[substream->number];
|
||
+ ptr = bytes_to_frames(substream->runtime, ptr);
|
||
if (ptr == substream->runtime->buffer_size)
|
||
ptr = 0;
|
||
- return bytes_to_frames(substream->runtime, ptr);
|
||
+ return ptr;
|
||
}
|
||
|
||
static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *substream)
|
||
@@ -718,9 +720,10 @@ static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *s
|
||
if (!(snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL) & 1))
|
||
return 0;
|
||
ptr = inl(ICEREG(ice, CONCAP_ADDR)) - ice->capture_con_virt_addr;
|
||
+ ptr = bytes_to_frames(substream->runtime, ptr);
|
||
if (ptr == substream->runtime->buffer_size)
|
||
ptr = 0;
|
||
- return bytes_to_frames(substream->runtime, ptr);
|
||
+ return ptr;
|
||
}
|
||
|
||
static const struct snd_pcm_hardware snd_ice1712_playback = {
|
||
@@ -1114,9 +1117,10 @@ static snd_pcm_uframes_t snd_ice1712_playback_pro_pointer(struct snd_pcm_substre
|
||
if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_PLAYBACK_START))
|
||
return 0;
|
||
ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2);
|
||
+ ptr = bytes_to_frames(substream->runtime, ptr);
|
||
if (ptr == substream->runtime->buffer_size)
|
||
ptr = 0;
|
||
- return bytes_to_frames(substream->runtime, ptr);
|
||
+ return ptr;
|
||
}
|
||
|
||
static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substream *substream)
|
||
@@ -1127,9 +1131,10 @@ static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substrea
|
||
if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_CAPTURE_START_SHADOW))
|
||
return 0;
|
||
ptr = ice->capture_pro_size - (inw(ICEMT(ice, CAPTURE_SIZE)) << 2);
|
||
+ ptr = bytes_to_frames(substream->runtime, ptr);
|
||
if (ptr == substream->runtime->buffer_size)
|
||
ptr = 0;
|
||
- return bytes_to_frames(substream->runtime, ptr);
|
||
+ return ptr;
|
||
}
|
||
|
||
static const struct snd_pcm_hardware snd_ice1712_playback_pro = {
|
||
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
|
||
index 793bdf0..7152746 100644
|
||
--- a/sound/pci/oxygen/xonar_dg.c
|
||
+++ b/sound/pci/oxygen/xonar_dg.c
|
||
@@ -294,6 +294,16 @@ static int output_switch_put(struct snd_kcontrol *ctl,
|
||
oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
|
||
data->output_sel == 1 ? GPIO_HP_REAR : 0,
|
||
GPIO_HP_REAR);
|
||
+ oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
|
||
+ data->output_sel == 0 ?
|
||
+ OXYGEN_PLAY_MUTE01 :
|
||
+ OXYGEN_PLAY_MUTE23 |
|
||
+ OXYGEN_PLAY_MUTE45 |
|
||
+ OXYGEN_PLAY_MUTE67,
|
||
+ OXYGEN_PLAY_MUTE01 |
|
||
+ OXYGEN_PLAY_MUTE23 |
|
||
+ OXYGEN_PLAY_MUTE45 |
|
||
+ OXYGEN_PLAY_MUTE67);
|
||
}
|
||
mutex_unlock(&chip->mutex);
|
||
return changed;
|
||
@@ -597,7 +607,7 @@ struct oxygen_model model_xonar_dg = {
|
||
.model_data_size = sizeof(struct dg),
|
||
.device_config = PLAYBACK_0_TO_I2S |
|
||
PLAYBACK_1_TO_SPDIF |
|
||
- CAPTURE_0_FROM_I2S_2 |
|
||
+ CAPTURE_0_FROM_I2S_1 |
|
||
CAPTURE_1_FROM_SPDIF,
|
||
.dac_channels_pcm = 6,
|
||
.dac_channels_mixer = 0,
|
||
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
|
||
index b737d16..f466080 100644
|
||
--- a/sound/pci/rme9652/rme9652.c
|
||
+++ b/sound/pci/rme9652/rme9652.c
|
||
@@ -285,7 +285,7 @@ static char channel_map_9636_ds[26] = {
|
||
/* ADAT channels are remapped */
|
||
1, 3, 5, 7, 9, 11, 13, 15,
|
||
/* channels 8 and 9 are S/PDIF */
|
||
- 24, 25
|
||
+ 24, 25,
|
||
/* others don't exist */
|
||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||
};
|
||
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
|
||
index 4dccf03..f59a961 100644
|
||
--- a/sound/soc/blackfin/bf5xx-i2s.c
|
||
+++ b/sound/soc/blackfin/bf5xx-i2s.c
|
||
@@ -111,6 +111,7 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
|
||
bf5xx_i2s->tcr2 |= 7;
|
||
bf5xx_i2s->rcr2 |= 7;
|
||
sport_handle->wdsize = 1;
|
||
+ break;
|
||
case SNDRV_PCM_FORMAT_S16_LE:
|
||
bf5xx_i2s->tcr2 |= 15;
|
||
bf5xx_i2s->rcr2 |= 15;
|
||
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
|
||
index 78e9ce4..192fc75 100644
|
||
--- a/sound/soc/codecs/adau1701.c
|
||
+++ b/sound/soc/codecs/adau1701.c
|
||
@@ -64,7 +64,7 @@
|
||
|
||
#define ADAU1701_SEROCTL_WORD_LEN_24 0x0000
|
||
#define ADAU1701_SEROCTL_WORD_LEN_20 0x0001
|
||
-#define ADAU1701_SEROCTL_WORD_LEN_16 0x0010
|
||
+#define ADAU1701_SEROCTL_WORD_LEN_16 0x0002
|
||
#define ADAU1701_SEROCTL_WORD_LEN_MASK 0x0003
|
||
|
||
#define ADAU1701_AUXNPOW_VBPD 0x40
|
||
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
|
||
index b3e24f2..7e4245f 100644
|
||
--- a/sound/soc/codecs/ak4642.c
|
||
+++ b/sound/soc/codecs/ak4642.c
|
||
@@ -262,7 +262,7 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
|
||
* This operation came from example code of
|
||
* "ASAHI KASEI AK4642" (japanese) manual p94.
|
||
*/
|
||
- snd_soc_write(codec, SG_SL1, PMMP | MGAIN0);
|
||
+ snd_soc_update_bits(codec, SG_SL1, PMMP | MGAIN0, PMMP | MGAIN0);
|
||
snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
|
||
snd_soc_write(codec, ALC_CTL1, ALC | LMTH0);
|
||
snd_soc_update_bits(codec, PW_MGMT1, PMADL, PMADL);
|
||
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
|
||
index 3686417..9c784c7 100644
|
||
--- a/sound/soc/codecs/cs42l73.c
|
||
+++ b/sound/soc/codecs/cs42l73.c
|
||
@@ -327,7 +327,7 @@ static const char * const cs42l73_mono_mix_texts[] = {
|
||
static const unsigned int cs42l73_mono_mix_values[] = { 0, 1, 2 };
|
||
|
||
static const struct soc_enum spk_asp_enum =
|
||
- SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 1,
|
||
+ SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 3,
|
||
ARRAY_SIZE(cs42l73_mono_mix_texts),
|
||
cs42l73_mono_mix_texts,
|
||
cs42l73_mono_mix_values);
|
||
@@ -345,7 +345,7 @@ static const struct snd_kcontrol_new spk_xsp_mixer =
|
||
SOC_DAPM_ENUM("Route", spk_xsp_enum);
|
||
|
||
static const struct soc_enum esl_asp_enum =
|
||
- SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 5,
|
||
+ SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 3,
|
||
ARRAY_SIZE(cs42l73_mono_mix_texts),
|
||
cs42l73_mono_mix_texts,
|
||
cs42l73_mono_mix_values);
|
||
@@ -354,7 +354,7 @@ static const struct snd_kcontrol_new esl_asp_mixer =
|
||
SOC_DAPM_ENUM("Route", esl_asp_enum);
|
||
|
||
static const struct soc_enum esl_xsp_enum =
|
||
- SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 7,
|
||
+ SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 3,
|
||
ARRAY_SIZE(cs42l73_mono_mix_texts),
|
||
cs42l73_mono_mix_texts,
|
||
cs42l73_mono_mix_values);
|
||
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
|
||
index 8e92fb8..f0b8d8e 100644
|
||
--- a/sound/soc/codecs/sgtl5000.c
|
||
+++ b/sound/soc/codecs/sgtl5000.c
|
||
@@ -37,7 +37,7 @@
|
||
static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET] = {
|
||
[SGTL5000_CHIP_CLK_CTRL] = 0x0008,
|
||
[SGTL5000_CHIP_I2S_CTRL] = 0x0010,
|
||
- [SGTL5000_CHIP_SSS_CTRL] = 0x0008,
|
||
+ [SGTL5000_CHIP_SSS_CTRL] = 0x0010,
|
||
[SGTL5000_CHIP_DAC_VOL] = 0x3c3c,
|
||
[SGTL5000_CHIP_PAD_STRENGTH] = 0x015f,
|
||
[SGTL5000_CHIP_ANA_HP_CTRL] = 0x1818,
|
||
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
|
||
index 7db6fa5..e05da91 100644
|
||
--- a/sound/soc/codecs/sta32x.c
|
||
+++ b/sound/soc/codecs/sta32x.c
|
||
@@ -147,42 +147,42 @@ static const unsigned int sta32x_limiter_drc_release_tlv[] = {
|
||
13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
|
||
};
|
||
|
||
-static const struct soc_enum sta32x_drc_ac_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
|
||
- 2, sta32x_drc_ac);
|
||
-static const struct soc_enum sta32x_auto_eq_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
|
||
- 3, sta32x_auto_eq_mode);
|
||
-static const struct soc_enum sta32x_auto_gc_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
|
||
- 4, sta32x_auto_gc_mode);
|
||
-static const struct soc_enum sta32x_auto_xo_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
|
||
- 16, sta32x_auto_xo_mode);
|
||
-static const struct soc_enum sta32x_preset_eq_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
|
||
- 32, sta32x_preset_eq_mode);
|
||
-static const struct soc_enum sta32x_limiter_ch1_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
|
||
- 3, sta32x_limiter_select);
|
||
-static const struct soc_enum sta32x_limiter_ch2_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
|
||
- 3, sta32x_limiter_select);
|
||
-static const struct soc_enum sta32x_limiter_ch3_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
|
||
- 3, sta32x_limiter_select);
|
||
-static const struct soc_enum sta32x_limiter1_attack_rate_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT,
|
||
- 16, sta32x_limiter_attack_rate);
|
||
-static const struct soc_enum sta32x_limiter2_attack_rate_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT,
|
||
- 16, sta32x_limiter_attack_rate);
|
||
-static const struct soc_enum sta32x_limiter1_release_rate_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT,
|
||
- 16, sta32x_limiter_release_rate);
|
||
-static const struct soc_enum sta32x_limiter2_release_rate_enum =
|
||
- SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT,
|
||
- 16, sta32x_limiter_release_rate);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
|
||
+ STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
|
||
+ sta32x_drc_ac);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum,
|
||
+ STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
|
||
+ sta32x_auto_eq_mode);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum,
|
||
+ STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
|
||
+ sta32x_auto_gc_mode);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum,
|
||
+ STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
|
||
+ sta32x_auto_xo_mode);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum,
|
||
+ STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
|
||
+ sta32x_preset_eq_mode);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum,
|
||
+ STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
|
||
+ sta32x_limiter_select);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum,
|
||
+ STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
|
||
+ sta32x_limiter_select);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum,
|
||
+ STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
|
||
+ sta32x_limiter_select);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum,
|
||
+ STA32X_L1AR, STA32X_LxA_SHIFT,
|
||
+ sta32x_limiter_attack_rate);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum,
|
||
+ STA32X_L2AR, STA32X_LxA_SHIFT,
|
||
+ sta32x_limiter_attack_rate);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum,
|
||
+ STA32X_L1AR, STA32X_LxR_SHIFT,
|
||
+ sta32x_limiter_release_rate);
|
||
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum,
|
||
+ STA32X_L2AR, STA32X_LxR_SHIFT,
|
||
+ sta32x_limiter_release_rate);
|
||
|
||
/* byte array controls for setting biquad, mixer, scaling coefficients;
|
||
* for biquads all five coefficients need to be set in one go,
|
||
@@ -394,7 +394,7 @@ SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0,
|
||
SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
|
||
SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
|
||
SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
|
||
-SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
|
||
+SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),
|
||
|
||
/* depending on mode, the attack/release thresholds have
|
||
* two different enum definitions; provide both
|
||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
|
||
index a32caa7..8b5afc1 100644
|
||
--- a/sound/soc/codecs/wm8731.c
|
||
+++ b/sound/soc/codecs/wm8731.c
|
||
@@ -406,10 +406,10 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||
iface |= 0x0001;
|
||
break;
|
||
case SND_SOC_DAIFMT_DSP_A:
|
||
- iface |= 0x0003;
|
||
+ iface |= 0x0013;
|
||
break;
|
||
case SND_SOC_DAIFMT_DSP_B:
|
||
- iface |= 0x0013;
|
||
+ iface |= 0x0003;
|
||
break;
|
||
default:
|
||
return -EINVAL;
|
||
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
|
||
index a5127b4..9e82674 100644
|
||
--- a/sound/soc/codecs/wm8770.c
|
||
+++ b/sound/soc/codecs/wm8770.c
|
||
@@ -162,8 +162,8 @@ static const char *ain_text[] = {
|
||
"AIN5", "AIN6", "AIN7", "AIN8"
|
||
};
|
||
|
||
-static const struct soc_enum ain_enum =
|
||
- SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text);
|
||
+static SOC_ENUM_DOUBLE_DECL(ain_enum,
|
||
+ WM8770_ADCMUX, 0, 4, ain_text);
|
||
|
||
static const struct snd_kcontrol_new ain_mux =
|
||
SOC_DAPM_ENUM("Capture Mux", ain_enum);
|
||
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
|
||
index 4e190b5..c93e360 100644
|
||
--- a/sound/soc/codecs/wm8904.c
|
||
+++ b/sound/soc/codecs/wm8904.c
|
||
@@ -1456,7 +1456,7 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||
|
||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||
case SND_SOC_DAIFMT_DSP_B:
|
||
- aif1 |= WM8904_AIF_LRCLK_INV;
|
||
+ aif1 |= 0x3 | WM8904_AIF_LRCLK_INV;
|
||
case SND_SOC_DAIFMT_DSP_A:
|
||
aif1 |= 0x3;
|
||
break;
|
||
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
|
||
index 1332692..77552b5 100644
|
||
--- a/sound/soc/codecs/wm8958-dsp2.c
|
||
+++ b/sound/soc/codecs/wm8958-dsp2.c
|
||
@@ -153,7 +153,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
|
||
|
||
data32 &= 0xffffff;
|
||
|
||
- wm8994_bulk_write(codec->control_data,
|
||
+ wm8994_bulk_write(wm8994->wm8994,
|
||
data32 & 0xffffff,
|
||
block_len / 2,
|
||
(void *)(data + 8));
|
||
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
|
||
index e96c6ed..451ec48 100644
|
||
--- a/sound/soc/codecs/wm8962.c
|
||
+++ b/sound/soc/codecs/wm8962.c
|
||
@@ -153,6 +153,7 @@ static struct reg_default wm8962_reg[] = {
|
||
{ 40, 0x0000 }, /* R40 - SPKOUTL volume */
|
||
{ 41, 0x0000 }, /* R41 - SPKOUTR volume */
|
||
|
||
+ { 49, 0x0010 }, /* R49 - Class D Control 1 */
|
||
{ 51, 0x0003 }, /* R51 - Class D Control 2 */
|
||
|
||
{ 56, 0x0506 }, /* R56 - Clocking 4 */
|
||
@@ -794,7 +795,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg)
|
||
case WM8962_ALC2:
|
||
case WM8962_THERMAL_SHUTDOWN_STATUS:
|
||
case WM8962_ADDITIONAL_CONTROL_4:
|
||
- case WM8962_CLASS_D_CONTROL_1:
|
||
case WM8962_DC_SERVO_6:
|
||
case WM8962_INTERRUPT_STATUS_1:
|
||
case WM8962_INTERRUPT_STATUS_2:
|
||
@@ -2888,13 +2888,22 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
|
||
static int wm8962_mute(struct snd_soc_dai *dai, int mute)
|
||
{
|
||
struct snd_soc_codec *codec = dai->codec;
|
||
- int val;
|
||
+ int val, ret;
|
||
|
||
if (mute)
|
||
- val = WM8962_DAC_MUTE;
|
||
+ val = WM8962_DAC_MUTE | WM8962_DAC_MUTE_ALT;
|
||
else
|
||
val = 0;
|
||
|
||
+ /**
|
||
+ * The DAC mute bit is mirrored in two registers, update both to keep
|
||
+ * the register cache consistent.
|
||
+ */
|
||
+ ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1,
|
||
+ WM8962_DAC_MUTE_ALT, val);
|
||
+ if (ret < 0)
|
||
+ return ret;
|
||
+
|
||
return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
|
||
WM8962_DAC_MUTE, val);
|
||
}
|
||
@@ -3675,6 +3684,8 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
|
||
if (ret < 0)
|
||
goto err_regmap;
|
||
|
||
+ regcache_cache_only(wm8962->regmap, true);
|
||
+
|
||
/* The drivers should power up as needed */
|
||
regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
|
||
|
||
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h
|
||
index a1a5d52..910aafd 100644
|
||
--- a/sound/soc/codecs/wm8962.h
|
||
+++ b/sound/soc/codecs/wm8962.h
|
||
@@ -1954,6 +1954,10 @@
|
||
#define WM8962_SPKOUTL_ENA_MASK 0x0040 /* SPKOUTL_ENA */
|
||
#define WM8962_SPKOUTL_ENA_SHIFT 6 /* SPKOUTL_ENA */
|
||
#define WM8962_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */
|
||
+#define WM8962_DAC_MUTE_ALT 0x0010 /* DAC_MUTE */
|
||
+#define WM8962_DAC_MUTE_ALT_MASK 0x0010 /* DAC_MUTE */
|
||
+#define WM8962_DAC_MUTE_ALT_SHIFT 4 /* DAC_MUTE */
|
||
+#define WM8962_DAC_MUTE_ALT_WIDTH 1 /* DAC_MUTE */
|
||
#define WM8962_SPKOUTL_PGA_MUTE 0x0002 /* SPKOUTL_PGA_MUTE */
|
||
#define WM8962_SPKOUTL_PGA_MUTE_MASK 0x0002 /* SPKOUTL_PGA_MUTE */
|
||
#define WM8962_SPKOUTL_PGA_MUTE_SHIFT 1 /* SPKOUTL_PGA_MUTE */
|
||
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
|
||
index 9d24235..d5ab335 100644
|
||
--- a/sound/soc/codecs/wm8990.c
|
||
+++ b/sound/soc/codecs/wm8990.c
|
||
@@ -1265,6 +1265,8 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
|
||
|
||
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
|
||
snd_soc_write(codec, WM8990_ANTIPOP2, 0x0);
|
||
+
|
||
+ codec->cache_sync = 1;
|
||
break;
|
||
}
|
||
|
||
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
|
||
index cd2dfe8..d3eac12 100644
|
||
--- a/sound/soc/codecs/wm_hubs.c
|
||
+++ b/sound/soc/codecs/wm_hubs.c
|
||
@@ -413,6 +413,7 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
|
||
hubs->hp_startup_mode);
|
||
break;
|
||
}
|
||
+ break;
|
||
|
||
case SND_SOC_DAPM_PRE_PMD:
|
||
snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
|
||
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
|
||
index 4f81ed4..30afae7 100644
|
||
--- a/sound/soc/imx/imx-ssi.c
|
||
+++ b/sound/soc/imx/imx-ssi.c
|
||
@@ -497,6 +497,8 @@ static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
|
||
|
||
if (imx_ssi->ac97_reset)
|
||
imx_ssi->ac97_reset(ac97);
|
||
+ /* First read sometimes fails, do a dummy read */
|
||
+ imx_ssi_ac97_read(ac97, 0);
|
||
}
|
||
|
||
static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
|
||
@@ -505,6 +507,9 @@ static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
|
||
|
||
if (imx_ssi->ac97_warm_reset)
|
||
imx_ssi->ac97_warm_reset(ac97);
|
||
+
|
||
+ /* First read sometimes fails, do a dummy read */
|
||
+ imx_ssi_ac97_read(ac97, 0);
|
||
}
|
||
|
||
struct snd_ac97_bus_ops soc_ac97_ops = {
|
||
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
|
||
index fd04ce1..540e30b 100644
|
||
--- a/sound/soc/pxa/pxa-ssp.c
|
||
+++ b/sound/soc/pxa/pxa-ssp.c
|
||
@@ -779,9 +779,7 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai)
|
||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
|
||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
|
||
|
||
-#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
|
||
- SNDRV_PCM_FMTBIT_S24_LE | \
|
||
- SNDRV_PCM_FMTBIT_S32_LE)
|
||
+#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||
|
||
static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
|
||
.startup = pxa_ssp_startup,
|
||
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
|
||
index 716da86..17f9348 100644
|
||
--- a/sound/soc/s6000/s6000-pcm.c
|
||
+++ b/sound/soc/s6000/s6000-pcm.c
|
||
@@ -128,7 +128,9 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
|
||
substream->runtime &&
|
||
snd_pcm_running(substream)) {
|
||
dev_dbg(pcm->dev, "xrun\n");
|
||
+ snd_pcm_stream_lock(substream);
|
||
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
|
||
+ snd_pcm_stream_unlock(substream);
|
||
ret = IRQ_HANDLED;
|
||
}
|
||
|
||
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
|
||
index 6ac7b82..9998719 100644
|
||
--- a/sound/soc/samsung/i2s.c
|
||
+++ b/sound/soc/samsung/i2s.c
|
||
@@ -392,7 +392,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
|
||
if (dir == SND_SOC_CLOCK_IN)
|
||
rfs = 0;
|
||
|
||
- if ((rfs && other->rfs && (other->rfs != rfs)) ||
|
||
+ if ((rfs && other && other->rfs && (other->rfs != rfs)) ||
|
||
(any_active(i2s) &&
|
||
(((dir == SND_SOC_CLOCK_IN)
|
||
&& !(mod & MOD_CDCLKCON)) ||
|
||
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
|
||
index 6d6678f..3d38ba2 100644
|
||
--- a/sound/soc/soc-dapm.c
|
||
+++ b/sound/soc/soc-dapm.c
|
||
@@ -1741,7 +1741,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
|
||
w->active ? "active" : "inactive");
|
||
|
||
list_for_each_entry(p, &w->sources, list_sink) {
|
||
- if (p->connected && !p->connected(w, p->sink))
|
||
+ if (p->connected && !p->connected(w, p->source))
|
||
continue;
|
||
|
||
if (p->connect)
|
||
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
|
||
index fc8cc82..f803348 100644
|
||
--- a/sound/usb/6fire/chip.c
|
||
+++ b/sound/usb/6fire/chip.c
|
||
@@ -101,7 +101,7 @@ static int __devinit usb6fire_chip_probe(struct usb_interface *intf,
|
||
usb_set_intfdata(intf, chips[i]);
|
||
mutex_unlock(®ister_mutex);
|
||
return 0;
|
||
- } else if (regidx < 0)
|
||
+ } else if (!devices[i] && regidx < 0)
|
||
regidx = i;
|
||
}
|
||
if (regidx < 0) {
|
||
diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c
|
||
index f0e5179..0c09867 100644
|
||
--- a/sound/usb/6fire/midi.c
|
||
+++ b/sound/usb/6fire/midi.c
|
||
@@ -19,6 +19,10 @@
|
||
#include "chip.h"
|
||
#include "comm.h"
|
||
|
||
+enum {
|
||
+ MIDI_BUFSIZE = 64
|
||
+};
|
||
+
|
||
static void usb6fire_midi_out_handler(struct urb *urb)
|
||
{
|
||
struct midi_runtime *rt = urb->context;
|
||
@@ -156,6 +160,12 @@ int __devinit usb6fire_midi_init(struct sfire_chip *chip)
|
||
if (!rt)
|
||
return -ENOMEM;
|
||
|
||
+ rt->out_buffer = kzalloc(MIDI_BUFSIZE, GFP_KERNEL);
|
||
+ if (!rt->out_buffer) {
|
||
+ kfree(rt);
|
||
+ return -ENOMEM;
|
||
+ }
|
||
+
|
||
rt->chip = chip;
|
||
rt->in_received = usb6fire_midi_in_received;
|
||
rt->out_buffer[0] = 0x80; /* 'send midi' command */
|
||
@@ -169,6 +179,7 @@ int __devinit usb6fire_midi_init(struct sfire_chip *chip)
|
||
|
||
ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance);
|
||
if (ret < 0) {
|
||
+ kfree(rt->out_buffer);
|
||
kfree(rt);
|
||
snd_printk(KERN_ERR PREFIX "unable to create midi.\n");
|
||
return ret;
|
||
@@ -197,6 +208,9 @@ void usb6fire_midi_abort(struct sfire_chip *chip)
|
||
|
||
void usb6fire_midi_destroy(struct sfire_chip *chip)
|
||
{
|
||
- kfree(chip->midi);
|
||
+ struct midi_runtime *rt = chip->midi;
|
||
+
|
||
+ kfree(rt->out_buffer);
|
||
+ kfree(rt);
|
||
chip->midi = NULL;
|
||
}
|
||
diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h
|
||
index 5114ecc..d101ecb 100644
|
||
--- a/sound/usb/6fire/midi.h
|
||
+++ b/sound/usb/6fire/midi.h
|
||
@@ -16,10 +16,6 @@
|
||
|
||
#include "common.h"
|
||
|
||
-enum {
|
||
- MIDI_BUFSIZE = 64
|
||
-};
|
||
-
|
||
struct midi_runtime {
|
||
struct sfire_chip *chip;
|
||
struct snd_rawmidi *instance;
|
||
@@ -32,7 +28,7 @@ struct midi_runtime {
|
||
struct snd_rawmidi_substream *out;
|
||
struct urb out_urb;
|
||
u8 out_serial; /* serial number of out packet */
|
||
- u8 out_buffer[MIDI_BUFSIZE];
|
||
+ u8 *out_buffer;
|
||
int buffer_offset;
|
||
|
||
void (*in_received)(struct midi_runtime *rt, u8 *data, int length);
|
||
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
|
||
index d93ab11..e0abe36 100644
|
||
--- a/sound/usb/6fire/pcm.c
|
||
+++ b/sound/usb/6fire/pcm.c
|
||
@@ -581,6 +581,33 @@ static void __devinit usb6fire_pcm_init_urb(struct pcm_urb *urb,
|
||
urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB;
|
||
}
|
||
|
||
+static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < PCM_N_URBS; i++) {
|
||
+ rt->out_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB
|
||
+ * PCM_MAX_PACKET_SIZE, GFP_KERNEL);
|
||
+ if (!rt->out_urbs[i].buffer)
|
||
+ return -ENOMEM;
|
||
+ rt->in_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB
|
||
+ * PCM_MAX_PACKET_SIZE, GFP_KERNEL);
|
||
+ if (!rt->in_urbs[i].buffer)
|
||
+ return -ENOMEM;
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < PCM_N_URBS; i++) {
|
||
+ kfree(rt->out_urbs[i].buffer);
|
||
+ kfree(rt->in_urbs[i].buffer);
|
||
+ }
|
||
+}
|
||
+
|
||
int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
|
||
{
|
||
int i;
|
||
@@ -592,6 +619,13 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
|
||
if (!rt)
|
||
return -ENOMEM;
|
||
|
||
+ ret = usb6fire_pcm_buffers_init(rt);
|
||
+ if (ret) {
|
||
+ usb6fire_pcm_buffers_destroy(rt);
|
||
+ kfree(rt);
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
rt->chip = chip;
|
||
rt->stream_state = STREAM_DISABLED;
|
||
rt->rate = ARRAY_SIZE(rates);
|
||
@@ -613,6 +647,7 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
|
||
|
||
ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm);
|
||
if (ret < 0) {
|
||
+ usb6fire_pcm_buffers_destroy(rt);
|
||
kfree(rt);
|
||
snd_printk(KERN_ERR PREFIX "cannot create pcm instance.\n");
|
||
return ret;
|
||
@@ -628,6 +663,7 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
|
||
snd_dma_continuous_data(GFP_KERNEL),
|
||
MAX_BUFSIZE, MAX_BUFSIZE);
|
||
if (ret) {
|
||
+ usb6fire_pcm_buffers_destroy(rt);
|
||
kfree(rt);
|
||
snd_printk(KERN_ERR PREFIX
|
||
"error preallocating pcm buffers.\n");
|
||
@@ -642,17 +678,25 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
|
||
void usb6fire_pcm_abort(struct sfire_chip *chip)
|
||
{
|
||
struct pcm_runtime *rt = chip->pcm;
|
||
+ unsigned long flags;
|
||
int i;
|
||
|
||
if (rt) {
|
||
rt->panic = true;
|
||
|
||
- if (rt->playback.instance)
|
||
+ if (rt->playback.instance) {
|
||
+ snd_pcm_stream_lock_irqsave(rt->playback.instance, flags);
|
||
snd_pcm_stop(rt->playback.instance,
|
||
SNDRV_PCM_STATE_XRUN);
|
||
- if (rt->capture.instance)
|
||
+ snd_pcm_stream_unlock_irqrestore(rt->playback.instance, flags);
|
||
+ }
|
||
+
|
||
+ if (rt->capture.instance) {
|
||
+ snd_pcm_stream_lock_irqsave(rt->capture.instance, flags);
|
||
snd_pcm_stop(rt->capture.instance,
|
||
SNDRV_PCM_STATE_XRUN);
|
||
+ snd_pcm_stream_unlock_irqrestore(rt->capture.instance, flags);
|
||
+ }
|
||
|
||
for (i = 0; i < PCM_N_URBS; i++) {
|
||
usb_poison_urb(&rt->in_urbs[i].instance);
|
||
@@ -664,6 +708,9 @@ void usb6fire_pcm_abort(struct sfire_chip *chip)
|
||
|
||
void usb6fire_pcm_destroy(struct sfire_chip *chip)
|
||
{
|
||
- kfree(chip->pcm);
|
||
+ struct pcm_runtime *rt = chip->pcm;
|
||
+
|
||
+ usb6fire_pcm_buffers_destroy(rt);
|
||
+ kfree(rt);
|
||
chip->pcm = NULL;
|
||
}
|
||
diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h
|
||
index 3104301..84610cf 100644
|
||
--- a/sound/usb/6fire/pcm.h
|
||
+++ b/sound/usb/6fire/pcm.h
|
||
@@ -32,7 +32,7 @@ struct pcm_urb {
|
||
struct urb instance;
|
||
struct usb_iso_packet_descriptor packets[PCM_N_PACKETS_PER_URB];
|
||
/* END DO NOT SEPARATE */
|
||
- u8 buffer[PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE];
|
||
+ u8 *buffer;
|
||
|
||
struct pcm_urb *peer;
|
||
};
|
||
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
|
||
index a1918e1..42d34c3 100644
|
||
--- a/sound/usb/mixer.c
|
||
+++ b/sound/usb/mixer.c
|
||
@@ -906,6 +906,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
|
||
}
|
||
break;
|
||
|
||
+ case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */
|
||
case USB_ID(0x046d, 0x0808):
|
||
case USB_ID(0x046d, 0x0809):
|
||
case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */
|
||
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
|
||
index 19961a6..164ceb0 100644
|
||
--- a/sound/usb/usx2y/usbusx2yaudio.c
|
||
+++ b/sound/usb/usx2y/usbusx2yaudio.c
|
||
@@ -273,7 +273,11 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
|
||
struct snd_usX2Y_substream *subs = usX2Y->subs[s];
|
||
if (subs) {
|
||
if (atomic_read(&subs->state) >= state_PRERUNNING) {
|
||
+ unsigned long flags;
|
||
+
|
||
+ snd_pcm_stream_lock_irqsave(subs->pcm_substream, flags);
|
||
snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
|
||
+ snd_pcm_stream_unlock_irqrestore(subs->pcm_substream, flags);
|
||
}
|
||
for (u = 0; u < NRURBS; u++) {
|
||
struct urb *urb = subs->urb[u];
|
||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
|
||
index f02e5c5..12f6c6d 100644
|
||
--- a/tools/perf/util/parse-events.c
|
||
+++ b/tools/perf/util/parse-events.c
|
||
@@ -446,7 +446,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
|
||
for (i = 0; (i < 2) && (op_result[i]); i++) {
|
||
char *str = op_result[i];
|
||
|
||
- snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
|
||
+ n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str);
|
||
|
||
if (cache_op == -1) {
|
||
cache_op = parse_aliases(str, hw_cache_op,
|
||
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
|
||
index ab2f682..0077266 100644
|
||
--- a/tools/power/x86/turbostat/turbostat.c
|
||
+++ b/tools/power/x86/turbostat/turbostat.c
|
||
@@ -34,6 +34,7 @@
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
#include <sched.h>
|
||
+#include <cpuid.h>
|
||
|
||
#define MSR_TSC 0x10
|
||
#define MSR_NEHALEM_PLATFORM_INFO 0xCE
|
||
@@ -932,7 +933,7 @@ void check_cpuid()
|
||
|
||
eax = ebx = ecx = edx = 0;
|
||
|
||
- asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0));
|
||
+ __get_cpuid(0, &max_level, &ebx, &ecx, &edx);
|
||
|
||
if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
|
||
genuine_intel = 1;
|
||
@@ -941,7 +942,7 @@ void check_cpuid()
|
||
fprintf(stderr, "%.4s%.4s%.4s ",
|
||
(char *)&ebx, (char *)&edx, (char *)&ecx);
|
||
|
||
- asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
|
||
+ __get_cpuid(1, &fms, &ebx, &ecx, &edx);
|
||
family = (fms >> 8) & 0xf;
|
||
model = (fms >> 4) & 0xf;
|
||
stepping = fms & 0xf;
|
||
@@ -963,7 +964,7 @@ void check_cpuid()
|
||
* This check is valid for both Intel and AMD.
|
||
*/
|
||
ebx = ecx = edx = 0;
|
||
- asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000));
|
||
+ __get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx);
|
||
|
||
if (max_level < 0x80000007) {
|
||
fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level);
|
||
@@ -974,7 +975,7 @@ void check_cpuid()
|
||
* Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
|
||
* this check is valid for both Intel and AMD
|
||
*/
|
||
- asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007));
|
||
+ __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
|
||
has_invariant_tsc = edx & (1 << 8);
|
||
|
||
if (!has_invariant_tsc) {
|
||
@@ -987,7 +988,7 @@ void check_cpuid()
|
||
* this check is valid for both Intel and AMD
|
||
*/
|
||
|
||
- asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
|
||
+ __get_cpuid(0x6, &eax, &ebx, &ecx, &edx);
|
||
has_aperf = ecx & (1 << 0);
|
||
if (!has_aperf) {
|
||
fprintf(stderr, "No APERF MSR\n");
|
||
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
|
||
index 8674b9e..b3dbf8e 100644
|
||
--- a/tools/usb/ffs-test.c
|
||
+++ b/tools/usb/ffs-test.c
|
||
@@ -116,8 +116,8 @@ static const struct {
|
||
.header = {
|
||
.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
|
||
.length = cpu_to_le32(sizeof descriptors),
|
||
- .fs_count = 3,
|
||
- .hs_count = 3,
|
||
+ .fs_count = cpu_to_le32(3),
|
||
+ .hs_count = cpu_to_le32(3),
|
||
},
|
||
.fs_descs = {
|
||
.intf = {
|
||
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
|
||
index 88b2fe3..00d8642 100644
|
||
--- a/virt/kvm/coalesced_mmio.c
|
||
+++ b/virt/kvm/coalesced_mmio.c
|
||
@@ -154,17 +154,13 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
|
||
list_add_tail(&dev->list, &kvm->coalesced_zones);
|
||
mutex_unlock(&kvm->slots_lock);
|
||
|
||
- return ret;
|
||
+ return 0;
|
||
|
||
out_free_dev:
|
||
mutex_unlock(&kvm->slots_lock);
|
||
-
|
||
kfree(dev);
|
||
|
||
- if (dev == NULL)
|
||
- return -ENXIO;
|
||
-
|
||
- return 0;
|
||
+ return ret;
|
||
}
|
||
|
||
int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
|
||
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
|
||
index 5aefbc4..89e4321 100644
|
||
--- a/virt/kvm/iommu.c
|
||
+++ b/virt/kvm/iommu.c
|
||
@@ -61,6 +61,14 @@ static pfn_t kvm_pin_pages(struct kvm *kvm, struct kvm_memory_slot *slot,
|
||
return pfn;
|
||
}
|
||
|
||
+static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
|
||
+{
|
||
+ unsigned long i;
|
||
+
|
||
+ for (i = 0; i < npages; ++i)
|
||
+ kvm_release_pfn_clean(pfn + i);
|
||
+}
|
||
+
|
||
int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
|
||
{
|
||
gfn_t gfn, end_gfn;
|
||
@@ -101,6 +109,10 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
|
||
while ((gfn << PAGE_SHIFT) & (page_size - 1))
|
||
page_size >>= 1;
|
||
|
||
+ /* Make sure hva is aligned to the page size we want to map */
|
||
+ while (gfn_to_hva_memslot(slot, gfn) & (page_size - 1))
|
||
+ page_size >>= 1;
|
||
+
|
||
/*
|
||
* Pin all pages we are about to map in memory. This is
|
||
* important because we unmap and unpin in 4kb steps later.
|
||
@@ -117,6 +129,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
|
||
if (r) {
|
||
printk(KERN_ERR "kvm_iommu_map_address:"
|
||
"iommu failed to map pfn=%llx\n", pfn);
|
||
+ kvm_unpin_pages(kvm, pfn, page_size);
|
||
goto unmap_pages;
|
||
}
|
||
|
||
@@ -128,7 +141,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
|
||
return 0;
|
||
|
||
unmap_pages:
|
||
- kvm_iommu_put_pages(kvm, slot->base_gfn, gfn);
|
||
+ kvm_iommu_put_pages(kvm, slot->base_gfn, gfn - slot->base_gfn);
|
||
return r;
|
||
}
|
||
|
||
@@ -270,14 +283,6 @@ int kvm_iommu_map_guest(struct kvm *kvm)
|
||
return r;
|
||
}
|
||
|
||
-static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
|
||
-{
|
||
- unsigned long i;
|
||
-
|
||
- for (i = 0; i < npages; ++i)
|
||
- kvm_release_pfn_clean(pfn + i);
|
||
-}
|
||
-
|
||
static void kvm_iommu_put_pages(struct kvm *kvm,
|
||
gfn_t base_gfn, unsigned long npages)
|
||
{
|
||
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
|
||
index 9f614b4..272407c 100644
|
||
--- a/virt/kvm/irq_comm.c
|
||
+++ b/virt/kvm/irq_comm.c
|
||
@@ -318,6 +318,7 @@ static int setup_routing_entry(struct kvm_irq_routing_table *rt,
|
||
*/
|
||
hlist_for_each_entry(ei, n, &rt->map[ue->gsi], link)
|
||
if (ei->type == KVM_IRQ_ROUTING_MSI ||
|
||
+ ue->type == KVM_IRQ_ROUTING_MSI ||
|
||
ue->u.irqchip.irqchip == ei->irqchip.irqchip)
|
||
return r;
|
||
|
||
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
|
||
index bdfbc1b..bc5ed14 100644
|
||
--- a/virt/kvm/kvm_main.c
|
||
+++ b/virt/kvm/kvm_main.c
|
||
@@ -774,7 +774,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
|
||
/* destroy any largepage mappings for dirty tracking */
|
||
}
|
||
|
||
- if (!npages) {
|
||
+ if (!npages || base_gfn != old.base_gfn) {
|
||
struct kvm_memory_slot *slot;
|
||
|
||
r = -ENOMEM;
|
||
@@ -790,8 +790,10 @@ int __kvm_set_memory_region(struct kvm *kvm,
|
||
old_memslots = kvm->memslots;
|
||
rcu_assign_pointer(kvm->memslots, slots);
|
||
synchronize_srcu_expedited(&kvm->srcu);
|
||
- /* From this point no new shadow pages pointing to a deleted
|
||
- * memslot will be created.
|
||
+ /* slot was deleted or moved, clear iommu mapping */
|
||
+ kvm_iommu_unmap_pages(kvm, &old);
|
||
+ /* From this point no new shadow pages pointing to a deleted,
|
||
+ * or moved, memslot will be created.
|
||
*
|
||
* validation of sp->gfn happens in:
|
||
* - gfn_to_hva (kvm_read_guest, gfn_to_pfn)
|
||
@@ -805,20 +807,19 @@ int __kvm_set_memory_region(struct kvm *kvm,
|
||
if (r)
|
||
goto out_free;
|
||
|
||
- /* map/unmap the pages in iommu page table */
|
||
- if (npages) {
|
||
- r = kvm_iommu_map_pages(kvm, &new);
|
||
- if (r)
|
||
- goto out_free;
|
||
- } else
|
||
- kvm_iommu_unmap_pages(kvm, &old);
|
||
-
|
||
r = -ENOMEM;
|
||
slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots),
|
||
GFP_KERNEL);
|
||
if (!slots)
|
||
goto out_free;
|
||
|
||
+ /* map new memory slot into the iommu */
|
||
+ if (npages) {
|
||
+ r = kvm_iommu_map_pages(kvm, &new);
|
||
+ if (r)
|
||
+ goto out_slots;
|
||
+ }
|
||
+
|
||
/* actual memory is freed via old in kvm_free_physmem_slot below */
|
||
if (!npages) {
|
||
new.rmap = NULL;
|
||
@@ -845,6 +846,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
|
||
|
||
return 0;
|
||
|
||
+out_slots:
|
||
+ kfree(slots);
|
||
out_free:
|
||
kvm_free_physmem_slot(&new, &old);
|
||
out:
|
||
@@ -1665,6 +1668,9 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
|
||
int r;
|
||
struct kvm_vcpu *vcpu, *v;
|
||
|
||
+ if (id >= KVM_MAX_VCPUS)
|
||
+ return -EINVAL;
|
||
+
|
||
vcpu = kvm_arch_vcpu_create(kvm, id);
|
||
if (IS_ERR(vcpu))
|
||
return PTR_ERR(vcpu);
|