]> rtime.felk.cvut.cz Git - linux-imx.git/commitdiff
Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 8 Aug 2013 16:32:20 +0000 (09:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 8 Aug 2013 16:32:20 +0000 (09:32 -0700)
Pull virtio fixes from Rusty Russell:
 "More virtio console fixes than I'm happy with, but all real issues,
  and all CC:stable.."

* tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux:
  virtio-scsi: Fix virtqueue affinity setup
  virtio: console: return -ENODEV on all read operations after unplug
  virtio: console: fix raising SIGIO after port unplug
  virtio: console: clean up port data immediately at time of unplug
  virtio: console: fix race in port_fops_open() and port unplug
  virtio: console: fix race with port unplug and open/close
  virtio/console: Add pipe_lock/unlock for splice_write
  virtio/console: Quit from splice_write if pipe->nrbufs is 0

758 files changed:
.gitignore
Documentation/ABI/testing/sysfs-driver-xen-blkback [new file with mode: 0644]
Documentation/ABI/testing/sysfs-driver-xen-blkfront [new file with mode: 0644]
Documentation/DocBook/device-drivers.tmpl
Documentation/bcache.txt
Documentation/devicetree/bindings/clock/imx27-clock.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/ja_JP/HOWTO
Documentation/sysctl/net.txt
MAINTAINERS
Makefile
arch/alpha/Kconfig
arch/alpha/include/asm/atomic.h
arch/alpha/include/asm/param.h
arch/alpha/include/asm/spinlock.h
arch/alpha/include/asm/unistd.h
arch/alpha/include/uapi/asm/param.h
arch/alpha/include/uapi/asm/unistd.h
arch/alpha/kernel/entry.S
arch/alpha/kernel/irq_alpha.c
arch/alpha/kernel/smp.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/systbls.S
arch/alpha/kernel/time.c
arch/alpha/kernel/traps.c
arch/arc/include/asm/entry.h
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/dts/atlas6.dtsi
arch/arm/boot/dts/imx28-apx4devkit.dts
arch/arm/boot/dts/imx28-evk.dts
arch/arm/boot/dts/imx28-m28evk.dts
arch/arm/boot/dts/imx28.dtsi
arch/arm/boot/dts/imx51-babbage.dts
arch/arm/boot/dts/imx53-mba53.dts
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/msm8960-cdp.dts
arch/arm/boot/dts/omap5-uevm.dts
arch/arm/boot/dts/prima2.dtsi
arch/arm/boot/dts/stih416-pinctrl.dtsi
arch/arm/boot/dts/stih416.dtsi
arch/arm/boot/dts/stih41x.dtsi
arch/arm/boot/dts/tegra20-colibri-512.dtsi
arch/arm/boot/dts/twl4030.dtsi
arch/arm/boot/dts/vf610.dtsi
arch/arm/common/edma.c
arch/arm/configs/da8xx_omapl_defconfig
arch/arm/configs/davinci_all_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/nhk8815_defconfig
arch/arm/include/asm/a.out-core.h [deleted file]
arch/arm/include/asm/cputype.h
arch/arm/include/asm/elf.h
arch/arm/include/asm/mmu.h
arch/arm/include/asm/mmu_context.h
arch/arm/include/asm/page.h
arch/arm/include/asm/processor.h
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/tlbflush.h
arch/arm/include/asm/virt.h
arch/arm/include/uapi/asm/Kbuild
arch/arm/include/uapi/asm/a.out.h [deleted file]
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-v7m.S
arch/arm/kernel/fiq.c
arch/arm/kernel/head-nommu.S
arch/arm/kernel/head.S
arch/arm/kernel/hyp-stub.S
arch/arm/kernel/process.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/kernel/signal.h [deleted file]
arch/arm/kernel/smp_tlb.c
arch/arm/kernel/traps.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-davinci/dm355.c
arch/arm/mach-davinci/dm365.c
arch/arm/mach-exynos/Kconfig
arch/arm/mach-exynos/Makefile
arch/arm/mach-exynos/common.c
arch/arm/mach-exynos/common.h
arch/arm/mach-exynos/cpuidle.c
arch/arm/mach-exynos/include/mach/memory.h
arch/arm/mach-exynos/pm.c
arch/arm/mach-footbridge/dc21285.c
arch/arm/mach-highbank/highbank.c
arch/arm/mach-imx/clk-imx6q.c
arch/arm/mach-imx/clk-vf610.c
arch/arm/mach-imx/mx27.h
arch/arm/mach-keystone/keystone.c
arch/arm/mach-msm/Kconfig
arch/arm/mach-msm/gpiomux-v1.c [deleted file]
arch/arm/mach-msm/gpiomux.h
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/omap_device.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.h
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
arch/arm/mach-omap2/omap_hwmod_33xx_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/omap_hwmod_54xx_data.c
arch/arm/mach-omap2/serial.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/stargate2.c
arch/arm/mach-s3c24xx/clock-s3c2410.c
arch/arm/mach-s3c24xx/clock-s3c2440.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-bockw.c
arch/arm/mach-shmobile/board-lager.c
arch/arm/mach-sti/Kconfig
arch/arm/mach-sti/headsmp.S
arch/arm/mach-zynq/common.c
arch/arm/mm/Kconfig
arch/arm/mm/context.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7-2level.S
arch/arm/mm/proc-v7-3level.S
arch/arm/mm/proc-v7.S
arch/arm/plat-samsung/Kconfig
arch/arm/plat-samsung/Makefile
arch/arm/plat-samsung/include/plat/clock.h
arch/arm/plat-samsung/include/plat/pm.h
arch/arm/plat-samsung/pm.c
arch/arm/xen/enlighten.c
arch/arm64/include/asm/thread_info.h
arch/arm64/include/asm/virt.h
arch/arm64/kernel/entry.S
arch/arm64/kernel/process.c
arch/ia64/configs/generic_defconfig
arch/ia64/configs/gensparse_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/xen_domu_defconfig
arch/mips/Kconfig
arch/mips/bcm47xx/Kconfig
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/mach-generic/spaces.h
arch/mips/include/uapi/asm/siginfo.h
arch/mips/kernel/bmips_vec.S
arch/mips/kernel/smp-bmips.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/pnx833x/common/platform.c
arch/mips/powertv/asic/asic_devices.c
arch/parisc/configs/c8000_defconfig [new file with mode: 0644]
arch/parisc/include/asm/parisc-device.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/inventory.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/signal32.c
arch/parisc/kernel/sys32.h [deleted file]
arch/parisc/kernel/sys_parisc32.c
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/configs/ppc64e_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/include/asm/eeh.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/module.h
arch/powerpc/include/asm/pci-bridge.h
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/uapi/asm/Kbuild
arch/powerpc/include/uapi/asm/perf_event.h [new file with mode: 0644]
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/eeh_cache.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/eeh_pe.c
arch/powerpc/kernel/eeh_sysfs.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci-hotplug.c
arch/powerpc/kernel/pci_of_scan.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/mm/hash_native_64.c
arch/powerpc/mm/numa.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/power8-pmu.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/eeh_pseries.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/ras.c
arch/s390/Kconfig
arch/s390/boot/compressed/Makefile
arch/s390/boot/compressed/misc.c
arch/s390/include/asm/bitops.h
arch/s390/kernel/perf_event.c
arch/s390/kernel/setup.c
arch/s390/mm/init.c
arch/s390/oprofile/init.c
arch/sh/configs/sh03_defconfig
arch/x86/boot/compressed/eboot.c
arch/x86/crypto/Makefile
arch/x86/crypto/crct10dif-pcl-asm_64.S [deleted file]
arch/x86/crypto/crct10dif-pclmul_glue.c [deleted file]
arch/x86/kernel/cpu/mcheck/mce-severity.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/i387.c
arch/x86/kernel/microcode_amd.c
arch/x86/platform/ce4100/ce4100.c
crypto/Kconfig
crypto/Makefile
crypto/crct10dif.c [deleted file]
crypto/tcrypt.c
crypto/testmgr.c
crypto/testmgr.h
drivers/accessibility/braille/braille_console.c
drivers/acpi/battery.c
drivers/acpi/internal.h
drivers/acpi/video.c
drivers/acpi/video_detect.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ahci_imx.c [new file with mode: 0644]
drivers/ata/ata_piix.c
drivers/ata/libata-scsi.c
drivers/ata/pata_imx.c
drivers/ata/sata_inic162x.c
drivers/block/Kconfig
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_state.c
drivers/block/rsxx/core.c
drivers/block/rsxx/cregs.c
drivers/block/rsxx/dev.c
drivers/block/rsxx/dma.c
drivers/block/rsxx/rsxx_priv.h
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkback/common.h
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/char/agp/parisc-agp.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpuidle/governors/menu.c
drivers/crypto/caam/caamhash.c
drivers/dma/pch_dma.c
drivers/dma/pl330.c
drivers/dma/sh/shdma.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/i5100_edac.c
drivers/firewire/core-cdev.c
drivers/firewire/ohci.c
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-msm-v1.c
drivers/gpio/gpio-msm-v2.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/exynos/exynos_ddc.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_drm_hdmi.c
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_rotator.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_hdmiphy.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/mgag200/mgag200_ttm.c
drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
drivers/gpu/drm/nouveau/core/engine/falcon.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
drivers/gpu/drm/nouveau/core/engine/xtensa.c
drivers/gpu/drm/nouveau/core/include/engine/falcon.h
drivers/gpu/drm/nouveau/core/include/subdev/vm.h
drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
drivers/gpu/drm/nouveau/core/subdev/vm/base.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nv17_fence.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_fence.c
drivers/gpu/drm/qxl/qxl_cmd.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_draw.c
drivers/gpu/drm/qxl/qxl_drv.h
drivers/gpu/drm/qxl/qxl_fb.c
drivers/gpu/drm/qxl/qxl_fence.c
drivers/gpu/drm/qxl/qxl_gem.c
drivers/gpu/drm/qxl/qxl_image.c
drivers/gpu/drm/qxl/qxl_ioctl.c
drivers/gpu/drm/qxl/qxl_object.c
drivers/gpu/drm/qxl/qxl_object.h
drivers/gpu/drm/qxl/qxl_release.c
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/rv6xx_dpm.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-dj.h
drivers/hid/hid-sony.c
drivers/hid/hidraw.c
drivers/hv/hv_balloon.c
drivers/hv/vmbus_drv.c
drivers/hwmon/max6697.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/mad.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/nes/nes_verbs.c
drivers/infiniband/hw/ocrdma/ocrdma_ah.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_sdma.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_netlink.c
drivers/macintosh/windfarm_rm31.c
drivers/md/bcache/alloc.c
drivers/md/bcache/bcache.h
drivers/md/bcache/bset.c
drivers/md/bcache/bset.h
drivers/md/bcache/btree.c
drivers/md/bcache/btree.h
drivers/md/bcache/closure.c
drivers/md/bcache/debug.c
drivers/md/bcache/debug.h
drivers/md/bcache/io.c
drivers/md/bcache/journal.c
drivers/md/bcache/movinggc.c
drivers/md/bcache/request.c
drivers/md/bcache/request.h
drivers/md/bcache/super.c
drivers/md/bcache/sysfs.c
drivers/md/bcache/trace.c
drivers/md/bcache/util.c
drivers/md/bcache/util.h
drivers/md/bcache/writeback.c
drivers/md/bcache/writeback.h [new file with mode: 0644]
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/misc/atmel-ssc.c
drivers/misc/mei/hbm.c
drivers/misc/mei/hw-me.c
drivers/misc/mei/init.c
drivers/mmc/host/pxamci.c
drivers/net/arcnet/arcnet.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/usb_8dev.c
drivers/net/ethernet/allwinner/Kconfig
drivers/net/ethernet/atheros/atl1c/atl1c.h
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/mellanox/mlx5/core/uar.c
drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/sfc/filter.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/macvlan.c
drivers/net/phy/mdio-sun4i.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/r8152.c
drivers/net/usb/r815x.c
drivers/net/usb/smsc75xx.c
drivers/net/veth.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath10k/Kconfig
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/wil6210/debugfs.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/cw1200/txrx.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cfp.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sdio.h
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rtlwifi/Kconfig
drivers/net/wireless/rtlwifi/Makefile
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/base.h
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/debug.c
drivers/net/wireless/rtlwifi/efuse.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/ps.h
drivers/net/wireless/rtlwifi/usb.c
drivers/of/irq.c
drivers/parisc/iosapic.c
drivers/pci/host/pci-mvebu.c
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/hotplug/rpadlpar_core.c
drivers/pci/pcie/Kconfig
drivers/pci/setup-bus.c
drivers/pinctrl/core.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/sh-pfc/pfc-sh73a0.c
drivers/pinctrl/sirf/pinctrl-atlas6.c
drivers/rapidio/rio.c
drivers/rtc/rtc-twl.c
drivers/s390/block/dasd.c
drivers/scsi/isci/request.c
drivers/scsi/isci/task.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/sd.c
drivers/staging/android/logger.c
drivers/staging/comedi/TODO
drivers/staging/comedi/comedi_fops.c
drivers/staging/frontier/alphatrack.c
drivers/staging/gdm72xx/gdm_qos.c
drivers/staging/imx-drm/Kconfig
drivers/staging/tidspbridge/pmgr/dbll.c
drivers/staging/zram/zram_drv.c
drivers/thermal/x86_pkg_temp_thermal.c
drivers/tty/serial/8250/8250_early.c
drivers/tty/serial/8250/8250_gsc.c
drivers/tty/serial/Kconfig
drivers/tty/serial/arc_uart.c
drivers/tty/serial/mxs-auart.c
drivers/tty/synclinkmp.c
drivers/tty/tty_port.c
drivers/usb/chipidea/Kconfig
drivers/usb/chipidea/bits.h
drivers/usb/core/hub.c
drivers/usb/core/hub.h
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/f_ecm.c
drivers/usb/gadget/f_eem.c
drivers/usb/gadget/f_ncm.c
drivers/usb/gadget/f_phonet.c
drivers/usb/gadget/f_rndis.c
drivers/usb/gadget/f_subset.c
drivers/usb/gadget/fotg210-udc.c
drivers/usb/gadget/multi.c
drivers/usb/gadget/mv_u3d_core.c
drivers/usb/gadget/udc-core.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/pci-quirks.h
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/phy/phy-omap-usb3.c
drivers/usb/phy/phy-samsung-usb2.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/mos7840.c
drivers/usb/serial/option.c
drivers/usb/serial/suunto.c [new file with mode: 0644]
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/storage/unusual_devs.h
drivers/vfio/pci/vfio_pci.c
drivers/vfio/vfio.c
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/vhost/test.c
drivers/vhost/vhost.h
drivers/video/aty/atyfb_base.c
drivers/video/backlight/max8925_bl.c
drivers/video/nuc900fb.c
drivers/video/sgivwfb.c
drivers/video/sh7760fb.c
drivers/video/vga16fb.c
drivers/video/xilinxfb.c
drivers/xen/Kconfig
drivers/xen/Makefile
drivers/xen/evtchn.c
drivers/xen/xenbus/xenbus_probe_frontend.c
fs/debugfs/inode.c
fs/fcntl.c
fs/fuse/dir.c
fs/namei.c
fs/nfs/nfs4xdr.c
fs/nfsd/vfs.c
fs/ocfs2/refcounttree.c
fs/open.c
fs/reiserfs/procfs.c
fs/reiserfs/super.c
fs/xfs/xfs_dinode.h
fs/xfs/xfs_inode.c
fs/xfs/xfs_log_recover.c
include/acpi/video.h
include/drm/drm_fixed.h
include/dt-bindings/clock/vf610-clock.h
include/dt-bindings/pinctrl/am33xx.h
include/linux/acpi.h
include/linux/cgroup.h
include/linux/cgroup_subsys.h
include/linux/crc-t10dif.h
include/linux/drbd.h
include/linux/drbd_genl.h
include/linux/drbd_limits.h
include/linux/edac.h
include/linux/firewire.h
include/linux/ftrace_event.h
include/linux/kernel.h
include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
include/linux/mlx5/device.h
include/linux/mlx5/driver.h
include/linux/mod_devicetable.h
include/linux/netdevice.h
include/linux/platform_data/mmc-pxamci.h
include/linux/sched.h
include/linux/shdma-base.h
include/linux/skbuff.h
include/linux/tick.h
include/linux/usb.h
include/linux/vmpressure.h
include/net/busy_poll.h
include/net/ip6_fib.h
include/net/ndisc.h
include/net/nfc/hci.h
include/net/nfc/nfc.h
include/net/sock.h
include/trace/events/bcache.h
include/trace/ftrace.h
include/uapi/linux/firewire-cdev.h
include/uapi/linux/nfc.h
include/uapi/linux/usb/ch11.h
include/xen/interface/io/blkif.h
include/xen/interface/io/ring.h
kernel/Makefile
kernel/cgroup.c
kernel/freezer.c
kernel/power/process.c
kernel/printk/Makefile [new file with mode: 0644]
kernel/printk/braille.c [new file with mode: 0644]
kernel/printk/braille.h [new file with mode: 0644]
kernel/printk/console_cmdline.h [new file with mode: 0644]
kernel/printk/printk.c [moved from kernel/printk.c with 95% similarity]
kernel/ptrace.c
kernel/sched/fair.c
kernel/sysctl.c
kernel/time/tick-sched.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_event_perf.c
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_functions.c
kernel/trace/trace_functions_graph.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_mmiotrace.c
kernel/trace/trace_output.c
kernel/trace/trace_syscalls.c
kernel/trace/trace_uprobe.c
kernel/user_namespace.c
kernel/wait.c
kernel/workqueue.c
lib/Kconfig
lib/crc-t10dif.c
lib/mpi/longlong.h
mm/huge_memory.c
mm/memcontrol.c
mm/mempolicy.c
mm/mmap.c
mm/shmem.c
mm/slub.c
mm/swap.c
mm/vmpressure.c
mm/zbud.c
net/Kconfig
net/bluetooth/hci_core.c
net/bridge/br_device.c
net/bridge/br_input.c
net/bridge/br_multicast.c
net/bridge/br_private.h
net/core/neighbour.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/ipv4/devinet.c
net/ipv4/fib_trie.c
net/ipv4/sysctl_net_ipv4.c
net/ipv6/addrconf.c
net/ipv6/ip6_fib.c
net/ipv6/ip6mr.c
net/ipv6/ndisc.c
net/ipv6/route.c
net/key/af_key.c
net/mac80211/cfg.c
net/mac80211/mesh_ps.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/xt_socket.c
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_domainhash.h
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_unlabeled.c
net/netlink/genetlink.c
net/nfc/core.c
net/nfc/hci/core.c
net/nfc/nci/Kconfig
net/nfc/netlink.c
net/nfc/nfc.h
net/sched/sch_atm.c
net/sched/sch_cbq.c
net/sched/sch_htb.c
net/socket.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/gss_rpc_xdr.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/svcsock.c
net/tipc/server.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/sme.c
sound/core/compress_offload.c
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/patch_sigmatel.c
sound/soc/au1x/ac97c.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ac97.h
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/codecs/max98088.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/wm0010.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra20_spdif.c
sound/usb/6fire/pcm.c
sound/usb/hiface/pcm.c
tools/hv/hv_kvp_daemon.c

index 3b8b9b33be380b75f9a4d19a4680723f3febfce7..7e9932e55475cef2891a790e391011b77b9ff666 100644 (file)
@@ -29,6 +29,7 @@ modules.builtin
 *.bz2
 *.lzma
 *.xz
+*.lz4
 *.lzo
 *.patch
 *.gcno
diff --git a/Documentation/ABI/testing/sysfs-driver-xen-blkback b/Documentation/ABI/testing/sysfs-driver-xen-blkback
new file mode 100644 (file)
index 0000000..8bb43b6
--- /dev/null
@@ -0,0 +1,17 @@
+What:           /sys/module/xen_blkback/parameters/max_buffer_pages
+Date:           March 2013
+KernelVersion:  3.11
+Contact:        Roger Pau Monné <roger.pau@citrix.com>
+Description:
+                Maximum number of free pages to keep in each block
+                backend buffer.
+
+What:           /sys/module/xen_blkback/parameters/max_persistent_grants
+Date:           March 2013
+KernelVersion:  3.11
+Contact:        Roger Pau Monné <roger.pau@citrix.com>
+Description:
+                Maximum number of grants to map persistently in
+                blkback. If the frontend tries to use more than
+                max_persistent_grants, the LRU kicks in and starts
+                removing 5% of max_persistent_grants every 100ms.
diff --git a/Documentation/ABI/testing/sysfs-driver-xen-blkfront b/Documentation/ABI/testing/sysfs-driver-xen-blkfront
new file mode 100644 (file)
index 0000000..c0a6cb7
--- /dev/null
@@ -0,0 +1,10 @@
+What:           /sys/module/xen_blkfront/parameters/max
+Date:           June 2013
+KernelVersion:  3.11
+Contact:        Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Description:
+                Maximum number of segments that the frontend will negotiate
+                with the backend for indirect descriptors. The default value
+                is 32 - higher value means more potential throughput but more
+                memory usage. The backend picks the minimum of the frontend
+                and its default backend value.
index cbfdf5486639a144c414cc46334144fccee8a1e5..fe397f90a34f50153f5936cfa13635ed7bc85b7b 100644 (file)
@@ -84,7 +84,7 @@ X!Iinclude/linux/kobject.h
 
      <sect1><title>Kernel utility functions</title>
 !Iinclude/linux/kernel.h
-!Ekernel/printk.c
+!Ekernel/printk/printk.c
 !Ekernel/panic.c
 !Ekernel/sys.c
 !Ekernel/rcupdate.c
index c3365f26b2d9f9da85d0ff5245bd6f89555f5256..32b6c3189d9826a53875ae6dc51ce62e9b86778b 100644 (file)
@@ -46,29 +46,33 @@ you format your backing devices and cache device at the same time, you won't
 have to manually attach:
   make-bcache -B /dev/sda /dev/sdb -C /dev/sdc
 
-To make bcache devices known to the kernel, echo them to /sys/fs/bcache/register:
+bcache-tools now ships udev rules, and bcache devices are known to the kernel
+immediately.  Without udev, you can manually register devices like this:
 
   echo /dev/sdb > /sys/fs/bcache/register
   echo /dev/sdc > /sys/fs/bcache/register
 
-To register your bcache devices automatically, you could add something like
-this to an init script:
+Registering the backing device makes the bcache device show up in /dev; you can
+now format it and use it as normal. But the first time using a new bcache
+device, it'll be running in passthrough mode until you attach it to a cache.
+See the section on attaching.
 
-  echo /dev/sd* > /sys/fs/bcache/register_quiet
+The devices show up as:
 
-It'll look for bcache superblocks and ignore everything that doesn't have one.
+  /dev/bcache<N>
 
-Registering the backing device makes the bcache show up in /dev; you can now
-format it and use it as normal. But the first time using a new bcache device,
-it'll be running in passthrough mode until you attach it to a cache. See the
-section on attaching.
+As well as (with udev):
 
-The devices show up at /dev/bcacheN, and can be controlled via sysfs from
-/sys/block/bcacheN/bcache:
+  /dev/bcache/by-uuid/<uuid>
+  /dev/bcache/by-label/<label>
+
+To get started:
 
   mkfs.ext4 /dev/bcache0
   mount /dev/bcache0 /mnt
 
+You can control bcache devices through sysfs at /sys/block/bcache<N>/bcache .
+
 Cache devices are managed as sets; multiple caches per set isn't supported yet
 but will allow for mirroring of metadata and dirty data in the future. Your new
 cache set shows up as /sys/fs/bcache/<UUID>
@@ -80,11 +84,11 @@ must be attached to your cache set to enable caching. Attaching a backing
 device to a cache set is done thusly, with the UUID of the cache set in
 /sys/fs/bcache:
 
-  echo <UUID> > /sys/block/bcache0/bcache/attach
+  echo <CSET-UUID> > /sys/block/bcache0/bcache/attach
 
 This only has to be done once. The next time you reboot, just reregister all
 your bcache devices. If a backing device has data in a cache somewhere, the
-/dev/bcache# device won't be created until the cache shows up - particularly
+/dev/bcache<N> device won't be created until the cache shows up - particularly
 important if you have writeback caching turned on.
 
 If you're booting up and your cache device is gone and never coming back, you
@@ -191,6 +195,9 @@ want for getting the best possible numbers when benchmarking.
 
 SYSFS - BACKING DEVICE:
 
+Available at /sys/block/<bdev>/bcache, /sys/block/bcache*/bcache and
+(if attached) /sys/fs/bcache/<cset-uuid>/bdev*
+
 attach
   Echo the UUID of a cache set to this file to enable caching.
 
@@ -300,6 +307,8 @@ cache_readaheads
 
 SYSFS - CACHE SET:
 
+Available at /sys/fs/bcache/<cset-uuid>
+
 average_key_size
   Average data per key in the btree.
 
@@ -390,6 +399,8 @@ trigger_gc
 
 SYSFS - CACHE DEVICE:
 
+Available at /sys/block/<cdev>/bcache
+
 block_size
   Minimum granularity of writes - should match hardware sector size.
 
index ab1a56e9de9dc5eea34126c907054c4c775c1885..7a2070393732aa84fc40d7a41220b4531a325248 100644 (file)
@@ -98,6 +98,7 @@ clocks and IDs.
        fpm                  83
        mpll_osc_sel         84
        mpll_sel             85
+       spll_gate            86
 
 Examples:
 
index d5a79caec147d36f993c769ddab2a6c15fb0686a..366ce9b872407e1dfb1964079da4fe95d6094df4 100644 (file)
@@ -26,6 +26,7 @@ est   ESTeem Wireless Modems
 fsl    Freescale Semiconductor
 GEFanuc        GE Fanuc Intelligent Platforms Embedded Systems, Inc.
 gef    GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+hisilicon      Hisilicon Limited.
 hp     Hewlett Packard
 ibm    International Business Machines (IBM)
 idt    Integrated Device Technologies, Inc.
@@ -43,6 +44,7 @@ nxp   NXP Semiconductors
 onnn   ON Semiconductor Corp.
 picochip       Picochip Ltd
 powervr        PowerVR (deprecated, use img)
+qca    Qualcomm Atheros, Inc.
 qcom   Qualcomm, Inc.
 ralink Mediatek/Ralink Technology Corp.
 ramtron        Ramtron International
index 050d37fe6d40a566f684891a626e17d519144472..8148a47fc70e17cbf76be1c6d88ad09f16c983b9 100644 (file)
@@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a
 fork. So if you have any comments or updates for this file, please try
 to update the original English file first.
 
-Last Updated: 2011/03/31
+Last Updated: 2013/07/19
 ==================================
 これは、
-linux-2.6.38/Documentation/HOWTO
+linux-3.10/Documentation/HOWTO
 の和訳です。
 
-翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
-翻訳日: 2011/3/28
+翻訳団体: JF プロジェクト < http://linuxjf.sourceforge.jp/ >
+翻訳日: 2013/7/19
 翻訳者: Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
 校正者: 松倉さん <nbh--mats at nifty dot com>
          小林 雅典さん (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
@@ -245,7 +245,7 @@ Linux カーネルソースツリーの中に含まれる、きれいにし、
 自己参照方式で、索引がついた web 形式で、ソースコードを参照することが
 できます。この最新の素晴しいカーネルコードのリポジトリは以下で見つかり
 ます-
-       http://sosdg.org/~qiyong/lxr/
+       http://lxr.linux.no/+trees
 
 開発プロセス
 -----------------------
@@ -253,24 +253,24 @@ Linux カーネルソースツリーの中に含まれる、きれいにし、
 Linux カーネルの開発プロセスは現在幾つかの異なるメインカーネル「ブラン
 チ」と多数のサブシステム毎のカーネルブランチから構成されます。
 これらのブランチとは-
-  - メインの 2.6.x カーネルツリー
-  - 2.6.x.y -stable カーネルツリー
-  - 2.6.x -git カーネルパッチ
+  - メインの 3.x カーネルツリー
+  - 3.x.y -stable カーネルツリー
+  - 3.x -git カーネルパッチ
   - サブシステム毎のカーネルツリーとパッチ
-  - 統合テストのための 2.6.x -next カーネルツリー
+  - 統合テストのための 3.x -next カーネルツリー
 
-2.6.x カーネルツリー
+3.x カーネルツリー
 -----------------
 
-2.6.x カーネルは Linus Torvalds によってメンテナンスされ、kernel.org
-の pub/linux/kernel/v2.6/ ディレクトリに存在します。この開発プロセスは
+3.x カーネルは Linus Torvalds によってメンテナンスされ、kernel.org
+の pub/linux/kernel/v3.x/ ディレクトリに存在します。この開発プロセスは
 以下のとおり-
 
   - 新しいカーネルがリリースされた直後に、2週間の特別期間が設けられ、
     この期間中に、メンテナ達は Linus に大きな差分を送ることができます。
     このような差分は通常 -next カーネルに数週間含まれてきたパッチです。
     大きな変更は git(カーネルのソース管理ツール、詳細は
-    http://git-scm.com/  参照) を使って送るのが好ましいやり方ですが、パッ
+    http://git-scm.com/ 参照) を使って送るのが好ましいやり方ですが、パッ
     チファイルの形式のまま送るのでも十分です。
 
   - 2週間後、-rc1 カーネルがリリースされ、この後にはカーネル全体の安定
@@ -302,20 +302,20 @@ Andrew Morton が Linux-kernel メーリングリストにカーネルリリー
   実に認識されたバグの状況によりリリースされるのであり、前もって決めら
   れた計画によってリリースされるものではないからです。」
 
-2.6.x.y -stable カーネルツリー
+3.x.y -stable カーネルツリー
 ---------------------------
 
-バージョン番号が4つの数字に分かれているカーネルは -stable カーネルです。
-これには、2.6.x カーネルで見つかったセキュリティ問題や重大な後戻りに対
+バージョン番号が3つの数字に分かれているカーネルは -stable カーネルです。
+これには、3.x カーネルで見つかったセキュリティ問題や重大な後戻りに対
 する比較的小さい重要な修正が含まれます。
 
 これは、開発/実験的バージョンのテストに協力することに興味が無く、
 最新の安定したカーネルを使いたいユーザに推奨するブランチです。
 
-もし、2.6.x.y カーネルが存在しない場合には、番号が一番大きい 2.6.x が
+もし、3.x.y カーネルが存在しない場合には、番号が一番大きい 3.x が
 最新の安定版カーネルです。
 
-2.6.x.y は "stable" チーム <stable@kernel.org> でメンテされており、必
+3.x.y は "stable" チーム <stable@kernel.org> でメンテされており、必
 要に応じてリリースされます。通常のリリース期間は 2週間毎ですが、差し迫っ
 た問題がなければもう少し長くなることもあります。セキュリティ関連の問題
 の場合はこれに対してだいたいの場合、すぐにリリースがされます。
@@ -324,7 +324,7 @@ Andrew Morton が Linux-kernel メーリングリストにカーネルリリー
 イルにはどのような種類の変更が -stable ツリーに受け入れ可能か、またリ
 リースプロセスがどう動くかが記述されています。
 
-2.6.x -git パッチ
+3.x -git パッチ
 ------------------
 
 git リポジトリで管理されているLinus のカーネルツリーの毎日のスナップ
@@ -358,14 +358,14 @@ quilt シリーズとして公開されているパッチキューも使われ
 をつけることができます。大部分のこれらの patchwork のサイトは
 http://patchwork.kernel.org/ でリストされています。
 
-統合テストのための 2.6.x -next カーネルツリー
+統合テストのための 3.x -next カーネルツリー
 ---------------------------------------------
 
-サブシステムツリーの更新内容がメインラインの 2.6.x ツリーにマージされ
+サブシステムツリーの更新内容がメインラインの 3.x ツリーにマージされ
 る前に、それらは統合テストされる必要があります。この目的のため、実質的
 に全サブシステムツリーからほぼ毎日プルされてできる特別なテスト用のリ
 ポジトリが存在します-
-       http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
+       http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
        http://linux.f-seidel.de/linux-next/pmwiki/
 
 このやり方によって、-next カーネルは次のマージ機会でどんなものがメイン
index 1c15043aaee4c89bf2c76aca10633557c1327bd3..d569f2a424d511218f679258bbb246cae2438b25 100644 (file)
@@ -52,7 +52,7 @@ Default: 64
 
 busy_read
 ----------------
-Low latency busy poll timeout for socket reads. (needs CONFIG_NET_LL_RX_POLL)
+Low latency busy poll timeout for socket reads. (needs CONFIG_NET_RX_BUSY_POLL)
 Approximate time in us to busy loop waiting for packets on the device queue.
 This sets the default value of the SO_BUSY_POLL socket option.
 Can be set or overridden per socket by setting socket option SO_BUSY_POLL,
@@ -63,7 +63,7 @@ Default: 0 (off)
 
 busy_poll
 ----------------
-Low latency busy poll timeout for poll and select. (needs CONFIG_NET_LL_RX_POLL)
+Low latency busy poll timeout for poll and select. (needs CONFIG_NET_RX_BUSY_POLL)
 Approximate time in us to busy loop waiting for events.
 Recommended value depends on the number of sockets you poll on.
 For several sockets 50, for several hundreds 100.
index bf61e04291abb2f2200544517ab144c89cb3ab8e..97053182fcf1ef71da77dab5077c5430893abcf4 100644 (file)
@@ -965,6 +965,12 @@ M: Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
+ARM/TEXAS INSTRUMENT KEYSTONE ARCHITECTURE
+M:     Santosh Shilimkar <santosh.shilimkar@ti.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-keystone/
+
 ARM/LOGICPD PXA270 MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1259,7 +1265,6 @@ F:        drivers/rtc/rtc-coh901331.c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
 
 ARM/Ux500 ARM ARCHITECTURE
-M:     Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
@@ -1406,7 +1411,7 @@ ATHEROS ATH6KL WIRELESS DRIVER
 M:     Kalle Valo <kvalo@qca.qualcomm.com>
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/en/users/Drivers/ath6kl
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath6kl.git
+T:     git git://github.com/kvalo/ath.git
 S:     Supported
 F:     drivers/net/wireless/ath/ath6kl/
 
@@ -1642,7 +1647,7 @@ S:        Maintained
 F:     drivers/net/hamradio/baycom*
 
 BCACHE (BLOCK LAYER CACHE)
-M:     Kent Overstreet <koverstreet@google.com>
+M:     Kent Overstreet <kmo@daterainc.com>
 L:     linux-bcache@vger.kernel.org
 W:     http://bcache.evilpiepirate.org
 S:     Maintained:
@@ -2871,7 +2876,7 @@ F:        drivers/media/usb/dvb-usb-v2/dvb_usb*
 F:     drivers/media/usb/dvb-usb-v2/usb_urb.c
 
 DYNAMIC DEBUG
-M:     Jason Baron <jbaron@redhat.com>
+M:     Jason Baron <jbaron@akamai.com>
 S:     Maintained
 F:     lib/dynamic_debug.c
 F:     include/linux/dynamic_debug.h
@@ -3346,7 +3351,7 @@ F:        Documentation/firmware_class/
 F:     drivers/base/firmware*.c
 F:     include/linux/firmware.h
 
-FLASHSYSTEM DRIVER (IBM FlashSystem 70/80 PCI SSD Flash Card)
+FLASH ADAPTER DRIVER (IBM Flash Adapter 900GB Full Height PCI Flash Card)
 M:     Joshua Morris <josh.h.morris@us.ibm.com>
 M:     Philip Kelleher <pjk1939@linux.vnet.ibm.com>
 S:     Maintained
@@ -3622,11 +3627,9 @@ F:       drivers/isdn/gigaset/
 F:     include/uapi/linux/gigaset_dev.h
 
 GPIO SUBSYSTEM
-M:     Grant Likely <grant.likely@linaro.org>
 M:     Linus Walleij <linus.walleij@linaro.org>
 S:     Maintained
 L:     linux-gpio@vger.kernel.org
-T:     git git://git.secretlab.ca/git/linux-2.6.git
 F:     Documentation/gpio.txt
 F:     drivers/gpio/
 F:     include/linux/gpio*
@@ -4472,8 +4475,6 @@ F:        drivers/irqchip/
 
 IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
 M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
-M:     Grant Likely <grant.likely@linaro.org>
-T:     git git://git.secretlab.ca/git/linux-2.6.git irqdomain/next
 S:     Maintained
 F:     Documentation/IRQ-domain.txt
 F:     include/linux/irqdomain.h
@@ -4990,7 +4991,7 @@ F:        arch/powerpc/platforms/44x/
 
 LINUX FOR POWERPC EMBEDDED XILINX VIRTEX
 L:     linuxppc-dev@lists.ozlabs.org
-S:     Unmaintained
+S:     Orphan
 F:     arch/powerpc/*/*virtex*
 F:     arch/powerpc/*/*/*virtex*
 
@@ -5886,7 +5887,7 @@ OMAP DEVICE TREE SUPPORT
 M:     Benoît Cousson <b-cousson@ti.com>
 M:     Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
-L:     devicetree-discuss@lists.ozlabs.org (moderated for non-subscribers)
+L:     devicetree@vger.kernel.org
 S:     Maintained
 F:     arch/arm/boot/dts/*omap*
 F:     arch/arm/boot/dts/*am3*
@@ -6050,17 +6051,28 @@ F:      drivers/i2c/busses/i2c-ocores.c
 OPEN FIRMWARE AND FLATTENED DEVICE TREE
 M:     Grant Likely <grant.likely@linaro.org>
 M:     Rob Herring <rob.herring@calxeda.com>
-L:     devicetree-discuss@lists.ozlabs.org (moderated for non-subscribers)
+L:     devicetree@vger.kernel.org
 W:     http://fdt.secretlab.ca
 T:     git git://git.secretlab.ca/git/linux-2.6.git
 S:     Maintained
-F:     Documentation/devicetree
-F:     drivers/of
+F:     drivers/of/
 F:     include/linux/of*.h
-F:     scripts/dtc
+F:     scripts/dtc/
 K:     of_get_property
 K:     of_match_table
 
+OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
+M:     Rob Herring <rob.herring@calxeda.com>
+M:     Pawel Moll <pawel.moll@arm.com>
+M:     Mark Rutland <mark.rutland@arm.com>
+M:     Stephen Warren <swarren@wwwdotorg.org>
+M:     Ian Campbell <ian.campbell@citrix.com>
+L:     devicetree@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/
+F:     arch/*/boot/dts/
+F:     include/dt-bindings/
+
 OPENRISC ARCHITECTURE
 M:     Jonas Bonn <jonas@southpole.se>
 W:     http://openrisc.net
@@ -6719,6 +6731,14 @@ T:       git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
 F:     drivers/media/tuners/qt1010*
 
+QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
+M:     Kalle Valo <kvalo@qca.qualcomm.com>
+L:     ath10k@lists.infradead.org
+W:     http://wireless.kernel.org/en/users/Drivers/ath10k
+T:     git git://github.com/kvalo/ath.git
+S:     Supported
+F:     drivers/net/wireless/ath/ath10k/
+
 QUALCOMM HEXAGON ARCHITECTURE
 M:     Richard Kuo <rkuo@codeaurora.org>
 L:     linux-hexagon@vger.kernel.org
@@ -7746,7 +7766,6 @@ F:        drivers/clk/spear/
 
 SPI SUBSYSTEM
 M:     Mark Brown <broonie@kernel.org>
-M:     Grant Likely <grant.likely@linaro.org>
 L:     linux-spi@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
 Q:     http://patchwork.kernel.org/project/spi-devel-general/list/
@@ -7812,7 +7831,7 @@ F:        drivers/staging/asus_oled/
 
 STAGING - COMEDI
 M:     Ian Abbott <abbotti@mev.co.uk>
-M:     Mori Hess <fmhess@users.sourceforge.net>
+M:     H Hartley Sweeten <hsweeten@visionengravers.com>
 S:     Odd Fixes
 F:     drivers/staging/comedi/
 
@@ -8264,7 +8283,7 @@ S:        Maintained
 F:     sound/soc/codecs/twl4030*
 
 TI WILINK WIRELESS DRIVERS
-M:     Luciano Coelho <coelho@ti.com>
+M:     Luciano Coelho <luca@coelho.fi>
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/en/users/Drivers/wl12xx
 W:     http://wireless.kernel.org/en/users/Drivers/wl1251
@@ -9288,7 +9307,7 @@ S:        Maintained
 F:     drivers/net/ethernet/xilinx/xilinx_axienet*
 
 XILINX SYSTEMACE DRIVER
-S:     Unmaintained
+S:     Orphan
 F:     drivers/block/xsysace.c
 
 XILINX UARTLITE SERIAL DRIVER
index a35f72a420c030da7e4b107f296c4402bd9cb162..f93d4f7a90c296bcffeec561c183ff9d492735ee 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 11
 SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc4
 NAME = Linux for Workgroups
 
 # *DOCUMENTATION*
index 837a1f2d8b965a60b61252521f21129be9e80afe..082d9b4b54723d0253e7ca3355387886b81f72f4 100644 (file)
@@ -15,6 +15,7 @@ config ALPHA
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
+       select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_CMOS_UPDATE
        select GENERIC_STRNCPY_FROM_USER
index c2cbe4fc391cd7d77d319cb0cbeabd19f7e5ecbb..78b03ef39f6f0c2960e0b9c4b45eeae47eff07fa 100644 (file)
@@ -186,17 +186,24 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
  */
 static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 {
-       int c, old;
-       c = atomic_read(v);
-       for (;;) {
-               if (unlikely(c == (u)))
-                       break;
-               old = atomic_cmpxchg((v), c, c + (a));
-               if (likely(old == c))
-                       break;
-               c = old;
-       }
-       return c;
+       int c, new, old;
+       smp_mb();
+       __asm__ __volatile__(
+       "1:     ldl_l   %[old],%[mem]\n"
+       "       cmpeq   %[old],%[u],%[c]\n"
+       "       addl    %[old],%[a],%[new]\n"
+       "       bne     %[c],2f\n"
+       "       stl_c   %[new],%[mem]\n"
+       "       beq     %[new],3f\n"
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br      1b\n"
+       ".previous"
+       : [old] "=&r"(old), [new] "=&r"(new), [c] "=&r"(c)
+       : [mem] "m"(*v), [a] "rI"(a), [u] "rI"((long)u)
+       : "memory");
+       smp_mb();
+       return old;
 }
 
 
@@ -207,21 +214,56 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
  * @u: ...unless v is equal to u.
  *
  * Atomically adds @a to @v, so long as it was not @u.
- * Returns the old value of @v.
+ * Returns true iff @v was not @u.
  */
 static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 {
-       long c, old;
-       c = atomic64_read(v);
-       for (;;) {
-               if (unlikely(c == (u)))
-                       break;
-               old = atomic64_cmpxchg((v), c, c + (a));
-               if (likely(old == c))
-                       break;
-               c = old;
-       }
-       return c != (u);
+       long c, tmp;
+       smp_mb();
+       __asm__ __volatile__(
+       "1:     ldq_l   %[tmp],%[mem]\n"
+       "       cmpeq   %[tmp],%[u],%[c]\n"
+       "       addq    %[tmp],%[a],%[tmp]\n"
+       "       bne     %[c],2f\n"
+       "       stq_c   %[tmp],%[mem]\n"
+       "       beq     %[tmp],3f\n"
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br      1b\n"
+       ".previous"
+       : [tmp] "=&r"(tmp), [c] "=&r"(c)
+       : [mem] "m"(*v), [a] "rI"(a), [u] "rI"(u)
+       : "memory");
+       smp_mb();
+       return !c;
+}
+
+/*
+ * atomic64_dec_if_positive - decrement by 1 if old value positive
+ * @v: pointer of type atomic_t
+ *
+ * The function returns the old value of *v minus 1, even if
+ * the atomic variable, v, was not decremented.
+ */
+static inline long atomic64_dec_if_positive(atomic64_t *v)
+{
+       long old, tmp;
+       smp_mb();
+       __asm__ __volatile__(
+       "1:     ldq_l   %[old],%[mem]\n"
+       "       subq    %[old],1,%[tmp]\n"
+       "       ble     %[old],2f\n"
+       "       stq_c   %[tmp],%[mem]\n"
+       "       beq     %[tmp],3f\n"
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br      1b\n"
+       ".previous"
+       : [old] "=&r"(old), [tmp] "=&r"(tmp)
+       : [mem] "m"(*v)
+       : "memory");
+       smp_mb();
+       return old - 1;
 }
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
index bf46af51941b058ad6b0de0df4156f796bbb5897..a5b68b268bcf34835a6376d8b8e2cb349d03feed 100644 (file)
@@ -3,7 +3,9 @@
 
 #include <uapi/asm/param.h>
 
-#define HZ             CONFIG_HZ
-#define USER_HZ                HZ
-# define CLOCKS_PER_SEC        HZ      /* frequency at which times() counts */
+# undef HZ
+# define HZ            CONFIG_HZ
+# define USER_HZ       1024
+# define CLOCKS_PER_SEC        USER_HZ /* frequency at which times() counts */
+
 #endif /* _ASM_ALPHA_PARAM_H */
index 3bba21e41b818e1ff8fb7f346721dc8e95f93950..37b570d01202e4ee62d5dcc11af345f1805e81a0 100644 (file)
@@ -168,8 +168,4 @@ static inline void arch_write_unlock(arch_rwlock_t * lock)
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
 
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* _ALPHA_SPINLOCK_H */
index 43baee17acdf43c065bc6a9bd59b2ffa2c391f80..f2c94402e2c8b95028bace631c3cbf6f2aeca5b1 100644 (file)
@@ -3,8 +3,7 @@
 
 #include <uapi/asm/unistd.h>
 
-
-#define NR_SYSCALLS                    506
+#define NR_SYSCALLS                    508
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
index 29daed819ebd0bd56bf3ca4fda4500cf4aaadfa4..dbcd9834af6d7f58eaad342356eee7a7dd12c5d2 100644 (file)
@@ -1,13 +1,7 @@
 #ifndef _UAPI_ASM_ALPHA_PARAM_H
 #define _UAPI_ASM_ALPHA_PARAM_H
 
-/* ??? Gross.  I don't want to parameterize this, and supposedly the
-   hardware ignores reprogramming.  We also need userland buy-in to the 
-   change in HZ, since this is visible in the wait4 resources etc.  */
-
-#ifndef __KERNEL__
 #define HZ             1024
-#endif
 
 #define EXEC_PAGESIZE  8192
 
@@ -17,5 +11,4 @@
 
 #define MAXHOSTNAMELEN 64      /* max length of hostname */
 
-
 #endif /* _UAPI_ASM_ALPHA_PARAM_H */
index 801d28bcea51f61c3b45a6fcd4504f01bc96b792..53ae7bb1bfd1b3841572ae69587b80dddd9c0657 100644 (file)
 #define __NR_sendmmsg                  503
 #define __NR_process_vm_readv          504
 #define __NR_process_vm_writev         505
+#define __NR_kcmp                      506
+#define __NR_finit_module              507
 
 #endif /* _UAPI_ALPHA_UNISTD_H */
index f62a994ef1263c1d9bea762371f7b797d5225cd3..a969b95ee5ac78a64d79dd4ffa815b4b4a0f5e98 100644 (file)
 
        .text
        .set noat
+       .cfi_sections   .debug_frame
 
 /* Stack offsets.  */
 #define SP_OFF                 184
 #define SWITCH_STACK_SIZE      320
 
+.macro CFI_START_OSF_FRAME     func
+       .align  4
+       .globl  \func
+       .type   \func,@function
+\func:
+       .cfi_startproc simple
+       .cfi_return_column 64
+       .cfi_def_cfa    $sp, 48
+       .cfi_rel_offset 64, 8
+       .cfi_rel_offset $gp, 16
+       .cfi_rel_offset $16, 24
+       .cfi_rel_offset $17, 32
+       .cfi_rel_offset $18, 40
+.endm
+
+.macro CFI_END_OSF_FRAME       func
+       .cfi_endproc
+       .size   \func, . - \func
+.endm
+
 /*
  * This defines the normal kernel pt-regs layout.
  *
  * the palcode-provided values are available to the signal handler.
  */
 
-#define SAVE_ALL                       \
-       subq    $sp, SP_OFF, $sp;       \
-       stq     $0, 0($sp);             \
-       stq     $1, 8($sp);             \
-       stq     $2, 16($sp);            \
-       stq     $3, 24($sp);            \
-       stq     $4, 32($sp);            \
-       stq     $28, 144($sp);          \
-       lda     $2, alpha_mv;           \
-       stq     $5, 40($sp);            \
-       stq     $6, 48($sp);            \
-       stq     $7, 56($sp);            \
-       stq     $8, 64($sp);            \
-       stq     $19, 72($sp);           \
-       stq     $20, 80($sp);           \
-       stq     $21, 88($sp);           \
-       ldq     $2, HAE_CACHE($2);      \
-       stq     $22, 96($sp);           \
-       stq     $23, 104($sp);          \
-       stq     $24, 112($sp);          \
-       stq     $25, 120($sp);          \
-       stq     $26, 128($sp);          \
-       stq     $27, 136($sp);          \
-       stq     $2, 152($sp);           \
-       stq     $16, 160($sp);          \
-       stq     $17, 168($sp);          \
+.macro SAVE_ALL
+       subq    $sp, SP_OFF, $sp
+       .cfi_adjust_cfa_offset  SP_OFF
+       stq     $0, 0($sp)
+       stq     $1, 8($sp)
+       stq     $2, 16($sp)
+       stq     $3, 24($sp)
+       stq     $4, 32($sp)
+       stq     $28, 144($sp)
+       .cfi_rel_offset $0, 0
+       .cfi_rel_offset $1, 8
+       .cfi_rel_offset $2, 16
+       .cfi_rel_offset $3, 24
+       .cfi_rel_offset $4, 32
+       .cfi_rel_offset $28, 144
+       lda     $2, alpha_mv
+       stq     $5, 40($sp)
+       stq     $6, 48($sp)
+       stq     $7, 56($sp)
+       stq     $8, 64($sp)
+       stq     $19, 72($sp)
+       stq     $20, 80($sp)
+       stq     $21, 88($sp)
+       ldq     $2, HAE_CACHE($2)
+       stq     $22, 96($sp)
+       stq     $23, 104($sp)
+       stq     $24, 112($sp)
+       stq     $25, 120($sp)
+       stq     $26, 128($sp)
+       stq     $27, 136($sp)
+       stq     $2, 152($sp)
+       stq     $16, 160($sp)
+       stq     $17, 168($sp)
        stq     $18, 176($sp)
+       .cfi_rel_offset $5, 40
+       .cfi_rel_offset $6, 48
+       .cfi_rel_offset $7, 56
+       .cfi_rel_offset $8, 64
+       .cfi_rel_offset $19, 72
+       .cfi_rel_offset $20, 80
+       .cfi_rel_offset $21, 88
+       .cfi_rel_offset $22, 96
+       .cfi_rel_offset $23, 104
+       .cfi_rel_offset $24, 112
+       .cfi_rel_offset $25, 120
+       .cfi_rel_offset $26, 128
+       .cfi_rel_offset $27, 136
+.endm
 
-#define RESTORE_ALL                    \
-       lda     $19, alpha_mv;          \
-       ldq     $0, 0($sp);             \
-       ldq     $1, 8($sp);             \
-       ldq     $2, 16($sp);            \
-       ldq     $3, 24($sp);            \
-       ldq     $21, 152($sp);          \
-       ldq     $20, HAE_CACHE($19);    \
-       ldq     $4, 32($sp);            \
-       ldq     $5, 40($sp);            \
-       ldq     $6, 48($sp);            \
-       ldq     $7, 56($sp);            \
-       subq    $20, $21, $20;          \
-       ldq     $8, 64($sp);            \
-       beq     $20, 99f;               \
-       ldq     $20, HAE_REG($19);      \
-       stq     $21, HAE_CACHE($19);    \
-       stq     $21, 0($20);            \
-99:;                                   \
-       ldq     $19, 72($sp);           \
-       ldq     $20, 80($sp);           \
-       ldq     $21, 88($sp);           \
-       ldq     $22, 96($sp);           \
-       ldq     $23, 104($sp);          \
-       ldq     $24, 112($sp);          \
-       ldq     $25, 120($sp);          \
-       ldq     $26, 128($sp);          \
-       ldq     $27, 136($sp);          \
-       ldq     $28, 144($sp);          \
+.macro RESTORE_ALL
+       lda     $19, alpha_mv
+       ldq     $0, 0($sp)
+       ldq     $1, 8($sp)
+       ldq     $2, 16($sp)
+       ldq     $3, 24($sp)
+       ldq     $21, 152($sp)
+       ldq     $20, HAE_CACHE($19)
+       ldq     $4, 32($sp)
+       ldq     $5, 40($sp)
+       ldq     $6, 48($sp)
+       ldq     $7, 56($sp)
+       subq    $20, $21, $20
+       ldq     $8, 64($sp)
+       beq     $20, 99f
+       ldq     $20, HAE_REG($19)
+       stq     $21, HAE_CACHE($19)
+       stq     $21, 0($20)
+99:    ldq     $19, 72($sp)
+       ldq     $20, 80($sp)
+       ldq     $21, 88($sp)
+       ldq     $22, 96($sp)
+       ldq     $23, 104($sp)
+       ldq     $24, 112($sp)
+       ldq     $25, 120($sp)
+       ldq     $26, 128($sp)
+       ldq     $27, 136($sp)
+       ldq     $28, 144($sp)
        addq    $sp, SP_OFF, $sp
+       .cfi_restore    $0
+       .cfi_restore    $1
+       .cfi_restore    $2
+       .cfi_restore    $3
+       .cfi_restore    $4
+       .cfi_restore    $5
+       .cfi_restore    $6
+       .cfi_restore    $7
+       .cfi_restore    $8
+       .cfi_restore    $19
+       .cfi_restore    $20
+       .cfi_restore    $21
+       .cfi_restore    $22
+       .cfi_restore    $23
+       .cfi_restore    $24
+       .cfi_restore    $25
+       .cfi_restore    $26
+       .cfi_restore    $27
+       .cfi_restore    $28
+       .cfi_adjust_cfa_offset  -SP_OFF
+.endm
+
+.macro DO_SWITCH_STACK
+       bsr     $1, do_switch_stack
+       .cfi_adjust_cfa_offset  SWITCH_STACK_SIZE
+       .cfi_rel_offset $9, 0
+       .cfi_rel_offset $10, 8
+       .cfi_rel_offset $11, 16
+       .cfi_rel_offset $12, 24
+       .cfi_rel_offset $13, 32
+       .cfi_rel_offset $14, 40
+       .cfi_rel_offset $15, 48
+       /* We don't really care about the FP registers for debugging.  */
+.endm
+
+.macro UNDO_SWITCH_STACK
+       bsr     $1, undo_switch_stack
+       .cfi_restore    $9
+       .cfi_restore    $10
+       .cfi_restore    $11
+       .cfi_restore    $12
+       .cfi_restore    $13
+       .cfi_restore    $14
+       .cfi_restore    $15
+       .cfi_adjust_cfa_offset  -SWITCH_STACK_SIZE
+.endm
 
 /*
  * Non-syscall kernel entry points.
  */
 
-       .align  4
-       .globl  entInt
-       .ent    entInt
-entInt:
+CFI_START_OSF_FRAME entInt
        SAVE_ALL
        lda     $8, 0x3fff
        lda     $26, ret_from_sys_call
        bic     $sp, $8, $8
        mov     $sp, $19
        jsr     $31, do_entInt
-.end entInt
+CFI_END_OSF_FRAME entInt
 
-       .align  4
-       .globl  entArith
-       .ent    entArith
-entArith:
+CFI_START_OSF_FRAME entArith
        SAVE_ALL
        lda     $8, 0x3fff
        lda     $26, ret_from_sys_call
        bic     $sp, $8, $8
        mov     $sp, $18
        jsr     $31, do_entArith
-.end entArith
+CFI_END_OSF_FRAME entArith
 
-       .align  4
-       .globl  entMM
-       .ent    entMM
-entMM:
+CFI_START_OSF_FRAME entMM
        SAVE_ALL
 /* save $9 - $15 so the inline exception code can manipulate them.  */
        subq    $sp, 56, $sp
+       .cfi_adjust_cfa_offset  56
        stq     $9, 0($sp)
        stq     $10, 8($sp)
        stq     $11, 16($sp)
@@ -128,6 +207,13 @@ entMM:
        stq     $13, 32($sp)
        stq     $14, 40($sp)
        stq     $15, 48($sp)
+       .cfi_rel_offset $9, 0
+       .cfi_rel_offset $10, 8
+       .cfi_rel_offset $11, 16
+       .cfi_rel_offset $12, 24
+       .cfi_rel_offset $13, 32
+       .cfi_rel_offset $14, 40
+       .cfi_rel_offset $15, 48
        addq    $sp, 56, $19
 /* handle the fault */
        lda     $8, 0x3fff
@@ -142,28 +228,33 @@ entMM:
        ldq     $14, 40($sp)
        ldq     $15, 48($sp)
        addq    $sp, 56, $sp
+       .cfi_restore    $9
+       .cfi_restore    $10
+       .cfi_restore    $11
+       .cfi_restore    $12
+       .cfi_restore    $13
+       .cfi_restore    $14
+       .cfi_restore    $15
+       .cfi_adjust_cfa_offset  -56
 /* finish up the syscall as normal.  */
        br      ret_from_sys_call
-.end entMM
+CFI_END_OSF_FRAME entMM
 
-       .align  4
-       .globl  entIF
-       .ent    entIF
-entIF:
+CFI_START_OSF_FRAME entIF
        SAVE_ALL
        lda     $8, 0x3fff
        lda     $26, ret_from_sys_call
        bic     $sp, $8, $8
        mov     $sp, $17
        jsr     $31, do_entIF
-.end entIF
+CFI_END_OSF_FRAME entIF
 
-       .align  4
-       .globl  entUna
-       .ent    entUna
-entUna:
+CFI_START_OSF_FRAME entUna
        lda     $sp, -256($sp)
+       .cfi_adjust_cfa_offset  256
        stq     $0, 0($sp)
+       .cfi_rel_offset $0, 0
+       .cfi_remember_state
        ldq     $0, 256($sp)    /* get PS */
        stq     $1, 8($sp)
        stq     $2, 16($sp)
@@ -195,6 +286,32 @@ entUna:
        stq     $28, 224($sp)
        mov     $sp, $19
        stq     $gp, 232($sp)
+       .cfi_rel_offset $1, 1*8
+       .cfi_rel_offset $2, 2*8
+       .cfi_rel_offset $3, 3*8
+       .cfi_rel_offset $4, 4*8
+       .cfi_rel_offset $5, 5*8
+       .cfi_rel_offset $6, 6*8
+       .cfi_rel_offset $7, 7*8
+       .cfi_rel_offset $8, 8*8
+       .cfi_rel_offset $9, 9*8
+       .cfi_rel_offset $10, 10*8
+       .cfi_rel_offset $11, 11*8
+       .cfi_rel_offset $12, 12*8
+       .cfi_rel_offset $13, 13*8
+       .cfi_rel_offset $14, 14*8
+       .cfi_rel_offset $15, 15*8
+       .cfi_rel_offset $19, 19*8
+       .cfi_rel_offset $20, 20*8
+       .cfi_rel_offset $21, 21*8
+       .cfi_rel_offset $22, 22*8
+       .cfi_rel_offset $23, 23*8
+       .cfi_rel_offset $24, 24*8
+       .cfi_rel_offset $25, 25*8
+       .cfi_rel_offset $26, 26*8
+       .cfi_rel_offset $27, 27*8
+       .cfi_rel_offset $28, 28*8
+       .cfi_rel_offset $29, 29*8
        lda     $8, 0x3fff
        stq     $31, 248($sp)
        bic     $sp, $8, $8
@@ -228,16 +345,45 @@ entUna:
        ldq     $28, 224($sp)
        ldq     $gp, 232($sp)
        lda     $sp, 256($sp)
+       .cfi_restore    $1
+       .cfi_restore    $2
+       .cfi_restore    $3
+       .cfi_restore    $4
+       .cfi_restore    $5
+       .cfi_restore    $6
+       .cfi_restore    $7
+       .cfi_restore    $8
+       .cfi_restore    $9
+       .cfi_restore    $10
+       .cfi_restore    $11
+       .cfi_restore    $12
+       .cfi_restore    $13
+       .cfi_restore    $14
+       .cfi_restore    $15
+       .cfi_restore    $19
+       .cfi_restore    $20
+       .cfi_restore    $21
+       .cfi_restore    $22
+       .cfi_restore    $23
+       .cfi_restore    $24
+       .cfi_restore    $25
+       .cfi_restore    $26
+       .cfi_restore    $27
+       .cfi_restore    $28
+       .cfi_restore    $29
+       .cfi_adjust_cfa_offset  -256
        call_pal PAL_rti
-.end entUna
 
        .align  4
-       .ent    entUnaUser
 entUnaUser:
+       .cfi_restore_state
        ldq     $0, 0($sp)      /* restore original $0 */
        lda     $sp, 256($sp)   /* pop entUna's stack frame */
+       .cfi_restore    $0
+       .cfi_adjust_cfa_offset  -256
        SAVE_ALL                /* setup normal kernel stack */
        lda     $sp, -56($sp)
+       .cfi_adjust_cfa_offset  56
        stq     $9, 0($sp)
        stq     $10, 8($sp)
        stq     $11, 16($sp)
@@ -245,6 +391,13 @@ entUnaUser:
        stq     $13, 32($sp)
        stq     $14, 40($sp)
        stq     $15, 48($sp)
+       .cfi_rel_offset $9, 0
+       .cfi_rel_offset $10, 8
+       .cfi_rel_offset $11, 16
+       .cfi_rel_offset $12, 24
+       .cfi_rel_offset $13, 32
+       .cfi_rel_offset $14, 40
+       .cfi_rel_offset $15, 48
        lda     $8, 0x3fff
        addq    $sp, 56, $19
        bic     $sp, $8, $8
@@ -257,20 +410,25 @@ entUnaUser:
        ldq     $14, 40($sp)
        ldq     $15, 48($sp)
        lda     $sp, 56($sp)
+       .cfi_restore    $9
+       .cfi_restore    $10
+       .cfi_restore    $11
+       .cfi_restore    $12
+       .cfi_restore    $13
+       .cfi_restore    $14
+       .cfi_restore    $15
+       .cfi_adjust_cfa_offset  -56
        br      ret_from_sys_call
-.end entUnaUser
+CFI_END_OSF_FRAME entUna
 
-       .align  4
-       .globl  entDbg
-       .ent    entDbg
-entDbg:
+CFI_START_OSF_FRAME entDbg
        SAVE_ALL
        lda     $8, 0x3fff
        lda     $26, ret_from_sys_call
        bic     $sp, $8, $8
        mov     $sp, $16
        jsr     $31, do_entDbg
-.end entDbg
+CFI_END_OSF_FRAME entDbg
 \f
 /*
  * The system call entry point is special.  Most importantly, it looks
@@ -285,8 +443,12 @@ entDbg:
 
        .align  4
        .globl  entSys
-       .globl  ret_from_sys_call
-       .ent    entSys
+       .type   entSys, @function
+       .cfi_startproc simple
+       .cfi_return_column 64
+       .cfi_def_cfa    $sp, 48
+       .cfi_rel_offset 64, 8
+       .cfi_rel_offset $gp, 16
 entSys:
        SAVE_ALL
        lda     $8, 0x3fff
@@ -300,6 +462,9 @@ entSys:
        stq     $17, SP_OFF+32($sp)
        s8addq  $0, $5, $5
        stq     $18, SP_OFF+40($sp)
+       .cfi_rel_offset $16, SP_OFF+24
+       .cfi_rel_offset $17, SP_OFF+32
+       .cfi_rel_offset $18, SP_OFF+40
        blbs    $3, strace
        beq     $4, 1f
        ldq     $27, 0($5)
@@ -310,6 +475,7 @@ entSys:
        stq     $31, 72($sp)            /* a3=0 => no error */
 
        .align  4
+       .globl  ret_from_sys_call
 ret_from_sys_call:
        cmovne  $26, 0, $18             /* $18 = 0 => non-restartable */
        ldq     $0, SP_OFF($sp)
@@ -324,10 +490,12 @@ ret_to_user:
        and     $17, _TIF_WORK_MASK, $2
        bne     $2, work_pending
 restore_all:
+       .cfi_remember_state
        RESTORE_ALL
        call_pal PAL_rti
 
 ret_to_kernel:
+       .cfi_restore_state
        lda     $16, 7
        call_pal PAL_swpipl
        br restore_all
@@ -356,7 +524,6 @@ $ret_success:
        stq     $0, 0($sp)
        stq     $31, 72($sp)    /* a3=0 => no error */
        br      ret_from_sys_call
-.end entSys
 
 /*
  * Do all cleanup when returning from all interrupts and system calls.
@@ -370,7 +537,7 @@ $ret_success:
  */
 
        .align  4
-       .ent    work_pending
+       .type   work_pending, @function
 work_pending:
        and     $17, _TIF_NOTIFY_RESUME | _TIF_SIGPENDING, $2
        bne     $2, $work_notifysig
@@ -387,23 +554,22 @@ $work_resched:
 
 $work_notifysig:
        mov     $sp, $16
-       bsr     $1, do_switch_stack
+       DO_SWITCH_STACK
        jsr     $26, do_work_pending
-       bsr     $1, undo_switch_stack
+       UNDO_SWITCH_STACK
        br      restore_all
-.end work_pending
 
 /*
  * PTRACE syscall handler
  */
 
        .align  4
-       .ent    strace
+       .type   strace, @function
 strace:
        /* set up signal stack, call syscall_trace */
-       bsr     $1, do_switch_stack
+       DO_SWITCH_STACK
        jsr     $26, syscall_trace_enter /* returns the syscall number */
-       bsr     $1, undo_switch_stack
+       UNDO_SWITCH_STACK
 
        /* get the arguments back.. */
        ldq     $16, SP_OFF+24($sp)
@@ -431,9 +597,9 @@ ret_from_straced:
 $strace_success:
        stq     $0, 0($sp)              /* save return value */
 
-       bsr     $1, do_switch_stack
+       DO_SWITCH_STACK
        jsr     $26, syscall_trace_leave
-       bsr     $1, undo_switch_stack
+       UNDO_SWITCH_STACK
        br      $31, ret_from_sys_call
 
        .align  3
@@ -447,26 +613,31 @@ $strace_error:
        stq     $0, 0($sp)
        stq     $1, 72($sp)     /* a3 for return */
 
-       bsr     $1, do_switch_stack
+       DO_SWITCH_STACK
        mov     $18, $9         /* save old syscall number */
        mov     $19, $10        /* save old a3 */
        jsr     $26, syscall_trace_leave
        mov     $9, $18
        mov     $10, $19
-       bsr     $1, undo_switch_stack
+       UNDO_SWITCH_STACK
 
        mov     $31, $26        /* tell "ret_from_sys_call" we can restart */
        br      ret_from_sys_call
-.end strace
+CFI_END_OSF_FRAME entSys
 \f
 /*
  * Save and restore the switch stack -- aka the balance of the user context.
  */
 
        .align  4
-       .ent    do_switch_stack
+       .type   do_switch_stack, @function
+       .cfi_startproc simple
+       .cfi_return_column 64
+       .cfi_def_cfa $sp, 0
+       .cfi_register 64, $1
 do_switch_stack:
        lda     $sp, -SWITCH_STACK_SIZE($sp)
+       .cfi_adjust_cfa_offset  SWITCH_STACK_SIZE
        stq     $9, 0($sp)
        stq     $10, 8($sp)
        stq     $11, 16($sp)
@@ -510,10 +681,14 @@ do_switch_stack:
        stt     $f0, 312($sp)   # save fpcr in slot of $f31
        ldt     $f0, 64($sp)    # dont let "do_switch_stack" change fp state.
        ret     $31, ($1), 1
-.end do_switch_stack
+       .cfi_endproc
+       .size   do_switch_stack, .-do_switch_stack
 
        .align  4
-       .ent    undo_switch_stack
+       .type   undo_switch_stack, @function
+       .cfi_startproc simple
+       .cfi_def_cfa $sp, 0
+       .cfi_register 64, $1
 undo_switch_stack:
        ldq     $9, 0($sp)
        ldq     $10, 8($sp)
@@ -558,7 +733,8 @@ undo_switch_stack:
        ldt     $f30, 304($sp)
        lda     $sp, SWITCH_STACK_SIZE($sp)
        ret     $31, ($1), 1
-.end undo_switch_stack
+       .cfi_endproc
+       .size   undo_switch_stack, .-undo_switch_stack
 \f
 /*
  * The meat of the context switch code.
@@ -566,17 +742,18 @@ undo_switch_stack:
 
        .align  4
        .globl  alpha_switch_to
-       .ent    alpha_switch_to
+       .type   alpha_switch_to, @function
+       .cfi_startproc
 alpha_switch_to:
-       .prologue 0
-       bsr     $1, do_switch_stack
+       DO_SWITCH_STACK
        call_pal PAL_swpctx
        lda     $8, 0x3fff
-       bsr     $1, undo_switch_stack
+       UNDO_SWITCH_STACK
        bic     $sp, $8, $8
        mov     $17, $0
        ret
-.end alpha_switch_to
+       .cfi_endproc
+       .size   alpha_switch_to, .-alpha_switch_to
 
 /*
  * New processes begin life here.
index f433fc11877a30ae096dd54d263b37b094132fac..28e4429596f3f208c1b868887112bad4faa33987 100644 (file)
@@ -236,7 +236,7 @@ void __init
 init_rtc_irq(void)
 {
        irq_set_chip_and_handler_name(RTC_IRQ, &dummy_irq_chip,
-                                     handle_simple_irq, "RTC");
+                                     handle_percpu_irq, "RTC");
        setup_irq(RTC_IRQ, &timer_irqaction);
 }
 
index 53b18a620e1c2a72a91bfa885653d81263a6ac7e..9dbbcb3b914675f80e3e0f097ced7e4545b533f9 100644 (file)
@@ -264,9 +264,10 @@ recv_secondary_console_msg(void)
                if (cnt <= 0 || cnt >= 80)
                        strcpy(buf, "<<< BOGUS MSG >>>");
                else {
-                       cp1 = (char *) &cpu->ipc_buffer[11];
+                       cp1 = (char *) &cpu->ipc_buffer[1];
                        cp2 = buf;
-                       strcpy(cp2, cp1);
+                       memcpy(cp2, cp1, cnt);
+                       cp2[cnt] = '\0';
                        
                        while ((cp2 = strchr(cp2, '\r')) != 0) {
                                *cp2 = ' ';
index 5bf401f7ea97f5379067facc21762c9dfdd1732d..6c35159bc00eb47860516bda8868801a74bbe868 100644 (file)
@@ -190,9 +190,6 @@ static struct irq_chip clipper_irq_type = {
 static void
 dp264_device_interrupt(unsigned long vector)
 {
-#if 1
-       printk("dp264_device_interrupt: NOT IMPLEMENTED YET!!\n");
-#else
        unsigned long pld;
        unsigned int i;
 
@@ -210,12 +207,7 @@ dp264_device_interrupt(unsigned long vector)
                        isa_device_interrupt(vector);
                else
                        handle_irq(16 + i);
-#if 0
-               TSUNAMI_cchip->dir0.csr = 1UL << i; mb();
-               tmp = TSUNAMI_cchip->dir0.csr;
-#endif
        }
-#endif
 }
 
 static void 
index 407accc808777bc4a6f36fa6b912b92686d09a0b..c92e389ff2192973f95f51073a5ce50e5f132a3b 100644 (file)
@@ -317,8 +317,9 @@ marvel_init_irq(void)
 }
 
 static int 
-marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+marvel_map_irq(const struct pci_dev *cdev, u8 slot, u8 pin)
 {
+       struct pci_dev *dev = (struct pci_dev *)cdev;
        struct pci_controller *hose = dev->sysdata;
        struct io7_port *io7_port = hose->sysdata;
        struct io7 *io7 = io7_port->io7;
index 4284ec798ec94c89ebe0e4b05e1eb2d1c6dbb0ed..dca9b3fb0071d8c24c1c5e1048a0da8461e12d8e 100644 (file)
@@ -524,6 +524,8 @@ sys_call_table:
        .quad sys_sendmmsg
        .quad sys_process_vm_readv
        .quad sys_process_vm_writev             /* 505 */
+       .quad sys_kcmp
+       .quad sys_finit_module
 
        .size sys_call_table, . - sys_call_table
        .type sys_call_table, @object
index e336694ca042127c39a4cef780dee557b2f068cd..ea3395036556ceea61c74c08452d5e7a7061e566 100644 (file)
@@ -105,9 +105,7 @@ void arch_irq_work_raise(void)
 
 static inline __u32 rpcc(void)
 {
-    __u32 result;
-    asm volatile ("rpcc %0" : "=r"(result));
-    return result;
+       return __builtin_alpha_rpcc();
 }
 
 int update_persistent_clock(struct timespec now)
index be1fba334bd07c04d42f3f004725b8d25b26841d..bd0665cdc840d3e9a79b752ec3a88279ede69344 100644 (file)
@@ -66,8 +66,8 @@ dik_show_regs(struct pt_regs *regs, unsigned long *r9_15)
 {
        printk("pc = [<%016lx>]  ra = [<%016lx>]  ps = %04lx    %s\n",
               regs->pc, regs->r26, regs->ps, print_tainted());
-       print_symbol("pc is at %s\n", regs->pc);
-       print_symbol("ra is at %s\n", regs->r26 );
+       printk("pc is at %pSR\n", (void *)regs->pc);
+       printk("ra is at %pSR\n", (void *)regs->r26);
        printk("v0 = %016lx  t0 = %016lx  t1 = %016lx\n",
               regs->r0, regs->r1, regs->r2);
        printk("t2 = %016lx  t3 = %016lx  t4 = %016lx\n",
@@ -132,9 +132,7 @@ dik_show_trace(unsigned long *sp)
                        continue;
                if (tmp >= (unsigned long) &_etext)
                        continue;
-               printk("[<%lx>]", tmp);
-               print_symbol(" %s", tmp);
-               printk("\n");
+               printk("[<%lx>] %pSR\n", tmp, (void *)tmp);
                if (i > 40) {
                        printk(" ...");
                        break;
index 8943c028d4bbe3ae2aea2875aae5c2d7e3dd2bda..df57611652e50b73322a6eaf7005598684208d4a 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>     /* For VMALLOC_START */
 #include <asm/thread_info.h>   /* For THREAD_SIZE */
+#include <asm/mmu.h>
 
 /* Note on the LD/ST addr modes with addr reg wback
  *
index ba412e02ec0c492abed190202cab324d976d0eec..43594d5116efce810798b763da8f3e7ea6891c93 100644 (file)
@@ -20,7 +20,6 @@ config ARM
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select HARDIRQS_SW_RESEND
-       select HAVE_AOUT
        select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_SECCOMP_FILTER
@@ -218,7 +217,8 @@ config VECTORS_BASE
        default DRAM_BASE if REMAP_VECTORS_TO_RAM
        default 0x00000000
        help
-         The base address of exception vectors.
+         The base address of exception vectors.  This must be two pages
+         in size.
 
 config ARM_PATCH_PHYS_VIRT
        bool "Patch physical to virtual translations at runtime" if EMBEDDED
@@ -1600,8 +1600,7 @@ config LOCAL_TIMERS
 config ARCH_NR_GPIO
        int
        default 1024 if ARCH_SHMOBILE || ARCH_TEGRA
-       default 512 if SOC_OMAP5
-       default 512 if ARCH_KEYSTONE
+       default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5
        default 392 if ARCH_U8500
        default 352 if ARCH_VT8500
        default 288 if ARCH_SUNXI
index e401a766c0bdaf633f9dd14977eb231d2b2656e9..583f4a00ec3210bf6cb3cf58dac4ae7ac8a2807c 100644 (file)
@@ -804,9 +804,19 @@ config DEBUG_LL_INCLUDE
 
 config DEBUG_UNCOMPRESS
        bool
-       default y if ARCH_MULTIPLATFORM && DEBUG_LL && \
-                    !DEBUG_OMAP2PLUS_UART && \
+       depends on ARCH_MULTIPLATFORM
+       default y if DEBUG_LL && !DEBUG_OMAP2PLUS_UART && \
                     !DEBUG_TEGRA_UART
+       help
+         This option influences the normal decompressor output for
+         multiplatform kernels.  Normally, multiplatform kernels disable
+         decompressor output because it is not possible to know where to
+         send the decompressor output.
+
+         When this option is set, the selected DEBUG_LL output method
+         will be re-used for normal decompressor output on multiplatform
+         kernels.
+         
 
 config UNCOMPRESS_INCLUDE
        string
index c0ac0f5e5e5c0900c5e0e081390e0af900005738..6fd2ceae305a6a5cf6c5d2e766e4c91848b147f7 100644 (file)
@@ -153,6 +153,7 @@ machine-$(CONFIG_ARCH_DAVINCI)              += davinci
 machine-$(CONFIG_ARCH_DOVE)            += dove
 machine-$(CONFIG_ARCH_EBSA110)         += ebsa110
 machine-$(CONFIG_ARCH_EP93XX)          += ep93xx
+machine-$(CONFIG_ARCH_EXYNOS)          += exynos
 machine-$(CONFIG_ARCH_GEMINI)          += gemini
 machine-$(CONFIG_ARCH_HIGHBANK)                += highbank
 machine-$(CONFIG_ARCH_INTEGRATOR)      += integrator
@@ -160,15 +161,16 @@ machine-$(CONFIG_ARCH_IOP13XX)            += iop13xx
 machine-$(CONFIG_ARCH_IOP32X)          += iop32x
 machine-$(CONFIG_ARCH_IOP33X)          += iop33x
 machine-$(CONFIG_ARCH_IXP4XX)          += ixp4xx
+machine-$(CONFIG_ARCH_KEYSTONE)                += keystone
 machine-$(CONFIG_ARCH_KIRKWOOD)                += kirkwood
 machine-$(CONFIG_ARCH_KS8695)          += ks8695
 machine-$(CONFIG_ARCH_LPC32XX)         += lpc32xx
 machine-$(CONFIG_ARCH_MMP)             += mmp
 machine-$(CONFIG_ARCH_MSM)             += msm
 machine-$(CONFIG_ARCH_MV78XX0)         += mv78xx0
+machine-$(CONFIG_ARCH_MVEBU)           += mvebu
 machine-$(CONFIG_ARCH_MXC)             += imx
 machine-$(CONFIG_ARCH_MXS)             += mxs
-machine-$(CONFIG_ARCH_MVEBU)           += mvebu
 machine-$(CONFIG_ARCH_NETX)            += netx
 machine-$(CONFIG_ARCH_NOMADIK)         += nomadik
 machine-$(CONFIG_ARCH_NSPIRE)          += nspire
@@ -176,7 +178,6 @@ machine-$(CONFIG_ARCH_OMAP1)                += omap1
 machine-$(CONFIG_ARCH_OMAP2PLUS)       += omap2
 machine-$(CONFIG_ARCH_ORION5X)         += orion5x
 machine-$(CONFIG_ARCH_PICOXCELL)       += picoxcell
-machine-$(CONFIG_ARCH_SIRF)            += prima2
 machine-$(CONFIG_ARCH_PXA)             += pxa
 machine-$(CONFIG_ARCH_REALVIEW)                += realview
 machine-$(CONFIG_ARCH_ROCKCHIP)                += rockchip
@@ -186,25 +187,24 @@ machine-$(CONFIG_ARCH_S3C64XX)            += s3c64xx
 machine-$(CONFIG_ARCH_S5P64X0)         += s5p64x0
 machine-$(CONFIG_ARCH_S5PC100)         += s5pc100
 machine-$(CONFIG_ARCH_S5PV210)         += s5pv210
-machine-$(CONFIG_ARCH_EXYNOS)          += exynos
 machine-$(CONFIG_ARCH_SA1100)          += sa1100
 machine-$(CONFIG_ARCH_SHARK)           += shark
 machine-$(CONFIG_ARCH_SHMOBILE)        += shmobile
+machine-$(CONFIG_ARCH_SIRF)            += prima2
+machine-$(CONFIG_ARCH_SOCFPGA)         += socfpga
+machine-$(CONFIG_ARCH_STI)             += sti
+machine-$(CONFIG_ARCH_SUNXI)           += sunxi
 machine-$(CONFIG_ARCH_TEGRA)           += tegra
 machine-$(CONFIG_ARCH_U300)            += u300
 machine-$(CONFIG_ARCH_U8500)           += ux500
 machine-$(CONFIG_ARCH_VERSATILE)       += versatile
 machine-$(CONFIG_ARCH_VEXPRESS)                += vexpress
+machine-$(CONFIG_ARCH_VIRT)            += virt
 machine-$(CONFIG_ARCH_VT8500)          += vt8500
 machine-$(CONFIG_ARCH_W90X900)         += w90x900
+machine-$(CONFIG_ARCH_ZYNQ)            += zynq
 machine-$(CONFIG_FOOTBRIDGE)           += footbridge
-machine-$(CONFIG_ARCH_SOCFPGA)         += socfpga
 machine-$(CONFIG_PLAT_SPEAR)           += spear
-machine-$(CONFIG_ARCH_STI)             += sti
-machine-$(CONFIG_ARCH_VIRT)            += virt
-machine-$(CONFIG_ARCH_ZYNQ)            += zynq
-machine-$(CONFIG_ARCH_SUNXI)           += sunxi
-machine-$(CONFIG_ARCH_KEYSTONE)                += keystone
 
 # Platform directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
index 9866cd736deea9143ac684b3c5d5313e658ab391..a0f2721ea583bbc358452e7e415c0eadc353e2d6 100644 (file)
                                                 sirf,function = "usp0";
                                         };
                                 };
+                               usp0_uart_nostreamctrl_pins_a: usp0@1 {
+                                        usp0 {
+                                                sirf,pins = "usp0_uart_nostreamctrl_grp";
+                                                sirf,function = "usp0_uart_nostreamctrl";
+                                        };
+                                };
                                 usp1_pins_a: usp1@0 {
                                         usp1 {
                                                 sirf,pins = "usp1grp";
                                                 sirf,function = "pulse_count";
                                         };
                                 };
-                                cko0_rst_pins_a: cko0_rst@0 {
-                                        cko0_rst {
-                                                sirf,pins = "cko0_rstgrp";
-                                                sirf,function = "cko0_rst";
+                                cko0_pins_a: cko0@0 {
+                                        cko0 {
+                                                sirf,pins = "cko0grp";
+                                                sirf,function = "cko0";
                                         };
                                 };
-                                cko1_rst_pins_a: cko1_rst@0 {
-                                        cko1_rst {
-                                                sirf,pins = "cko1_rstgrp";
-                                                sirf,function = "cko1_rst";
+                                cko1_pins_a: cko1@0 {
+                                        cko1 {
+                                                sirf,pins = "cko1grp";
+                                                sirf,function = "cko1";
                                         };
                                 };
                        };
index 43bf3c796cba9cfef5d45032ebcf05b6807dcd4c..0e7fed47bd8d2941292ce8b7411036cf46883f44 100644 (file)
                                        reg = <0x0a>;
                                        VDDA-supply = <&reg_3p3v>;
                                        VDDIO-supply = <&reg_3p3v>;
-
+                                       clocks = <&saif0>;
                                };
 
                                pcf8563: rtc@51 {
index 1f0d38d7b16f5477d2f3b5ec41e6eb78e0f5068b..e035f4664b97493b2261b97b33cfbc97da8b539c 100644 (file)
                                        reg = <0x0a>;
                                        VDDA-supply = <&reg_3p3v>;
                                        VDDIO-supply = <&reg_3p3v>;
-
+                                       clocks = <&saif0>;
                                };
 
                                at24@51 {
index 880df2f13be8d761d679e980e4e756dd9e401d91..44d9da57736e637ef4fcc4a113fcef651a07d58d 100644 (file)
                                        reg = <0x0a>;
                                        VDDA-supply = <&reg_3p3v>;
                                        VDDIO-supply = <&reg_3p3v>;
-
+                                       clocks = <&saif0>;
                                };
 
                                eeprom: eeprom@51 {
index 6a8acb01b1d3ccef1b2a8c82cdacad41bf277f30..9524a05712810bba53382f2b066943cc03c7a675 100644 (file)
                                compatible = "fsl,imx28-saif";
                                reg = <0x80042000 0x2000>;
                                interrupts = <59 80>;
+                               #clock-cells = <0>;
                                clocks = <&clks 53>;
                                dmas = <&dma_apbx 4>;
                                dma-names = "rx-tx";
index 6dd9486c755ba7ac5c3f912a998c978e12602391..ad3471ca17c7aad36904f26b3f0070eac4b58d3a 100644 (file)
                mux-int-port = <2>;
                mux-ext-port = <3>;
        };
+
+       clocks {
+               clk_26M: codec_clock {
+                       compatible = "fixed-clock";
+                       reg=<0>;
+                       #clock-cells = <0>;
+                       clock-frequency = <26000000>;
+                       gpios = <&gpio4 26 1>;
+               };
+       };
 };
 
 &esdhc1 {
                                MX51_PAD_EIM_A27__GPIO2_21   0x5
                                MX51_PAD_CSPI1_SS0__GPIO4_24 0x85
                                MX51_PAD_CSPI1_SS1__GPIO4_25 0x85
+                               MX51_PAD_CSPI1_RDY__GPIO4_26 0x80000000
                        >;
                };
        };
        sgtl5000: codec@0a {
                compatible = "fsl,sgtl5000";
                reg = <0x0a>;
-               clock-frequency = <26000000>;
+               clocks = <&clk_26M>;
                VDDA-supply = <&vdig_reg>;
                VDDIO-supply = <&vvideo_reg>;
        };
index aaa33bc99f78fe6ea3877713482cc35203186868..a630902679410f9a4f356ab430a3199bf3ac852b 100644 (file)
@@ -27,7 +27,7 @@
 
        backlight {
                compatible = "pwm-backlight";
-               pwms = <&pwm2 0 50000 0 0>;
+               pwms = <&pwm2 0 50000>;
                brightness-levels = <0 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100>;
                default-brightness-level = <10>;
                enable-gpios = <&gpio7 7 0>;
index 3895fbba8fce7fff6302f9b30deb72049c24f003..569aa9f2c4eddb90736b47ea20c8a705b31e295b 100644 (file)
                                uart1 {
                                        pinctrl_uart1_1: uart1grp-1 {
                                                fsl,pins = <
-                                                       MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1c5
-                                                       MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1c5
+                                                       MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4
+                                                       MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4
                                                >;
                                        };
 
                                        pinctrl_uart1_2: uart1grp-2 {
                                                fsl,pins = <
-                                                       MX53_PAD_PATA_DIOW__UART1_TXD_MUX  0x1c5
-                                                       MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1c5
+                                                       MX53_PAD_PATA_DIOW__UART1_TXD_MUX  0x1e4
+                                                       MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4
                                                >;
                                        };
 
                                uart2 {
                                        pinctrl_uart2_1: uart2grp-1 {
                                                fsl,pins = <
-                                                       MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1c5
-                                                       MX53_PAD_PATA_DMARQ__UART2_TXD_MUX     0x1c5
+                                                       MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4
+                                                       MX53_PAD_PATA_DMARQ__UART2_TXD_MUX     0x1e4
                                                >;
                                        };
 
                                uart3 {
                                        pinctrl_uart3_1: uart3grp-1 {
                                                fsl,pins = <
-                                                       MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1c5
-                                                       MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1c5
-                                                       MX53_PAD_PATA_DA_1__UART3_CTS     0x1c5
-                                                       MX53_PAD_PATA_DA_2__UART3_RTS     0x1c5
+                                                       MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4
+                                                       MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4
+                                                       MX53_PAD_PATA_DA_1__UART3_CTS     0x1e4
+                                                       MX53_PAD_PATA_DA_2__UART3_RTS     0x1e4
                                                >;
                                        };
 
                                        pinctrl_uart3_2: uart3grp-2 {
                                                fsl,pins = <
-                                                       MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1c5
-                                                       MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1c5
+                                                       MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4
+                                                       MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4
                                                >;
                                        };
 
                                uart4 {
                                        pinctrl_uart4_1: uart4grp-1 {
                                                fsl,pins = <
-                                                       MX53_PAD_KEY_COL0__UART4_TXD_MUX 0x1c5
-                                                       MX53_PAD_KEY_ROW0__UART4_RXD_MUX 0x1c5
+                                                       MX53_PAD_KEY_COL0__UART4_TXD_MUX 0x1e4
+                                                       MX53_PAD_KEY_ROW0__UART4_RXD_MUX 0x1e4
                                                >;
                                        };
                                };
                                uart5 {
                                        pinctrl_uart5_1: uart5grp-1 {
                                                fsl,pins = <
-                                                       MX53_PAD_KEY_COL1__UART5_TXD_MUX 0x1c5
-                                                       MX53_PAD_KEY_ROW1__UART5_RXD_MUX 0x1c5
+                                                       MX53_PAD_KEY_COL1__UART5_TXD_MUX 0x1e4
+                                                       MX53_PAD_KEY_ROW1__UART5_RXD_MUX 0x1e4
                                                >;
                                        };
                                };
index db2060c465404d81faab3cd8d2c8427588c1354f..9c1167b0459b6b3e4afd9f2a7e60f1f2f8584e1a 100644 (file)
@@ -26,7 +26,7 @@
                cpu-offset = <0x80000>;
        };
 
-       msmgpio: gpio@fd510000 {
+       msmgpio: gpio@800000 {
                compatible = "qcom,msm-gpio";
                gpio-controller;
                #gpio-cells = <2>;
@@ -34,7 +34,7 @@
                interrupts = <0 32 0x4>;
                interrupt-controller;
                #interrupt-cells = <2>;
-               reg = <0xfd510000 0x4000>;
+               reg = <0x800000 0x4000>;
        };
 
        serial@16440000 {
index 08b72678abff0cc4dbd9058fb95bf26c4b779b01..65d7b601651c390f78272602c79d6fb3b172ce4f 100644 (file)
 };
 
 &mmc1 {
-       vmmc-supply = <&vmmcsd_fixed>;
+       vmmc-supply = <&ldo9_reg>;
        bus-width = <4>;
 };
 
 
                        regulators {
                                smps123_reg: smps123 {
+                                       /* VDD_OPP_MPU */
                                        regulator-name = "smps123";
                                        regulator-min-microvolt = < 600000>;
                                        regulator-max-microvolt = <1500000>;
                                };
 
                                smps45_reg: smps45 {
+                                       /* VDD_OPP_MM */
                                        regulator-name = "smps45";
                                        regulator-min-microvolt = < 600000>;
                                        regulator-max-microvolt = <1310000>;
                                };
 
                                smps6_reg: smps6 {
+                                       /* VDD_DDR3 - over VDD_SMPS6 */
                                        regulator-name = "smps6";
                                        regulator-min-microvolt = <1200000>;
                                        regulator-max-microvolt = <1200000>;
                                };
 
                                smps7_reg: smps7 {
+                                       /* VDDS_1v8_OMAP over VDDS_1v8_MAIN */
                                        regulator-name = "smps7";
                                        regulator-min-microvolt = <1800000>;
                                        regulator-max-microvolt = <1800000>;
                                };
 
                                smps8_reg: smps8 {
+                                       /* VDD_OPP_CORE */
                                        regulator-name = "smps8";
                                        regulator-min-microvolt = < 600000>;
                                        regulator-max-microvolt = <1310000>;
                                };
 
                                smps9_reg: smps9 {
+                                       /* VDDA_2v1_AUD over VDD_2v1 */
                                        regulator-name = "smps9";
                                        regulator-min-microvolt = <2100000>;
                                        regulator-max-microvolt = <2100000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
                                        ti,smps-range = <0x80>;
                                };
 
                                smps10_reg: smps10 {
+                                       /* VBUS_5V_OTG */
                                        regulator-name = "smps10";
                                        regulator-min-microvolt = <5000000>;
                                        regulator-max-microvolt = <5000000>;
                                };
 
                                ldo1_reg: ldo1 {
+                                       /* VDDAPHY_CAM: vdda_csiport */
                                        regulator-name = "ldo1";
-                                       regulator-min-microvolt = <2800000>;
-                                       regulator-max-microvolt = <2800000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
+                                       regulator-min-microvolt = <1500000>;
+                                       regulator-max-microvolt = <1800000>;
                                };
 
                                ldo2_reg: ldo2 {
+                                       /* VCC_2V8_DISP: Does not go anywhere */
                                        regulator-name = "ldo2";
-                                       regulator-min-microvolt = <2900000>;
-                                       regulator-max-microvolt = <2900000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
+                                       regulator-min-microvolt = <2800000>;
+                                       regulator-max-microvolt = <2800000>;
+                                       /* Unused */
+                                       status = "disabled";
                                };
 
                                ldo3_reg: ldo3 {
+                                       /* VDDAPHY_MDM: vdda_lli */
                                        regulator-name = "ldo3";
-                                       regulator-min-microvolt = <3000000>;
-                                       regulator-max-microvolt = <3000000>;
-                                       regulator-always-on;
+                                       regulator-min-microvolt = <1500000>;
+                                       regulator-max-microvolt = <1500000>;
                                        regulator-boot-on;
+                                       /* Only if Modem is used */
+                                       status = "disabled";
                                };
 
                                ldo4_reg: ldo4 {
+                                       /* VDDAPHY_DISP: vdda_dsiport/hdmi */
                                        regulator-name = "ldo4";
-                                       regulator-min-microvolt = <2200000>;
-                                       regulator-max-microvolt = <2200000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
+                                       regulator-min-microvolt = <1500000>;
+                                       regulator-max-microvolt = <1800000>;
                                };
 
                                ldo5_reg: ldo5 {
+                                       /* VDDA_1V8_PHY: usb/sata/hdmi.. */
                                        regulator-name = "ldo5";
                                        regulator-min-microvolt = <1800000>;
                                        regulator-max-microvolt = <1800000>;
                                };
 
                                ldo6_reg: ldo6 {
+                                       /* VDDS_1V2_WKUP: hsic/ldo_emu_wkup */
                                        regulator-name = "ldo6";
-                                       regulator-min-microvolt = <1500000>;
-                                       regulator-max-microvolt = <1500000>;
+                                       regulator-min-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1200000>;
                                        regulator-always-on;
                                        regulator-boot-on;
                                };
 
                                ldo7_reg: ldo7 {
+                                       /* VDD_VPP: vpp1 */
                                        regulator-name = "ldo7";
-                                       regulator-min-microvolt = <1500000>;
-                                       regulator-max-microvolt = <1500000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
+                                       regulator-min-microvolt = <2000000>;
+                                       regulator-max-microvolt = <2000000>;
+                                       /* Only for efuse reprograming! */
+                                       status = "disabled";
                                };
 
                                ldo8_reg: ldo8 {
+                                       /* VDD_3v0: Does not go anywhere */
                                        regulator-name = "ldo8";
-                                       regulator-min-microvolt = <1500000>;
-                                       regulator-max-microvolt = <1500000>;
-                                       regulator-always-on;
+                                       regulator-min-microvolt = <3000000>;
+                                       regulator-max-microvolt = <3000000>;
                                        regulator-boot-on;
+                                       /* Unused */
+                                       status = "disabled";
                                };
 
                                ldo9_reg: ldo9 {
+                                       /* VCC_DV_SDIO: vdds_sdcard */
                                        regulator-name = "ldo9";
                                        regulator-min-microvolt = <1800000>;
-                                       regulator-max-microvolt = <3300000>;
-                                       regulator-always-on;
+                                       regulator-max-microvolt = <3000000>;
                                        regulator-boot-on;
                                };
 
                                ldoln_reg: ldoln {
+                                       /* VDDA_1v8_REF: vdds_osc/mm_l4per.. */
                                        regulator-name = "ldoln";
                                        regulator-min-microvolt = <1800000>;
                                        regulator-max-microvolt = <1800000>;
                                };
 
                                ldousb_reg: ldousb {
+                                       /* VDDA_3V_USB: VDDA_USBHS33 */
                                        regulator-name = "ldousb";
                                        regulator-min-microvolt = <3250000>;
                                        regulator-max-microvolt = <3250000>;
                                        regulator-always-on;
                                        regulator-boot-on;
                                };
+
+                               regen3_reg: regen3 {
+                                       /* REGEN3 controls LDO9 supply to card */
+                                       regulator-name = "regen3";
+                                       regulator-always-on;
+                                       regulator-boot-on;
+                               };
                        };
                };
        };
index 05e9489cf95c835f4442e90fb47fd3eb92900e79..bbeb623fc2c6f82dc9f92b1c77a90811946f9736 100644 (file)
                                                 sirf,function = "pulse_count";
                                         };
                                 };
-                                cko0_rst_pins_a: cko0_rst@0 {
-                                        cko0_rst {
-                                                sirf,pins = "cko0_rstgrp";
-                                                sirf,function = "cko0_rst";
+                                cko0_pins_a: cko0@0 {
+                                        cko0 {
+                                                sirf,pins = "cko0grp";
+                                                sirf,function = "cko0";
                                         };
                                 };
-                                cko1_rst_pins_a: cko1_rst@0 {
-                                        cko1_rst {
-                                                sirf,pins = "cko1_rstgrp";
-                                                sirf,function = "cko1_rst";
+                                cko1_pins_a: cko1@0 {
+                                        cko1 {
+                                                sirf,pins = "cko1grp";
+                                                sirf,function = "cko1";
                                         };
                                 };
                        };
index 957b21a71b4b7f24267908afe8aae4279eaa3c48..0f246c979262d3c39676576fdde4c2797cb0d118 100644 (file)
                                reg             = <0x9000 0x100>;
                                st,bank-name    = "PIO31";
                        };
+
+                       serial2-oe {
+                               pinctrl_serial2_oe: serial2-1 {
+                                       st,pins {
+                                               output-enable   = <&PIO11 3 ALT2 OUT>;
+                                       };
+                               };
+                       };
+
                };
 
                pin-controller-rear {
                                        st,pins {
                                                tx      = <&PIO17 4 ALT2 OUT>;
                                                rx      = <&PIO17 5 ALT2 IN>;
-                                               output-enable   = <&PIO11 3 ALT2 OUT>;
                                        };
                                };
                        };
index 3cecd9689a4999927d60aeb1f320dafed99d0965..1a0326ea7d070ad762d6f83719aa0fcc29a98dd2 100644 (file)
@@ -79,7 +79,7 @@
                        interrupts      = <0 197 0>;
                        clocks          = <&CLK_S_ICN_REG_0>;
                        pinctrl-names   = "default";
-                       pinctrl-0       = <&pinctrl_serial2>;
+                       pinctrl-0       = <&pinctrl_serial2 &pinctrl_serial2_oe>;
                };
 
                /* SBC_UART1 */
index 7321403cab8a2eaf6811bc93c8ee78b181afbe08..f5b9898d9c6e60330417abc3cfad494d27474d75 100644 (file)
@@ -6,10 +6,12 @@
                #address-cells = <1>;
                #size-cells = <0>;
                cpu@0 {
+                       device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0>;
                };
                cpu@1 {
+                       device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <1>;
                };
index 2fcb3f2ca160411f12575672e0cdd68319605865..5592be6f2f7a7ad58cf9eb3cf0cd17cd38e207f8 100644 (file)
        };
 
        usb-phy@c5004000 {
+               status = "okay";
                nvidia,phy-reset-gpio = <&gpio TEGRA_GPIO(V, 1)
                        GPIO_ACTIVE_LOW>;
        };
index b3034da00a37bfe6a5361420bc2fb8d99101fb5a..ae6a17aed9ee224c85498b2bc6b1e0fa43e75e56 100644 (file)
                regulator-max-microvolt = <3150000>;
        };
 
+       vmmc2: regulator-vmmc2 {
+               compatible = "ti,twl4030-vmmc2";
+               regulator-min-microvolt = <1850000>;
+               regulator-max-microvolt = <3150000>;
+       };
+
        vusb1v5: regulator-vusb1v5 {
                compatible = "ti,twl4030-vusb1v5";
        };
index e1eb7dadda80a56255c63d1a646885f41115d6e0..67d929cf98045235a1a39eeeb7c884c2b2bccddc 100644 (file)
                                compatible = "fsl,mvf600-fec";
                                reg = <0x400d0000 0x1000>;
                                interrupts = <0 78 0x04>;
-                               clocks = <&clks VF610_CLK_ENET>,
-                                       <&clks VF610_CLK_ENET>,
+                               clocks = <&clks VF610_CLK_ENET0>,
+                                       <&clks VF610_CLK_ENET0>,
                                        <&clks VF610_CLK_ENET>;
                                clock-names = "ipg", "ahb", "ptp";
                                status = "disabled";
                                compatible = "fsl,mvf600-fec";
                                reg = <0x400d1000 0x1000>;
                                interrupts = <0 79 0x04>;
-                               clocks = <&clks VF610_CLK_ENET>,
-                                       <&clks VF610_CLK_ENET>,
+                               clocks = <&clks VF610_CLK_ENET1>,
+                                       <&clks VF610_CLK_ENET1>,
                                        <&clks VF610_CLK_ENET>;
                                clock-names = "ipg", "ahb", "ptp";
                                status = "disabled";
index a432e6c1dac18fdf33d1b5d85bfb6c1b7e6cfed0..39ad030ac0c72b529b9cf3166a003b9feaa1f879 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/edma.h>
-#include <linux/err.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
index 7c868139bdb0dd42e9b97d34b794d6cabe83dc64..1571bea48bed12b6702ea9d1e09deb7cffb803cf 100644 (file)
@@ -102,6 +102,8 @@ CONFIG_SND_SOC=m
 CONFIG_SND_DAVINCI_SOC=m
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
+CONFIG_DMADEVICES=y
+CONFIG_TI_EDMA=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 CONFIG_XFS_FS=m
index c86fd75e181ab003df201b1966f22594c2d24013..ab2f7378352c7e1861bac50cf4a21527a7d9564c 100644 (file)
@@ -162,6 +162,8 @@ CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=m
 CONFIG_LEDS_TRIGGER_HEARTBEAT=m
 CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_TI_EDMA=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 CONFIG_XFS_FS=m
index fe0bdc361d2c2fea4ebf5a274415683e07445d1a..6e572c64cf5a1258008232a002301ab7925b0911 100644 (file)
@@ -53,6 +53,7 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_OMAP_OCP2SCP=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI_PLATFORM=y
@@ -61,6 +62,7 @@ CONFIG_SATA_MV=y
 CONFIG_NETDEVICES=y
 CONFIG_SUN4I_EMAC=y
 CONFIG_NET_CALXEDA_XGMAC=y
+CONFIG_KS8851=y
 CONFIG_SMSC911X=y
 CONFIG_STMMAC_ETH=y
 CONFIG_MDIO_SUN4I=y
@@ -89,6 +91,7 @@ CONFIG_I2C_DESIGNWARE_PLATFORM=y
 CONFIG_I2C_SIRF=y
 CONFIG_I2C_TEGRA=y
 CONFIG_SPI=y
+CONFIG_SPI_OMAP24XX=y
 CONFIG_SPI_PL022=y
 CONFIG_SPI_SIRF=y
 CONFIG_SPI_TEGRA114=y
@@ -111,11 +114,12 @@ CONFIG_FB_SIMPLE=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_MXC=y
 CONFIG_USB_EHCI_TEGRA=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
 CONFIG_USB_ISP1760_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_CHIPIDEA=y
+CONFIG_USB_CHIPIDEA_HOST=y
 CONFIG_AB8500_USB=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_OMAP_USB2=y
index 35f8cf299fa2186f0f27ab42470dbd582f55d6f6..263ae3869e32c5f9ecf8bc2f2fd63b8ce8291eda 100644 (file)
@@ -1,6 +1,8 @@
 # CONFIG_LOCALVERSION_AUTO is not set
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
@@ -48,7 +50,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_TESTS=m
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_NAND_ECC_SMC=y
 CONFIG_MTD_NAND=y
@@ -94,8 +95,10 @@ CONFIG_I2C_GPIO=y
 CONFIG_I2C_NOMADIK=y
 CONFIG_DEBUG_GPIO=y
 # CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
 CONFIG_MMC=y
-CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_ARMMMCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
diff --git a/arch/arm/include/asm/a.out-core.h b/arch/arm/include/asm/a.out-core.h
deleted file mode 100644 (file)
index 92f10cb..0000000
+++ /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 */
index 8c25dc4e98514d85db8ce77f4d9e7fa8f828262d..9672e978d50df67d94c3dd86d23f3bcdd187c54d 100644 (file)
@@ -89,13 +89,18 @@ extern unsigned int processor_id;
                __val;                                                  \
        })
 
+/*
+ * The memory clobber prevents gcc 4.5 from reordering the mrc before
+ * any is_smp() tests, which can cause undefined instruction aborts on
+ * ARM1136 r0 due to the missing extended CP15 registers.
+ */
 #define read_cpuid_ext(ext_reg)                                                \
        ({                                                              \
                unsigned int __val;                                     \
                asm("mrc        p15, 0, %0, c0, " ext_reg               \
                    : "=r" (__val)                                      \
                    :                                                   \
-                   : "cc");                                            \
+                   : "memory");                                        \
                __val;                                                  \
        })
 
index 38050b1c4800b90b190a415b7d173e9948e20b97..56211f2084ef871841215a0c4adfec6f778689d3 100644 (file)
@@ -130,4 +130,10 @@ struct mm_struct;
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
+#ifdef CONFIG_MMU
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+int arch_setup_additional_pages(struct linux_binprm *, int);
+#endif
+
 #endif
index e3d55547e75592a9eb98fa1704ee8df9e872c2c5..6f18da09668b5f324ad8c32e6fd6058e5b837e2a 100644 (file)
@@ -6,8 +6,11 @@
 typedef struct {
 #ifdef CONFIG_CPU_HAS_ASID
        atomic64_t      id;
+#else
+       int             switch_pending;
 #endif
        unsigned int    vmalloc_seq;
+       unsigned long   sigpage;
 } mm_context_t;
 
 #ifdef CONFIG_CPU_HAS_ASID
index b5792b7fd8d3149c94c87f5650410b3ece3a2bd2..9b32f76bb0ddaa6d6e485d79cc9f2bdfeb24d776 100644 (file)
@@ -56,7 +56,7 @@ static inline void check_and_switch_context(struct mm_struct *mm,
                 * on non-ASID CPUs, the old mm will remain valid until the
                 * finish_arch_post_lock_switch() call.
                 */
-               set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM);
+               mm->context.switch_pending = 1;
        else
                cpu_switch_mm(mm->pgd, mm);
 }
@@ -65,9 +65,21 @@ static inline void check_and_switch_context(struct mm_struct *mm,
        finish_arch_post_lock_switch
 static inline void finish_arch_post_lock_switch(void)
 {
-       if (test_and_clear_thread_flag(TIF_SWITCH_MM)) {
-               struct mm_struct *mm = current->mm;
-               cpu_switch_mm(mm->pgd, mm);
+       struct mm_struct *mm = current->mm;
+
+       if (mm && mm->context.switch_pending) {
+               /*
+                * Preemption must be disabled during cpu_switch_mm() as we
+                * have some stateful cache flush implementations. Check
+                * switch_pending again in case we were preempted and the
+                * switch to this mm was already done.
+                */
+               preempt_disable();
+               if (mm->context.switch_pending) {
+                       mm->context.switch_pending = 0;
+                       cpu_switch_mm(mm->pgd, mm);
+               }
+               preempt_enable_no_resched();
        }
 }
 
index 6363f3d1d505292c57a26fbd3585b3f147738771..4355f0ec44d62e9b5d7c40132f28f0ff6710f387 100644 (file)
@@ -142,7 +142,9 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
 #define clear_page(page)       memset((void *)(page), 0, PAGE_SIZE)
 extern void copy_page(void *to, const void *from);
 
+#ifdef CONFIG_KUSER_HELPERS
 #define __HAVE_ARCH_GATE_AREA 1
+#endif
 
 #ifdef CONFIG_ARM_LPAE
 #include <asm/pgtable-3level-types.h>
index 06e7d509eaac218864cc9d089ce9e6f4177c22f9..413f3876341cd6fd2e7bc4b1c6a71873cadaa887 100644 (file)
@@ -54,7 +54,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;                              \
@@ -65,9 +64,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);                                       \
 })
 
index 214d4158089afce9c04102604fe07c5257c454e5..2b8114fcba09a3c5b9d6aceefbc6e456a8c9050a 100644 (file)
@@ -156,7 +156,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
 #define TIF_USING_IWMMXT       17
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK    20
-#define TIF_SWITCH_MM          22      /* deferred switch_mm */
 
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
index fdbb9e369745c4b09d776a4568caa52702b7e9a7..f467e9b3f8d5d5b35c1d6fce386c718eb1b21e8f 100644 (file)
@@ -443,7 +443,18 @@ static inline void local_flush_bp_all(void)
                isb();
 }
 
+#include <asm/cputype.h>
 #ifdef CONFIG_ARM_ERRATA_798181
+static inline int erratum_a15_798181(void)
+{
+       unsigned int midr = read_cpuid_id();
+
+       /* Cortex-A15 r0p0..r3p2 affected */
+       if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
+               return 0;
+       return 1;
+}
+
 static inline void dummy_flush_tlb_a15_erratum(void)
 {
        /*
@@ -453,6 +464,11 @@ static inline void dummy_flush_tlb_a15_erratum(void)
        dsb();
 }
 #else
+static inline int erratum_a15_798181(void)
+{
+       return 0;
+}
+
 static inline void dummy_flush_tlb_a15_erratum(void)
 {
 }
index 50af92bac7373eb7fbc01c8f38c4d7dfd6ccb05d..4371f45c578401c7f233e565dbb5fd36d9d59d52 100644 (file)
@@ -29,6 +29,7 @@
 #define BOOT_CPU_MODE_MISMATCH PSR_N_BIT
 
 #ifndef __ASSEMBLY__
+#include <asm/cacheflush.h>
 
 #ifdef CONFIG_ARM_VIRT_EXT
 /*
  */
 extern int __boot_cpu_mode;
 
+static inline void sync_boot_mode(void)
+{
+       /*
+        * As secondaries write to __boot_cpu_mode with caches disabled, we
+        * must flush the corresponding cache entries to ensure the visibility
+        * of their writes.
+        */
+       sync_cache_r(&__boot_cpu_mode);
+}
+
 void __hyp_set_vectors(unsigned long phys_vector_base);
 unsigned long __hyp_get_vectors(void);
 #else
 #define __boot_cpu_mode        (SVC_MODE)
+#define sync_boot_mode()
 #endif
 
 #ifndef ZIMAGE
index 47bcb2d254af8e4fdb3bacee96131d88a0e4f37e..18d76fd5a2afb2bf27b91980f29c77094e6638c0 100644 (file)
@@ -1,7 +1,6 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
-header-y += a.out.h
 header-y += byteorder.h
 header-y += fcntl.h
 header-y += hwcap.h
diff --git a/arch/arm/include/uapi/asm/a.out.h b/arch/arm/include/uapi/asm/a.out.h
deleted file mode 100644 (file)
index 083894b..0000000
+++ /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__ */
index a39cfc2a1f905f7a4e09d9db8810dcd4ce8ac995..d40d0ef389db61ef7f4eadcf810c9569de35cba2 100644 (file)
@@ -742,6 +742,18 @@ ENDPROC(__switch_to)
 #endif
        .endm
 
+       .macro  kuser_pad, sym, size
+       .if     (. - \sym) & 3
+       .rept   4 - (. - \sym) & 3
+       .byte   0
+       .endr
+       .endif
+       .rept   (\size - (. - \sym)) / 4
+       .word   0xe7fddef1
+       .endr
+       .endm
+
+#ifdef CONFIG_KUSER_HELPERS
        .align  5
        .globl  __kuser_helper_start
 __kuser_helper_start:
@@ -832,18 +844,13 @@ kuser_cmpxchg64_fixup:
 #error "incoherent kernel configuration"
 #endif
 
-       /* pad to next slot */
-       .rept   (16 - (. - __kuser_cmpxchg64)/4)
-       .word   0
-       .endr
-
-       .align  5
+       kuser_pad __kuser_cmpxchg64, 64
 
 __kuser_memory_barrier:                                @ 0xffff0fa0
        smp_dmb arm
        usr_ret lr
 
-       .align  5
+       kuser_pad __kuser_memory_barrier, 32
 
 __kuser_cmpxchg:                               @ 0xffff0fc0
 
@@ -916,13 +923,14 @@ kuser_cmpxchg32_fixup:
 
 #endif
 
-       .align  5
+       kuser_pad __kuser_cmpxchg, 32
 
 __kuser_get_tls:                               @ 0xffff0fe0
        ldr     r0, [pc, #(16 - 8)]     @ read TLS, set in kuser_get_tls_init
        usr_ret lr
        mrc     p15, 0, r0, c13, c0, 3  @ 0xffff0fe8 hardware TLS code
-       .rep    4
+       kuser_pad __kuser_get_tls, 16
+       .rep    3
        .word   0                       @ 0xffff0ff0 software TLS value, then
        .endr                           @ pad up to __kuser_helper_version
 
@@ -932,14 +940,16 @@ __kuser_helper_version:                           @ 0xffff0ffc
        .globl  __kuser_helper_end
 __kuser_helper_end:
 
+#endif
+
  THUMB(        .thumb  )
 
 /*
  * Vector stubs.
  *
- * This code is copied to 0xffff0200 so we can use branches in the
- * vectors, rather than ldr's.  Note that this code must not
- * exceed 0x300 bytes.
+ * This code is copied to 0xffff1000 so we can use branches in the
+ * vectors, rather than ldr's.  Note that this code must not exceed
+ * a page size.
  *
  * Common stub entry macro:
  *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
@@ -986,8 +996,17 @@ ENDPROC(vector_\name)
 1:
        .endm
 
-       .globl  __stubs_start
+       .section .stubs, "ax", %progbits
 __stubs_start:
+       @ This must be the first word
+       .word   vector_swi
+
+vector_rst:
+ ARM(  swi     SYS_ERROR0      )
+ THUMB(        svc     #0              )
+ THUMB(        nop                     )
+       b       vector_und
+
 /*
  * Interrupt dispatcher
  */
@@ -1081,6 +1100,16 @@ __stubs_start:
 
        .align  5
 
+/*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen, and won't happen in 32-bit data mode).
+ */
+
+vector_addrexcptn:
+       b       vector_addrexcptn
+
 /*=============================================================================
  * Undefined FIQs
  *-----------------------------------------------------------------------------
@@ -1094,45 +1123,19 @@ __stubs_start:
 vector_fiq:
        subs    pc, lr, #4
 
-/*=============================================================================
- * Address exception handler
- *-----------------------------------------------------------------------------
- * These aren't too critical.
- * (they're not supposed to happen, and won't happen in 32-bit data mode).
- */
-
-vector_addrexcptn:
-       b       vector_addrexcptn
-
-/*
- * We group all the following data together to optimise
- * for CPUs with separate I & D caches.
- */
-       .align  5
-
-.LCvswi:
-       .word   vector_swi
-
-       .globl  __stubs_end
-__stubs_end:
-
-       .equ    stubs_offset, __vectors_start + 0x200 - __stubs_start
+       .globl  vector_fiq_offset
+       .equ    vector_fiq_offset, vector_fiq
 
-       .globl  __vectors_start
+       .section .vectors, "ax", %progbits
 __vectors_start:
- ARM(  swi     SYS_ERROR0      )
- THUMB(        svc     #0              )
- THUMB(        nop                     )
-       W(b)    vector_und + stubs_offset
-       W(ldr)  pc, .LCvswi + stubs_offset
-       W(b)    vector_pabt + stubs_offset
-       W(b)    vector_dabt + stubs_offset
-       W(b)    vector_addrexcptn + stubs_offset
-       W(b)    vector_irq + stubs_offset
-       W(b)    vector_fiq + stubs_offset
-
-       .globl  __vectors_end
-__vectors_end:
+       W(b)    vector_rst
+       W(b)    vector_und
+       W(ldr)  pc, __vectors_start + 0x1000
+       W(b)    vector_pabt
+       W(b)    vector_dabt
+       W(b)    vector_addrexcptn
+       W(b)    vector_irq
+       W(b)    vector_fiq
 
        .data
 
index e00621f1403f7c44765103591cbefd6e3315702f..52b26432c9a9941e8281a4483dd7aed148a99995 100644 (file)
@@ -49,7 +49,7 @@ __irq_entry:
        mov     r1, sp
        stmdb   sp!, {lr}
        @ routine called with r0 = irq number, r1 = struct pt_regs *
-       bl      nvic_do_IRQ
+       bl      nvic_handle_irq
 
        pop     {lr}
        @
index 2adda11f712fe02fa2fdaa63e944e17199bd3748..25442f451148ee107ad8db89de891c8ff42b3bc0 100644 (file)
 #include <asm/irq.h>
 #include <asm/traps.h>
 
+#define FIQ_OFFSET ({                                  \
+               extern void *vector_fiq_offset;         \
+               (unsigned)&vector_fiq_offset;           \
+       })
+
 static unsigned long no_fiq_insn;
 
 /* Default reacquire function
@@ -80,13 +85,16 @@ int show_fiq_list(struct seq_file *p, int prec)
 void set_fiq_handler(void *start, unsigned int length)
 {
 #if defined(CONFIG_CPU_USE_DOMAINS)
-       memcpy((void *)0xffff001c, start, length);
+       void *base = (void *)0xffff0000;
 #else
-       memcpy(vectors_page + 0x1c, start, length);
+       void *base = vectors_page;
 #endif
-       flush_icache_range(0xffff001c, 0xffff001c + length);
+       unsigned offset = FIQ_OFFSET;
+
+       memcpy(base + offset, start, length);
+       flush_icache_range(0xffff0000 + offset, 0xffff0000 + offset + length);
        if (!vectors_high())
-               flush_icache_range(0x1c, 0x1c + length);
+               flush_icache_range(offset, offset + length);
 }
 
 int claim_fiq(struct fiq_handler *f)
@@ -144,6 +152,7 @@ EXPORT_SYMBOL(disable_fiq);
 
 void __init init_FIQ(int start)
 {
-       no_fiq_insn = *(unsigned long *)0xffff001c;
+       unsigned offset = FIQ_OFFSET;
+       no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
        fiq_start = start;
 }
index b361de143756d4a3412f4512d794eebc173e25e8..14235ba64a90736ecebad575f5d88ea4568e8eaf 100644 (file)
@@ -87,6 +87,7 @@ ENTRY(stext)
 ENDPROC(stext)
 
 #ifdef CONFIG_SMP
+       .text
 ENTRY(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
index 9cf6063020ae99ce68afb617bf88905ec5f6212f..2c7cc1e03473aee9463e86d7dbedfc999f6e51f7 100644 (file)
@@ -343,6 +343,7 @@ __turn_mmu_on_loc:
        .long   __turn_mmu_on_end
 
 #if defined(CONFIG_SMP)
+       .text
 ENTRY(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
index 4910232c48330d4dc857d6bf32754bfd781008b5..797b1a6a4906da0f8ca3f942186ac0e033250ce6 100644 (file)
@@ -56,8 +56,8 @@ ENTRY(__boot_cpu_mode)
        ldr     \reg3, [\reg2]
        ldr     \reg1, [\reg2, \reg3]
        cmp     \mode, \reg1            @ matches primary CPU boot mode?
-       orrne   r7, r7, #BOOT_CPU_MODE_MISMATCH
-       strne   r7, [r5, r6]            @ record what happened and give up
+       orrne   \reg1, \reg1, #BOOT_CPU_MODE_MISMATCH
+       strne   \reg1, [\reg2, \reg3]   @ record what happened and give up
        .endm
 
 #else  /* ZIMAGE */
index d3ca4f6915af746d5f13c4427cb42bacbd61b694..536c85fe72a838aafe3371e0280175b8cda2b452 100644 (file)
@@ -197,6 +197,7 @@ void machine_shutdown(void)
  */
 void machine_halt(void)
 {
+       local_irq_disable();
        smp_send_stop();
 
        local_irq_disable();
@@ -211,6 +212,7 @@ void machine_halt(void)
  */
 void machine_power_off(void)
 {
+       local_irq_disable();
        smp_send_stop();
 
        if (pm_power_off)
@@ -230,6 +232,7 @@ void machine_power_off(void)
  */
 void machine_restart(char *cmd)
 {
+       local_irq_disable();
        smp_send_stop();
 
        arm_pm_restart(reboot_mode, cmd);
@@ -426,10 +429,11 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
 }
 
 #ifdef CONFIG_MMU
+#ifdef CONFIG_KUSER_HELPERS
 /*
  * The vectors page is always readable from user space for the
- * atomic helpers and the signal restart code. Insert it into the
- * gate_vma so that it is visible through ptrace and /proc/<pid>/mem.
+ * atomic helpers. Insert it into the gate_vma so that it is visible
+ * through ptrace and /proc/<pid>/mem.
  */
 static struct vm_area_struct gate_vma = {
        .vm_start       = 0xffff0000,
@@ -458,9 +462,48 @@ int in_gate_area_no_mm(unsigned long addr)
 {
        return in_gate_area(NULL, addr);
 }
+#define is_gate_vma(vma)       ((vma) = &gate_vma)
+#else
+#define is_gate_vma(vma)       0
+#endif
 
 const char *arch_vma_name(struct vm_area_struct *vma)
 {
-       return (vma == &gate_vma) ? "[vectors]" : NULL;
+       return is_gate_vma(vma) ? "[vectors]" :
+               (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage) ?
+                "[sigpage]" : NULL;
+}
+
+static struct page *signal_page;
+extern struct page *get_signal_page(void);
+
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr;
+       int ret;
+
+       if (!signal_page)
+               signal_page = get_signal_page();
+       if (!signal_page)
+               return -ENOMEM;
+
+       down_write(&mm->mmap_sem);
+       addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+       if (IS_ERR_VALUE(addr)) {
+               ret = addr;
+               goto up_fail;
+       }
+
+       ret = install_special_mapping(mm, addr, PAGE_SIZE,
+               VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+               &signal_page);
+
+       if (ret == 0)
+               mm->context.sigpage = addr;
+
+ up_fail:
+       up_write(&mm->mmap_sem);
+       return ret;
 }
 #endif
index 63af9a7ae5124f82484feb8b33a88114b915753d..afc2489ee13bc098523f92549baa4a69728c1ced 100644 (file)
@@ -836,6 +836,8 @@ static int __init meminfo_cmp(const void *_a, const void *_b)
 void __init hyp_mode_check(void)
 {
 #ifdef CONFIG_ARM_VIRT_EXT
+       sync_boot_mode();
+
        if (is_hyp_mode_available()) {
                pr_info("CPU: All CPU(s) started in HYP mode.\n");
                pr_info("CPU: Virtualization extensions available.\n");
@@ -971,6 +973,7 @@ static const char *hwcap_str[] = {
        "vfpv4",
        "idiva",
        "idivt",
+       "vfpd32",
        "lpae",
        NULL
 };
index 1c16c35c271af5a3cb4de53736344a9ed286d7d9..ab330422527203417472a21727b1062c8a38e70f 100644 (file)
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/errno.h>
+#include <linux/random.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
 #include <linux/uaccess.h>
 
 #include <asm/elf.h>
 #include <asm/cacheflush.h>
+#include <asm/traps.h>
 #include <asm/ucontext.h>
 #include <asm/unistd.h>
 #include <asm/vfp.h>
 
-#include "signal.h"
-
 /*
  * For ARM syscalls, we encode the syscall number into the instruction.
  */
 #define SWI_THUMB_SIGRETURN    (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
 #define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
 
-const unsigned long sigreturn_codes[7] = {
+static const unsigned long sigreturn_codes[7] = {
        MOV_R7_NR_SIGRETURN,    SWI_SYS_SIGRETURN,    SWI_THUMB_SIGRETURN,
        MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
 };
 
+static unsigned long signal_return_offset;
+
 #ifdef CONFIG_CRUNCH
 static int preserve_crunch_context(struct crunch_sigframe __user *frame)
 {
@@ -400,14 +402,20 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
                    __put_user(sigreturn_codes[idx+1], rc+1))
                        return 1;
 
-               if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) {
+#ifdef CONFIG_MMU
+               if (cpsr & MODE32_BIT) {
+                       struct mm_struct *mm = current->mm;
+
                        /*
-                        * 32-bit code can use the new high-page
-                        * signal return code support except when the MPU has
-                        * protected the vectors page from PL0
+                        * 32-bit code can use the signal return page
+                        * except when the MPU has protected the vectors
+                        * page from PL0
                         */
-                       retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
-               } else {
+                       retcode = mm->context.sigpage + signal_return_offset +
+                                 (idx << 2) + thumb;
+               } else
+#endif
+               {
                        /*
                         * Ensure that the instruction cache sees
                         * the return code written onto the stack.
@@ -608,3 +616,33 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
        } while (thread_flags & _TIF_WORK_MASK);
        return 0;
 }
+
+struct page *get_signal_page(void)
+{
+       unsigned long ptr;
+       unsigned offset;
+       struct page *page;
+       void *addr;
+
+       page = alloc_pages(GFP_KERNEL, 0);
+
+       if (!page)
+               return NULL;
+
+       addr = page_address(page);
+
+       /* Give the signal return code some randomness */
+       offset = 0x200 + (get_random_int() & 0x7fc);
+       signal_return_offset = offset;
+
+       /*
+        * Copy signal return handlers into the vector page, and
+        * set sigreturn to be a pointer to these.
+        */
+       memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
+
+       ptr = (unsigned long)addr + offset;
+       flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
+
+       return page;
+}
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
deleted file mode 100644 (file)
index 5ff067b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- *  linux/arch/arm/kernel/signal.h
- *
- *  Copyright (C) 2005-2009 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#define KERN_SIGRETURN_CODE    (CONFIG_VECTORS_BASE + 0x00000500)
-
-extern const unsigned long sigreturn_codes[7];
index a98b62dca2faf9bbce7fbcb786d4c325513f7231..c2edfff573c2c9e2e68193cf729a98f460ac1a2d 100644 (file)
@@ -70,23 +70,6 @@ static inline void ipi_flush_bp_all(void *ignored)
        local_flush_bp_all();
 }
 
-#ifdef CONFIG_ARM_ERRATA_798181
-static int erratum_a15_798181(void)
-{
-       unsigned int midr = read_cpuid_id();
-
-       /* Cortex-A15 r0p0..r3p2 affected */
-       if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
-               return 0;
-       return 1;
-}
-#else
-static int erratum_a15_798181(void)
-{
-       return 0;
-}
-#endif
-
 static void ipi_flush_tlb_a15_erratum(void *arg)
 {
        dmb();
index cab094c234ee85d646b9534d2044010c10c727ee..ab517fcce21b8308dc957bc5b6809039c2e5f1fe 100644 (file)
@@ -35,8 +35,6 @@
 #include <asm/tls.h>
 #include <asm/system_misc.h>
 
-#include "signal.h"
-
 static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
 
 void *vectors_page;
@@ -800,15 +798,26 @@ void __init trap_init(void)
        return;
 }
 
-static void __init kuser_get_tls_init(unsigned long vectors)
+#ifdef CONFIG_KUSER_HELPERS
+static void __init kuser_init(void *vectors)
 {
+       extern char __kuser_helper_start[], __kuser_helper_end[];
+       int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+
+       memcpy(vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+
        /*
         * vectors + 0xfe0 = __kuser_get_tls
         * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
         */
        if (tls_emu || has_tls_reg)
-               memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4);
+               memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);
 }
+#else
+static void __init kuser_init(void *vectors)
+{
+}
+#endif
 
 void __init early_trap_init(void *vectors_base)
 {
@@ -816,33 +825,30 @@ void __init early_trap_init(void *vectors_base)
        unsigned long vectors = (unsigned long)vectors_base;
        extern char __stubs_start[], __stubs_end[];
        extern char __vectors_start[], __vectors_end[];
-       extern char __kuser_helper_start[], __kuser_helper_end[];
-       int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+       unsigned i;
 
        vectors_page = vectors_base;
 
+       /*
+        * Poison the vectors page with an undefined instruction.  This
+        * instruction is chosen to be undefined for both ARM and Thumb
+        * ISAs.  The Thumb version is an undefined instruction with a
+        * branch back to the undefined instruction.
+        */
+       for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
+               ((u32 *)vectors_base)[i] = 0xe7fddef1;
+
        /*
         * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
         * into the vector page, mapped at 0xffff0000, and ensure these
         * are visible to the instruction stream.
         */
        memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
-       memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
-       memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+       memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
 
-       /*
-        * Do processor specific fixups for the kuser helpers
-        */
-       kuser_get_tls_init(vectors);
-
-       /*
-        * Copy signal return handlers into the vector page, and
-        * set sigreturn to be a pointer to these.
-        */
-       memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
-              sigreturn_codes, sizeof(sigreturn_codes));
+       kuser_init(vectors_base);
 
-       flush_icache_range(vectors, vectors + PAGE_SIZE);
+       flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
        modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 #else /* ifndef CONFIG_CPU_V7M */
        /*
index fa25e4e425f6070c0a6055de98271f865dde3823..7bcee5c9b6049c2723df9e3e9fc9b0b088b5fe0b 100644 (file)
@@ -148,6 +148,23 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);
        __init_begin = .;
 #endif
+       /*
+        * The vectors and stubs are relocatable code, and the
+        * only thing that matters is their relative offsets
+        */
+       __vectors_start = .;
+       .vectors 0 : AT(__vectors_start) {
+               *(.vectors)
+       }
+       . = __vectors_start + SIZEOF(.vectors);
+       __vectors_end = .;
+
+       __stubs_start = .;
+       .stubs 0x1000 : AT(__stubs_start) {
+               *(.stubs)
+       }
+       . = __stubs_start + SIZEOF(.stubs);
+       __stubs_end = .;
 
        INIT_TEXT_SECTION(8)
        .exit.text : {
index afbc439f11d4fba53bd3882535eda6b41540fe2f..4cdb61c5445943d7aa2e9a50b23c151b0ecf6a9c 100644 (file)
@@ -505,7 +505,7 @@ static struct vpbe_output dm365evm_vpbe_outputs[] = {
 /*
  * Amplifiers on the board
  */
-struct ths7303_platform_data ths7303_pdata = {
+static struct ths7303_platform_data ths7303_pdata = {
        .ch_1 = 3,
        .ch_2 = 3,
        .ch_3 = 3,
index 42ef53f62c6ce44344a42ac49b71f2b8e34f6ecf..86100d17969473112cbea30c4b3d3a1113420eee 100644 (file)
@@ -860,7 +860,7 @@ static struct platform_device dm355_vpbe_display = {
        },
 };
 
-struct venc_platform_data dm355_venc_pdata = {
+static struct venc_platform_data dm355_venc_pdata = {
        .setup_pinmux   = dm355_vpbe_setup_pinmux,
        .setup_clock    = dm355_venc_setup_clock,
 };
index fa7af5eda52d1bcf17a6120e3a603251e2b6de7f..dad28029ba9bee623ccbc0c29efb0a773453b388 100644 (file)
@@ -1349,7 +1349,7 @@ static struct platform_device dm365_vpbe_display = {
        },
 };
 
-struct venc_platform_data dm365_venc_pdata = {
+static struct venc_platform_data dm365_venc_pdata = {
        .setup_pinmux   = dm365_vpbe_setup_pinmux,
        .setup_clock    = dm365_venc_setup_clock,
 };
index 855d4a7b462d12fd0fc67b4abd3a55b0b0522530..5952e68c76c40e622e828a9e1849542b69f12aad 100644 (file)
@@ -92,6 +92,7 @@ config SOC_EXYNOS5440
        bool "SAMSUNG EXYNOS5440"
        default y
        depends on ARCH_EXYNOS5
+       select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
        select ARCH_HAS_OPP
        select HAVE_ARM_ARCH_TIMER
        select AUTO_ZRELADDR
index e970a7a4e278c137f6dffc358811f55cfea1c45d..53696154aead3da032d710720cd45ca72e634827 100644 (file)
@@ -14,7 +14,7 @@ obj-                          :=
 
 obj-$(CONFIG_ARCH_EXYNOS)      += common.o
 
-obj-$(CONFIG_PM)               += pm.o
+obj-$(CONFIG_S5P_PM)           += pm.o
 obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
 obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
 
index 164685bd25c82ec0f01f1eaeb39f36a125fd4738..ba95e5db25011a0801c2ef1f7c27270b713280ee 100644 (file)
@@ -58,7 +58,6 @@ static const char name_exynos5440[] = "EXYNOS5440";
 
 static void exynos4_map_io(void);
 static void exynos5_map_io(void);
-static void exynos5440_map_io(void);
 static int exynos_init(void);
 
 static struct cpu_table cpu_ids[] __initdata = {
@@ -95,7 +94,6 @@ static struct cpu_table cpu_ids[] __initdata = {
        }, {
                .idcode         = EXYNOS5440_SOC_ID,
                .idmask         = EXYNOS5_SOC_MASK,
-               .map_io         = exynos5440_map_io,
                .init           = exynos_init,
                .name           = name_exynos5440,
        },
@@ -149,11 +147,6 @@ static struct map_desc exynos4_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(EXYNOS4_PA_GIC_DIST),
                .length         = SZ_64K,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S3C_VA_UART,
-               .pfn            = __phys_to_pfn(EXYNOS4_PA_UART),
-               .length         = SZ_512K,
-               .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)S5P_VA_CMU,
                .pfn            = __phys_to_pfn(EXYNOS4_PA_CMU),
@@ -268,20 +261,6 @@ static struct map_desc exynos5_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(EXYNOS5_PA_PMU),
                .length         = SZ_64K,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S3C_VA_UART,
-               .pfn            = __phys_to_pfn(EXYNOS5_PA_UART),
-               .length         = SZ_512K,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc exynos5440_iodesc0[] __initdata = {
-       {
-               .virtual        = (unsigned long)S3C_VA_UART,
-               .pfn            = __phys_to_pfn(EXYNOS5440_PA_UART0),
-               .length         = SZ_512K,
-               .type           = MT_DEVICE,
        },
 };
 
@@ -388,11 +367,6 @@ static void __init exynos5_map_io(void)
                iotable_init(exynos5250_iodesc, ARRAY_SIZE(exynos5250_iodesc));
 }
 
-static void __init exynos5440_map_io(void)
-{
-       iotable_init(exynos5440_iodesc0, ARRAY_SIZE(exynos5440_iodesc0));
-}
-
 void __init exynos_init_time(void)
 {
        of_clk_init(NULL);
index 3e156bcddcb4cc65586ab652c7de52b60d47208f..972490fc09d627241a1d3c63e7d234693b4f03d8 100644 (file)
@@ -97,6 +97,5 @@ struct exynos_pmu_conf {
 };
 
 extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
-extern void s3c_cpu_resume(void);
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
index 17a18ff3d71e289df9909cb3976d6e414c768dff..225ee8431c7282d1301d17c255687189482e7042 100644 (file)
@@ -25,6 +25,7 @@
 #include <mach/regs-pmu.h>
 
 #include <plat/cpu.h>
+#include <plat/pm.h>
 
 #include "common.h"
 
index 374ef2cf7152c366fe56388909f751dac4d658c0..2a4cdb7cb326a400060fd9c959042145dedb17c2 100644 (file)
 
 #define PLAT_PHYS_OFFSET               UL(0x40000000)
 
+#ifndef CONFIG_ARM_LPAE
 /* Maximum of 256MiB in one bank */
 #define MAX_PHYSMEM_BITS       32
 #define SECTION_SIZE_BITS      28
+#else
+#define MAX_PHYSMEM_BITS       36
+#define SECTION_SIZE_BITS      31
+#endif
 
 #endif /* __ASM_ARCH_MEMORY_H */
index 41c20692a13f0f189c1acaf011831048b6944a0a..c679db57726934de2f0338fadbbda0be05e49e74 100644 (file)
@@ -217,6 +217,9 @@ static __init int exynos_pm_drvinit(void)
        struct clk *pll_base;
        unsigned int tmp;
 
+       if (soc_is_exynos5440())
+               return 0;
+
        s3c_pm_init();
 
        /* All wakeup disable */
@@ -340,6 +343,9 @@ static struct syscore_ops exynos_pm_syscore_ops = {
 
 static __init int exynos_pm_syscore_init(void)
 {
+       if (soc_is_exynos5440())
+               return 0;
+
        register_syscore_ops(&exynos_pm_syscore_ops);
        return 0;
 }
index a7cd2cf5e08de32c2ceafc508559d3201919dcc4..3490a24f969e4a0b450ef146cee72f37e1cb6c9f 100644 (file)
@@ -276,8 +276,6 @@ int __init dc21285_setup(int nr, struct pci_sys_data *sys)
 
        sys->mem_offset  = DC21285_PCI_MEM;
 
-       pci_ioremap_io(0, DC21285_PCI_IO);
-
        pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
        pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
index dc5d6becd8c7c13f54406eaebead83bf11ffd9d2..88815795fe2678f7c41e54fd296397ace8de9a62 100644 (file)
@@ -115,6 +115,7 @@ static int highbank_platform_notifier(struct notifier_block *nb,
 {
        struct resource *res;
        int reg = -1;
+       u32 val;
        struct device *dev = __dev;
 
        if (event != BUS_NOTIFY_ADD_DEVICE)
@@ -141,10 +142,10 @@ static int highbank_platform_notifier(struct notifier_block *nb,
                return NOTIFY_DONE;
 
        if (of_property_read_bool(dev->of_node, "dma-coherent")) {
-               writel(0xff31, sregs_base + reg);
+               val = readl(sregs_base + reg);
+               writel(val | 0xff01, sregs_base + reg);
                set_dma_ops(dev, &arm_coherent_dma_ops);
-       } else
-               writel(0, sregs_base + reg);
+       }
 
        return NOTIFY_OK;
 }
index 4282e99f5ca1803254a44449aee835c653429c6b..86567d980b0743df9eadf44bfac489bc01634b9d 100644 (file)
@@ -199,7 +199,8 @@ static const char *pcie_axi_sels[]  = { "axi", "ahb", };
 static const char *ssi_sels[]          = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_post_div", };
 static const char *usdhc_sels[]        = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
 static const char *enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", };
-static const char *emi_sels[]          = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *emi_sels[]          = { "pll2_pfd2_396m", "pll3_usb_otg", "axi", "pll2_pfd0_352m", };
+static const char *emi_slow_sels[]      = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", };
 static const char *vdo_axi_sels[]      = { "axi", "ahb", };
 static const char *vpu_axi_sels[]      = { "axi", "pll2_pfd2_396m", "pll2_pfd0_352m", };
 static const char *cko1_sels[] = { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div",
@@ -392,7 +393,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        clk[usdhc4_sel]       = imx_clk_mux("usdhc4_sel",       base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
        clk[enfc_sel]         = imx_clk_mux("enfc_sel",         base + 0x2c, 16, 2, enfc_sels,         ARRAY_SIZE(enfc_sels));
        clk[emi_sel]          = imx_clk_mux("emi_sel",          base + 0x1c, 27, 2, emi_sels,          ARRAY_SIZE(emi_sels));
-       clk[emi_slow_sel]     = imx_clk_mux("emi_slow_sel",     base + 0x1c, 29, 2, emi_sels,          ARRAY_SIZE(emi_sels));
+       clk[emi_slow_sel]     = imx_clk_mux("emi_slow_sel",     base + 0x1c, 29, 2, emi_slow_sels,     ARRAY_SIZE(emi_slow_sels));
        clk[vdo_axi_sel]      = imx_clk_mux("vdo_axi_sel",      base + 0x18, 11, 1, vdo_axi_sels,      ARRAY_SIZE(vdo_axi_sels));
        clk[vpu_axi_sel]      = imx_clk_mux("vpu_axi_sel",      base + 0x18, 14, 2, vpu_axi_sels,      ARRAY_SIZE(vpu_axi_sels));
        clk[cko1_sel]         = imx_clk_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
index d617c0b7c8095f23c3273c86aadd5421ad0d29d0..b169a396d93bfcf193c83d7329a6fdc290101425 100644 (file)
@@ -183,6 +183,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
        clk[VF610_CLK_ENET_TS_SEL] = imx_clk_mux("enet_ts_sel", CCM_CSCMR2, 0, 3, enet_ts_sels, 7);
        clk[VF610_CLK_ENET] = imx_clk_gate("enet", "enet_sel", CCM_CSCDR1, 24);
        clk[VF610_CLK_ENET_TS] = imx_clk_gate("enet_ts", "enet_ts_sel", CCM_CSCDR1, 23);
+       clk[VF610_CLK_ENET0] = imx_clk_gate2("enet0", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(0));
+       clk[VF610_CLK_ENET1] = imx_clk_gate2("enet1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(1));
 
        clk[VF610_CLK_PIT] = imx_clk_gate2("pit", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(7));
 
index e074616d54ca5e034e0b6331b8235c7a72971a37..8a65f192e7f31fb82b998b9e094ae9e1f69441a7 100644 (file)
 #define MX27_INT_GPT4          (NR_IRQS_LEGACY + 4)
 #define MX27_INT_RTIC          (NR_IRQS_LEGACY + 5)
 #define MX27_INT_CSPI3         (NR_IRQS_LEGACY + 6)
-#define MX27_INT_SDHC          (NR_IRQS_LEGACY + 7)
+#define MX27_INT_MSHC          (NR_IRQS_LEGACY + 7)
 #define MX27_INT_GPIO          (NR_IRQS_LEGACY + 8)
 #define MX27_INT_SDHC3         (NR_IRQS_LEGACY + 9)
 #define MX27_INT_SDHC2         (NR_IRQS_LEGACY + 10)
index fe4d9ff93a7ef8560cd6948aaa99720242df5865..b661c5c2870a88d09a76b51d7166650a693250ac 100644 (file)
@@ -49,7 +49,7 @@ static const char *keystone_match[] __initconst = {
        NULL,
 };
 
-void keystone_restart(char mode, const char *cmd)
+void keystone_restart(enum reboot_mode mode, const char *cmd)
 {
        u32 val;
 
index 614e41e7881b538b77bc4c5ab0b5430de7175bea..905efc8cac797d5d30ae0db0ff0e28eba7fa140d 100644 (file)
@@ -121,8 +121,7 @@ config MSM_SMD
        bool
 
 config MSM_GPIOMUX
-       depends on !(ARCH_MSM8X60 || ARCH_MSM8960)
-       bool "MSM V1 TLMM GPIOMUX architecture"
+       bool
        help
          Support for MSM V1 TLMM GPIOMUX architecture.
 
diff --git a/arch/arm/mach-msm/gpiomux-v1.c b/arch/arm/mach-msm/gpiomux-v1.c
deleted file mode 100644 (file)
index 27de2ab..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-#include <linux/kernel.h>
-#include "gpiomux.h"
-#include "proc_comm.h"
-
-void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val)
-{
-       unsigned tlmm_config  = (val & ~GPIOMUX_CTL_MASK) |
-                               ((gpio & 0x3ff) << 4);
-       unsigned tlmm_disable = 0;
-       int rc;
-
-       rc = msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
-                          &tlmm_config, &tlmm_disable);
-       if (rc)
-               pr_err("%s: unexpected proc_comm failure %d: %08x %08x\n",
-                      __func__, rc, tlmm_config, tlmm_disable);
-}
index 8e82f41a89235e4fbef3f7f2b7e0b7c26c84dbfc..4410d7766f93be5995c620c1c36cf2be8ce23877 100644 (file)
@@ -73,16 +73,6 @@ extern struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS];
 int msm_gpiomux_write(unsigned gpio,
                      gpiomux_config_t active,
                      gpiomux_config_t suspended);
-
-/* Architecture-internal function for use by the framework only.
- * This function can assume the following:
- * - the gpio value has passed a bounds-check
- * - the gpiomux spinlock has been obtained
- *
- * This function is not for public consumption.  External users
- * should use msm_gpiomux_write.
- */
-void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val);
 #else
 static inline int msm_gpiomux_write(unsigned gpio,
                                    gpiomux_config_t active,
index 627fa7e41fbabbeccf38c1703dc26ed2a98d66db..3eed0006d189c0c0e88412485dba67e1800b2d6e 100644 (file)
@@ -62,7 +62,7 @@ config SOC_OMAP5
        select HAVE_SMP
        select COMMON_CLK
        select HAVE_ARM_ARCH_TIMER
-       select ARM_ERRATA_798181
+       select ARM_ERRATA_798181 if SMP
 
 config SOC_AM33XX
        bool "AM33XX support"
index e5fbfed69aa2bc5094b508a3219c8988d0d3dbe7..be5d005ebad2866ea7432586beba45e000330be9 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/irqdomain.h>
+#include <linux/clk.h>
 
 #include <asm/mach/arch.h>
 
@@ -35,6 +36,21 @@ static struct of_device_id omap_dt_match_table[] __initdata = {
        { }
 };
 
+/*
+ * Create alias for USB host PHY clock.
+ * Remove this when clock phandle can be provided via DT
+ */
+static void __init legacy_init_ehci_clk(char *clkname)
+{
+       int ret;
+
+       ret = clk_add_alias("main_clk", NULL, clkname, NULL);
+       if (ret) {
+               pr_err("%s:Failed to add main_clk alias to %s :%d\n",
+                                               __func__, clkname, ret);
+       }
+}
+
 static void __init omap_generic_init(void)
 {
        omap_sdrc_init(NULL, NULL);
@@ -45,10 +61,15 @@ static void __init omap_generic_init(void)
         * HACK: call display setup code for selected boards to enable omapdss.
         * This will be removed when omapdss supports DT.
         */
-       if (of_machine_is_compatible("ti,omap4-panda"))
+       if (of_machine_is_compatible("ti,omap4-panda")) {
                omap4_panda_display_init_of();
+               legacy_init_ehci_clk("auxclk3_ck");
+
+       }
        else if (of_machine_is_compatible("ti,omap4-sdp"))
                omap_4430sdp_display_init_of();
+       else if (of_machine_is_compatible("ti,omap5-uevm"))
+               legacy_init_ehci_clk("auxclk1_ck");
 }
 
 #ifdef CONFIG_SOC_OMAP2420
index 5cc92874be7e6f22d81767c0f75e141376ab83d6..f99f68e1e85bd3748c5965a0bd27c47d0f6d538e 100644 (file)
@@ -129,6 +129,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
        struct device_node *node = pdev->dev.of_node;
        const char *oh_name;
        int oh_cnt, i, ret = 0;
+       bool device_active = false;
 
        oh_cnt = of_property_count_strings(node, "ti,hwmods");
        if (oh_cnt <= 0) {
@@ -152,6 +153,8 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
                        goto odbfd_exit1;
                }
                hwmods[i] = oh;
+               if (oh->flags & HWMOD_INIT_NO_IDLE)
+                       device_active = true;
        }
 
        od = omap_device_alloc(pdev, hwmods, oh_cnt);
@@ -172,6 +175,11 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
 
        pdev->dev.pm_domain = &omap_device_pm_domain;
 
+       if (device_active) {
+               omap_device_enable(pdev);
+               pm_runtime_set_active(&pdev->dev);
+       }
+
 odbfd_exit1:
        kfree(hwmods);
 odbfd_exit:
@@ -842,6 +850,7 @@ static int __init omap_device_late_idle(struct device *dev, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_device *od = to_omap_device(pdev);
+       int i;
 
        if (!od)
                return 0;
@@ -850,6 +859,15 @@ static int __init omap_device_late_idle(struct device *dev, void *data)
         * If omap_device state is enabled, but has no driver bound,
         * idle it.
         */
+
+       /*
+        * Some devices (like memory controllers) are always kept
+        * enabled, and should not be idled even with no drivers.
+        */
+       for (i = 0; i < od->hwmods_cnt; i++)
+               if (od->hwmods[i]->flags & HWMOD_INIT_NO_IDLE)
+                       return 0;
+
        if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
                if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
                        dev_warn(dev, "%s: enabled but no driver.  Idling\n",
index 7341eff63f56df8f58d5b72d8db9a71feb86112d..7f4db12b1459881ddc2fcbf66d404bab28d89792 100644 (file)
@@ -2386,7 +2386,7 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data)
 
                np = of_dev_hwmod_lookup(of_find_node_by_name(NULL, "ocp"), oh);
                if (np)
-                       va_start = of_iomap(np, 0);
+                       va_start = of_iomap(np, oh->mpu_rt_idx);
        } else {
                va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
        }
index aab33fd814c0329e178cbfe265fdf9ff5ffb766c..e1482a9b3bc22f7cd7de82ac9f66474e1efbccc8 100644 (file)
@@ -95,6 +95,54 @@ extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type3;
 #define MODULEMODE_HWCTRL              1
 #define MODULEMODE_SWCTRL              2
 
+#define DEBUG_OMAP2UART1_FLAGS 0
+#define DEBUG_OMAP2UART2_FLAGS 0
+#define DEBUG_OMAP2UART3_FLAGS 0
+#define DEBUG_OMAP3UART3_FLAGS 0
+#define DEBUG_OMAP3UART4_FLAGS 0
+#define DEBUG_OMAP4UART3_FLAGS 0
+#define DEBUG_OMAP4UART4_FLAGS 0
+#define DEBUG_TI81XXUART1_FLAGS        0
+#define DEBUG_TI81XXUART2_FLAGS        0
+#define DEBUG_TI81XXUART3_FLAGS        0
+#define DEBUG_AM33XXUART1_FLAGS        0
+
+#define DEBUG_OMAPUART_FLAGS   (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET)
+
+#if defined(CONFIG_DEBUG_OMAP2UART1)
+#undef DEBUG_OMAP2UART1_FLAGS
+#define DEBUG_OMAP2UART1_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP2UART2)
+#undef DEBUG_OMAP2UART2_FLAGS
+#define DEBUG_OMAP2UART2_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP2UART3)
+#undef DEBUG_OMAP2UART3_FLAGS
+#define DEBUG_OMAP2UART3_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP3UART3)
+#undef DEBUG_OMAP3UART3_FLAGS
+#define DEBUG_OMAP3UART3_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP3UART4)
+#undef DEBUG_OMAP3UART4_FLAGS
+#define DEBUG_OMAP3UART4_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP4UART3)
+#undef DEBUG_OMAP4UART3_FLAGS
+#define DEBUG_OMAP4UART3_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP4UART4)
+#undef DEBUG_OMAP4UART4_FLAGS
+#define DEBUG_OMAP4UART4_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_TI81XXUART1)
+#undef DEBUG_TI81XXUART1_FLAGS
+#define DEBUG_TI81XXUART1_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_TI81XXUART2)
+#undef DEBUG_TI81XXUART2_FLAGS
+#define DEBUG_TI81XXUART2_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_TI81XXUART3)
+#undef DEBUG_TI81XXUART3_FLAGS
+#define DEBUG_TI81XXUART3_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_AM33XXUART1)
+#undef DEBUG_AM33XXUART1_FLAGS
+#define DEBUG_AM33XXUART1_FLAGS DEBUG_OMAPUART_FLAGS
+#endif
 
 /**
  * struct omap_hwmod_mux_info - hwmod specific mux configuration
@@ -568,6 +616,7 @@ struct omap_hwmod_link {
  * @voltdm: pointer to voltage domain (filled in at runtime)
  * @dev_attr: arbitrary device attributes that can be passed to the driver
  * @_sysc_cache: internal-use hwmod flags
+ * @mpu_rt_idx: index of device address space for register target (for DT boot)
  * @_mpu_rt_va: cached register target start address (internal use)
  * @_mpu_port: cached MPU register target slave (internal use)
  * @opt_clks_cnt: number of @opt_clks
@@ -617,6 +666,7 @@ struct omap_hwmod {
        struct list_head                node;
        struct omap_hwmod_ocp_if        *_mpu_port;
        u16                             flags;
+       u8                              mpu_rt_idx;
        u8                              response_lat;
        u8                              rst_lines_cnt;
        u8                              opt_clks_cnt;
index d05fc7b54567f0dbb6597a1d641ce130caf7ee9b..56cebb05509e15c0054f342e158a21214b7a6603 100644 (file)
@@ -512,7 +512,7 @@ struct omap_hwmod omap2xxx_uart1_hwmod = {
        .mpu_irqs       = omap2_uart1_mpu_irqs,
        .sdma_reqs      = omap2_uart1_sdma_reqs,
        .main_clk       = "uart1_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP2UART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
@@ -532,7 +532,7 @@ struct omap_hwmod omap2xxx_uart2_hwmod = {
        .mpu_irqs       = omap2_uart2_mpu_irqs,
        .sdma_reqs      = omap2_uart2_sdma_reqs,
        .main_clk       = "uart2_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP2UART2_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
@@ -552,7 +552,7 @@ struct omap_hwmod omap2xxx_uart3_hwmod = {
        .mpu_irqs       = omap2_uart3_mpu_irqs,
        .sdma_reqs      = omap2_uart3_sdma_reqs,
        .main_clk       = "uart3_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP2UART3_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
index 28bbd56346a93ab67fc377eb1ea066a8be8280f7..eb2f3b93b51c9a4d7ce32eed8f23d63cb3083d33 100644 (file)
@@ -562,6 +562,7 @@ static struct omap_hwmod am33xx_cpgmac0_hwmod = {
        .clkdm_name     = "cpsw_125mhz_clkdm",
        .flags          = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY),
        .main_clk       = "cpsw_125mhz_gclk",
+       .mpu_rt_idx     = 1,
        .prcm           = {
                .omap4  = {
                        .clkctrl_offs   = AM33XX_CM_PER_CPGMAC0_CLKCTRL_OFFSET,
@@ -1512,7 +1513,7 @@ static struct omap_hwmod am33xx_uart1_hwmod = {
        .name           = "uart1",
        .class          = &uart_class,
        .clkdm_name     = "l4_wkup_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_AM33XXUART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .main_clk       = "dpll_per_m2_div4_wkupdm_ck",
        .prcm           = {
                .omap4  = {
index f7a3df2fb579613a761f9a484dbb0254cadcda9c..0c3a427da5445a5d2f990e05f2f3fcec50634143 100644 (file)
@@ -490,7 +490,7 @@ static struct omap_hwmod omap3xxx_uart1_hwmod = {
        .mpu_irqs       = omap2_uart1_mpu_irqs,
        .sdma_reqs      = omap2_uart1_sdma_reqs,
        .main_clk       = "uart1_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_TI81XXUART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
@@ -509,7 +509,7 @@ static struct omap_hwmod omap3xxx_uart2_hwmod = {
        .mpu_irqs       = omap2_uart2_mpu_irqs,
        .sdma_reqs      = omap2_uart2_sdma_reqs,
        .main_clk       = "uart2_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_TI81XXUART2_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
@@ -528,7 +528,8 @@ static struct omap_hwmod omap3xxx_uart3_hwmod = {
        .mpu_irqs       = omap2_uart3_mpu_irqs,
        .sdma_reqs      = omap2_uart3_sdma_reqs,
        .main_clk       = "uart3_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP3UART3_FLAGS | DEBUG_TI81XXUART3_FLAGS |
+                               HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = OMAP3430_PER_MOD,
@@ -558,7 +559,7 @@ static struct omap_hwmod omap36xx_uart4_hwmod = {
        .mpu_irqs       = uart4_mpu_irqs,
        .sdma_reqs      = uart4_sdma_reqs,
        .main_clk       = "uart4_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP3UART4_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = OMAP3430_PER_MOD,
index d04b5e60fdbec74c6accf27c349a79f07a8c01fb..9c3b504477d7b341b4492ec350bb3404769fa219 100644 (file)
@@ -2858,8 +2858,7 @@ static struct omap_hwmod omap44xx_uart3_hwmod = {
        .name           = "uart3",
        .class          = &omap44xx_uart_hwmod_class,
        .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET |
-                               HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP4UART3_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .main_clk       = "func_48m_fclk",
        .prcm = {
                .omap4 = {
@@ -2875,7 +2874,7 @@ static struct omap_hwmod omap44xx_uart4_hwmod = {
        .name           = "uart4",
        .class          = &omap44xx_uart_hwmod_class,
        .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP4UART4_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .main_clk       = "func_48m_fclk",
        .prcm = {
                .omap4 = {
index f37ae96b70a1a9e2c67085b2a0a466992358a4e6..3c70f5c1860fc2b96401fe6ad1256c1a975539e0 100644 (file)
@@ -1375,7 +1375,7 @@ static struct omap_hwmod omap54xx_uart3_hwmod = {
        .name           = "uart3",
        .class          = &omap54xx_uart_hwmod_class,
        .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+       .flags          = DEBUG_OMAP4UART3_FLAGS,
        .main_clk       = "func_48m_fclk",
        .prcm = {
                .omap4 = {
@@ -1391,6 +1391,7 @@ static struct omap_hwmod omap54xx_uart4_hwmod = {
        .name           = "uart4",
        .class          = &omap54xx_uart_hwmod_class,
        .clkdm_name     = "l4per_clkdm",
+       .flags          = DEBUG_OMAP4UART4_FLAGS,
        .main_clk       = "func_48m_fclk",
        .prcm = {
                .omap4 = {
index 3a674de6cb632d21dade993c9e0cb3ca2c7babd8..a388f8c1bcb3cb2c69a199613ee3710eeb333c7b 100644 (file)
@@ -208,17 +208,6 @@ static int __init omap_serial_early_init(void)
                                pr_info("%s used as console in debug mode: uart%d clocks will not be gated",
                                        uart_name, uart->num);
                        }
-
-                       /*
-                        * omap-uart can be used for earlyprintk logs
-                        * So if omap-uart is used as console then prevent
-                        * uart reset and idle to get logs from omap-uart
-                        * until uart console driver is available to take
-                        * care for console messages.
-                        * Idling or resetting omap-uart while printing logs
-                        * early boot logs can stall the boot-up.
-                        */
-                       oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
                }
        } while (1);
 
index f6726bb4eb954bf1cdaf073b4940269137673916..3a3362fa793edd06e2dab0f4d88d08c8a1af4d0f 100644 (file)
@@ -477,16 +477,24 @@ static int em_x270_usb_hub_init(void)
        /* USB Hub power-on and reset */
        gpio_direction_output(usb_hub_reset, 1);
        gpio_direction_output(GPIO9_USB_VBUS_EN, 0);
-       regulator_enable(em_x270_usb_ldo);
+       err = regulator_enable(em_x270_usb_ldo);
+       if (err)
+               goto err_free_rst_gpio;
+
        gpio_set_value(usb_hub_reset, 0);
        gpio_set_value(usb_hub_reset, 1);
        regulator_disable(em_x270_usb_ldo);
-       regulator_enable(em_x270_usb_ldo);
+       err = regulator_enable(em_x270_usb_ldo);
+       if (err)
+               goto err_free_rst_gpio;
+
        gpio_set_value(usb_hub_reset, 0);
        gpio_set_value(GPIO9_USB_VBUS_EN, 1);
 
        return 0;
 
+err_free_rst_gpio:
+       gpio_free(usb_hub_reset);
 err_free_vbus_gpio:
        gpio_free(GPIO9_USB_VBUS_EN);
 err_free_usb_ldo:
@@ -592,7 +600,7 @@ err_irq:
        return err;
 }
 
-static void em_x270_mci_setpower(struct device *dev, unsigned int vdd)
+static int em_x270_mci_setpower(struct device *dev, unsigned int vdd)
 {
        struct pxamci_platform_data* p_d = dev->platform_data;
 
@@ -600,10 +608,11 @@ static void em_x270_mci_setpower(struct device *dev, unsigned int vdd)
                int vdd_uV = (2000 + (vdd - __ffs(MMC_VDD_20_21)) * 100) * 1000;
 
                regulator_set_voltage(em_x270_sdio_ldo, vdd_uV, vdd_uV);
-               regulator_enable(em_x270_sdio_ldo);
+               return regulator_enable(em_x270_sdio_ldo);
        } else {
                regulator_disable(em_x270_sdio_ldo);
        }
+       return 0;
 }
 
 static void em_x270_mci_exit(struct device *dev, void *data)
index d2c6523183764c2e809076bca2fc527826a209b1..dd70343c87085edf4da384fedd434a339802756c 100644 (file)
@@ -408,7 +408,7 @@ static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_in
        return err;
 }
 
-static void mainstone_mci_setpower(struct device *dev, unsigned int vdd)
+static int mainstone_mci_setpower(struct device *dev, unsigned int vdd)
 {
        struct pxamci_platform_data* p_d = dev->platform_data;
 
@@ -420,6 +420,7 @@ static void mainstone_mci_setpower(struct device *dev, unsigned int vdd)
                printk(KERN_DEBUG "%s: off\n", __func__);
                MST_MSCWR1 &= ~MST_MSCWR1_MMC_ON;
        }
+       return 0;
 }
 
 static void mainstone_mci_exit(struct device *dev, void *data)
index fb7f1d1627dc1d11863ae4bcaeeabb0bccda4524..13e5b00eae900beb689a2c0293be84600913a890 100644 (file)
@@ -335,7 +335,7 @@ static int pcm990_mci_init(struct device *dev, irq_handler_t mci_detect_int,
        return err;
 }
 
-static void pcm990_mci_setpower(struct device *dev, unsigned int vdd)
+static int pcm990_mci_setpower(struct device *dev, unsigned int vdd)
 {
        struct pxamci_platform_data *p_d = dev->platform_data;
        u8 val;
@@ -348,6 +348,7 @@ static void pcm990_mci_setpower(struct device *dev, unsigned int vdd)
                val &= ~PCM990_CTRL_MMC2PWR;
 
        pcm990_cpld_writeb(PCM990_CTRL_MMC2PWR, PCM990_CTRL_REG5);
+       return 0;
 }
 
 static void pcm990_mci_exit(struct device *dev, void *data)
index 711d37e26bd8111b1b4821c849b96394cc4f102b..aedf053a1de5ccac5f3505c93f802ef6dadbe50a 100644 (file)
@@ -258,7 +258,7 @@ err_free_2:
        return err;
 }
 
-static void poodle_mci_setpower(struct device *dev, unsigned int vdd)
+static int poodle_mci_setpower(struct device *dev, unsigned int vdd)
 {
        struct pxamci_platform_data* p_d = dev->platform_data;
 
@@ -270,6 +270,8 @@ static void poodle_mci_setpower(struct device *dev, unsigned int vdd)
                gpio_set_value(POODLE_GPIO_SD_PWR1, 0);
                gpio_set_value(POODLE_GPIO_SD_PWR, 0);
        }
+
+       return 0;
 }
 
 static void poodle_mci_exit(struct device *dev, void *data)
index 2125df0444e7be24f7aa1e3c6ce153fe0b78655c..4c29173026e8e67ff6ec0409f1862e205e5ffc4c 100644 (file)
@@ -598,7 +598,7 @@ static inline void spitz_spi_init(void) {}
  * NOTE: The card detect interrupt isn't debounced so we delay it by 250ms to
  * give the card a chance to fully insert/eject.
  */
-static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
+static int spitz_mci_setpower(struct device *dev, unsigned int vdd)
 {
        struct pxamci_platform_data* p_d = dev->platform_data;
 
@@ -606,6 +606,8 @@ static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
                spitz_card_pwr_ctrl(SCOOP_CPR_SD_3V, SCOOP_CPR_SD_3V);
        else
                spitz_card_pwr_ctrl(SCOOP_CPR_SD_3V, 0x0);
+
+       return 0;
 }
 
 static struct pxamci_platform_data spitz_mci_platform_data = {
index 88fde43c948c740a1bccd8f2520d4d3a8dc63f98..62aea3e835f315266ba887367310ec249503cd21 100644 (file)
@@ -734,9 +734,10 @@ static int stargate2_mci_init(struct device *dev,
  *
  * Very simple control. Either it is on or off and is controlled by
  * a gpio pin */
-static void stargate2_mci_setpower(struct device *dev, unsigned int vdd)
+static int stargate2_mci_setpower(struct device *dev, unsigned int vdd)
 {
        gpio_set_value(SG2_SD_POWER_ENABLE, !!vdd);
+       return 0;
 }
 
 static void stargate2_mci_exit(struct device *dev, void *data)
index 34fffdf6fc1dc4b7f699418976e0b3d943c512a6..564553694b543d24df4eca3fa6a305c59520ce79 100644 (file)
@@ -119,66 +119,101 @@ static struct clk init_clocks_off[] = {
        }
 };
 
-static struct clk init_clocks[] = {
-       {
-               .name           = "lcd",
-               .parent         = &clk_h,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_LCDC,
-       }, {
-               .name           = "gpio",
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_GPIO,
-       }, {
-               .name           = "usb-host",
-               .parent         = &clk_h,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_USBH,
-       }, {
-               .name           = "usb-device",
-               .parent         = &clk_h,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_USBD,
-       }, {
-               .name           = "timers",
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_PWMT,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2410-uart.0",
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_UART0,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2410-uart.1",
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_UART1,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2410-uart.2",
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_UART2,
-       }, {
-               .name           = "rtc",
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_RTC,
-       }, {
-               .name           = "watchdog",
-               .parent         = &clk_p,
-               .ctrlbit        = 0,
-       }, {
-               .name           = "usb-bus-host",
-               .parent         = &clk_usb_bus,
-       }, {
-               .name           = "usb-bus-gadget",
-               .parent         = &clk_usb_bus,
-       },
+static struct clk clk_lcd = {
+       .name           = "lcd",
+       .parent         = &clk_h,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2410_CLKCON_LCDC,
+};
+
+static struct clk clk_gpio = {
+       .name           = "gpio",
+       .parent         = &clk_p,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2410_CLKCON_GPIO,
+};
+
+static struct clk clk_usb_host = {
+       .name           = "usb-host",
+       .parent         = &clk_h,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2410_CLKCON_USBH,
+};
+
+static struct clk clk_usb_device = {
+       .name           = "usb-device",
+       .parent         = &clk_h,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2410_CLKCON_USBD,
+};
+
+static struct clk clk_timers = {
+       .name           = "timers",
+       .parent         = &clk_p,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2410_CLKCON_PWMT,
+};
+
+struct clk s3c24xx_clk_uart0 = {
+       .name           = "uart",
+       .devname        = "s3c2410-uart.0",
+       .parent         = &clk_p,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2410_CLKCON_UART0,
+};
+
+struct clk s3c24xx_clk_uart1 = {
+       .name           = "uart",
+       .devname        = "s3c2410-uart.1",
+       .parent         = &clk_p,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2410_CLKCON_UART1,
+};
+
+struct clk s3c24xx_clk_uart2 = {
+       .name           = "uart",
+       .devname        = "s3c2410-uart.2",
+       .parent         = &clk_p,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2410_CLKCON_UART2,
+};
+
+static struct clk clk_rtc = {
+       .name           = "rtc",
+       .parent         = &clk_p,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2410_CLKCON_RTC,
+};
+
+static struct clk clk_watchdog = {
+       .name           = "watchdog",
+       .parent         = &clk_p,
+       .ctrlbit        = 0,
+};
+
+static struct clk clk_usb_bus_host = {
+       .name           = "usb-bus-host",
+       .parent         = &clk_usb_bus,
+};
+
+static struct clk clk_usb_bus_gadget = {
+       .name           = "usb-bus-gadget",
+       .parent         = &clk_usb_bus,
+};
+
+static struct clk *init_clocks[] = {
+       &clk_lcd,
+       &clk_gpio,
+       &clk_usb_host,
+       &clk_usb_device,
+       &clk_timers,
+       &s3c24xx_clk_uart0,
+       &s3c24xx_clk_uart1,
+       &s3c24xx_clk_uart2,
+       &clk_rtc,
+       &clk_watchdog,
+       &clk_usb_bus_host,
+       &clk_usb_bus_gadget,
 };
 
 /* s3c2410_baseclk_add()
@@ -195,7 +230,6 @@ int __init s3c2410_baseclk_add(void)
 {
        unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
        unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
-       struct clk *clkp;
        struct clk *xtal;
        int ret;
        int ptr;
@@ -207,8 +241,9 @@ int __init s3c2410_baseclk_add(void)
 
        /* register clocks from clock array */
 
-       clkp = init_clocks;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++) {
+               struct clk *clkp = init_clocks[ptr];
+
                /* ensure that we note the clock state */
 
                clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
index 1069b56808265b5efaf9877b9ed6a1b7dc5ea833..aaf006d1d6dc9ec6111ae080e3e4f15350615561 100644 (file)
@@ -166,6 +166,9 @@ static struct clk_lookup s3c2440_clk_lookup[] = {
        CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
        CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
        CLKDEV_INIT(NULL, "clk_uart_baud3", &s3c2440_clk_fclk_n),
+       CLKDEV_INIT("s3c2440-uart.0", "uart", &s3c24xx_clk_uart0),
+       CLKDEV_INIT("s3c2440-uart.1", "uart", &s3c24xx_clk_uart1),
+       CLKDEV_INIT("s3c2440-uart.2", "uart", &s3c24xx_clk_uart2),
        CLKDEV_INIT("s3c2440-camif", "camera", &s3c2440_clk_cam_upll),
 };
 
index e115f67421078cd7390cc2cc92a6b0ae43c4b36c..c5be60d85e4b95fa1339f64492d28097ac3763dc 100644 (file)
@@ -1162,9 +1162,6 @@ static void __init eva_init(void)
        gpio_request_one(61, GPIOF_OUT_INIT_HIGH, NULL); /* LCDDON */
        gpio_request_one(202, GPIOF_OUT_INIT_LOW, NULL); /* LCD0_LED_CONT */
 
-       /* Touchscreen */
-       gpio_request_one(166, GPIOF_OUT_INIT_HIGH, NULL); /* TP_RST_B */
-
        /* GETHER */
        gpio_request_one(18, GPIOF_OUT_INIT_HIGH, NULL); /* PHY_RST */
 
index d5554646916c34a962a9e1790653fc22d8beefd0..3354a85c90f7091c776ab248df641d9dddb3990d 100644 (file)
@@ -167,7 +167,13 @@ static const struct pinctrl_map bockw_pinctrl_map[] = {
                                  "usb1", "usb1"),
        /* SDHI0 */
        PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
-                                 "sdhi0", "sdhi0"),
+                                 "sdhi0_data4", "sdhi0"),
+       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
+                                 "sdhi0_ctrl", "sdhi0"),
+       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
+                                 "sdhi0_cd", "sdhi0"),
+       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
+                                 "sdhi0_wp", "sdhi0"),
 };
 
 #define FPGA   0x18200000
index d73e21d3ea8ad9cf036483262a2010334ec0e062..8d6bd5c5efb9cd092fe4dd857057a1e6f59b9420 100644 (file)
@@ -59,7 +59,7 @@ static __initdata struct gpio_led_platform_data lager_leds_pdata = {
 #define GPIO_KEY(c, g, d, ...) \
        { .code = c, .gpio = g, .desc = d, .active_low = 1 }
 
-static __initdata struct gpio_keys_button gpio_buttons[] = {
+static struct gpio_keys_button gpio_buttons[] = {
        GPIO_KEY(KEY_4,         RCAR_GP_PIN(1, 28),     "SW2-pin4"),
        GPIO_KEY(KEY_3,         RCAR_GP_PIN(1, 26),     "SW2-pin3"),
        GPIO_KEY(KEY_2,         RCAR_GP_PIN(1, 24),     "SW2-pin2"),
index d04e3bfe19189082823e4a74c60d1de1de9eed7f..835833e3c4f8fb193f6d177c88ef35199488b33f 100644 (file)
@@ -11,8 +11,9 @@ menuconfig ARCH_STI
        select HAVE_SMP
        select HAVE_ARM_SCU if SMP
        select ARCH_REQUIRE_GPIOLIB
-       select ARM_ERRATA_720789
        select ARM_ERRATA_754322
+       select ARM_ERRATA_764369
+       select ARM_ERRATA_775420
        select PL310_ERRATA_753970 if CACHE_PL310
        select PL310_ERRATA_769419 if CACHE_PL310
        help
index 78ebc7559f5309e025c3796ff90017293570bc6e..4c09bae86edf02cb4f9408821fea25cd84d9dddb 100644 (file)
@@ -16,8 +16,6 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 
-       __INIT
-
 /*
  * ST specific entry point for secondary CPUs.  This provides
  * a "holding pen" into which all secondary cores are held until we're
index 5b799c29886e544778d115a0e7570f3f100875ad..5f252569c68987d908546b55bb921d5f7693c7af 100644 (file)
@@ -91,7 +91,7 @@ static void __init zynq_map_io(void)
        zynq_scu_map_io();
 }
 
-static void zynq_system_reset(char mode, const char *cmd)
+static void zynq_system_reset(enum reboot_mode mode, const char *cmd)
 {
        zynq_slcr_system_reset();
 }
index 6cacdc8dd654dd11ecbfb45f7576f1ead0a1062e..db5c2cab8fda4251bb636aa5567afafe5cfdb406 100644 (file)
@@ -421,24 +421,28 @@ config CPU_32v3
        select CPU_USE_DOMAINS if MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
        select TLS_REG_EMUL if SMP || !MMU
+       select NEED_KUSER_HELPERS
 
 config CPU_32v4
        bool
        select CPU_USE_DOMAINS if MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
        select TLS_REG_EMUL if SMP || !MMU
+       select NEED_KUSER_HELPERS
 
 config CPU_32v4T
        bool
        select CPU_USE_DOMAINS if MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
        select TLS_REG_EMUL if SMP || !MMU
+       select NEED_KUSER_HELPERS
 
 config CPU_32v5
        bool
        select CPU_USE_DOMAINS if MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
        select TLS_REG_EMUL if SMP || !MMU
+       select NEED_KUSER_HELPERS
 
 config CPU_32v6
        bool
@@ -776,6 +780,7 @@ config CPU_BPREDICT_DISABLE
 
 config TLS_REG_EMUL
        bool
+       select NEED_KUSER_HELPERS
        help
          An SMP system using a pre-ARMv6 processor (there are apparently
          a few prototypes like that in existence) and therefore access to
@@ -783,11 +788,40 @@ config TLS_REG_EMUL
 
 config NEEDS_SYSCALL_FOR_CMPXCHG
        bool
+       select NEED_KUSER_HELPERS
        help
          SMP on a pre-ARMv6 processor?  Well OK then.
          Forget about fast user space cmpxchg support.
          It is just not possible.
 
+config NEED_KUSER_HELPERS
+       bool
+
+config KUSER_HELPERS
+       bool "Enable kuser helpers in vector page" if !NEED_KUSER_HELPERS
+       default y
+       help
+         Warning: disabling this option may break user programs.
+
+         Provide kuser helpers in the vector page.  The kernel provides
+         helper code to userspace in read only form at a fixed location
+         in the high vector page to allow userspace to be independent of
+         the CPU type fitted to the system.  This permits binaries to be
+         run on ARMv4 through to ARMv7 without modification.
+
+         However, the fixed address nature of these helpers can be used
+         by ROP (return orientated programming) authors when creating
+         exploits.
+
+         If all of the binaries and libraries which run on your platform
+         are built specifically for your platform, and make no use of
+         these helpers, then you can turn this option off.  However,
+         when such an binary or library is run, it will receive a SIGILL
+         signal, which will terminate the program.
+
+         Say N here only if you are absolutely certain that you do not
+         need these helpers; otherwise, the safe option is to say Y.
+
 config DMA_CACHE_RWFO
        bool "Enable read/write for ownership DMA cache maintenance"
        depends on CPU_V6K && SMP
index b55b1015724b56931c57ad7b2920d760b80529e8..4a0544492f10e4cd63d490f61d3cff3e54adbd19 100644 (file)
@@ -245,7 +245,8 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
        if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) {
                local_flush_bp_all();
                local_flush_tlb_all();
-               dummy_flush_tlb_a15_erratum();
+               if (erratum_a15_798181())
+                       dummy_flush_tlb_a15_erratum();
        }
 
        atomic64_set(&per_cpu(active_asids, cpu), asid);
index 4f56617a2392d58e52f96582a3631c4c49a4f5f2..53cdbd39ec8e23c1facab667f56fa9441aa870c6 100644 (file)
@@ -989,6 +989,7 @@ phys_addr_t arm_lowmem_limit __initdata = 0;
 
 void __init sanity_check_meminfo(void)
 {
+       phys_addr_t memblock_limit = 0;
        int i, j, highmem = 0;
        phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
 
@@ -1052,9 +1053,32 @@ void __init sanity_check_meminfo(void)
                        bank->size = size_limit;
                }
 #endif
-               if (!bank->highmem && bank->start + bank->size > arm_lowmem_limit)
-                       arm_lowmem_limit = bank->start + bank->size;
+               if (!bank->highmem) {
+                       phys_addr_t bank_end = bank->start + bank->size;
 
+                       if (bank_end > arm_lowmem_limit)
+                               arm_lowmem_limit = bank_end;
+
+                       /*
+                        * Find the first non-section-aligned page, and point
+                        * memblock_limit at it. This relies on rounding the
+                        * limit down to be section-aligned, which happens at
+                        * the end of this function.
+                        *
+                        * With this algorithm, the start or end of almost any
+                        * bank can be non-section-aligned. The only exception
+                        * is that the start of the bank 0 must be section-
+                        * aligned, since otherwise memory would need to be
+                        * allocated when mapping the start of bank 0, which
+                        * occurs before any free memory is mapped.
+                        */
+                       if (!memblock_limit) {
+                               if (!IS_ALIGNED(bank->start, SECTION_SIZE))
+                                       memblock_limit = bank->start;
+                               else if (!IS_ALIGNED(bank_end, SECTION_SIZE))
+                                       memblock_limit = bank_end;
+                       }
+               }
                j++;
        }
 #ifdef CONFIG_HIGHMEM
@@ -1079,7 +1103,18 @@ void __init sanity_check_meminfo(void)
 #endif
        meminfo.nr_banks = j;
        high_memory = __va(arm_lowmem_limit - 1) + 1;
-       memblock_set_current_limit(arm_lowmem_limit);
+
+       /*
+        * Round the memblock limit down to a section size.  This
+        * helps to ensure that we will allocate memory from the
+        * last full section, which should be mapped.
+        */
+       if (memblock_limit)
+               memblock_limit = round_down(memblock_limit, SECTION_SIZE);
+       if (!memblock_limit)
+               memblock_limit = arm_lowmem_limit;
+
+       memblock_set_current_limit(memblock_limit);
 }
 
 static inline void prepare_page_table(void)
@@ -1160,7 +1195,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
        /*
         * Allocate the vector page early.
         */
-       vectors = early_alloc(PAGE_SIZE);
+       vectors = early_alloc(PAGE_SIZE * 2);
 
        early_trap_init(vectors);
 
@@ -1205,15 +1240,27 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
        map.pfn = __phys_to_pfn(virt_to_phys(vectors));
        map.virtual = 0xffff0000;
        map.length = PAGE_SIZE;
+#ifdef CONFIG_KUSER_HELPERS
        map.type = MT_HIGH_VECTORS;
+#else
+       map.type = MT_LOW_VECTORS;
+#endif
        create_mapping(&map);
 
        if (!vectors_high()) {
                map.virtual = 0;
+               map.length = PAGE_SIZE * 2;
                map.type = MT_LOW_VECTORS;
                create_mapping(&map);
        }
 
+       /* Now create a kernel read-only mapping */
+       map.pfn += 1;
+       map.virtual = 0xffff0000 + PAGE_SIZE;
+       map.length = PAGE_SIZE;
+       map.type = MT_LOW_VECTORS;
+       create_mapping(&map);
+
        /*
         * Ask the machine support to map in the statically mapped devices.
         */
@@ -1276,8 +1323,6 @@ void __init paging_init(struct machine_desc *mdesc)
 {
        void *zero_page;
 
-       memblock_set_current_limit(arm_lowmem_limit);
-
        build_mem_type_table();
        prepare_page_table();
        map_lowmem();
index f64afb9f1bd595a9fb1b9c0cd8bb442c9fda0337..bdd3be4be77aa50c93dcc20c8afdaa3af3c0cf5f 100644 (file)
@@ -110,7 +110,7 @@ ENTRY(cpu_v7_set_pte_ext)
  ARM(  str     r3, [r0, #2048]! )
  THUMB(        add     r0, r0, #2048 )
  THUMB(        str     r3, [r0] )
-       ALT_SMP(mov     pc,lr)
+       ALT_SMP(W(nop))
        ALT_UP (mcr     p15, 0, r0, c7, c10, 1)         @ flush_pte
 #endif
        mov     pc, lr
index c36ac69488c8fa60b17d91d085d1f8efcae42cb6..01a719e18bb047c655694c336d5a42e1388d1062 100644 (file)
@@ -81,7 +81,7 @@ ENTRY(cpu_v7_set_pte_ext)
        tst     r3, #1 << (55 - 32)             @ L_PTE_DIRTY
        orreq   r2, #L_PTE_RDONLY
 1:     strd    r2, r3, [r0]
-       ALT_SMP(mov     pc, lr)
+       ALT_SMP(W(nop))
        ALT_UP (mcr     p15, 0, r0, c7, c10, 1)         @ flush_pte
 #endif
        mov     pc, lr
index 5c6d5a3050eac65f1f2f89465d8398c971f866e4..73398bcf9bd8ea8d7293803828cb837306742fb7 100644 (file)
@@ -75,13 +75,14 @@ ENTRY(cpu_v7_do_idle)
 ENDPROC(cpu_v7_do_idle)
 
 ENTRY(cpu_v7_dcache_clean_area)
-       ALT_SMP(mov     pc, lr)                 @ MP extensions imply L1 PTW
-       ALT_UP(W(nop))
-       dcache_line_size r2, r3
-1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       ALT_SMP(W(nop))                 @ MP extensions imply L1 PTW
+       ALT_UP_B(1f)
+       mov     pc, lr
+1:     dcache_line_size r2, r3
+2:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, r2
        subs    r1, r1, r2
-       bhi     1b
+       bhi     2b
        dsb
        mov     pc, lr
 ENDPROC(cpu_v7_dcache_clean_area)
index 3dc5cbea86cc9cc838d5b864f0eabaed76777e23..a5b5ff6e68d2015e4080112c821fb6d0ac0bf3d6 100644 (file)
@@ -29,6 +29,13 @@ config PLAT_S5P
        help
          Base platform code for Samsung's S5P series SoC.
 
+config SAMSUNG_PM
+       bool
+       depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || S5P_PM)
+       default y
+       help
+         Base platform power management code for samsung code
+
 if PLAT_SAMSUNG
 
 # boot configurations
index 98d07d8fc7a71ffa869fa397cc8f74977264f17c..199bbe304d02f1e70838c0f012a73e7688655436 100644 (file)
@@ -51,7 +51,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV)  += dma-ops.o
 
 # PM support
 
-obj-$(CONFIG_PM)               += pm.o
+obj-$(CONFIG_SAMSUNG_PM)       += pm.o
 obj-$(CONFIG_SAMSUNG_PM_GPIO)  += pm-gpio.o
 obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o
 
index a62753dc15baf144ecfc2ea7efe53bfc6f13a9fe..df45d6edc98d9e723242f3890e1ea4df124d8888 100644 (file)
@@ -83,6 +83,11 @@ extern struct clk clk_ext;
 extern struct clksrc_clk clk_epllref;
 extern struct clksrc_clk clk_esysclk;
 
+/* S3C24XX UART clocks */
+extern struct clk s3c24xx_clk_uart0;
+extern struct clk s3c24xx_clk_uart1;
+extern struct clk s3c24xx_clk_uart2;
+
 /* S3C64XX specific clocks */
 extern struct clk clk_h2;
 extern struct clk clk_27m;
index 5d47ca35cabde40cfa56ae05344a275909ac9e72..6bc1a8f471e391e127be0dd7cfadf0eefa33a0f2 100644 (file)
@@ -19,7 +19,7 @@
 
 struct device;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_SAMSUNG_PM
 
 extern __init int s3c_pm_init(void);
 extern __init int s3c64xx_pm_init(void);
@@ -58,8 +58,6 @@ extern unsigned char pm_uart_udivslot;  /* true to save UART UDIVSLOT */
 
 /* from sleep.S */
 
-extern void s3c_cpu_resume(void);
-
 extern int s3c2410_cpu_suspend(unsigned long);
 
 /* sleep save info */
@@ -106,12 +104,14 @@ extern void s3c_pm_do_save(struct sleep_save *ptr, int count);
 extern void s3c_pm_do_restore(struct sleep_save *ptr, int count);
 extern void s3c_pm_do_restore_core(struct sleep_save *ptr, int count);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_SAMSUNG_PM
 extern int s3c_irq_wake(struct irq_data *data, unsigned int state);
 extern int s3c_irqext_wake(struct irq_data *data, unsigned int state);
+extern void s3c_cpu_resume(void);
 #else
 #define s3c_irq_wake NULL
 #define s3c_irqext_wake NULL
+#define s3c_cpu_resume NULL
 #endif
 
 /* PM debug functions */
index ea36136424511b4d3c7518b0e839897e266f7137..d0c23010b693a57625d002694528d0cd2fffaaa5 100644 (file)
@@ -80,7 +80,7 @@ unsigned char pm_uart_udivslot;
 
 #ifdef CONFIG_SAMSUNG_PM_DEBUG
 
-static struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS];
+static struct pm_uart_save uart_save;
 
 static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save)
 {
@@ -101,11 +101,7 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save)
 
 static void s3c_pm_save_uarts(void)
 {
-       struct pm_uart_save *save = uart_save;
-       unsigned int uart;
-
-       for (uart = 0; uart < CONFIG_SERIAL_SAMSUNG_UARTS; uart++, save++)
-               s3c_pm_save_uart(uart, save);
+       s3c_pm_save_uart(CONFIG_DEBUG_S3C_UART, &uart_save);
 }
 
 static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save)
@@ -126,11 +122,7 @@ static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save)
 
 static void s3c_pm_restore_uarts(void)
 {
-       struct pm_uart_save *save = uart_save;
-       unsigned int uart;
-
-       for (uart = 0; uart < CONFIG_SERIAL_SAMSUNG_UARTS; uart++, save++)
-               s3c_pm_restore_uart(uart, save);
+       s3c_pm_restore_uart(CONFIG_DEBUG_S3C_UART, &uart_save);
 }
 #else
 static void s3c_pm_save_uarts(void) { }
index f71c37edca263a88038199514995cf92d8b79d9e..c9770ba5c7df5c3b68c909c32db7fa2fb7be39f1 100644 (file)
@@ -172,7 +172,7 @@ static void __init xen_percpu_init(void *unused)
        enable_percpu_irq(xen_events_irq, 0);
 }
 
-static void xen_restart(char str, const char *cmd)
+static void xen_restart(enum reboot_mode reboot_mode, const char *cmd)
 {
        struct sched_shutdown r = { .reason = SHUTDOWN_reboot };
        int rc;
index 3659e460071ddfb1f84715ff7736c97ef9f9bb20..23a3c4791d86cb71f9a2520e2176212b1e107503 100644 (file)
 #include <linux/compiler.h>
 
 #ifndef CONFIG_ARM64_64K_PAGES
-#define THREAD_SIZE_ORDER      1
+#define THREAD_SIZE_ORDER      2
 #endif
 
-#define THREAD_SIZE            8192
+#define THREAD_SIZE            16384
 #define THREAD_START_SP                (THREAD_SIZE - 16)
 
 #ifndef __ASSEMBLY__
index 439827271e3d5bfada26390c9a226bbf6ec763e5..26e310c5434446c7bfc0a9a3f9b443139ffa3368 100644 (file)
@@ -21,6 +21,7 @@
 #define BOOT_CPU_MODE_EL2      (0x0e12b007)
 
 #ifndef __ASSEMBLY__
+#include <asm/cacheflush.h>
 
 /*
  * __boot_cpu_mode records what mode CPUs were booted in.
@@ -36,9 +37,20 @@ extern u32 __boot_cpu_mode[2];
 void __hyp_set_vectors(phys_addr_t phys_vector_base);
 phys_addr_t __hyp_get_vectors(void);
 
+static inline void sync_boot_mode(void)
+{
+       /*
+        * As secondaries write to __boot_cpu_mode with caches disabled, we
+        * must flush the corresponding cache entries to ensure the visibility
+        * of their writes.
+        */
+       __flush_dcache_area(__boot_cpu_mode, sizeof(__boot_cpu_mode));
+}
+
 /* Reports the availability of HYP mode */
 static inline bool is_hyp_mode_available(void)
 {
+       sync_boot_mode();
        return (__boot_cpu_mode[0] == BOOT_CPU_MODE_EL2 &&
                __boot_cpu_mode[1] == BOOT_CPU_MODE_EL2);
 }
@@ -46,6 +58,7 @@ static inline bool is_hyp_mode_available(void)
 /* Check if the bootloader has booted CPUs in different modes */
 static inline bool is_hyp_mode_mismatched(void)
 {
+       sync_boot_mode();
        return __boot_cpu_mode[0] != __boot_cpu_mode[1];
 }
 
index 1d1314280a03a678c4ef63092712d49079386cdd..6ad781b21c080a50c4c061dbd4037beafe8ba09b 100644 (file)
 
        .macro  get_thread_info, rd
        mov     \rd, sp
-       and     \rd, \rd, #~((1 << 13) - 1)     // top of 8K stack
+       and     \rd, \rd, #~(THREAD_SIZE - 1)   // top of stack
        .endm
 
 /*
index 1788bf6b471f63a6fe708cb608039c51fe1e40fa..57fb55c44c901c19c7264f02ff44d6c481fadc56 100644 (file)
@@ -81,7 +81,7 @@ void soft_restart(unsigned long addr)
 void (*pm_power_off)(void);
 EXPORT_SYMBOL_GPL(pm_power_off);
 
-void (*arm_pm_restart)(char str, const char *cmd);
+void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
 EXPORT_SYMBOL_GPL(arm_pm_restart);
 
 void arch_cpu_idle_prepare(void)
index 7913695b2fcbe5605830b9e1da6441188a591b8b..efbd2929aeb75c563b5ccbf4b267be596ce921e2 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_ACPI_FAN=m
 CONFIG_ACPI_DOCK=y
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=m
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index f8e91336542392236c878276ad8abcef4d786166..f64980dd20c3f3851174c25c63152578910f255d 100644 (file)
@@ -25,7 +25,7 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=m
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index a5a9e02e60a05c94e9b9a4c6c35a6cf78eecf429..0f4e9e41f130623baae948b022dbd01468869331 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=m
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index 37b9b422caadf9c89196aa63781d9cdb2a05830d..b025acfde5c1dc4fff39be616007fd7391f11276 100644 (file)
@@ -32,7 +32,7 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=m
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index c3abed332301fe70572e8de451eda0d70f51eadd..e12764c2a9d08163e7d066f276f4b8b87e16e208 100644 (file)
@@ -114,6 +114,7 @@ config BCM47XX
        select FW_CFE
        select HW_HAS_PCI
        select IRQ_CPU
+       select SYS_HAS_CPU_MIPS32_R1
        select NO_EXCEPT_FILL
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
index ba611927749b9f81def164126a2b2b1d00bf42c5..2b8b118398c458573652c5b9e058a302ddcaf766 100644 (file)
@@ -2,7 +2,6 @@ if BCM47XX
 
 config BCM47XX_SSB
        bool "SSB Support for Broadcom BCM47XX"
-       select SYS_HAS_CPU_MIPS32_R1
        select SSB
        select SSB_DRIVER_MIPS
        select SSB_DRIVER_EXTIF
index 1dc086087a723fd9c90c427d05f4eb3c8ca919f6..fa44f3ec530214f5014664cda4611b1a5a027251 100644 (file)
@@ -17,6 +17,8 @@
 #define current_cpu_type()     current_cpu_data.cputype
 #endif
 
+#define boot_cpu_type()                cpu_data[0].cputype
+
 /*
  * SMP assumption: Options of CPU 0 are a superset of all processors.
  * This is true for all known MIPS systems.
index 5b2f2e68e57f08210be7d4a98370cb3895111adf..9488fa5f886603fdef1ac258182bf82d61004faf 100644 (file)
 #else
 #define CAC_BASE               _AC(0x80000000, UL)
 #endif
+#ifndef IO_BASE
 #define IO_BASE                        _AC(0xa0000000, UL)
+#endif
+#ifndef UNCAC_BASE
 #define UNCAC_BASE             _AC(0xa0000000, UL)
+#endif
 
 #ifndef MAP_BASE
 #ifdef CONFIG_KVM_GUEST
index b7a23064841f2171173dbaca04027381000e02d4..88e292b7719e99963f74692f0ffbd36e60e79c83 100644 (file)
@@ -25,11 +25,12 @@ struct siginfo;
 /*
  * Careful to keep union _sifields from shifting ...
  */
-#if __SIZEOF_LONG__ == 4
+#if _MIPS_SZLONG == 32
 #define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
-#endif
-#if __SIZEOF_LONG__ == 8
+#elif _MIPS_SZLONG == 64
 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+#else
+#error _MIPS_SZLONG neither 32 nor 64
 #endif
 
 #include <asm-generic/siginfo.h>
index f739aedcb509ada01eb9f579b98bc5c1752e03de..bd79c4f9bff403eeb2e320343b83d81d70855852 100644 (file)
@@ -54,7 +54,11 @@ LEAF(bmips_smp_movevec)
        /* set up CPU1 CBR; move BASE to 0xa000_0000 */
        li      k0, 0xff400000
        mtc0    k0, $22, 6
-       li      k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_1
+       /* set up relocation vector address based on thread ID */
+       mfc0    k1, $22, 3
+       srl     k1, 16
+       andi    k1, 0x8000
+       or      k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_0
        or      k0, k1
        li      k1, 0xa0080000
        sw      k1, 0(k0)
index c0bb4d59076a79bdc85cf59caf57fd2b2c87303c..126da74d4c5559faf40962b80bddef9a39721757 100644 (file)
@@ -66,6 +66,8 @@ static void __init bmips_smp_setup(void)
        int i, cpu = 1, boot_cpu = 0;
 
 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
+       int cpu_hw_intr;
+
        /* arbitration priority */
        clear_c0_brcm_cmt_ctrl(0x30);
 
@@ -79,15 +81,13 @@ static void __init bmips_smp_setup(void)
         * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other thread
         * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output
         * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output
-        *
-        * If booting from TP1, leave the existing CMT interrupt routing
-        * such that TP0 responds to SW1 and TP1 responds to SW0.
         */
        if (boot_cpu == 0)
-               change_c0_brcm_cmt_intr(0xf8018000,
-                                       (0x02 << 27) | (0x03 << 15));
+               cpu_hw_intr = 0x02;
        else
-               change_c0_brcm_cmt_intr(0xf8018000, (0x1d << 27));
+               cpu_hw_intr = 0x1d;
+
+       change_c0_brcm_cmt_intr(0xf8018000, (cpu_hw_intr << 27) | (0x03 << 15));
 
        /* single core, 2 threads (2 pipelines) */
        max_cpus = 2;
@@ -202,9 +202,15 @@ static void bmips_init_secondary(void)
 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
        void __iomem *cbr = BMIPS_GET_CBR();
        unsigned long old_vec;
+       unsigned long relo_vector;
+       int boot_cpu;
+
+       boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
+       relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 :
+                         BMIPS_RELO_VECTOR_CONTROL_1;
 
-       old_vec = __raw_readl(cbr + BMIPS_RELO_VECTOR_CONTROL_1);
-       __raw_writel(old_vec & ~0x20000000, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
+       old_vec = __raw_readl(cbr + relo_vector);
+       __raw_writel(old_vec & ~0x20000000, cbr + relo_vector);
 
        clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0);
 #elif defined(CONFIG_CPU_BMIPS5000)
index e4b1140cdae060dca0de8bfdd6a5985b1429de58..3a2b6e9f25cfb95ab0f2f5ee1eeccf069bde8f22 100644 (file)
@@ -166,7 +166,7 @@ static void mipsxx_reg_setup(struct op_counter_config *ctr)
                        reg.control[i] |= M_PERFCTL_USER;
                if (ctr[i].exl)
                        reg.control[i] |= M_PERFCTL_EXL;
-               if (current_cpu_type() == CPU_XLR)
+               if (boot_cpu_type() == CPU_XLR)
                        reg.control[i] |= M_PERFCTL_COUNT_ALL_THREADS;
                reg.counter[i] = 0x80000000 - ctr[i].count;
        }
index d22dc0d6f28922e0f6beefbc2cabad28da0d70e1..2b7e837dc2e2c275e698e101eb1fd961bc44d7ee 100644 (file)
@@ -206,11 +206,13 @@ static struct resource pnx833x_ethernet_resources[] = {
                .end   = PNX8335_IP3902_PORTS_END,
                .flags = IORESOURCE_MEM,
        },
+#ifdef CONFIG_SOC_PNX8335
        [1] = {
                .start = PNX8335_PIC_ETHERNET_INT,
                .end   = PNX8335_PIC_ETHERNET_INT,
                .flags = IORESOURCE_IRQ,
        },
+#endif
 };
 
 static struct platform_device pnx833x_ethernet_device = {
index 9f64c23878082c7e5622733486652381af0315b4..0238af1ba50383689138a929c268a1a592a1464d 100644 (file)
@@ -529,8 +529,7 @@ EXPORT_SYMBOL(asic_resource_get);
  */
 void platform_release_memory(void *ptr, int size)
 {
-       free_reserved_area((unsigned long)ptr, (unsigned long)(ptr + size),
-                          -1, NULL);
+       free_reserved_area(ptr, ptr + size, -1, NULL);
 }
 EXPORT_SYMBOL(platform_release_memory);
 
diff --git a/arch/parisc/configs/c8000_defconfig b/arch/parisc/configs/c8000_defconfig
new file mode 100644 (file)
index 0000000..f110063
--- /dev/null
@@ -0,0 +1,279 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_PA8X00=y
+CONFIG_MLONGCALLS=y
+CONFIG_64BIT=y
+CONFIG_SMP=y
+CONFIG_PREEMPT=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_IOMMU_CCIO=y
+CONFIG_PCI=y
+CONFIG_PCI_LBA=y
+# CONFIG_SUPERIO is not set
+# CONFIG_CHASSIS_LCD_LED is not set
+# CONFIG_PDC_CHASSIS is not set
+# CONFIG_PDC_CHASSIS_WARN is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_DIAG=m
+# CONFIG_IPV6 is not set
+CONFIG_IP_DCCP=m
+# CONFIG_IP_DCCP_CCID3 is not set
+CONFIG_TIPC=m
+CONFIG_LLC2=m
+CONFIG_DNS_RESOLVER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_STANDALONE is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=6144
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_WCACHE=y
+CONFIG_ATA_OVER_ETH=m
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_PLATFORM=y
+CONFIG_BLK_DEV_GENERIC=y
+CONFIG_BLK_DEV_SIIMAGE=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION_SAS=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_NETCONSOLE=m
+CONFIG_TUN=y
+CONFIG_E1000=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_WLAN is not set
+CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_HIL_OLD is not set
+# CONFIG_KEYBOARD_HIL is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_CM109=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_GSCPS2=m
+# CONFIG_HP_SDC is not set
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_RUNTIME_UARTS=8
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_MUX is not set
+CONFIG_SERIAL_JSM=m
+CONFIG_PRINTER=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=m
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_SSB=m
+CONFIG_SSB_DRIVER_PCICORE=y
+CONFIG_AGP=y
+CONFIG_AGP_PARISC=y
+CONFIG_DRM=y
+CONFIG_DRM_RADEON=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_FOREIGN_ENDIAN=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_STI is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_STI_CONSOLE is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_AD1889=m
+# CONFIG_SND_USB is not set
+# CONFIG_SND_GSC is not set
+CONFIG_HID_A4TECH=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_KYE=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_USB_HID=m
+CONFIG_USB=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=m
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_NFS_FS=m
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SLAB_LEAK=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_RT_MUTEX_TESTER=y
+CONFIG_PROVE_RCU_DELAY=y
+CONFIG_DEBUG_BLOCK_EXT_DEVT=y
+CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
+CONFIG_KEYS=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_FONTS=y
index 9afdad6c2ffb81db7f8ffb68dd003bd3b5cd4980..eaf4dc1c729440688a169bd11fe81b250b8c776f 100644 (file)
@@ -23,6 +23,7 @@ struct parisc_device {
        /* generic info returned from pdc_pat_cell_module() */
        unsigned long   mod_info;       /* PAT specific - Misc Module info */
        unsigned long   pmod_loc;       /* physical Module location */
+       unsigned long   mod0;
 #endif
        u64             dma_mask;       /* DMA mask for I/O */
        struct device   dev;
@@ -61,4 +62,6 @@ parisc_get_drvdata(struct parisc_device *d)
 
 extern struct bus_type parisc_bus_type;
 
+int iosapic_serial_irq(struct parisc_device *dev);
+
 #endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
index 2e65aa54bd101b7dc5600297858929687e90d549..c035673209f732f0850aaa4dc98d2d49eee3b74c 100644 (file)
@@ -71,18 +71,27 @@ flush_cache_all_local(void)
 }
 EXPORT_SYMBOL(flush_cache_all_local);
 
+/* Virtual address of pfn.  */
+#define pfn_va(pfn)    __va(PFN_PHYS(pfn))
+
 void
 update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
-       struct page *page = pte_page(*ptep);
+       unsigned long pfn = pte_pfn(*ptep);
+       struct page *page;
 
-       if (pfn_valid(page_to_pfn(page)) && page_mapping(page) &&
-           test_bit(PG_dcache_dirty, &page->flags)) {
+       /* We don't have pte special.  As a result, we can be called with
+          an invalid pfn and we don't need to flush the kernel dcache page.
+          This occurs with FireGL card in C8000.  */
+       if (!pfn_valid(pfn))
+               return;
 
-               flush_kernel_dcache_page(page);
+       page = pfn_to_page(pfn);
+       if (page_mapping(page) && test_bit(PG_dcache_dirty, &page->flags)) {
+               flush_kernel_dcache_page_addr(pfn_va(pfn));
                clear_bit(PG_dcache_dirty, &page->flags);
        } else if (parisc_requires_coherency())
-               flush_kernel_dcache_page(page);
+               flush_kernel_dcache_page_addr(pfn_va(pfn));
 }
 
 void
@@ -495,44 +504,42 @@ static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr)
 
 void flush_cache_mm(struct mm_struct *mm)
 {
+       struct vm_area_struct *vma;
+       pgd_t *pgd;
+
        /* Flushing the whole cache on each cpu takes forever on
           rp3440, etc.  So, avoid it if the mm isn't too big.  */
-       if (mm_total_size(mm) < parisc_cache_flush_threshold) {
-               struct vm_area_struct *vma;
-
-               if (mm->context == mfsp(3)) {
-                       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-                               flush_user_dcache_range_asm(vma->vm_start,
-                                       vma->vm_end);
-                               if (vma->vm_flags & VM_EXEC)
-                                       flush_user_icache_range_asm(
-                                         vma->vm_start, vma->vm_end);
-                       }
-               } else {
-                       pgd_t *pgd = mm->pgd;
-
-                       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-                               unsigned long addr;
-
-                               for (addr = vma->vm_start; addr < vma->vm_end;
-                                    addr += PAGE_SIZE) {
-                                       pte_t *ptep = get_ptep(pgd, addr);
-                                       if (ptep != NULL) {
-                                               pte_t pte = *ptep;
-                                               __flush_cache_page(vma, addr,
-                                                 page_to_phys(pte_page(pte)));
-                                       }
-                               }
-                       }
+       if (mm_total_size(mm) >= parisc_cache_flush_threshold) {
+               flush_cache_all();
+               return;
+       }
+
+       if (mm->context == mfsp(3)) {
+               for (vma = mm->mmap; vma; vma = vma->vm_next) {
+                       flush_user_dcache_range_asm(vma->vm_start, vma->vm_end);
+                       if ((vma->vm_flags & VM_EXEC) == 0)
+                               continue;
+                       flush_user_icache_range_asm(vma->vm_start, vma->vm_end);
                }
                return;
        }
 
-#ifdef CONFIG_SMP
-       flush_cache_all();
-#else
-       flush_cache_all_local();
-#endif
+       pgd = mm->pgd;
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               unsigned long addr;
+
+               for (addr = vma->vm_start; addr < vma->vm_end;
+                    addr += PAGE_SIZE) {
+                       unsigned long pfn;
+                       pte_t *ptep = get_ptep(pgd, addr);
+                       if (!ptep)
+                               continue;
+                       pfn = pte_pfn(*ptep);
+                       if (!pfn_valid(pfn))
+                               continue;
+                       __flush_cache_page(vma, addr, PFN_PHYS(pfn));
+               }
+       }
 }
 
 void
@@ -556,33 +563,32 @@ flush_user_icache_range(unsigned long start, unsigned long end)
 void flush_cache_range(struct vm_area_struct *vma,
                unsigned long start, unsigned long end)
 {
+       unsigned long addr;
+       pgd_t *pgd;
+
        BUG_ON(!vma->vm_mm->context);
 
-       if ((end - start) < parisc_cache_flush_threshold) {
-               if (vma->vm_mm->context == mfsp(3)) {
-                       flush_user_dcache_range_asm(start, end);
-                       if (vma->vm_flags & VM_EXEC)
-                               flush_user_icache_range_asm(start, end);
-               } else {
-                       unsigned long addr;
-                       pgd_t *pgd = vma->vm_mm->pgd;
-
-                       for (addr = start & PAGE_MASK; addr < end;
-                            addr += PAGE_SIZE) {
-                               pte_t *ptep = get_ptep(pgd, addr);
-                               if (ptep != NULL) {
-                                       pte_t pte = *ptep;
-                                       flush_cache_page(vma,
-                                          addr, pte_pfn(pte));
-                               }
-                       }
-               }
-       } else {
-#ifdef CONFIG_SMP
+       if ((end - start) >= parisc_cache_flush_threshold) {
                flush_cache_all();
-#else
-               flush_cache_all_local();
-#endif
+               return;
+       }
+
+       if (vma->vm_mm->context == mfsp(3)) {
+               flush_user_dcache_range_asm(start, end);
+               if (vma->vm_flags & VM_EXEC)
+                       flush_user_icache_range_asm(start, end);
+               return;
+       }
+
+       pgd = vma->vm_mm->pgd;
+       for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
+               unsigned long pfn;
+               pte_t *ptep = get_ptep(pgd, addr);
+               if (!ptep)
+                       continue;
+               pfn = pte_pfn(*ptep);
+               if (pfn_valid(pfn))
+                       __flush_cache_page(vma, addr, PFN_PHYS(pfn));
        }
 }
 
@@ -591,9 +597,10 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
 {
        BUG_ON(!vma->vm_mm->context);
 
-       flush_tlb_page(vma, vmaddr);
-       __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn)));
-
+       if (pfn_valid(pfn)) {
+               flush_tlb_page(vma, vmaddr);
+               __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
+       }
 }
 
 #ifdef CONFIG_PARISC_TMPALIAS
index 3295ef4a185d06327c84b806276f31ac4c7cdaab..f0b6722fc706169b37a407a1fad6b063984722e8 100644 (file)
@@ -211,6 +211,7 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
        /* REVISIT: who is the consumer of this? not sure yet... */
        dev->mod_info = pa_pdc_cell->mod_info;  /* pass to PAT_GET_ENTITY() */
        dev->pmod_loc = pa_pdc_cell->mod_location;
+       dev->mod0 = pa_pdc_cell->mod[0];
 
        register_parisc_device(dev);    /* advertise device */
 
index 940188d1942caeb993ffc58aa7148fea50c91683..07349b00268750581d1badb79b2c2487732831b8 100644 (file)
  * this. */
 #define A(__x) ((unsigned long)(__x))
 
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-#ifdef CONFIG_64BIT
-#include "sys32.h"
-#endif
-
 /*
  * Do a signal return - restore sigcontext.
  */
index 33eca1b04926ad09184d703e9c2fcb55cd127069..6c6a271a6140e639183334a70a470860f906d7bf 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/uaccess.h>
 
 #include "signal32.h"
-#include "sys32.h"
 
 #define DEBUG_COMPAT_SIG 0 
 #define DEBUG_COMPAT_SIG_LEVEL 2
diff --git a/arch/parisc/kernel/sys32.h b/arch/parisc/kernel/sys32.h
deleted file mode 100644 (file)
index 60dd470..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 
- *    Copyright (C) 2002 Richard Hirst <rhirst at parisc-linux.org>
- *    Copyright (C) 2003 James Bottomley <jejb at parisc-linux.org>
- *    Copyright (C) 2003 Randolph Chung <tausq with parisc-linux.org>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that 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.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef _PARISC64_KERNEL_SYS32_H
-#define _PARISC64_KERNEL_SYS32_H
-
-#include <linux/compat.h>
-
-/* Call a kernel syscall which will use kernel space instead of user
- * space for its copy_to/from_user.
- */
-#define KERNEL_SYSCALL(ret, syscall, args...) \
-{ \
-    mm_segment_t old_fs = get_fs(); \
-    set_fs(KERNEL_DS); \
-    ret = syscall(args); \
-    set_fs (old_fs); \
-}
-
-#endif
index a134ff4da12ee1e4ad39a78e514328f578573ca3..bb9f3b64de55b2583f9fc930b6a1fa368237fd49 100644 (file)
@@ -42,8 +42,6 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 
-#include "sys32.h"
-
 #undef DEBUG
 
 #ifdef DEBUG
index c86fcb92358e27bc93bd723375d04c9e1c247071..0e8cfd09da2f65dd95197c2e8ca86d5ae6dfbf24 100644 (file)
@@ -58,7 +58,7 @@ CONFIG_SCHED_SMT=y
 CONFIG_PPC_DENORMALISATION=y
 CONFIG_PCCARD=y
 CONFIG_ELECTRA_CF=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_RPA=m
 CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
 CONFIG_PACKET=y
index 4b20f76172e2efb2f2d3d1e1c5a8c8bdbc6656dc..0085dc4642c5bb107b61bcbe80c9935449d64b8d 100644 (file)
@@ -32,7 +32,7 @@ CONFIG_IRQ_ALL_CPUS=y
 CONFIG_SPARSEMEM_MANUAL=y
 CONFIG_PCI_MSI=y
 CONFIG_PCCARD=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_XFRM_USER=m
index bea8587c3af509b1540fe6138614f73dcbf97c9c..1d4b9763895df77dafcfd61bb4eea7bed6a18621 100644 (file)
@@ -53,7 +53,7 @@ CONFIG_PPC_64K_PAGES=y
 CONFIG_PPC_SUBPAGE_PROT=y
 CONFIG_SCHED_SMT=y
 CONFIG_PPC_DENORMALISATION=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_RPA=m
 CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
 CONFIG_PACKET=y
index 09a8743143f37a046e8d57e3d65f58f9a1bd3cb4..d3e5e9bc8f946fa3fd7158a3ecc931561c71c1a3 100644 (file)
@@ -55,6 +55,8 @@ struct device_node;
 #define EEH_PE_RECOVERING      (1 << 1)        /* Recovering PE        */
 #define EEH_PE_PHB_DEAD                (1 << 2)        /* Dead PHB             */
 
+#define EEH_PE_KEEP            (1 << 8)        /* Keep PE on hotplug   */
+
 struct eeh_pe {
        int type;                       /* PE type: PHB/Bus/Device      */
        int state;                      /* PE EEH dependent mode        */
@@ -72,8 +74,8 @@ struct eeh_pe {
        struct list_head child;         /* Child PEs                    */
 };
 
-#define eeh_pe_for_each_dev(pe, edev) \
-               list_for_each_entry(edev, &pe->edevs, list)
+#define eeh_pe_for_each_dev(pe, edev, tmp) \
+               list_for_each_entry_safe(edev, tmp, &pe->edevs, list)
 
 /*
  * The struct is used to trace EEH state for the associated
@@ -82,7 +84,13 @@ struct eeh_pe {
  * another tree except the currently existing tree of PCI
  * buses and PCI devices
  */
-#define EEH_DEV_IRQ_DISABLED   (1<<0)  /* Interrupt disabled           */
+#define EEH_DEV_BRIDGE         (1 << 0)        /* PCI bridge           */
+#define EEH_DEV_ROOT_PORT      (1 << 1)        /* PCIe root port       */
+#define EEH_DEV_DS_PORT                (1 << 2)        /* Downstream port      */
+#define EEH_DEV_IRQ_DISABLED   (1 << 3)        /* Interrupt disabled   */
+#define EEH_DEV_DISCONNECTED   (1 << 4)        /* Removing from PE     */
+
+#define EEH_DEV_SYSFS          (1 << 8)        /* Sysfs created        */
 
 struct eeh_dev {
        int mode;                       /* EEH mode                     */
@@ -90,11 +98,13 @@ struct eeh_dev {
        int config_addr;                /* Config address               */
        int pe_config_addr;             /* PE config address            */
        u32 config_space[16];           /* Saved PCI config space       */
+       u8 pcie_cap;                    /* Saved PCIe capability        */
        struct eeh_pe *pe;              /* Associated PE                */
        struct list_head list;          /* Form link list in the PE     */
        struct pci_controller *phb;     /* Associated PHB               */
        struct device_node *dn;         /* Associated device node       */
        struct pci_dev *pdev;           /* Associated PCI device        */
+       struct pci_bus *bus;            /* PCI bus for partial hotplug  */
 };
 
 static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev)
@@ -193,8 +203,10 @@ int eeh_phb_pe_create(struct pci_controller *phb);
 struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb);
 struct eeh_pe *eeh_pe_get(struct eeh_dev *edev);
 int eeh_add_to_parent_pe(struct eeh_dev *edev);
-int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe);
+int eeh_rmv_from_parent_pe(struct eeh_dev *edev);
 void eeh_pe_update_time_stamp(struct eeh_pe *pe);
+void *eeh_pe_traverse(struct eeh_pe *root,
+               eeh_traverse_func fn, void *flag);
 void *eeh_pe_dev_traverse(struct eeh_pe *root,
                eeh_traverse_func fn, void *flag);
 void eeh_pe_restore_bars(struct eeh_pe *pe);
@@ -209,10 +221,12 @@ unsigned long eeh_check_failure(const volatile void __iomem *token,
                                unsigned long val);
 int eeh_dev_check_failure(struct eeh_dev *edev);
 void eeh_addr_cache_build(void);
+void eeh_add_device_early(struct device_node *);
 void eeh_add_device_tree_early(struct device_node *);
+void eeh_add_device_late(struct pci_dev *);
 void eeh_add_device_tree_late(struct pci_bus *);
 void eeh_add_sysfs_files(struct pci_bus *);
-void eeh_remove_bus_device(struct pci_dev *, int);
+void eeh_remove_device(struct pci_dev *);
 
 /**
  * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
@@ -252,13 +266,17 @@ static inline unsigned long eeh_check_failure(const volatile void __iomem *token
 
 static inline void eeh_addr_cache_build(void) { }
 
+static inline void eeh_add_device_early(struct device_node *dn) { }
+
 static inline void eeh_add_device_tree_early(struct device_node *dn) { }
 
+static inline void eeh_add_device_late(struct pci_dev *dev) { }
+
 static inline void eeh_add_device_tree_late(struct pci_bus *bus) { }
 
 static inline void eeh_add_sysfs_files(struct pci_bus *bus) { }
 
-static inline void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) { }
+static inline void eeh_remove_device(struct pci_dev *dev) { }
 
 #define EEH_POSSIBLE_ERROR(val, type) (0)
 #define EEH_IO_ERROR_VALUE(size) (-1UL)
index ba713f166fa57fb2f9b08002a8a5cf8c0162d196..10be1dd01c6b4bcd79f88725f9b5067dc8a0db8a 100644 (file)
@@ -96,10 +96,11 @@ static inline bool arch_irqs_disabled(void)
 #endif
 
 #define hard_irq_disable()     do {                    \
-       u8 _was_enabled = get_paca()->soft_enabled;     \
+       u8 _was_enabled;                                \
        __hard_irq_disable();                           \
-       get_paca()->soft_enabled = 0;                   \
-       get_paca()->irq_happened |= PACA_IRQ_HARD_DIS;  \
+       _was_enabled = local_paca->soft_enabled;        \
+       local_paca->soft_enabled = 0;                   \
+       local_paca->irq_happened |= PACA_IRQ_HARD_DIS;  \
        if (_was_enabled)                               \
                trace_hardirqs_off();                   \
 } while(0)
index c1df590ec4440a96f81b97f6048ad79a7f326179..49fa55bfbac4fba38f26368cbbdcdf1513aa590c 100644 (file)
@@ -82,10 +82,9 @@ struct exception_table_entry;
 void sort_ex_table(struct exception_table_entry *start,
                   struct exception_table_entry *finish);
 
-#ifdef CONFIG_MODVERSIONS
+#if defined(CONFIG_MODVERSIONS) && defined(CONFIG_PPC64)
 #define ARCH_RELOCATES_KCRCTAB
-
-extern const unsigned long reloc_start[];
+#define reloc_start PHYSICAL_START
 #endif
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MODULE_H */
index 2c1d8cb9b26562a295ab6b6016261b0d692df30b..32d0d2018faf84afe15814f13cb7f1fe4933fa4e 100644 (file)
@@ -209,7 +209,6 @@ static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
 extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn);
 
 /** Remove all of the PCI devices under this bus */
-extern void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe);
 extern void pcibios_remove_pci_devices(struct pci_bus *bus);
 
 /** Discover new pci devices under this bus, and add them */
index 2dd7bfc459bed73eba9f1be705acf44d7fb36c3d..8b24926447544c2fed3eb44de6464071a20f15dc 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <asm/hw_irq.h>
 #include <linux/device.h>
+#include <uapi/asm/perf_event.h>
 
 #define MAX_HWEVENTS           8
 #define MAX_EVENT_ALTERNATIVES 8
@@ -69,11 +70,6 @@ struct power_pmu {
 #define PPMU_LIMITED_PMC_REQD  2       /* have to put this on a limited PMC */
 #define PPMU_ONLY_COUNT_RUN    4       /* only counting in run state */
 
-/*
- * We use the event config bit 63 as a flag to request EBB.
- */
-#define EVENT_CONFIG_EBB_SHIFT 63
-
 extern int register_power_pmu(struct power_pmu *);
 
 struct pt_regs;
index 5d7d9c2a547373dbb692ebded8b519df476bb2e4..a6840e4e24f7abe68d918d6dc576bcab18d0183d 100644 (file)
 #define PVR_970MP      0x0044
 #define PVR_970GX      0x0045
 #define PVR_POWER7p    0x004A
-#define PVR_POWER8     0x004B
+#define PVR_POWER8E    0x004B
+#define PVR_POWER8     0x004D
 #define PVR_BE         0x0070
 #define PVR_PA6T       0x0090
 
index ffbaabebcdca71eb1130ccaf12cfcf36c82501c4..48cfc858abd6dfa70c4c95172a5e4003fa62c53d 100644 (file)
@@ -145,6 +145,10 @@ extern void __cpu_die(unsigned int cpu);
 #define smp_setup_cpu_maps()
 static inline void inhibit_secondary_onlining(void) {}
 static inline void uninhibit_secondary_onlining(void) {}
+static inline const struct cpumask *cpu_sibling_mask(int cpu)
+{
+       return cpumask_of(cpu);
+}
 
 #endif /* CONFIG_SMP */
 
index 5182c8622b54eea94ba18cfad7236872ae056865..48be855ef37b294cf034db138842cf56526ff4ea 100644 (file)
@@ -20,6 +20,7 @@ header-y += mman.h
 header-y += msgbuf.h
 header-y += nvram.h
 header-y += param.h
+header-y += perf_event.h
 header-y += poll.h
 header-y += posix_types.h
 header-y += ps3fb.h
diff --git a/arch/powerpc/include/uapi/asm/perf_event.h b/arch/powerpc/include/uapi/asm/perf_event.h
new file mode 100644 (file)
index 0000000..80a4d40
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2013 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ */
+
+#ifndef _UAPI_ASM_POWERPC_PERF_EVENT_H
+#define _UAPI_ASM_POWERPC_PERF_EVENT_H
+
+/*
+ * We use bit 63 of perf_event_attr.config as a flag to request EBB.
+ */
+#define PERF_EVENT_CONFIG_EBB_SHIFT    63
+
+#endif /* _UAPI_ASM_POWERPC_PERF_EVENT_H */
index 2a45d0f043852a33cc41826c7835c59471b1ed60..22973a74df7342b1146a3dd2881432c3cd8ad2b8 100644 (file)
@@ -494,9 +494,27 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_restore            = __restore_cpu_power7,
                .platform               = "power7+",
        },
-       {       /* Power8 */
+       {       /* Power8E */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x004b0000,
+               .cpu_name               = "POWER8E (raw)",
+               .cpu_features           = CPU_FTRS_POWER8,
+               .cpu_user_features      = COMMON_USER_POWER8,
+               .cpu_user_features2     = COMMON_USER2_POWER8,
+               .mmu_features           = MMU_FTRS_POWER8,
+               .icache_bsize           = 128,
+               .dcache_bsize           = 128,
+               .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_IBM,
+               .oprofile_cpu_type      = "ppc64/power8",
+               .oprofile_type          = PPC_OPROFILE_INVALID,
+               .cpu_setup              = __setup_cpu_power8,
+               .cpu_restore            = __restore_cpu_power8,
+               .platform               = "power8",
+       },
+       {       /* Power8 */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x004d0000,
                .cpu_name               = "POWER8 (raw)",
                .cpu_features           = CPU_FTRS_POWER8,
                .cpu_user_features      = COMMON_USER_POWER8,
index 39954fe941b87e45a95951f9c39bb2beae6724db..ea9414c8088d01289411eded7d67315c9a2e8661 100644 (file)
@@ -231,7 +231,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
 void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
 {
        size_t loglen = 0;
-       struct eeh_dev *edev;
+       struct eeh_dev *edev, *tmp;
        bool valid_cfg_log = true;
 
        /*
@@ -251,7 +251,7 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
                eeh_pe_restore_bars(pe);
 
                pci_regs_buf[0] = 0;
-               eeh_pe_for_each_dev(pe, edev) {
+               eeh_pe_for_each_dev(pe, edev, tmp) {
                        loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen,
                                                      EEH_PCI_REGS_LOG_LEN - loglen);
                }
@@ -499,8 +499,6 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon
        }
 
        eeh_dev_check_failure(edev);
-
-       pci_dev_put(eeh_dev_to_pci_dev(edev));
        return val;
 }
 
@@ -838,7 +836,7 @@ core_initcall_sync(eeh_init);
  * on the CEC architecture, type of the device, on earlier boot
  * command-line arguments & etc.
  */
-static void eeh_add_device_early(struct device_node *dn)
+void eeh_add_device_early(struct device_node *dn)
 {
        struct pci_controller *phb;
 
@@ -886,7 +884,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
  * This routine must be used to complete EEH initialization for PCI
  * devices that were added after system boot (e.g. hotplug, dlpar).
  */
-static void eeh_add_device_late(struct pci_dev *dev)
+void eeh_add_device_late(struct pci_dev *dev)
 {
        struct device_node *dn;
        struct eeh_dev *edev;
@@ -902,9 +900,23 @@ static void eeh_add_device_late(struct pci_dev *dev)
                pr_debug("EEH: Already referenced !\n");
                return;
        }
-       WARN_ON(edev->pdev);
 
-       pci_dev_get(dev);
+       /*
+        * The EEH cache might not be removed correctly because of
+        * unbalanced kref to the device during unplug time, which
+        * relies on pcibios_release_device(). So we have to remove
+        * that here explicitly.
+        */
+       if (edev->pdev) {
+               eeh_rmv_from_parent_pe(edev);
+               eeh_addr_cache_rmv_dev(edev->pdev);
+               eeh_sysfs_remove_device(edev->pdev);
+               edev->mode &= ~EEH_DEV_SYSFS;
+
+               edev->pdev = NULL;
+               dev->dev.archdata.edev = NULL;
+       }
+
        edev->pdev = dev;
        dev->dev.archdata.edev = edev;
 
@@ -967,7 +979,6 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files);
 /**
  * eeh_remove_device - Undo EEH setup for the indicated pci device
  * @dev: pci device to be removed
- * @purge_pe: remove the PE or not
  *
  * This routine should be called when a device is removed from
  * a running system (e.g. by hotplug or dlpar).  It unregisters
@@ -975,7 +986,7 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files);
  * this device will no longer be detected after this call; thus,
  * i/o errors affecting this slot may leave this device unusable.
  */
-static void eeh_remove_device(struct pci_dev *dev, int purge_pe)
+void eeh_remove_device(struct pci_dev *dev)
 {
        struct eeh_dev *edev;
 
@@ -986,42 +997,29 @@ static void eeh_remove_device(struct pci_dev *dev, int purge_pe)
        /* Unregister the device with the EEH/PCI address search system */
        pr_debug("EEH: Removing device %s\n", pci_name(dev));
 
-       if (!edev || !edev->pdev) {
+       if (!edev || !edev->pdev || !edev->pe) {
                pr_debug("EEH: Not referenced !\n");
                return;
        }
+
+       /*
+        * During the hotplug for EEH error recovery, we need the EEH
+        * device attached to the parent PE in order for BAR restore
+        * a bit later. So we keep it for BAR restore and remove it
+        * from the parent PE during the BAR resotre.
+        */
        edev->pdev = NULL;
        dev->dev.archdata.edev = NULL;
-       pci_dev_put(dev);
+       if (!(edev->pe->state & EEH_PE_KEEP))
+               eeh_rmv_from_parent_pe(edev);
+       else
+               edev->mode |= EEH_DEV_DISCONNECTED;
 
-       eeh_rmv_from_parent_pe(edev, purge_pe);
        eeh_addr_cache_rmv_dev(dev);
        eeh_sysfs_remove_device(dev);
+       edev->mode &= ~EEH_DEV_SYSFS;
 }
 
-/**
- * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device
- * @dev: PCI device
- * @purge_pe: remove the corresponding PE or not
- *
- * This routine must be called when a device is removed from the
- * running system through hotplug or dlpar. The corresponding
- * PCI address cache will be removed.
- */
-void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe)
-{
-       struct pci_bus *bus = dev->subordinate;
-       struct pci_dev *child, *tmp;
-
-       eeh_remove_device(dev, purge_pe);
-
-       if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-               list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
-                        eeh_remove_bus_device(child, purge_pe);
-       }
-}
-EXPORT_SYMBOL_GPL(eeh_remove_bus_device);
-
 static int proc_eeh_show(struct seq_file *m, void *v)
 {
        if (0 == eeh_subsystem_enabled) {
index f9ac1232a746c595d696ef7b66469a093070c877..e8c9fd546a5c477b4c7755527ffb19dd64c04eca 100644 (file)
@@ -68,16 +68,12 @@ static inline struct eeh_dev *__eeh_addr_cache_get_device(unsigned long addr)
                struct pci_io_addr_range *piar;
                piar = rb_entry(n, struct pci_io_addr_range, rb_node);
 
-               if (addr < piar->addr_lo) {
+               if (addr < piar->addr_lo)
                        n = n->rb_left;
-               } else {
-                       if (addr > piar->addr_hi) {
-                               n = n->rb_right;
-                       } else {
-                               pci_dev_get(piar->pcidev);
-                               return piar->edev;
-                       }
-               }
+               else if (addr > piar->addr_hi)
+                       n = n->rb_right;
+               else
+                       return piar->edev;
        }
 
        return NULL;
@@ -156,7 +152,6 @@ eeh_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
        if (!piar)
                return NULL;
 
-       pci_dev_get(dev);
        piar->addr_lo = alo;
        piar->addr_hi = ahi;
        piar->edev = pci_dev_to_eeh_dev(dev);
@@ -250,7 +245,6 @@ restart:
 
                if (piar->pcidev == dev) {
                        rb_erase(n, &pci_io_addr_cache_root.rb_root);
-                       pci_dev_put(piar->pcidev);
                        kfree(piar);
                        goto restart;
                }
@@ -302,12 +296,10 @@ void eeh_addr_cache_build(void)
                if (!edev)
                        continue;
 
-               pci_dev_get(dev);  /* matching put is in eeh_remove_device() */
                dev->dev.archdata.edev = edev;
                edev->pdev = dev;
 
                eeh_addr_cache_insert_dev(dev);
-
                eeh_sysfs_add_device(dev);
        }
 
index 2b1ce17cae504d95a5be5e04e16828a5e3f7516e..36bed5a12750b639e2c305153585869be536ddef 100644 (file)
@@ -143,10 +143,14 @@ static void eeh_disable_irq(struct pci_dev *dev)
 static void eeh_enable_irq(struct pci_dev *dev)
 {
        struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
+       struct irq_desc *desc;
 
        if ((edev->mode) & EEH_DEV_IRQ_DISABLED) {
                edev->mode &= ~EEH_DEV_IRQ_DISABLED;
-               enable_irq(dev->irq);
+
+               desc = irq_to_desc(dev->irq);
+               if (desc && desc->depth > 0)
+                       enable_irq(dev->irq);
        }
 }
 
@@ -338,6 +342,54 @@ static void *eeh_report_failure(void *data, void *userdata)
        return NULL;
 }
 
+static void *eeh_rmv_device(void *data, void *userdata)
+{
+       struct pci_driver *driver;
+       struct eeh_dev *edev = (struct eeh_dev *)data;
+       struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
+       int *removed = (int *)userdata;
+
+       /*
+        * Actually, we should remove the PCI bridges as well.
+        * However, that's lots of complexity to do that,
+        * particularly some of devices under the bridge might
+        * support EEH. So we just care about PCI devices for
+        * simplicity here.
+        */
+       if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE))
+               return NULL;
+       driver = eeh_pcid_get(dev);
+       if (driver && driver->err_handler)
+               return NULL;
+
+       /* Remove it from PCI subsystem */
+       pr_debug("EEH: Removing %s without EEH sensitive driver\n",
+                pci_name(dev));
+       edev->bus = dev->bus;
+       edev->mode |= EEH_DEV_DISCONNECTED;
+       (*removed)++;
+
+       pci_stop_and_remove_bus_device(dev);
+
+       return NULL;
+}
+
+static void *eeh_pe_detach_dev(void *data, void *userdata)
+{
+       struct eeh_pe *pe = (struct eeh_pe *)data;
+       struct eeh_dev *edev, *tmp;
+
+       eeh_pe_for_each_dev(pe, edev, tmp) {
+               if (!(edev->mode & EEH_DEV_DISCONNECTED))
+                       continue;
+
+               edev->mode &= ~(EEH_DEV_DISCONNECTED | EEH_DEV_IRQ_DISABLED);
+               eeh_rmv_from_parent_pe(edev);
+       }
+
+       return NULL;
+}
+
 /**
  * eeh_reset_device - Perform actual reset of a pci slot
  * @pe: EEH PE
@@ -349,8 +401,9 @@ static void *eeh_report_failure(void *data, void *userdata)
  */
 static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
 {
+       struct pci_bus *frozen_bus = eeh_pe_bus_get(pe);
        struct timeval tstamp;
-       int cnt, rc;
+       int cnt, rc, removed = 0;
 
        /* pcibios will clear the counter; save the value */
        cnt = pe->freeze_count;
@@ -362,8 +415,11 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
         * devices are expected to be attached soon when calling
         * into pcibios_add_pci_devices().
         */
+       eeh_pe_state_mark(pe, EEH_PE_KEEP);
        if (bus)
-               __pcibios_remove_pci_devices(bus, 0);
+               pcibios_remove_pci_devices(bus);
+       else if (frozen_bus)
+               eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed);
 
        /* Reset the pci controller. (Asserts RST#; resets config space).
         * Reconfigure bridges and devices. Don't try to bring the system
@@ -384,9 +440,24 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
         * potentially weird things happen.
         */
        if (bus) {
+               pr_info("EEH: Sleep 5s ahead of complete hotplug\n");
                ssleep(5);
+
+               /*
+                * The EEH device is still connected with its parent
+                * PE. We should disconnect it so the binding can be
+                * rebuilt when adding PCI devices.
+                */
+               eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL);
                pcibios_add_pci_devices(bus);
+       } else if (frozen_bus && removed) {
+               pr_info("EEH: Sleep 5s ahead of partial hotplug\n");
+               ssleep(5);
+
+               eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL);
+               pcibios_add_pci_devices(frozen_bus);
        }
+       eeh_pe_state_clear(pe, EEH_PE_KEEP);
 
        pe->tstamp = tstamp;
        pe->freeze_count = cnt;
index 016588a6f5ede19c9c45b0ab6a3bd44cfce962ae..f9450537e335a350354dec35ff5fdf15876ef0a6 100644 (file)
@@ -149,8 +149,8 @@ static struct eeh_pe *eeh_pe_next(struct eeh_pe *pe,
  * callback returns something other than NULL, or no more PEs
  * to be traversed.
  */
-static void *eeh_pe_traverse(struct eeh_pe *root,
-                       eeh_traverse_func fn, void *flag)
+void *eeh_pe_traverse(struct eeh_pe *root,
+                     eeh_traverse_func fn, void *flag)
 {
        struct eeh_pe *pe;
        void *ret;
@@ -176,7 +176,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
                eeh_traverse_func fn, void *flag)
 {
        struct eeh_pe *pe;
-       struct eeh_dev *edev;
+       struct eeh_dev *edev, *tmp;
        void *ret;
 
        if (!root) {
@@ -186,7 +186,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
 
        /* Traverse root PE */
        for (pe = root; pe; pe = eeh_pe_next(pe, root)) {
-               eeh_pe_for_each_dev(pe, edev) {
+               eeh_pe_for_each_dev(pe, edev, tmp) {
                        ret = fn(edev, flag);
                        if (ret)
                                return ret;
@@ -333,7 +333,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
                while (parent) {
                        if (!(parent->type & EEH_PE_INVALID))
                                break;
-                       parent->type &= ~EEH_PE_INVALID;
+                       parent->type &= ~(EEH_PE_INVALID | EEH_PE_KEEP);
                        parent = parent->parent;
                }
                pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
@@ -397,21 +397,20 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
 /**
  * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE
  * @edev: EEH device
- * @purge_pe: remove PE or not
  *
  * The PE hierarchy tree might be changed when doing PCI hotplug.
  * Also, the PCI devices or buses could be removed from the system
  * during EEH recovery. So we have to call the function remove the
  * corresponding PE accordingly if necessary.
  */
-int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
+int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
 {
        struct eeh_pe *pe, *parent, *child;
        int cnt;
 
        if (!edev->pe) {
-               pr_warning("%s: No PE found for EEH device %s\n",
-                       __func__, edev->dn->full_name);
+               pr_debug("%s: No PE found for EEH device %s\n",
+                        __func__, edev->dn->full_name);
                return -EEXIST;
        }
 
@@ -431,7 +430,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
                if (pe->type & EEH_PE_PHB)
                        break;
 
-               if (purge_pe) {
+               if (!(pe->state & EEH_PE_KEEP)) {
                        if (list_empty(&pe->edevs) &&
                            list_empty(&pe->child_list)) {
                                list_del(&pe->child);
@@ -502,7 +501,7 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
 {
        struct eeh_pe *pe = (struct eeh_pe *)data;
        int state = *((int *)flag);
-       struct eeh_dev *tmp;
+       struct eeh_dev *edev, *tmp;
        struct pci_dev *pdev;
 
        /*
@@ -512,8 +511,8 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
         * the PCI device driver.
         */
        pe->state |= state;
-       eeh_pe_for_each_dev(pe, tmp) {
-               pdev = eeh_dev_to_pci_dev(tmp);
+       eeh_pe_for_each_dev(pe, edev, tmp) {
+               pdev = eeh_dev_to_pci_dev(edev);
                if (pdev)
                        pdev->error_state = pci_channel_io_frozen;
        }
@@ -579,7 +578,7 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state)
  * blocked on normal path during the stage. So we need utilize
  * eeh operations, which is always permitted.
  */
-static void eeh_bridge_check_link(struct pci_dev *pdev,
+static void eeh_bridge_check_link(struct eeh_dev *edev,
                                  struct device_node *dn)
 {
        int cap;
@@ -590,16 +589,17 @@ static void eeh_bridge_check_link(struct pci_dev *pdev,
         * We only check root port and downstream ports of
         * PCIe switches
         */
-       if (!pci_is_pcie(pdev) ||
-           (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
-            pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM))
+       if (!(edev->mode & (EEH_DEV_ROOT_PORT | EEH_DEV_DS_PORT)))
                return;
 
-       pr_debug("%s: Check PCIe link for %s ...\n",
-                __func__, pci_name(pdev));
+       pr_debug("%s: Check PCIe link for %04x:%02x:%02x.%01x ...\n",
+                __func__, edev->phb->global_number,
+                edev->config_addr >> 8,
+                PCI_SLOT(edev->config_addr & 0xFF),
+                PCI_FUNC(edev->config_addr & 0xFF));
 
        /* Check slot status */
-       cap = pdev->pcie_cap;
+       cap = edev->pcie_cap;
        eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val);
        if (!(val & PCI_EXP_SLTSTA_PDS)) {
                pr_debug("  No card in the slot (0x%04x) !\n", val);
@@ -653,8 +653,7 @@ static void eeh_bridge_check_link(struct pci_dev *pdev,
 #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
 #define SAVED_BYTE(OFF)        (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
 
-static void eeh_restore_bridge_bars(struct pci_dev *pdev,
-                                   struct eeh_dev *edev,
+static void eeh_restore_bridge_bars(struct eeh_dev *edev,
                                    struct device_node *dn)
 {
        int i;
@@ -680,7 +679,7 @@ static void eeh_restore_bridge_bars(struct pci_dev *pdev,
        eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]);
 
        /* Check the PCIe link is ready */
-       eeh_bridge_check_link(pdev, dn);
+       eeh_bridge_check_link(edev, dn);
 }
 
 static void eeh_restore_device_bars(struct eeh_dev *edev,
@@ -729,19 +728,12 @@ static void eeh_restore_device_bars(struct eeh_dev *edev,
  */
 static void *eeh_restore_one_device_bars(void *data, void *flag)
 {
-       struct pci_dev *pdev = NULL;
        struct eeh_dev *edev = (struct eeh_dev *)data;
        struct device_node *dn = eeh_dev_to_of_node(edev);
 
-       /* Trace the PCI bridge */
-       if (eeh_probe_mode_dev()) {
-               pdev = eeh_dev_to_pci_dev(edev);
-               if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
-                        pdev = NULL;
-        }
-
-       if (pdev)
-               eeh_restore_bridge_bars(pdev, edev, dn);
+       /* Do special restore for bridges */
+       if (edev->mode & EEH_DEV_BRIDGE)
+               eeh_restore_bridge_bars(edev, dn);
        else
                eeh_restore_device_bars(edev, dn);
 
index e7ae3484918c29639ff1a1baa597579a973fe6cd..5d753d4f2c75938e5fdd2c75b821ff98877cd2c9 100644 (file)
@@ -56,19 +56,40 @@ EEH_SHOW_ATTR(eeh_pe_config_addr,  pe_config_addr,  "0x%x");
 
 void eeh_sysfs_add_device(struct pci_dev *pdev)
 {
+       struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
        int rc=0;
 
+       if (edev && (edev->mode & EEH_DEV_SYSFS))
+               return;
+
        rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode);
        rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr);
        rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
 
        if (rc)
                printk(KERN_WARNING "EEH: Unable to create sysfs entries\n");
+       else if (edev)
+               edev->mode |= EEH_DEV_SYSFS;
 }
 
 void eeh_sysfs_remove_device(struct pci_dev *pdev)
 {
+       struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
+
+       /*
+        * The parent directory might have been removed. We needn't
+        * continue for that case.
+        */
+       if (!pdev->dev.kobj.sd) {
+               if (edev)
+                       edev->mode &= ~EEH_DEV_SYSFS;
+               return;
+       }
+
        device_remove_file(&pdev->dev, &dev_attr_eeh_mode);
        device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr);
        device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
+
+       if (edev)
+               edev->mode &= ~EEH_DEV_SYSFS;
 }
index 2e51cde616d2de1fc93cdb75547debab72cf66c2..c69440cef7af43413987f3cd4b2c936cd0e8f788 100644 (file)
@@ -362,7 +362,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
                seq_printf(p, "%10u ", per_cpu(irq_stat, j).spurious_irqs);
        seq_printf(p, "  Spurious interrupts\n");
 
-       seq_printf(p, "%*s: ", prec, "CNT");
+       seq_printf(p, "%*s: ", prec, "PMI");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", per_cpu(irq_stat, j).pmu_irqs);
        seq_printf(p, "  Performance monitoring interrupts\n");
index f46914a0f33ea6fd3cacbdddb76288722dfb42cb..7d22a675fe1a3338d5f1a9d64eb44ce70d8f8f7b 100644 (file)
@@ -1462,6 +1462,8 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus)
        /* Allocate bus and devices resources */
        pcibios_allocate_bus_resources(bus);
        pcibios_claim_one_bus(bus);
+       if (!pci_has_flag(PCI_PROBE_ONLY))
+               pci_assign_unassigned_bus_resources(bus);
 
        /* Fixup EEH */
        eeh_add_device_tree_late(bus);
index 3f608800c06b59082116c3bcd642d26146b357c2..c1e17ae68a08047a0a60154aed49684d8b4aad2f 100644 (file)
 #include <asm/eeh.h>
 
 /**
- * __pcibios_remove_pci_devices - remove all devices under this bus
+ * pcibios_release_device - release PCI device
+ * @dev: PCI device
+ *
+ * The function is called before releasing the indicated PCI device.
+ */
+void pcibios_release_device(struct pci_dev *dev)
+{
+       eeh_remove_device(dev);
+}
+
+/**
+ * pcibios_remove_pci_devices - remove all devices under this bus
  * @bus: the indicated PCI bus
- * @purge_pe: destroy the PE on removal of PCI devices
  *
  * Remove all of the PCI devices under this bus both from the
  * linux pci device tree, and from the powerpc EEH address cache.
- * By default, the corresponding PE will be destroied during the
- * normal PCI hotplug path. For PCI hotplug during EEH recovery,
- * the corresponding PE won't be destroied and deallocated.
  */
-void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe)
+void pcibios_remove_pci_devices(struct pci_bus *bus)
 {
        struct pci_dev *dev, *tmp;
        struct pci_bus *child_bus;
 
        /* First go down child busses */
        list_for_each_entry(child_bus, &bus->children, node)
-               __pcibios_remove_pci_devices(child_bus, purge_pe);
+               pcibios_remove_pci_devices(child_bus);
 
        pr_debug("PCI: Removing devices on bus %04x:%02x\n",
                 pci_domain_nr(bus),  bus->number);
        list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
-               pr_debug("     * Removing %s...\n", pci_name(dev));
-               eeh_remove_bus_device(dev, purge_pe);
+               pr_debug("   Removing %s...\n", pci_name(dev));
                pci_stop_and_remove_bus_device(dev);
        }
 }
 
-/**
- * pcibios_remove_pci_devices - remove all devices under this bus
- * @bus: the indicated PCI bus
- *
- * Remove all of the PCI devices under this bus both from the
- * linux pci device tree, and from the powerpc EEH address cache.
- */
-void pcibios_remove_pci_devices(struct pci_bus *bus)
-{
-       __pcibios_remove_pci_devices(bus, 1);
-}
 EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
 
 /**
@@ -76,7 +71,7 @@ EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
  */
 void pcibios_add_pci_devices(struct pci_bus * bus)
 {
-       int slotno, num, mode, pass, max;
+       int slotno, mode, pass, max;
        struct pci_dev *dev;
        struct device_node *dn = pci_bus_to_OF_node(bus);
 
@@ -90,11 +85,15 @@ void pcibios_add_pci_devices(struct pci_bus * bus)
                /* use ofdt-based probe */
                of_rescan_bus(dn, bus);
        } else if (mode == PCI_PROBE_NORMAL) {
-               /* use legacy probe */
+               /*
+                * Use legacy probe. In the partial hotplug case, we
+                * probably have grandchildren devices unplugged. So
+                * we don't check the return value from pci_scan_slot() in
+                * order for fully rescan all the way down to pick them up.
+                * They can have been removed during partial hotplug.
+                */
                slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
-               num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
-               if (!num)
-                       return;
+               pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
                pcibios_setup_bus_devices(bus);
                max = bus->busn_res.start;
                for (pass = 0; pass < 2; pass++) {
index 6b0ba5854d9960aff03bbd01b810543c9e369588..15d9105323bf5048009428c4bfc83d06edffb38f 100644 (file)
@@ -230,11 +230,14 @@ void of_scan_pci_bridge(struct pci_dev *dev)
                return;
        }
 
-       bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
+       bus = pci_find_bus(pci_domain_nr(dev->bus), busrange[0]);
        if (!bus) {
-               printk(KERN_ERR "Failed to create pci bus for %s\n",
-                      node->full_name);
-               return;
+               bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
+               if (!bus) {
+                       printk(KERN_ERR "Failed to create pci bus for %s\n",
+                              node->full_name);
+                       return;
+               }
        }
 
        bus->primary = dev->bus->number;
@@ -292,6 +295,38 @@ void of_scan_pci_bridge(struct pci_dev *dev)
 }
 EXPORT_SYMBOL(of_scan_pci_bridge);
 
+static struct pci_dev *of_scan_pci_dev(struct pci_bus *bus,
+                           struct device_node *dn)
+{
+       struct pci_dev *dev = NULL;
+       const u32 *reg;
+       int reglen, devfn;
+
+       pr_debug("  * %s\n", dn->full_name);
+       if (!of_device_is_available(dn))
+               return NULL;
+
+       reg = of_get_property(dn, "reg", &reglen);
+       if (reg == NULL || reglen < 20)
+               return NULL;
+       devfn = (reg[0] >> 8) & 0xff;
+
+       /* Check if the PCI device is already there */
+       dev = pci_get_slot(bus, devfn);
+       if (dev) {
+               pci_dev_put(dev);
+               return dev;
+       }
+
+       /* create a new pci_dev for this device */
+       dev = of_create_pci_dev(dn, bus, devfn);
+       if (!dev)
+               return NULL;
+
+       pr_debug("  dev header type: %x\n", dev->hdr_type);
+       return dev;
+}
+
 /**
  * __of_scan_bus - given a PCI bus node, setup bus and scan for child devices
  * @node: device tree node for the PCI bus
@@ -302,8 +337,6 @@ static void __of_scan_bus(struct device_node *node, struct pci_bus *bus,
                          int rescan_existing)
 {
        struct device_node *child;
-       const u32 *reg;
-       int reglen, devfn;
        struct pci_dev *dev;
 
        pr_debug("of_scan_bus(%s) bus no %d...\n",
@@ -311,16 +344,7 @@ static void __of_scan_bus(struct device_node *node, struct pci_bus *bus,
 
        /* Scan direct children */
        for_each_child_of_node(node, child) {
-               pr_debug("  * %s\n", child->full_name);
-               if (!of_device_is_available(child))
-                       continue;
-               reg = of_get_property(child, "reg", &reglen);
-               if (reg == NULL || reglen < 20)
-                       continue;
-               devfn = (reg[0] >> 8) & 0xff;
-
-               /* create a new pci_dev for this device */
-               dev = of_create_pci_dev(child, bus, devfn);
+               dev = of_scan_pci_dev(bus, child);
                if (!dev)
                        continue;
                pr_debug("    dev header type: %x\n", dev->hdr_type);
index 5eccda9fd33f5396b5a5c231db1c8051bcacf747..607902424e7377046943a14f7a8aeb56471327e4 100644 (file)
@@ -644,7 +644,8 @@ unsigned char ibm_architecture_vec[] = {
        W(0xfffe0000), W(0x003a0000),   /* POWER5/POWER5+ */
        W(0xffff0000), W(0x003e0000),   /* POWER6 */
        W(0xffff0000), W(0x003f0000),   /* POWER7 */
-       W(0xffff0000), W(0x004b0000),   /* POWER8 */
+       W(0xffff0000), W(0x004b0000),   /* POWER8E */
+       W(0xffff0000), W(0x004d0000),   /* POWER8 */
        W(0xffffffff), W(0x0f000004),   /* all 2.07-compliant */
        W(0xffffffff), W(0x0f000003),   /* all 2.06-compliant */
        W(0xffffffff), W(0x0f000002),   /* all 2.05-compliant */
@@ -706,7 +707,7 @@ unsigned char ibm_architecture_vec[] = {
         * must match by the macro below. Update the definition if
         * the structure layout changes.
         */
-#define IBM_ARCH_VEC_NRCORES_OFFSET    117
+#define IBM_ARCH_VEC_NRCORES_OFFSET    125
        W(NR_CPUS),                     /* number of cores supported */
        0,
        0,
index 654e479802f2098afb74c0fea0bb0b68e25707f5..f096e72262f41d121398f8fa27d5286bd8641bf4 100644 (file)
@@ -38,9 +38,6 @@ jiffies = jiffies_64 + 4;
 #endif
 SECTIONS
 {
-       . = 0;
-       reloc_start = .;
-
        . = KERNELBASE;
 
 /*
index 3f0c30ae4791db7597c3fac74740e09e0fb3b7c1..c33d939120c970f3f800b42b5dfa3739e28ac16f 100644 (file)
@@ -43,6 +43,7 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
 {
        unsigned long va;
        unsigned int penc;
+       unsigned long sllp;
 
        /*
         * We need 14 to 65 bits of va for a tlibe of 4K page
@@ -64,7 +65,9 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
                /* clear out bits after (52) [0....52.....63] */
                va &= ~((1ul << (64 - 52)) - 1);
                va |= ssize << 8;
-               va |= mmu_psize_defs[apsize].sllp << 6;
+               sllp = ((mmu_psize_defs[apsize].sllp & SLB_VSID_L) >> 6) |
+                       ((mmu_psize_defs[apsize].sllp & SLB_VSID_LP) >> 4);
+               va |= sllp << 5;
                asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2)
                             : : "r" (va), "r"(0), "i" (CPU_FTR_ARCH_206)
                             : "memory");
@@ -98,6 +101,7 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
 {
        unsigned long va;
        unsigned int penc;
+       unsigned long sllp;
 
        /* VPN_SHIFT can be atmost 12 */
        va = vpn << VPN_SHIFT;
@@ -113,7 +117,9 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
                /* clear out bits after(52) [0....52.....63] */
                va &= ~((1ul << (64 - 52)) - 1);
                va |= ssize << 8;
-               va |= mmu_psize_defs[apsize].sllp << 6;
+               sllp = ((mmu_psize_defs[apsize].sllp & SLB_VSID_L) >> 6) |
+                       ((mmu_psize_defs[apsize].sllp & SLB_VSID_LP) >> 4);
+               va |= sllp << 5;
                asm volatile(".long 0x7c000224 | (%0 << 11) | (0 << 21)"
                             : : "r"(va) : "memory");
                break;
@@ -554,6 +560,7 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
                        seg_off |= vpi << shift;
                }
                *vpn = vsid << (SID_SHIFT - VPN_SHIFT) | seg_off >> VPN_SHIFT;
+               break;
        case MMU_SEGSIZE_1T:
                /* We only have 40 - 23 bits of seg_off in avpn */
                seg_off = (avpn & 0x1ffff) << 23;
@@ -563,6 +570,7 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
                        seg_off |= vpi << shift;
                }
                *vpn = vsid << (SID_SHIFT_1T - VPN_SHIFT) | seg_off >> VPN_SHIFT;
+               break;
        default:
                *vpn = size = 0;
        }
index 08397217e8ace2d6ce3abc1a09a4fcc14977413f..5850798826cde0be9570368cb7968a9ea279b1e1 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <asm/cputhreads.h>
 #include <asm/sparsemem.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
@@ -1318,7 +1319,8 @@ static int update_cpu_associativity_changes_mask(void)
                        }
                }
                if (changed) {
-                       cpumask_set_cpu(cpu, changes);
+                       cpumask_or(changes, changes, cpu_sibling_mask(cpu));
+                       cpu = cpu_last_thread_sibling(cpu);
                }
        }
 
@@ -1426,7 +1428,7 @@ static int update_cpu_topology(void *data)
        if (!data)
                return -EINVAL;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
 
        for (update = data; update; update = update->next) {
                if (cpu != update->cpu)
@@ -1446,12 +1448,12 @@ static int update_cpu_topology(void *data)
  */
 int arch_update_cpu_topology(void)
 {
-       unsigned int cpu, changed = 0;
+       unsigned int cpu, sibling, changed = 0;
        struct topology_update_data *updates, *ud;
        unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
        cpumask_t updated_cpus;
        struct device *dev;
-       int weight, i = 0;
+       int weight, new_nid, i = 0;
 
        weight = cpumask_weight(&cpu_associativity_changes_mask);
        if (!weight)
@@ -1464,19 +1466,46 @@ int arch_update_cpu_topology(void)
        cpumask_clear(&updated_cpus);
 
        for_each_cpu(cpu, &cpu_associativity_changes_mask) {
-               ud = &updates[i++];
-               ud->cpu = cpu;
-               vphn_get_associativity(cpu, associativity);
-               ud->new_nid = associativity_to_nid(associativity);
-
-               if (ud->new_nid < 0 || !node_online(ud->new_nid))
-                       ud->new_nid = first_online_node;
+               /*
+                * If siblings aren't flagged for changes, updates list
+                * will be too short. Skip on this update and set for next
+                * update.
+                */
+               if (!cpumask_subset(cpu_sibling_mask(cpu),
+                                       &cpu_associativity_changes_mask)) {
+                       pr_info("Sibling bits not set for associativity "
+                                       "change, cpu%d\n", cpu);
+                       cpumask_or(&cpu_associativity_changes_mask,
+                                       &cpu_associativity_changes_mask,
+                                       cpu_sibling_mask(cpu));
+                       cpu = cpu_last_thread_sibling(cpu);
+                       continue;
+               }
 
-               ud->old_nid = numa_cpu_lookup_table[cpu];
-               cpumask_set_cpu(cpu, &updated_cpus);
+               /* Use associativity from first thread for all siblings */
+               vphn_get_associativity(cpu, associativity);
+               new_nid = associativity_to_nid(associativity);
+               if (new_nid < 0 || !node_online(new_nid))
+                       new_nid = first_online_node;
+
+               if (new_nid == numa_cpu_lookup_table[cpu]) {
+                       cpumask_andnot(&cpu_associativity_changes_mask,
+                                       &cpu_associativity_changes_mask,
+                                       cpu_sibling_mask(cpu));
+                       cpu = cpu_last_thread_sibling(cpu);
+                       continue;
+               }
 
-               if (i < weight)
-                       ud->next = &updates[i];
+               for_each_cpu(sibling, cpu_sibling_mask(cpu)) {
+                       ud = &updates[i++];
+                       ud->cpu = sibling;
+                       ud->new_nid = new_nid;
+                       ud->old_nid = numa_cpu_lookup_table[sibling];
+                       cpumask_set_cpu(sibling, &updated_cpus);
+                       if (i < weight)
+                               ud->next = &updates[i];
+               }
+               cpu = cpu_last_thread_sibling(cpu);
        }
 
        stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
index a3985aee77fec1ecd2fe9756257e3a46b9643b94..eeae308cf98253888a1af8792dd150e4410b08ef 100644 (file)
@@ -484,7 +484,7 @@ static bool is_ebb_event(struct perf_event *event)
         * use bit 63 of the event code for something else if they wish.
         */
        return (ppmu->flags & PPMU_EBB) &&
-              ((event->attr.config >> EVENT_CONFIG_EBB_SHIFT) & 1);
+              ((event->attr.config >> PERF_EVENT_CONFIG_EBB_SHIFT) & 1);
 }
 
 static int ebb_event_check(struct perf_event *event)
@@ -1252,8 +1252,11 @@ nocheck:
 
        ret = 0;
  out:
-       if (has_branch_stack(event))
+       if (has_branch_stack(event)) {
                power_pmu_bhrb_enable(event);
+               cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
+                                       event->attr.branch_sample_type);
+       }
 
        perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
index 96a64d6a8bdf3dfbba1c5a57f16bcb38d3c8a7ce..2ee4a707f0df85c37dba15c6ab5f4e7f84e553fc 100644 (file)
         (EVENT_UNIT_MASK      << EVENT_UNIT_SHIFT)             |       \
         (EVENT_COMBINE_MASK   << EVENT_COMBINE_SHIFT)          |       \
         (EVENT_MARKED_MASK    << EVENT_MARKED_SHIFT)           |       \
-        (EVENT_EBB_MASK       << EVENT_CONFIG_EBB_SHIFT)       |       \
+        (EVENT_EBB_MASK       << PERF_EVENT_CONFIG_EBB_SHIFT)  |       \
          EVENT_PSEL_MASK)
 
 /* MMCRA IFM bits - POWER8 */
@@ -233,10 +233,10 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
        pmc   = (event >> EVENT_PMC_SHIFT)        & EVENT_PMC_MASK;
        unit  = (event >> EVENT_UNIT_SHIFT)       & EVENT_UNIT_MASK;
        cache = (event >> EVENT_CACHE_SEL_SHIFT)  & EVENT_CACHE_SEL_MASK;
-       ebb   = (event >> EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
+       ebb   = (event >> PERF_EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
 
        /* Clear the EBB bit in the event, so event checks work below */
-       event &= ~(EVENT_EBB_MASK << EVENT_CONFIG_EBB_SHIFT);
+       event &= ~(EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT);
 
        if (pmc) {
                if (pmc > 6)
@@ -561,18 +561,13 @@ static int power8_generic_events[] = {
 static u64 power8_bhrb_filter_map(u64 branch_sample_type)
 {
        u64 pmu_bhrb_filter = 0;
-       u64 br_privilege = branch_sample_type & ONLY_PLM;
 
-       /* BHRB and regular PMU events share the same prvillege state
+       /* BHRB and regular PMU events share the same privilege state
         * filter configuration. BHRB is always recorded along with a
-        * regular PMU event. So privilege state filter criteria for BHRB
-        * and the companion PMU events has to be the same. As a default
-        * "perf record" tool sets all privillege bits ON when no filter
-        * criteria is provided in the command line. So as along as all
-        * privillege bits are ON or they are OFF, we are good to go.
+        * regular PMU event. As the privilege state filter is handled
+        * in the basic PMC configuration of the accompanying regular
+        * PMU event, we ignore any separate BHRB specific request.
         */
-       if ((br_privilege != 7) && (br_privilege != 0))
-               return -1;
 
        /* No branch filter requested */
        if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY)
@@ -621,10 +616,19 @@ static struct power_pmu power8_pmu = {
 
 static int __init init_power8_pmu(void)
 {
+       int rc;
+
        if (!cur_cpu_spec->oprofile_cpu_type ||
            strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power8"))
                return -ENODEV;
 
-       return register_power_pmu(&power8_pmu);
+       rc = register_power_pmu(&power8_pmu);
+       if (rc)
+               return rc;
+
+       /* Tell userspace that EBB is supported */
+       cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_EBB;
+
+       return 0;
 }
 early_initcall(init_power8_pmu);
index 969cce73055af337f3b15c9c12df27dc3aebb4ed..79663d26e6eaa1de8749c6994316737f991106ab 100644 (file)
@@ -114,7 +114,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
         * the root bridge. So it's not reasonable to continue
         * the probing.
         */
-       if (!dn || !edev)
+       if (!dn || !edev || edev->pe)
                return 0;
 
        /* Skip for PCI-ISA bridge */
@@ -122,8 +122,19 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
                return 0;
 
        /* Initialize eeh device */
-       edev->class_code        = dev->class;
-       edev->mode              = 0;
+       edev->class_code = dev->class;
+       edev->mode      &= 0xFFFFFF00;
+       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+               edev->mode |= EEH_DEV_BRIDGE;
+       if (pci_is_pcie(dev)) {
+               edev->pcie_cap = pci_pcie_cap(dev);
+
+               if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
+                       edev->mode |= EEH_DEV_ROOT_PORT;
+               else if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM)
+                       edev->mode |= EEH_DEV_DS_PORT;
+       }
+
        edev->config_addr       = ((dev->bus->number << 8) | dev->devfn);
        edev->pe_config_addr    = phb->bdfn_to_pe(phb, dev->bus, dev->devfn & 0xff);
 
index 49b57b9f835d787977817db8f093d40c354ac7d5..d8140b125e62508720388d683a5028199d62ff28 100644 (file)
@@ -1266,7 +1266,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
                opal_pci_set_pe(phb_id, 0, 0, 7, 1, 1 , OPAL_MAP_PE);
 }
 
-void pnv_pci_init_ioda2_phb(struct device_node *np)
+void __init pnv_pci_init_ioda2_phb(struct device_node *np)
 {
        pnv_pci_init_ioda_phb(np, 0, PNV_PHB_IODA2);
 }
index 1bd3399146ed6f945f24308ea95883bffdce8d28..62b4f8025de005ad77bdbfcd42024d25614eb79c 100644 (file)
@@ -19,7 +19,6 @@ config PPC_PSERIES
        select ZLIB_DEFLATE
        select PPC_DOORBELL
        select HAVE_CONTEXT_TRACKING
-       select HOTPLUG if SMP
        select HOTPLUG_CPU if SMP
        default y
 
index b456b157d33d107842a42d3b0c3d0da36e9ea121..7fbc25b1813fe59ea80eceba65cb2a76027c0eec 100644 (file)
@@ -133,6 +133,48 @@ static int pseries_eeh_init(void)
        return 0;
 }
 
+static int pseries_eeh_cap_start(struct device_node *dn)
+{
+       struct pci_dn *pdn = PCI_DN(dn);
+       u32 status;
+
+       if (!pdn)
+               return 0;
+
+       rtas_read_config(pdn, PCI_STATUS, 2, &status);
+       if (!(status & PCI_STATUS_CAP_LIST))
+               return 0;
+
+       return PCI_CAPABILITY_LIST;
+}
+
+
+static int pseries_eeh_find_cap(struct device_node *dn, int cap)
+{
+       struct pci_dn *pdn = PCI_DN(dn);
+       int pos = pseries_eeh_cap_start(dn);
+       int cnt = 48;   /* Maximal number of capabilities */
+       u32 id;
+
+       if (!pos)
+               return 0;
+
+        while (cnt--) {
+               rtas_read_config(pdn, pos, 1, &pos);
+               if (pos < 0x40)
+                       break;
+               pos &= ~3;
+               rtas_read_config(pdn, pos + PCI_CAP_LIST_ID, 1, &id);
+               if (id == 0xff)
+                       break;
+               if (id == cap)
+                       return pos;
+               pos += PCI_CAP_LIST_NEXT;
+       }
+
+       return 0;
+}
+
 /**
  * pseries_eeh_of_probe - EEH probe on the given device
  * @dn: OF node
@@ -146,14 +188,16 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
 {
        struct eeh_dev *edev;
        struct eeh_pe pe;
+       struct pci_dn *pdn = PCI_DN(dn);
        const u32 *class_code, *vendor_id, *device_id;
        const u32 *regs;
+       u32 pcie_flags;
        int enable = 0;
        int ret;
 
        /* Retrieve OF node and eeh device */
        edev = of_node_to_eeh_dev(dn);
-       if (!of_device_is_available(dn))
+       if (edev->pe || !of_device_is_available(dn))
                return NULL;
 
        /* Retrieve class/vendor/device IDs */
@@ -167,9 +211,26 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
        if (dn->type && !strcmp(dn->type, "isa"))
                return NULL;
 
-       /* Update class code and mode of eeh device */
+       /*
+        * Update class code and mode of eeh device. We need
+        * correctly reflects that current device is root port
+        * or PCIe switch downstream port.
+        */
        edev->class_code = *class_code;
-       edev->mode = 0;
+       edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP);
+       edev->mode &= 0xFFFFFF00;
+       if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) {
+               edev->mode |= EEH_DEV_BRIDGE;
+               if (edev->pcie_cap) {
+                       rtas_read_config(pdn, edev->pcie_cap + PCI_EXP_FLAGS,
+                                        2, &pcie_flags);
+                       pcie_flags = (pcie_flags & PCI_EXP_FLAGS_TYPE) >> 4;
+                       if (pcie_flags == PCI_EXP_TYPE_ROOT_PORT)
+                               edev->mode |= EEH_DEV_ROOT_PORT;
+                       else if (pcie_flags == PCI_EXP_TYPE_DOWNSTREAM)
+                               edev->mode |= EEH_DEV_DS_PORT;
+               }
+       }
 
        /* Retrieve the device address */
        regs = of_get_property(dn, "reg", NULL);
index 02d6e21619bb6c677771c0dc6ecaabb5e1d417d5..8bad880bd177a2efaf9887b0509593401112aee4 100644 (file)
@@ -146,7 +146,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
        flags = 0;
 
        /* Make pHyp happy */
-       if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU))
+       if ((rflags & _PAGE_NO_CACHE) && !(rflags & _PAGE_WRITETHRU))
                hpte_r &= ~_PAGE_COHERENT;
        if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N))
                flags |= H_COALESCE_CAND;
index 7b3cbde8c78378e25fb0d82ca60b58e20ffe51f5..721c0586b284d42aec0dfe69bdc178e191bcf222 100644 (file)
@@ -287,6 +287,9 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
        unsigned long *savep;
        struct rtas_error_log *h, *errhdr = NULL;
 
+       /* Mask top two bits */
+       regs->gpr[3] &= ~(0x3UL << 62);
+
        if (!VALID_FWNMI_BUFFER(regs->gpr[3])) {
                printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]);
                return NULL;
index 22f75b504f7f9bb8ef91ef80e8a1433995e6c6dc..8a4cae78f03c91e510f307d25e8f5467211725c3 100644 (file)
@@ -118,6 +118,7 @@ config S390
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
+       select HAVE_KERNEL_LZ4
        select HAVE_KERNEL_LZMA
        select HAVE_KERNEL_LZO
        select HAVE_KERNEL_XZ
@@ -227,11 +228,12 @@ config MARCH_Z196
          not work on older machines.
 
 config MARCH_ZEC12
-       bool "IBM zEC12"
+       bool "IBM zBC12 and zEC12"
        select HAVE_MARCH_ZEC12_FEATURES if 64BIT
        help
-         Select this to enable optimizations for IBM zEC12 (2827 series). The
-         kernel will be slightly faster but will not work on older machines.
+         Select this to enable optimizations for IBM zBC12 and zEC12 (2828 and
+         2827 series). The kernel will be slightly faster but will not work on
+         older machines.
 
 endchoice
 
@@ -709,6 +711,7 @@ config S390_GUEST
        def_bool y
        prompt "s390 support for virtio devices"
        depends on 64BIT
+       select TTY
        select VIRTUALIZATION
        select VIRTIO
        select VIRTIO_CONSOLE
index 3ad8f61c99852c3fe7183a15aacfcd96ace3535a..866ecbe670e499632ef59d514dd04a280f46b890 100644 (file)
@@ -6,9 +6,9 @@
 
 BITS := $(if $(CONFIG_64BIT),64,31)
 
-targets        := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \
-          vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo misc.o piggy.o \
-          sizes.h head$(BITS).o
+targets        := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2
+targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4
+targets += misc.o piggy.o sizes.h head$(BITS).o
 
 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
@@ -48,6 +48,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin
 
 suffix-$(CONFIG_KERNEL_GZIP)  := gz
 suffix-$(CONFIG_KERNEL_BZIP2) := bz2
+suffix-$(CONFIG_KERNEL_LZ4)  := lz4
 suffix-$(CONFIG_KERNEL_LZMA)  := lzma
 suffix-$(CONFIG_KERNEL_LZO)  := lzo
 suffix-$(CONFIG_KERNEL_XZ)  := xz
@@ -56,6 +57,8 @@ $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y)
        $(call if_changed,gzip)
 $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y)
        $(call if_changed,bzip2)
+$(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y)
+       $(call if_changed,lz4)
 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y)
        $(call if_changed,lzma)
 $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y)
index c4c6a1cf221bde749673b59dccb6e3c6113a0b4c..57cbaff1f39778b98b1de870e34f99cc14043687 100644 (file)
@@ -47,6 +47,10 @@ static unsigned long free_mem_end_ptr;
 #include "../../../../lib/decompress_bunzip2.c"
 #endif
 
+#ifdef CONFIG_KERNEL_LZ4
+#include "../../../../lib/decompress_unlz4.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZMA
 #include "../../../../lib/decompress_unlzma.c"
 #endif
index 4d8604e311f3aaf6b1799bd78760bcc52a5befab..7d46767587337c3874bd61c43e01a0a72f965303 100644 (file)
@@ -693,7 +693,7 @@ static inline int find_next_bit_left(const unsigned long *addr,
        size -= offset;
        p = addr + offset / BITS_PER_LONG;
        if (bit) {
-               set = __flo_word(0, *p & (~0UL << bit));
+               set = __flo_word(0, *p & (~0UL >> bit));
                if (set >= size)
                        return size + offset;
                if (set < BITS_PER_LONG)
index a6fc037671b11d0a2e96226256f9e36cd8e4d65d..500aa1029bcb2d2ed12ae352a91cec068322615b 100644 (file)
@@ -52,12 +52,13 @@ static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs)
 
 static bool is_in_guest(struct pt_regs *regs)
 {
-       unsigned long ip = instruction_pointer(regs);
-
        if (user_mode(regs))
                return false;
-
-       return ip == (unsigned long) &sie_exit;
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
+       return instruction_pointer(regs) == (unsigned long) &sie_exit;
+#else
+       return false;
+#endif
 }
 
 static unsigned long guest_is_user_mode(struct pt_regs *regs)
index 497451ec5e267f3be025b9b719cf4f2278262d97..aeed8a61fa0d4f1b4862a98cab44e29beda63699 100644 (file)
@@ -994,6 +994,7 @@ static void __init setup_hwcaps(void)
                strcpy(elf_platform, "z196");
                break;
        case 0x2827:
+       case 0x2828:
                strcpy(elf_platform, "zEC12");
                break;
        }
index ce36ea80e4f9157f5c754b51c1ff9c700106d689..ad446b0c55b6076d5aaf7f095f1ddc91b5e38bf4 100644 (file)
@@ -69,6 +69,7 @@ static void __init setup_zero_pages(void)
                order = 2;
                break;
        case 0x2827:    /* zEC12 */
+       case 0x2828:    /* zEC12 */
        default:
                order = 5;
                break;
index ffeb17ce7f313d914a38de3ee21dad5867991b9d..930783d2c99beb305b2346a220f414d98a4ba406 100644 (file)
@@ -440,7 +440,7 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops)
                switch (id.machine) {
                case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break;
                case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break;
-               case 0x2827:              ops->cpu_type = "s390/zEC12"; break;
+               case 0x2827: case 0x2828: ops->cpu_type = "s390/zEC12"; break;
                default: return -ENODEV;
                }
        }
index 2051821724c6db6d33ac89b333bc5214b61b68ea..0cf4097b71e8d02051a3976d86b63226ab2b8924 100644 (file)
@@ -22,7 +22,7 @@ CONFIG_PREEMPT=y
 CONFIG_CMDLINE_OVERWRITE=y
 CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs"
 CONFIG_PCI=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
 CONFIG_PACKET=y
index d606463aa6d63bfdab5641e6bd7e6b68545e32d9..b7388a425f0994ba87a30a27fe8ba57d7e3e5457 100644 (file)
@@ -225,7 +225,7 @@ static void low_free(unsigned long size, unsigned long addr)
        unsigned long nr_pages;
 
        nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
-       efi_call_phys2(sys_table->boottime->free_pages, addr, size);
+       efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages);
 }
 
 static void find_bits(unsigned long mask, u8 *pos, u8 *size)
index 7d6ba9db1be99696784aeba62343eeebff9c32dd..6c63c358a7e689070881361b003f102c154e9c96 100644 (file)
@@ -27,7 +27,6 @@ obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o
 obj-$(CONFIG_CRYPTO_CRC32_PCLMUL) += crc32-pclmul.o
 obj-$(CONFIG_CRYPTO_SHA256_SSSE3) += sha256-ssse3.o
 obj-$(CONFIG_CRYPTO_SHA512_SSSE3) += sha512-ssse3.o
-obj-$(CONFIG_CRYPTO_CRCT10DIF_PCLMUL) += crct10dif-pclmul.o
 
 # These modules require assembler to support AVX.
 ifeq ($(avx_supported),yes)
@@ -82,4 +81,3 @@ crc32c-intel-$(CONFIG_64BIT) += crc32c-pcl-intel-asm_64.o
 crc32-pclmul-y := crc32-pclmul_asm.o crc32-pclmul_glue.o
 sha256-ssse3-y := sha256-ssse3-asm.o sha256-avx-asm.o sha256-avx2-asm.o sha256_ssse3_glue.o
 sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o
-crct10dif-pclmul-y := crct10dif-pcl-asm_64.o crct10dif-pclmul_glue.o
diff --git a/arch/x86/crypto/crct10dif-pcl-asm_64.S b/arch/x86/crypto/crct10dif-pcl-asm_64.S
deleted file mode 100644 (file)
index 35e9756..0000000
+++ /dev/null
@@ -1,643 +0,0 @@
-########################################################################
-# Implement fast CRC-T10DIF computation with SSE and PCLMULQDQ instructions
-#
-# Copyright (c) 2013, Intel Corporation
-#
-# Authors:
-#     Erdinc Ozturk <erdinc.ozturk@intel.com>
-#     Vinodh Gopal <vinodh.gopal@intel.com>
-#     James Guilford <james.guilford@intel.com>
-#     Tim Chen <tim.c.chen@linux.intel.com>
-#
-# This software is available to you under a choice of one of two
-# licenses.  You may choose to be licensed under the terms of the GNU
-# General Public License (GPL) Version 2, available from the file
-# COPYING in the main directory of this source tree, or the
-# OpenIB.org BSD license below:
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the
-#   distribution.
-#
-# * Neither the name of the Intel Corporation nor the names of its
-#   contributors may be used to endorse or promote products derived from
-#   this software without specific prior written permission.
-#
-#
-# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY
-# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-########################################################################
-#       Function API:
-#       UINT16 crc_t10dif_pcl(
-#               UINT16 init_crc, //initial CRC value, 16 bits
-#               const unsigned char *buf, //buffer pointer to calculate CRC on
-#               UINT64 len //buffer length in bytes (64-bit data)
-#       );
-#
-#       Reference paper titled "Fast CRC Computation for Generic
-#      Polynomials Using PCLMULQDQ Instruction"
-#       URL: http://www.intel.com/content/dam/www/public/us/en/documents
-#  /white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
-#
-#
-
-#include <linux/linkage.h>
-
-.text
-
-#define        arg1 %rdi
-#define        arg2 %rsi
-#define        arg3 %rdx
-
-#define        arg1_low32 %edi
-
-ENTRY(crc_t10dif_pcl)
-.align 16
-
-       # adjust the 16-bit initial_crc value, scale it to 32 bits
-       shl     $16, arg1_low32
-
-       # Allocate Stack Space
-       mov     %rsp, %rcx
-       sub     $16*2, %rsp
-       # align stack to 16 byte boundary
-       and     $~(0x10 - 1), %rsp
-
-       # check if smaller than 256
-       cmp     $256, arg3
-
-       # for sizes less than 128, we can't fold 64B at a time...
-       jl      _less_than_128
-
-
-       # load the initial crc value
-       movd    arg1_low32, %xmm10      # initial crc
-
-       # crc value does not need to be byte-reflected, but it needs
-       # to be moved to the high part of the register.
-       # because data will be byte-reflected and will align with
-       # initial crc at correct place.
-       pslldq  $12, %xmm10
-
-       movdqa  SHUF_MASK(%rip), %xmm11
-       # receive the initial 64B data, xor the initial crc value
-       movdqu  16*0(arg2), %xmm0
-       movdqu  16*1(arg2), %xmm1
-       movdqu  16*2(arg2), %xmm2
-       movdqu  16*3(arg2), %xmm3
-       movdqu  16*4(arg2), %xmm4
-       movdqu  16*5(arg2), %xmm5
-       movdqu  16*6(arg2), %xmm6
-       movdqu  16*7(arg2), %xmm7
-
-       pshufb  %xmm11, %xmm0
-       # XOR the initial_crc value
-       pxor    %xmm10, %xmm0
-       pshufb  %xmm11, %xmm1
-       pshufb  %xmm11, %xmm2
-       pshufb  %xmm11, %xmm3
-       pshufb  %xmm11, %xmm4
-       pshufb  %xmm11, %xmm5
-       pshufb  %xmm11, %xmm6
-       pshufb  %xmm11, %xmm7
-
-       movdqa  rk3(%rip), %xmm10       #xmm10 has rk3 and rk4
-                                       #imm value of pclmulqdq instruction
-                                       #will determine which constant to use
-
-       #################################################################
-       # we subtract 256 instead of 128 to save one instruction from the loop
-       sub     $256, arg3
-
-       # at this section of the code, there is 64*x+y (0<=y<64) bytes of
-       # buffer. The _fold_64_B_loop will fold 64B at a time
-       # until we have 64+y Bytes of buffer
-
-
-       # fold 64B at a time. This section of the code folds 4 xmm
-       # registers in parallel
-_fold_64_B_loop:
-
-       # update the buffer pointer
-       add     $128, arg2              #    buf += 64#
-
-       movdqu  16*0(arg2), %xmm9
-       movdqu  16*1(arg2), %xmm12
-       pshufb  %xmm11, %xmm9
-       pshufb  %xmm11, %xmm12
-       movdqa  %xmm0, %xmm8
-       movdqa  %xmm1, %xmm13
-       pclmulqdq       $0x0 , %xmm10, %xmm0
-       pclmulqdq       $0x11, %xmm10, %xmm8
-       pclmulqdq       $0x0 , %xmm10, %xmm1
-       pclmulqdq       $0x11, %xmm10, %xmm13
-       pxor    %xmm9 , %xmm0
-       xorps   %xmm8 , %xmm0
-       pxor    %xmm12, %xmm1
-       xorps   %xmm13, %xmm1
-
-       movdqu  16*2(arg2), %xmm9
-       movdqu  16*3(arg2), %xmm12
-       pshufb  %xmm11, %xmm9
-       pshufb  %xmm11, %xmm12
-       movdqa  %xmm2, %xmm8
-       movdqa  %xmm3, %xmm13
-       pclmulqdq       $0x0, %xmm10, %xmm2
-       pclmulqdq       $0x11, %xmm10, %xmm8
-       pclmulqdq       $0x0, %xmm10, %xmm3
-       pclmulqdq       $0x11, %xmm10, %xmm13
-       pxor    %xmm9 , %xmm2
-       xorps   %xmm8 , %xmm2
-       pxor    %xmm12, %xmm3
-       xorps   %xmm13, %xmm3
-
-       movdqu  16*4(arg2), %xmm9
-       movdqu  16*5(arg2), %xmm12
-       pshufb  %xmm11, %xmm9
-       pshufb  %xmm11, %xmm12
-       movdqa  %xmm4, %xmm8
-       movdqa  %xmm5, %xmm13
-       pclmulqdq       $0x0,  %xmm10, %xmm4
-       pclmulqdq       $0x11, %xmm10, %xmm8
-       pclmulqdq       $0x0,  %xmm10, %xmm5
-       pclmulqdq       $0x11, %xmm10, %xmm13
-       pxor    %xmm9 ,  %xmm4
-       xorps   %xmm8 ,  %xmm4
-       pxor    %xmm12,  %xmm5
-       xorps   %xmm13,  %xmm5
-
-       movdqu  16*6(arg2), %xmm9
-       movdqu  16*7(arg2), %xmm12
-       pshufb  %xmm11, %xmm9
-       pshufb  %xmm11, %xmm12
-       movdqa  %xmm6 , %xmm8
-       movdqa  %xmm7 , %xmm13
-       pclmulqdq       $0x0 , %xmm10, %xmm6
-       pclmulqdq       $0x11, %xmm10, %xmm8
-       pclmulqdq       $0x0 , %xmm10, %xmm7
-       pclmulqdq       $0x11, %xmm10, %xmm13
-       pxor    %xmm9 , %xmm6
-       xorps   %xmm8 , %xmm6
-       pxor    %xmm12, %xmm7
-       xorps   %xmm13, %xmm7
-
-       sub     $128, arg3
-
-       # check if there is another 64B in the buffer to be able to fold
-       jge     _fold_64_B_loop
-       ##################################################################
-
-
-       add     $128, arg2
-       # at this point, the buffer pointer is pointing at the last y Bytes
-       # of the buffer the 64B of folded data is in 4 of the xmm
-       # registers: xmm0, xmm1, xmm2, xmm3
-
-
-       # fold the 8 xmm registers to 1 xmm register with different constants
-
-       movdqa  rk9(%rip), %xmm10
-       movdqa  %xmm0, %xmm8
-       pclmulqdq       $0x11, %xmm10, %xmm0
-       pclmulqdq       $0x0 , %xmm10, %xmm8
-       pxor    %xmm8, %xmm7
-       xorps   %xmm0, %xmm7
-
-       movdqa  rk11(%rip), %xmm10
-       movdqa  %xmm1, %xmm8
-       pclmulqdq        $0x11, %xmm10, %xmm1
-       pclmulqdq        $0x0 , %xmm10, %xmm8
-       pxor    %xmm8, %xmm7
-       xorps   %xmm1, %xmm7
-
-       movdqa  rk13(%rip), %xmm10
-       movdqa  %xmm2, %xmm8
-       pclmulqdq        $0x11, %xmm10, %xmm2
-       pclmulqdq        $0x0 , %xmm10, %xmm8
-       pxor    %xmm8, %xmm7
-       pxor    %xmm2, %xmm7
-
-       movdqa  rk15(%rip), %xmm10
-       movdqa  %xmm3, %xmm8
-       pclmulqdq       $0x11, %xmm10, %xmm3
-       pclmulqdq       $0x0 , %xmm10, %xmm8
-       pxor    %xmm8, %xmm7
-       xorps   %xmm3, %xmm7
-
-       movdqa  rk17(%rip), %xmm10
-       movdqa  %xmm4, %xmm8
-       pclmulqdq       $0x11, %xmm10, %xmm4
-       pclmulqdq       $0x0 , %xmm10, %xmm8
-       pxor    %xmm8, %xmm7
-       pxor    %xmm4, %xmm7
-
-       movdqa  rk19(%rip), %xmm10
-       movdqa  %xmm5, %xmm8
-       pclmulqdq       $0x11, %xmm10, %xmm5
-       pclmulqdq       $0x0 , %xmm10, %xmm8
-       pxor    %xmm8, %xmm7
-       xorps   %xmm5, %xmm7
-
-       movdqa  rk1(%rip), %xmm10       #xmm10 has rk1 and rk2
-                                       #imm value of pclmulqdq instruction
-                                       #will determine which constant to use
-       movdqa  %xmm6, %xmm8
-       pclmulqdq       $0x11, %xmm10, %xmm6
-       pclmulqdq       $0x0 , %xmm10, %xmm8
-       pxor    %xmm8, %xmm7
-       pxor    %xmm6, %xmm7
-
-
-       # instead of 64, we add 48 to the loop counter to save 1 instruction
-       # from the loop instead of a cmp instruction, we use the negative
-       # flag with the jl instruction
-       add     $128-16, arg3
-       jl      _final_reduction_for_128
-
-       # now we have 16+y bytes left to reduce. 16 Bytes is in register xmm7
-       # and the rest is in memory. We can fold 16 bytes at a time if y>=16
-       # continue folding 16B at a time
-
-_16B_reduction_loop:
-       movdqa  %xmm7, %xmm8
-       pclmulqdq       $0x11, %xmm10, %xmm7
-       pclmulqdq       $0x0 , %xmm10, %xmm8
-       pxor    %xmm8, %xmm7
-       movdqu  (arg2), %xmm0
-       pshufb  %xmm11, %xmm0
-       pxor    %xmm0 , %xmm7
-       add     $16, arg2
-       sub     $16, arg3
-       # instead of a cmp instruction, we utilize the flags with the
-       # jge instruction equivalent of: cmp arg3, 16-16
-       # check if there is any more 16B in the buffer to be able to fold
-       jge     _16B_reduction_loop
-
-       #now we have 16+z bytes left to reduce, where 0<= z < 16.
-       #first, we reduce the data in the xmm7 register
-
-
-_final_reduction_for_128:
-       # check if any more data to fold. If not, compute the CRC of
-       # the final 128 bits
-       add     $16, arg3
-       je      _128_done
-
-       # here we are getting data that is less than 16 bytes.
-       # since we know that there was data before the pointer, we can
-       # offset the input pointer before the actual point, to receive
-       # exactly 16 bytes. after that the registers need to be adjusted.
-_get_last_two_xmms:
-       movdqa  %xmm7, %xmm2
-
-       movdqu  -16(arg2, arg3), %xmm1
-       pshufb  %xmm11, %xmm1
-
-       # get rid of the extra data that was loaded before
-       # load the shift constant
-       lea     pshufb_shf_table+16(%rip), %rax
-       sub     arg3, %rax
-       movdqu  (%rax), %xmm0
-
-       # shift xmm2 to the left by arg3 bytes
-       pshufb  %xmm0, %xmm2
-
-       # shift xmm7 to the right by 16-arg3 bytes
-       pxor    mask1(%rip), %xmm0
-       pshufb  %xmm0, %xmm7
-       pblendvb        %xmm2, %xmm1    #xmm0 is implicit
-
-       # fold 16 Bytes
-       movdqa  %xmm1, %xmm2
-       movdqa  %xmm7, %xmm8
-       pclmulqdq       $0x11, %xmm10, %xmm7
-       pclmulqdq       $0x0 , %xmm10, %xmm8
-       pxor    %xmm8, %xmm7
-       pxor    %xmm2, %xmm7
-
-_128_done:
-       # compute crc of a 128-bit value
-       movdqa  rk5(%rip), %xmm10       # rk5 and rk6 in xmm10
-       movdqa  %xmm7, %xmm0
-
-       #64b fold
-       pclmulqdq       $0x1, %xmm10, %xmm7
-       pslldq  $8   ,  %xmm0
-       pxor    %xmm0,  %xmm7
-
-       #32b fold
-       movdqa  %xmm7, %xmm0
-
-       pand    mask2(%rip), %xmm0
-
-       psrldq  $12, %xmm7
-       pclmulqdq       $0x10, %xmm10, %xmm7
-       pxor    %xmm0, %xmm7
-
-       #barrett reduction
-_barrett:
-       movdqa  rk7(%rip), %xmm10       # rk7 and rk8 in xmm10
-       movdqa  %xmm7, %xmm0
-       pclmulqdq       $0x01, %xmm10, %xmm7
-       pslldq  $4, %xmm7
-       pclmulqdq       $0x11, %xmm10, %xmm7
-
-       pslldq  $4, %xmm7
-       pxor    %xmm0, %xmm7
-       pextrd  $1, %xmm7, %eax
-
-_cleanup:
-       # scale the result back to 16 bits
-       shr     $16, %eax
-       mov     %rcx, %rsp
-       ret
-
-########################################################################
-
-.align 16
-_less_than_128:
-
-       # check if there is enough buffer to be able to fold 16B at a time
-       cmp     $32, arg3
-       jl      _less_than_32
-       movdqa  SHUF_MASK(%rip), %xmm11
-
-       # now if there is, load the constants
-       movdqa  rk1(%rip), %xmm10       # rk1 and rk2 in xmm10
-
-       movd    arg1_low32, %xmm0       # get the initial crc value
-       pslldq  $12, %xmm0      # align it to its correct place
-       movdqu  (arg2), %xmm7   # load the plaintext
-       pshufb  %xmm11, %xmm7   # byte-reflect the plaintext
-       pxor    %xmm0, %xmm7
-
-
-       # update the buffer pointer
-       add     $16, arg2
-
-       # update the counter. subtract 32 instead of 16 to save one
-       # instruction from the loop
-       sub     $32, arg3
-
-       jmp     _16B_reduction_loop
-
-
-.align 16
-_less_than_32:
-       # mov initial crc to the return value. this is necessary for
-       # zero-length buffers.
-       mov     arg1_low32, %eax
-       test    arg3, arg3
-       je      _cleanup
-
-       movdqa  SHUF_MASK(%rip), %xmm11
-
-       movd    arg1_low32, %xmm0       # get the initial crc value
-       pslldq  $12, %xmm0      # align it to its correct place
-
-       cmp     $16, arg3
-       je      _exact_16_left
-       jl      _less_than_16_left
-
-       movdqu  (arg2), %xmm7   # load the plaintext
-       pshufb  %xmm11, %xmm7   # byte-reflect the plaintext
-       pxor    %xmm0 , %xmm7   # xor the initial crc value
-       add     $16, arg2
-       sub     $16, arg3
-       movdqa  rk1(%rip), %xmm10       # rk1 and rk2 in xmm10
-       jmp     _get_last_two_xmms
-
-
-.align 16
-_less_than_16_left:
-       # use stack space to load data less than 16 bytes, zero-out
-       # the 16B in memory first.
-
-       pxor    %xmm1, %xmm1
-       mov     %rsp, %r11
-       movdqa  %xmm1, (%r11)
-
-       cmp     $4, arg3
-       jl      _only_less_than_4
-
-       # backup the counter value
-       mov     arg3, %r9
-       cmp     $8, arg3
-       jl      _less_than_8_left
-
-       # load 8 Bytes
-       mov     (arg2), %rax
-       mov     %rax, (%r11)
-       add     $8, %r11
-       sub     $8, arg3
-       add     $8, arg2
-_less_than_8_left:
-
-       cmp     $4, arg3
-       jl      _less_than_4_left
-
-       # load 4 Bytes
-       mov     (arg2), %eax
-       mov     %eax, (%r11)
-       add     $4, %r11
-       sub     $4, arg3
-       add     $4, arg2
-_less_than_4_left:
-
-       cmp     $2, arg3
-       jl      _less_than_2_left
-
-       # load 2 Bytes
-       mov     (arg2), %ax
-       mov     %ax, (%r11)
-       add     $2, %r11
-       sub     $2, arg3
-       add     $2, arg2
-_less_than_2_left:
-       cmp     $1, arg3
-        jl      _zero_left
-
-       # load 1 Byte
-       mov     (arg2), %al
-       mov     %al, (%r11)
-_zero_left:
-       movdqa  (%rsp), %xmm7
-       pshufb  %xmm11, %xmm7
-       pxor    %xmm0 , %xmm7   # xor the initial crc value
-
-       # shl r9, 4
-       lea     pshufb_shf_table+16(%rip), %rax
-       sub     %r9, %rax
-       movdqu  (%rax), %xmm0
-       pxor    mask1(%rip), %xmm0
-
-       pshufb  %xmm0, %xmm7
-       jmp     _128_done
-
-.align 16
-_exact_16_left:
-       movdqu  (arg2), %xmm7
-       pshufb  %xmm11, %xmm7
-       pxor    %xmm0 , %xmm7   # xor the initial crc value
-
-       jmp     _128_done
-
-_only_less_than_4:
-       cmp     $3, arg3
-       jl      _only_less_than_3
-
-       # load 3 Bytes
-       mov     (arg2), %al
-       mov     %al, (%r11)
-
-       mov     1(arg2), %al
-       mov     %al, 1(%r11)
-
-       mov     2(arg2), %al
-       mov     %al, 2(%r11)
-
-       movdqa   (%rsp), %xmm7
-       pshufb   %xmm11, %xmm7
-       pxor     %xmm0 , %xmm7  # xor the initial crc value
-
-       psrldq  $5, %xmm7
-
-       jmp     _barrett
-_only_less_than_3:
-       cmp     $2, arg3
-       jl      _only_less_than_2
-
-       # load 2 Bytes
-       mov     (arg2), %al
-       mov     %al, (%r11)
-
-       mov     1(arg2), %al
-       mov     %al, 1(%r11)
-
-       movdqa  (%rsp), %xmm7
-       pshufb  %xmm11, %xmm7
-       pxor    %xmm0 , %xmm7   # xor the initial crc value
-
-       psrldq  $6, %xmm7
-
-       jmp     _barrett
-_only_less_than_2:
-
-       # load 1 Byte
-       mov     (arg2), %al
-       mov     %al, (%r11)
-
-       movdqa  (%rsp), %xmm7
-       pshufb  %xmm11, %xmm7
-       pxor    %xmm0 , %xmm7   # xor the initial crc value
-
-       psrldq  $7, %xmm7
-
-       jmp     _barrett
-
-ENDPROC(crc_t10dif_pcl)
-
-.data
-
-# precomputed constants
-# these constants are precomputed from the poly:
-# 0x8bb70000 (0x8bb7 scaled to 32 bits)
-.align 16
-# Q = 0x18BB70000
-# rk1 = 2^(32*3) mod Q << 32
-# rk2 = 2^(32*5) mod Q << 32
-# rk3 = 2^(32*15) mod Q << 32
-# rk4 = 2^(32*17) mod Q << 32
-# rk5 = 2^(32*3) mod Q << 32
-# rk6 = 2^(32*2) mod Q << 32
-# rk7 = floor(2^64/Q)
-# rk8 = Q
-rk1:
-.quad 0x2d56000000000000
-rk2:
-.quad 0x06df000000000000
-rk3:
-.quad 0x9d9d000000000000
-rk4:
-.quad 0x7cf5000000000000
-rk5:
-.quad 0x2d56000000000000
-rk6:
-.quad 0x1368000000000000
-rk7:
-.quad 0x00000001f65a57f8
-rk8:
-.quad 0x000000018bb70000
-
-rk9:
-.quad 0xceae000000000000
-rk10:
-.quad 0xbfd6000000000000
-rk11:
-.quad 0x1e16000000000000
-rk12:
-.quad 0x713c000000000000
-rk13:
-.quad 0xf7f9000000000000
-rk14:
-.quad 0x80a6000000000000
-rk15:
-.quad 0x044c000000000000
-rk16:
-.quad 0xe658000000000000
-rk17:
-.quad 0xad18000000000000
-rk18:
-.quad 0xa497000000000000
-rk19:
-.quad 0x6ee3000000000000
-rk20:
-.quad 0xe7b5000000000000
-
-
-
-mask1:
-.octa 0x80808080808080808080808080808080
-mask2:
-.octa 0x00000000FFFFFFFFFFFFFFFFFFFFFFFF
-
-SHUF_MASK:
-.octa 0x000102030405060708090A0B0C0D0E0F
-
-pshufb_shf_table:
-# use these values for shift constants for the pshufb instruction
-# different alignments result in values as shown:
-#      DDQ 0x008f8e8d8c8b8a898887868584838281 # shl 15 (16-1) / shr1
-#      DDQ 0x01008f8e8d8c8b8a8988878685848382 # shl 14 (16-3) / shr2
-#      DDQ 0x0201008f8e8d8c8b8a89888786858483 # shl 13 (16-4) / shr3
-#      DDQ 0x030201008f8e8d8c8b8a898887868584 # shl 12 (16-4) / shr4
-#      DDQ 0x04030201008f8e8d8c8b8a8988878685 # shl 11 (16-5) / shr5
-#      DDQ 0x0504030201008f8e8d8c8b8a89888786 # shl 10 (16-6) / shr6
-#      DDQ 0x060504030201008f8e8d8c8b8a898887 # shl 9  (16-7) / shr7
-#      DDQ 0x07060504030201008f8e8d8c8b8a8988 # shl 8  (16-8) / shr8
-#      DDQ 0x0807060504030201008f8e8d8c8b8a89 # shl 7  (16-9) / shr9
-#      DDQ 0x090807060504030201008f8e8d8c8b8a # shl 6  (16-10) / shr10
-#      DDQ 0x0a090807060504030201008f8e8d8c8b # shl 5  (16-11) / shr11
-#      DDQ 0x0b0a090807060504030201008f8e8d8c # shl 4  (16-12) / shr12
-#      DDQ 0x0c0b0a090807060504030201008f8e8d # shl 3  (16-13) / shr13
-#      DDQ 0x0d0c0b0a090807060504030201008f8e # shl 2  (16-14) / shr14
-#      DDQ 0x0e0d0c0b0a090807060504030201008f # shl 1  (16-15) / shr15
-.octa 0x8f8e8d8c8b8a89888786858483828100
-.octa 0x000e0d0c0b0a09080706050403020100
diff --git a/arch/x86/crypto/crct10dif-pclmul_glue.c b/arch/x86/crypto/crct10dif-pclmul_glue.c
deleted file mode 100644 (file)
index 7845d7f..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Cryptographic API.
- *
- * T10 Data Integrity Field CRC16 Crypto Transform using PCLMULQDQ Instructions
- *
- * Copyright (C) 2013 Intel Corporation
- * Author: Tim Chen <tim.c.chen@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/crc-t10dif.h>
-#include <crypto/internal/hash.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <asm/i387.h>
-#include <asm/cpufeature.h>
-#include <asm/cpu_device_id.h>
-
-asmlinkage __u16 crc_t10dif_pcl(__u16 crc, const unsigned char *buf,
-                               size_t len);
-
-struct chksum_desc_ctx {
-       __u16 crc;
-};
-
-/*
- * Steps through buffer one byte at at time, calculates reflected
- * crc using table.
- */
-
-static int chksum_init(struct shash_desc *desc)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       ctx->crc = 0;
-
-       return 0;
-}
-
-static int chksum_update(struct shash_desc *desc, const u8 *data,
-                        unsigned int length)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       if (irq_fpu_usable()) {
-               kernel_fpu_begin();
-               ctx->crc = crc_t10dif_pcl(ctx->crc, data, length);
-               kernel_fpu_end();
-       } else
-               ctx->crc = crc_t10dif_generic(ctx->crc, data, length);
-       return 0;
-}
-
-static int chksum_final(struct shash_desc *desc, u8 *out)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       *(__u16 *)out = ctx->crc;
-       return 0;
-}
-
-static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
-                       u8 *out)
-{
-       if (irq_fpu_usable()) {
-               kernel_fpu_begin();
-               *(__u16 *)out = crc_t10dif_pcl(*crcp, data, len);
-               kernel_fpu_end();
-       } else
-               *(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
-       return 0;
-}
-
-static int chksum_finup(struct shash_desc *desc, const u8 *data,
-                       unsigned int len, u8 *out)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       return __chksum_finup(&ctx->crc, data, len, out);
-}
-
-static int chksum_digest(struct shash_desc *desc, const u8 *data,
-                        unsigned int length, u8 *out)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       return __chksum_finup(&ctx->crc, data, length, out);
-}
-
-static struct shash_alg alg = {
-       .digestsize             =       CRC_T10DIF_DIGEST_SIZE,
-       .init           =       chksum_init,
-       .update         =       chksum_update,
-       .final          =       chksum_final,
-       .finup          =       chksum_finup,
-       .digest         =       chksum_digest,
-       .descsize               =       sizeof(struct chksum_desc_ctx),
-       .base                   =       {
-               .cra_name               =       "crct10dif",
-               .cra_driver_name        =       "crct10dif-pclmul",
-               .cra_priority           =       200,
-               .cra_blocksize          =       CRC_T10DIF_BLOCK_SIZE,
-               .cra_module             =       THIS_MODULE,
-       }
-};
-
-static const struct x86_cpu_id crct10dif_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ),
-       {}
-};
-MODULE_DEVICE_TABLE(x86cpu, crct10dif_cpu_id);
-
-static int __init crct10dif_intel_mod_init(void)
-{
-       if (!x86_match_cpu(crct10dif_cpu_id))
-               return -ENODEV;
-
-       return crypto_register_shash(&alg);
-}
-
-static void __exit crct10dif_intel_mod_fini(void)
-{
-       crypto_unregister_shash(&alg);
-}
-
-module_init(crct10dif_intel_mod_init);
-module_exit(crct10dif_intel_mod_fini);
-
-MODULE_AUTHOR("Tim Chen <tim.c.chen@linux.intel.com>");
-MODULE_DESCRIPTION("T10 DIF CRC calculation accelerated with PCLMULQDQ.");
-MODULE_LICENSE("GPL");
-
-MODULE_ALIAS("crct10dif");
-MODULE_ALIAS("crct10dif-pclmul");
index e2703520d1208539d21447d6f570a767b7e51f48..c370e1c4468ba1a82d98eaef03d7100c05922eeb 100644 (file)
@@ -111,8 +111,8 @@ static struct severity {
 #ifdef CONFIG_MEMORY_FAILURE
        MCESEV(
                KEEP, "Action required but unaffected thread is continuable",
-               SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR),
-               MCGMASK(MCG_STATUS_RIPV, MCG_STATUS_RIPV)
+               SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR, MCI_UC_SAR|MCI_ADDR),
+               MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, MCG_STATUS_RIPV)
                ),
        MCESEV(
                AR, "Action required: data load error in a user process",
index 94ab6b90dd3fabdaf2856a5d7fc2abfd4ed2af88..63bdb29b25497edfb0a97ec7cfb9aa5b746d200a 100644 (file)
@@ -196,15 +196,23 @@ static void __init ati_bugs_contd(int num, int slot, int func)
 static void __init intel_remapping_check(int num, int slot, int func)
 {
        u8 revision;
+       u16 device;
 
+       device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
        revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID);
 
        /*
-        * Revision 0x13 of this chipset supports irq remapping
-        * but has an erratum that breaks its behavior, flag it as such
+        * Revision 13 of all triggering devices id in this quirk have
+        * a problem draining interrupts when irq remapping is enabled,
+        * and should be flagged as broken.  Additionally revisions 0x12
+        * and 0x22 of device id 0x3405 has this problem.
         */
        if (revision == 0x13)
                set_irq_remapping_broken();
+       else if ((device == 0x3405) &&
+           ((revision == 0x12) ||
+            (revision == 0x22)))
+               set_irq_remapping_broken();
 
 }
 
@@ -239,6 +247,8 @@ static struct chipset early_qrk[] __initdata = {
          PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
        { PCI_VENDOR_ID_INTEL, 0x3403, PCI_CLASS_BRIDGE_HOST,
          PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
+       { PCI_VENDOR_ID_INTEL, 0x3405, PCI_CLASS_BRIDGE_HOST,
+         PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
        { PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
          PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
        {}
index 202d24f0f7e70546a2020212b97fb450e41cc9c5..5d576ab344030832617450ac2330d63f135596a4 100644 (file)
@@ -116,7 +116,7 @@ static void mxcsr_feature_mask_init(void)
 
        if (cpu_has_fxsr) {
                memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
-               asm volatile("fxsave %0" : : "m" (fx_scratch));
+               asm volatile("fxsave %0" : "+m" (fx_scratch));
                mask = fx_scratch.mxcsr_mask;
                if (mask == 0)
                        mask = 0x0000ffbf;
index 47ebb1dbfbcb2413ddaf9d4cc86b7d8558eb3c72..7a0adb7ee43397aa9a9fcbf733c3b1c9308f2b71 100644 (file)
@@ -220,12 +220,13 @@ int apply_microcode_amd(int cpu)
                return 0;
        }
 
-       if (__apply_microcode_amd(mc_amd))
+       if (__apply_microcode_amd(mc_amd)) {
                pr_err("CPU%d: update failed for patch_level=0x%08x\n",
                        cpu, mc_amd->hdr.patch_id);
-       else
-               pr_info("CPU%d: new patch_level=0x%08x\n", cpu,
-                       mc_amd->hdr.patch_id);
+               return -1;
+       }
+       pr_info("CPU%d: new patch_level=0x%08x\n", cpu,
+               mc_amd->hdr.patch_id);
 
        uci->cpu_sig.rev = mc_amd->hdr.patch_id;
        c->microcode = mc_amd->hdr.patch_id;
index 643b8b5eee86b3eee7edb2cf99dfa31ad7f9318d..8244f5ec2f4c7520284ff2388c328a17c10e3440 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/reboot.h>
 #include <linux/serial_reg.h>
 #include <linux/serial_8250.h>
 #include <linux/reboot.h>
index 69ce573f1224560b4f5c7532e21053b27c651da4..aca01164f00200a8d14efa8a82e4a400b67d0bf1 100644 (file)
@@ -376,25 +376,6 @@ config CRYPTO_CRC32_PCLMUL
          which will enable any routine to use the CRC-32-IEEE 802.3 checksum
          and gain better performance as compared with the table implementation.
 
-config CRYPTO_CRCT10DIF
-       tristate "CRCT10DIF algorithm"
-       select CRYPTO_HASH
-       help
-         CRC T10 Data Integrity Field computation is being cast as
-         a crypto transform.  This allows for faster crc t10 diff
-         transforms to be used if they are available.
-
-config CRYPTO_CRCT10DIF_PCLMUL
-       tristate "CRCT10DIF PCLMULQDQ hardware acceleration"
-       depends on X86 && 64BIT && CRC_T10DIF
-       select CRYPTO_HASH
-       help
-         For x86_64 processors with SSE4.2 and PCLMULQDQ supported,
-         CRC T10 DIF PCLMULQDQ computation can be hardware
-         accelerated PCLMULQDQ instruction. This option will create
-         'crct10dif-plcmul' module, which is faster when computing the
-         crct10dif checksum as compared with the generic table implementation.
-
 config CRYPTO_GHASH
        tristate "GHASH digest algorithm"
        select CRYPTO_GF128MUL
index 2d5ed08a239fa3e79110c9dfd077d30da8954192..2ba0df2f908f5985ef23f0794c1f49e6fd5f3720 100644 (file)
@@ -83,7 +83,6 @@ obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_CRC32) += crc32.o
-obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
 obj-$(CONFIG_CRYPTO_LZO) += lzo.o
 obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
diff --git a/crypto/crct10dif.c b/crypto/crct10dif.c
deleted file mode 100644 (file)
index 92aca96..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Cryptographic API.
- *
- * T10 Data Integrity Field CRC16 Crypto Transform
- *
- * Copyright (c) 2007 Oracle Corporation.  All rights reserved.
- * Written by Martin K. Petersen <martin.petersen@oracle.com>
- * Copyright (C) 2013 Intel Corporation
- * Author: Tim Chen <tim.c.chen@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/crc-t10dif.h>
-#include <crypto/internal/hash.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-struct chksum_desc_ctx {
-       __u16 crc;
-};
-
-/* Table generated using the following polynomium:
- * x^16 + x^15 + x^11 + x^9 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
- * gt: 0x8bb7
- */
-static const __u16 t10_dif_crc_table[256] = {
-       0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
-       0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
-       0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
-       0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
-       0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
-       0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
-       0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
-       0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
-       0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
-       0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
-       0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
-       0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
-       0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
-       0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
-       0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
-       0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
-       0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
-       0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
-       0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
-       0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
-       0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
-       0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
-       0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
-       0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
-       0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
-       0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
-       0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
-       0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
-       0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
-       0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
-       0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
-       0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
-};
-
-__u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer, size_t len)
-{
-       unsigned int i;
-
-       for (i = 0 ; i < len ; i++)
-               crc = (crc << 8) ^ t10_dif_crc_table[((crc >> 8) ^ buffer[i]) & 0xff];
-
-       return crc;
-}
-EXPORT_SYMBOL(crc_t10dif_generic);
-
-/*
- * Steps through buffer one byte at at time, calculates reflected
- * crc using table.
- */
-
-static int chksum_init(struct shash_desc *desc)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       ctx->crc = 0;
-
-       return 0;
-}
-
-static int chksum_update(struct shash_desc *desc, const u8 *data,
-                        unsigned int length)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       ctx->crc = crc_t10dif_generic(ctx->crc, data, length);
-       return 0;
-}
-
-static int chksum_final(struct shash_desc *desc, u8 *out)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       *(__u16 *)out = ctx->crc;
-       return 0;
-}
-
-static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
-                       u8 *out)
-{
-       *(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
-       return 0;
-}
-
-static int chksum_finup(struct shash_desc *desc, const u8 *data,
-                       unsigned int len, u8 *out)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       return __chksum_finup(&ctx->crc, data, len, out);
-}
-
-static int chksum_digest(struct shash_desc *desc, const u8 *data,
-                        unsigned int length, u8 *out)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       return __chksum_finup(&ctx->crc, data, length, out);
-}
-
-static struct shash_alg alg = {
-       .digestsize             =       CRC_T10DIF_DIGEST_SIZE,
-       .init           =       chksum_init,
-       .update         =       chksum_update,
-       .final          =       chksum_final,
-       .finup          =       chksum_finup,
-       .digest         =       chksum_digest,
-       .descsize               =       sizeof(struct chksum_desc_ctx),
-       .base                   =       {
-               .cra_name               =       "crct10dif",
-               .cra_driver_name        =       "crct10dif-generic",
-               .cra_priority           =       100,
-               .cra_blocksize          =       CRC_T10DIF_BLOCK_SIZE,
-               .cra_module             =       THIS_MODULE,
-       }
-};
-
-static int __init crct10dif_mod_init(void)
-{
-       int ret;
-
-       ret = crypto_register_shash(&alg);
-       return ret;
-}
-
-static void __exit crct10dif_mod_fini(void)
-{
-       crypto_unregister_shash(&alg);
-}
-
-module_init(crct10dif_mod_init);
-module_exit(crct10dif_mod_fini);
-
-MODULE_AUTHOR("Tim Chen <tim.c.chen@linux.intel.com>");
-MODULE_DESCRIPTION("T10 DIF CRC calculation.");
-MODULE_LICENSE("GPL");
index 25a5934f0e50a011f73db08a84735ae76b2a7f60..66d254ce0d11b35ca55e07b8b0fd786c0b0f0c10 100644 (file)
@@ -1174,10 +1174,6 @@ static int do_test(int m)
                ret += tcrypt_test("ghash");
                break;
 
-       case 47:
-               ret += tcrypt_test("crct10dif");
-               break;
-
        case 100:
                ret += tcrypt_test("hmac(md5)");
                break;
@@ -1502,10 +1498,6 @@ static int do_test(int m)
                test_hash_speed("crc32c", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
 
-       case 320:
-               test_hash_speed("crct10dif", sec, generic_hash_speed_template);
-               if (mode > 300 && mode < 400) break;
-
        case 399:
                break;
 
index 2f00607039e2ad7c808d273f08756a8e463732d4..ecddf921a9db401ee30bea1bf24b30f0ee8dd85d 100644 (file)
@@ -2045,16 +2045,6 @@ static const struct alg_test_desc alg_test_descs[] = {
                                .count = CRC32C_TEST_VECTORS
                        }
                }
-       }, {
-               .alg = "crct10dif",
-               .test = alg_test_hash,
-               .fips_allowed = 1,
-               .suite = {
-                       .hash = {
-                               .vecs = crct10dif_tv_template,
-                               .count = CRCT10DIF_TEST_VECTORS
-                       }
-               }
        }, {
                .alg = "cryptd(__driver-cbc-aes-aesni)",
                .test = alg_test_null,
index 7d44aa3d6b4472646dd9b93a77d97a0a58762eae..1e701bc075b907521c0e0cd4a06e41858cda0a5f 100644 (file)
@@ -450,39 +450,6 @@ static struct hash_testvec rmd320_tv_template[] = {
        }
 };
 
-#define CRCT10DIF_TEST_VECTORS 3
-static struct hash_testvec crct10dif_tv_template[] = {
-       {
-               .plaintext = "abc",
-               .psize  = 3,
-#ifdef __LITTLE_ENDIAN
-               .digest = "\x3b\x44",
-#else
-               .digest = "\x44\x3b",
-#endif
-       }, {
-               .plaintext = "1234567890123456789012345678901234567890"
-                            "123456789012345678901234567890123456789",
-               .psize  = 79,
-#ifdef __LITTLE_ENDIAN
-               .digest = "\x70\x4b",
-#else
-               .digest = "\x4b\x70",
-#endif
-       }, {
-               .plaintext =
-               "abcddddddddddddddddddddddddddddddddddddddddddddddddddddd",
-               .psize  = 56,
-#ifdef __LITTLE_ENDIAN
-               .digest = "\xe3\x9c",
-#else
-               .digest = "\x9c\xe3",
-#endif
-               .np     = 2,
-               .tap    = { 28, 28 }
-       }
-};
-
 /*
  * SHA1 test vectors  from from FIPS PUB 180-1
  * Long vector from CAVS 5.0
index d21167bfc86564b480f21c9b690fe263a0609a73..dc34a5b8bceeea2d9dfac6ccccee6bb7ed64c0e2 100644 (file)
@@ -359,6 +359,9 @@ int braille_register_console(struct console *console, int index,
                char *console_options, char *braille_options)
 {
        int ret;
+
+       if (!(console->flags & CON_BRL))
+               return 0;
        if (!console_options)
                /* Only support VisioBraille for now */
                console_options = "57600o8";
@@ -374,15 +377,17 @@ int braille_register_console(struct console *console, int index,
        braille_co = console;
        register_keyboard_notifier(&keyboard_notifier_block);
        register_vt_notifier(&vt_notifier_block);
-       return 0;
+       return 1;
 }
 
 int braille_unregister_console(struct console *console)
 {
        if (braille_co != console)
                return -EINVAL;
+       if (!(console->flags & CON_BRL))
+               return 0;
        unregister_keyboard_notifier(&keyboard_notifier_block);
        unregister_vt_notifier(&vt_notifier_block);
        braille_co = NULL;
-       return 0;
+       return 1;
 }
index 082b4dd252a82ab17f7fe7249913e1f7030d35fd..d405fbad406ac75cc9bb41c8734a457d60e14222 100644 (file)
@@ -117,6 +117,7 @@ struct acpi_battery {
        struct acpi_device *device;
        struct notifier_block pm_nb;
        unsigned long update_time;
+       int revision;
        int rate_now;
        int capacity_now;
        int voltage_now;
@@ -359,6 +360,7 @@ static struct acpi_offsets info_offsets[] = {
 };
 
 static struct acpi_offsets extended_info_offsets[] = {
+       {offsetof(struct acpi_battery, revision), 0},
        {offsetof(struct acpi_battery, power_unit), 0},
        {offsetof(struct acpi_battery, design_capacity), 0},
        {offsetof(struct acpi_battery, full_charge_capacity), 0},
index 227aca77ee1ef7777277d34a4b5e5774efa1286e..5da44e81dd4d70f7ed42ae1f1587734c0b6a5a55 100644 (file)
@@ -169,10 +169,8 @@ int acpi_create_platform_device(struct acpi_device *adev,
   -------------------------------------------------------------------------- */
 #if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
 bool acpi_video_backlight_quirks(void);
-bool acpi_video_verify_backlight_support(void);
 #else
 static inline bool acpi_video_backlight_quirks(void) { return false; }
-static inline bool acpi_video_verify_backlight_support(void) { return false; }
 #endif
 
 #endif /* _ACPI_INTERNAL_H_ */
index 6dd237e79b4f977e2f8c2a934303fd5e46d13690..0ec434d2586da29d65003aed0b7d9c7dd244944e 100644 (file)
@@ -911,7 +911,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
        if (acpi_video_init_brightness(device))
                return;
 
-       if (acpi_video_verify_backlight_support()) {
+       if (acpi_video_backlight_support()) {
                struct backlight_properties props;
                struct pci_dev *pdev;
                acpi_handle acpi_parent;
@@ -1366,8 +1366,8 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
        unsigned long long level_current, level_next;
        int result = -EINVAL;
 
-       /* no warning message if acpi_backlight=vendor or a quirk is used */
-       if (!acpi_video_verify_backlight_support())
+       /* no warning message if acpi_backlight=vendor is used */
+       if (!acpi_video_backlight_support())
                return 0;
 
        if (!device->brightness)
@@ -1875,46 +1875,6 @@ static int acpi_video_bus_remove(struct acpi_device *device)
        return 0;
 }
 
-static acpi_status video_unregister_backlight(acpi_handle handle, u32 lvl,
-                                             void *context, void **rv)
-{
-       struct acpi_device *acpi_dev;
-       struct acpi_video_bus *video;
-       struct acpi_video_device *dev, *next;
-
-       if (acpi_bus_get_device(handle, &acpi_dev))
-               return AE_OK;
-
-       if (acpi_match_device_ids(acpi_dev, video_device_ids))
-               return AE_OK;
-
-       video = acpi_driver_data(acpi_dev);
-       if (!video)
-               return AE_OK;
-
-       acpi_video_bus_stop_devices(video);
-       mutex_lock(&video->device_list_lock);
-       list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
-               if (dev->backlight) {
-                       backlight_device_unregister(dev->backlight);
-                       dev->backlight = NULL;
-                       kfree(dev->brightness->levels);
-                       kfree(dev->brightness);
-               }
-               if (dev->cooling_dev) {
-                       sysfs_remove_link(&dev->dev->dev.kobj,
-                                         "thermal_cooling");
-                       sysfs_remove_link(&dev->cooling_dev->device.kobj,
-                                         "device");
-                       thermal_cooling_device_unregister(dev->cooling_dev);
-                       dev->cooling_dev = NULL;
-               }
-       }
-       mutex_unlock(&video->device_list_lock);
-       acpi_video_bus_start_devices(video);
-       return AE_OK;
-}
-
 static int __init is_i740(struct pci_dev *dev)
 {
        if (dev->device == 0x00D1)
@@ -1946,25 +1906,14 @@ static int __init intel_opregion_present(void)
        return opregion;
 }
 
-int __acpi_video_register(bool backlight_quirks)
+int acpi_video_register(void)
 {
-       bool no_backlight;
-       int result;
-
-       no_backlight = backlight_quirks ? acpi_video_backlight_quirks() : false;
-
+       int result = 0;
        if (register_count) {
                /*
-                * If acpi_video_register() has been called already, don't try
-                * to register acpi_video_bus, but unregister backlight devices
-                * if no backlight support is requested.
+                * if the function of acpi_video_register is already called,
+                * don't register the acpi_vide_bus again and return no error.
                 */
-               if (no_backlight)
-                       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-                                           ACPI_UINT32_MAX,
-                                           video_unregister_backlight,
-                                           NULL, NULL, NULL);
-
                return 0;
        }
 
@@ -1980,7 +1929,7 @@ int __acpi_video_register(bool backlight_quirks)
 
        return 0;
 }
-EXPORT_SYMBOL(__acpi_video_register);
+EXPORT_SYMBOL(acpi_video_register);
 
 void acpi_video_unregister(void)
 {
index 826e52def08074bad91038ad25df387917b690ec..c3397748ba466ca13f41c664b4c374c7dea5d028 100644 (file)
@@ -238,12 +238,7 @@ static void acpi_video_caps_check(void)
 
 bool acpi_video_backlight_quirks(void)
 {
-       if (acpi_gbl_osi_data >= ACPI_OSI_WIN_8) {
-               acpi_video_caps_check();
-               acpi_video_support |= ACPI_VIDEO_SKIP_BACKLIGHT;
-               return true;
-       }
-       return false;
+       return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;
 }
 EXPORT_SYMBOL(acpi_video_backlight_quirks);
 
@@ -291,14 +286,6 @@ int acpi_video_backlight_support(void)
 }
 EXPORT_SYMBOL(acpi_video_backlight_support);
 
-/* For the ACPI video driver use only. */
-bool acpi_video_verify_backlight_support(void)
-{
-       return (acpi_video_support & ACPI_VIDEO_SKIP_BACKLIGHT) ?
-               false : acpi_video_backlight_support();
-}
-EXPORT_SYMBOL(acpi_video_verify_backlight_support);
-
 /*
  * Use acpi_backlight=vendor/video to force that backlight switching
  * is processed by vendor specific acpi drivers or video.ko driver.
index 80dc988f01e4f1eebb7d12311ab98c8ac48dc013..4e737728aee207a5d644d6fa0d39b0e3c402bd47 100644 (file)
@@ -97,6 +97,15 @@ config SATA_AHCI_PLATFORM
 
          If unsure, say N.
 
+config AHCI_IMX
+       tristate "Freescale i.MX AHCI SATA support"
+       depends on SATA_AHCI_PLATFORM && MFD_SYSCON
+       help
+         This option enables support for the Freescale i.MX SoC's
+         onboard AHCI SATA.
+
+         If unsure, say N.
+
 config SATA_FSL
        tristate "Freescale 3.0Gbps SATA support"
        depends on FSL_SOC
@@ -107,7 +116,7 @@ config SATA_FSL
          If unsure, say N.
 
 config SATA_INIC162X
-       tristate "Initio 162x SATA support"
+       tristate "Initio 162x SATA support (Very Experimental)"
        depends on PCI
        help
          This option enables support for Initio 162x Serial ATA.
index c04d0fd038a312485712ed2be8a42d77b32df5c9..46518c622460942cdf8e2971dd95f3b069961ada 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_SATA_INIC162X)   += sata_inic162x.o
 obj-$(CONFIG_SATA_SIL24)       += sata_sil24.o
 obj-$(CONFIG_SATA_DWC)         += sata_dwc_460ex.o
 obj-$(CONFIG_SATA_HIGHBANK)    += sata_highbank.o libahci.o
+obj-$(CONFIG_AHCI_IMX)         += ahci_imx.o
 
 # SFF w/ custom DMA
 obj-$(CONFIG_PDC_ADMA)         += pdc_adma.o
index 5064f3ea20f1b6f362928bd7a5b3cce39894b259..db4380d7003115ef8c4d05c1ca3543adce0efecb 100644 (file)
@@ -1146,11 +1146,18 @@ int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
                return rc;
 
        for (i = 0; i < host->n_ports; i++) {
+               const char* desc;
                struct ahci_port_priv *pp = host->ports[i]->private_data;
 
+               /* pp is NULL for dummy ports */
+               if (pp)
+                       desc = pp->irq_desc;
+               else
+                       desc = dev_driver_string(host->dev);
+
                rc = devm_request_threaded_irq(host->dev,
                        irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
-                       pp->irq_desc, host->ports[i]);
+                       desc, host->ports[i]);
                if (rc)
                        goto out_free_irqs;
        }
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
new file mode 100644 (file)
index 0000000..58debb0
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Freescale IMX AHCI SATA platform driver
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/ahci_platform.h>
+#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include "ahci.h"
+
+enum {
+       HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
+};
+
+struct imx_ahci_priv {
+       struct platform_device *ahci_pdev;
+       struct clk *sata_ref_clk;
+       struct clk *ahb_clk;
+       struct regmap *gpr;
+};
+
+static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
+{
+       int ret = 0;
+       unsigned int reg_val;
+       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+
+       imxpriv->gpr =
+               syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+       if (IS_ERR(imxpriv->gpr)) {
+               dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n");
+               return PTR_ERR(imxpriv->gpr);
+       }
+
+       ret = clk_prepare_enable(imxpriv->sata_ref_clk);
+       if (ret < 0) {
+               dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret);
+               return ret;
+       }
+
+       /*
+        * set PHY Paremeters, two steps to configure the GPR13,
+        * one write for rest of parameters, mask of first write
+        * is 0x07fffffd, and the other one write for setting
+        * the mpll_clk_en.
+        */
+       regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK
+                       | IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK
+                       | IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK
+                       | IMX6Q_GPR13_SATA_SPD_MODE_MASK
+                       | IMX6Q_GPR13_SATA_MPLL_SS_EN
+                       | IMX6Q_GPR13_SATA_TX_ATTEN_MASK
+                       | IMX6Q_GPR13_SATA_TX_BOOST_MASK
+                       | IMX6Q_GPR13_SATA_TX_LVL_MASK
+                       | IMX6Q_GPR13_SATA_TX_EDGE_RATE
+                       , IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB
+                       | IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M
+                       | IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F
+                       | IMX6Q_GPR13_SATA_SPD_MODE_3P0G
+                       | IMX6Q_GPR13_SATA_MPLL_SS_EN
+                       | IMX6Q_GPR13_SATA_TX_ATTEN_9_16
+                       | IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB
+                       | IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
+       regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+                       IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+       usleep_range(100, 200);
+
+       /*
+        * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
+        * and IP vendor specific register HOST_TIMER1MS.
+        * Configure CAP_SSS (support stagered spin up).
+        * Implement the port0.
+        * Get the ahb clock rate, and configure the TIMER1MS register.
+        */
+       reg_val = readl(mmio + HOST_CAP);
+       if (!(reg_val & HOST_CAP_SSS)) {
+               reg_val |= HOST_CAP_SSS;
+               writel(reg_val, mmio + HOST_CAP);
+       }
+       reg_val = readl(mmio + HOST_PORTS_IMPL);
+       if (!(reg_val & 0x1)) {
+               reg_val |= 0x1;
+               writel(reg_val, mmio + HOST_PORTS_IMPL);
+       }
+
+       reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+       writel(reg_val, mmio + HOST_TIMER1MS);
+
+       return 0;
+}
+
+static void imx6q_sata_exit(struct device *dev)
+{
+       struct imx_ahci_priv *imxpriv =  dev_get_drvdata(dev->parent);
+
+       regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+                       !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+       clk_disable_unprepare(imxpriv->sata_ref_clk);
+}
+
+static struct ahci_platform_data imx6q_sata_pdata = {
+       .init = imx6q_sata_init,
+       .exit = imx6q_sata_exit,
+};
+
+static const struct of_device_id imx_ahci_of_match[] = {
+       { .compatible = "fsl,imx6q-ahci", .data = &imx6q_sata_pdata},
+       {},
+};
+MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
+
+static int imx_ahci_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *mem, *irq, res[2];
+       const struct of_device_id *of_id;
+       const struct ahci_platform_data *pdata = NULL;
+       struct imx_ahci_priv *imxpriv;
+       struct device *ahci_dev;
+       struct platform_device *ahci_pdev;
+       int ret;
+
+       imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
+       if (!imxpriv) {
+               dev_err(dev, "can't alloc ahci_host_priv\n");
+               return -ENOMEM;
+       }
+
+       ahci_pdev = platform_device_alloc("ahci", -1);
+       if (!ahci_pdev)
+               return -ENODEV;
+
+       ahci_dev = &ahci_pdev->dev;
+       ahci_dev->parent = dev;
+
+       imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
+       if (IS_ERR(imxpriv->ahb_clk)) {
+               dev_err(dev, "can't get ahb clock.\n");
+               ret = PTR_ERR(imxpriv->ahb_clk);
+               goto err_out;
+       }
+
+       imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
+       if (IS_ERR(imxpriv->sata_ref_clk)) {
+               dev_err(dev, "can't get sata_ref clock.\n");
+               ret = PTR_ERR(imxpriv->sata_ref_clk);
+               goto err_out;
+       }
+
+       imxpriv->ahci_pdev = ahci_pdev;
+       platform_set_drvdata(pdev, imxpriv);
+
+       of_id = of_match_device(imx_ahci_of_match, dev);
+       if (of_id) {
+               pdata = of_id->data;
+       } else {
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!mem || !irq) {
+               dev_err(dev, "no mmio/irq resource\n");
+               ret = -ENOMEM;
+               goto err_out;
+       }
+
+       res[0] = *mem;
+       res[1] = *irq;
+
+       ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32);
+       ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
+       ahci_dev->of_node = dev->of_node;
+
+       ret = platform_device_add_resources(ahci_pdev, res, 2);
+       if (ret)
+               goto err_out;
+
+       ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
+       if (ret)
+               goto err_out;
+
+       ret = platform_device_add(ahci_pdev);
+       if (ret) {
+err_out:
+               platform_device_put(ahci_pdev);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int imx_ahci_remove(struct platform_device *pdev)
+{
+       struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
+       struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
+
+       platform_device_unregister(ahci_pdev);
+       return 0;
+}
+
+static struct platform_driver imx_ahci_driver = {
+       .probe = imx_ahci_probe,
+       .remove = imx_ahci_remove,
+       .driver = {
+               .name = "ahci-imx",
+               .owner = THIS_MODULE,
+               .of_match_table = imx_ahci_of_match,
+       },
+};
+module_platform_driver(imx_ahci_driver);
+
+MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver");
+MODULE_AUTHOR("Richard Zhu <Hong-Xing.Zhu@freescale.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ahci:imx");
index b52a10c8eeb9b775cd1c7fd438ace85571e2ca27..513ad7ed0c997e19c3b3c4190b09221199c3d16c 100644 (file)
@@ -330,7 +330,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
        /* SATA Controller IDE (Wellsburg) */
        { 0x8086, 0x8d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
        /* SATA Controller IDE (Wellsburg) */
-       { 0x8086, 0x8d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+       { 0x8086, 0x8d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
        /* SATA Controller IDE (Wellsburg) */
        { 0x8086, 0x8d60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
        /* SATA Controller IDE (Wellsburg) */
index 83c08907e0428bd44c6fad7f1f634357ea5606cd..b1e880a3c3dabb9b5bd253da522c8879632d993c 100644 (file)
@@ -206,8 +206,10 @@ static ssize_t ata_scsi_park_store(struct device *device,
        unsigned long flags;
        int rc;
 
-       rc = strict_strtol(buf, 10, &input);
-       if (rc || input < -2)
+       rc = kstrtol(buf, 10, &input);
+       if (rc)
+               return rc;
+       if (input < -2)
                return -EINVAL;
        if (input > ATA_TMOUT_MAX_PARK) {
                rc = -EOVERFLOW;
index 4ec7c04b3f8279dff1f2e39f356106e92815e39f..26386f0b89a8f4583c397ca9da154a9c499c6d2f 100644 (file)
@@ -237,6 +237,7 @@ static const struct of_device_id imx_pata_dt_ids[] = {
                /* sentinel */
        }
 };
+MODULE_DEVICE_TABLE(of, imx_pata_dt_ids);
 
 static struct platform_driver pata_imx_driver = {
        .probe          = pata_imx_probe,
index e4513174824830fa67d3e000ec97a449245fb0c8..5c54d957370afcaf9cf6c0d1962d87cc1b98eaac 100644 (file)
@@ -6,6 +6,18 @@
  *
  * This file is released under GPL v2.
  *
+ * **** WARNING ****
+ *
+ * This driver never worked properly and unfortunately data corruption is
+ * relatively common.  There isn't anyone working on the driver and there's
+ * no support from the vendor.  Do not use this driver in any production
+ * environment.
+ *
+ * http://thread.gmane.org/gmane.linux.debian.devel.bugs.rc/378525/focus=54491
+ * https://bugzilla.kernel.org/show_bug.cgi?id=60565
+ *
+ * *****************
+ *
  * This controller is eccentric and easily locks up if something isn't
  * right.  Documentation is available at initio's website but it only
  * documents registers (not programming model).
@@ -807,6 +819,8 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        ata_print_version_once(&pdev->dev, DRV_VERSION);
 
+       dev_alert(&pdev->dev, "inic162x support is broken with common data corruption issues and will be disabled by default, contact linux-ide@vger.kernel.org if in production use\n");
+
        /* alloc host */
        host = ata_host_alloc_pinfo(&pdev->dev, ppi, NR_PORTS);
        hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
index b81ddfea1da075ad3c1d0cbeb9ab7bf854593436..e07a5fd58ad7463f8775f7334fd692c7e51df2ad 100644 (file)
@@ -532,11 +532,11 @@ config BLK_DEV_RBD
          If unsure, say N.
 
 config BLK_DEV_RSXX
-       tristate "IBM FlashSystem 70/80 PCIe SSD Device Driver"
+       tristate "IBM Flash Adapter 900GB Full Height PCIe Device Driver"
        depends on PCI
        help
          Device driver for IBM's high speed PCIe SSD
-         storage devices: FlashSystem-70 and FlashSystem-80.
+         storage device: Flash Adapter 900GB Full Height.
 
          To compile this driver as a module, choose M here: the
          module will be called rsxx.
index 6608076dc39e73cda5f3aaf705579e3189421e3e..28c73ca320a8f7f9b1741492785fa2f18e042d8c 100644 (file)
@@ -659,6 +659,27 @@ void drbd_al_shrink(struct drbd_conf *mdev)
        wake_up(&mdev->al_wait);
 }
 
+int drbd_initialize_al(struct drbd_conf *mdev, void *buffer)
+{
+       struct al_transaction_on_disk *al = buffer;
+       struct drbd_md *md = &mdev->ldev->md;
+       sector_t al_base = md->md_offset + md->al_offset;
+       int al_size_4k = md->al_stripes * md->al_stripe_size_4k;
+       int i;
+
+       memset(al, 0, 4096);
+       al->magic = cpu_to_be32(DRBD_AL_MAGIC);
+       al->transaction_type = cpu_to_be16(AL_TR_INITIALIZED);
+       al->crc32c = cpu_to_be32(crc32c(0, al, 4096));
+
+       for (i = 0; i < al_size_4k; i++) {
+               int err = drbd_md_sync_page_io(mdev, mdev->ldev, al_base + i * 8, WRITE);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
 static int w_update_odbm(struct drbd_work *w, int unused)
 {
        struct update_odbm_work *udw = container_of(w, struct update_odbm_work, w);
index f943aacfdad8a90aa07416d905fa2a0bb207b665..2d7f608d181ce8cf2eb26ab3859dcccb0ec38474 100644 (file)
@@ -832,6 +832,7 @@ struct drbd_tconn {                 /* is a resource from the config file */
        unsigned susp_nod:1;            /* IO suspended because no data */
        unsigned susp_fen:1;            /* IO suspended because fence peer handler runs */
        struct mutex cstate_mutex;      /* Protects graceful disconnects */
+       unsigned int connect_cnt;       /* Inc each time a connection is established */
 
        unsigned long flags;
        struct net_conf *net_conf;      /* content protected by rcu */
@@ -1132,6 +1133,7 @@ extern void drbd_mdev_cleanup(struct drbd_conf *mdev);
 void drbd_print_uuids(struct drbd_conf *mdev, const char *text);
 
 extern void conn_md_sync(struct drbd_tconn *tconn);
+extern void drbd_md_write(struct drbd_conf *mdev, void *buffer);
 extern void drbd_md_sync(struct drbd_conf *mdev);
 extern int  drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev);
 extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
@@ -1466,8 +1468,16 @@ extern void drbd_suspend_io(struct drbd_conf *mdev);
 extern void drbd_resume_io(struct drbd_conf *mdev);
 extern char *ppsize(char *buf, unsigned long long size);
 extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, sector_t, int);
-enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 };
-extern enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local);
+enum determine_dev_size {
+       DS_ERROR_SHRINK = -3,
+       DS_ERROR_SPACE_MD = -2,
+       DS_ERROR = -1,
+       DS_UNCHANGED = 0,
+       DS_SHRUNK = 1,
+       DS_GREW = 2
+};
+extern enum determine_dev_size
+drbd_determine_dev_size(struct drbd_conf *, enum dds_flags, struct resize_parms *) __must_hold(local);
 extern void resync_after_online_grow(struct drbd_conf *);
 extern void drbd_reconsider_max_bio_size(struct drbd_conf *mdev);
 extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev,
@@ -1633,6 +1643,7 @@ extern int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector,
 #define drbd_set_out_of_sync(mdev, sector, size) \
        __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__)
 extern void drbd_al_shrink(struct drbd_conf *mdev);
+extern int drbd_initialize_al(struct drbd_conf *, void *);
 
 /* drbd_nl.c */
 /* state info broadcast */
index a5dca6affcbb894dc2c5d97c63c84f8972503d4e..55635edf563be741d56cccda715ab70ff23248a4 100644 (file)
@@ -2762,8 +2762,6 @@ int __init drbd_init(void)
        /*
         * allocate all necessary structs
         */
-       err = -ENOMEM;
-
        init_waitqueue_head(&drbd_pp_wait);
 
        drbd_proc = NULL; /* play safe for drbd_cleanup */
@@ -2773,6 +2771,7 @@ int __init drbd_init(void)
        if (err)
                goto fail;
 
+       err = -ENOMEM;
        drbd_proc = proc_create_data("drbd", S_IFREG | S_IRUGO , NULL, &drbd_proc_fops, NULL);
        if (!drbd_proc) {
                printk(KERN_ERR "drbd: unable to register proc file\n");
@@ -2803,7 +2802,6 @@ int __init drbd_init(void)
 fail:
        drbd_cleanup();
        if (err == -ENOMEM)
-               /* currently always the case */
                printk(KERN_ERR "drbd: ran out of memory\n");
        else
                printk(KERN_ERR "drbd: initialization failure\n");
@@ -2881,34 +2879,14 @@ struct meta_data_on_disk {
        u8 reserved_u8[4096 - (7*8 + 10*4)];
 } __packed;
 
-/**
- * drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set
- * @mdev:      DRBD device.
- */
-void drbd_md_sync(struct drbd_conf *mdev)
+
+
+void drbd_md_write(struct drbd_conf *mdev, void *b)
 {
-       struct meta_data_on_disk *buffer;
+       struct meta_data_on_disk *buffer = b;
        sector_t sector;
        int i;
 
-       /* Don't accidentally change the DRBD meta data layout. */
-       BUILD_BUG_ON(UI_SIZE != 4);
-       BUILD_BUG_ON(sizeof(struct meta_data_on_disk) != 4096);
-
-       del_timer(&mdev->md_sync_timer);
-       /* timer may be rearmed by drbd_md_mark_dirty() now. */
-       if (!test_and_clear_bit(MD_DIRTY, &mdev->flags))
-               return;
-
-       /* We use here D_FAILED and not D_ATTACHING because we try to write
-        * metadata even if we detach due to a disk failure! */
-       if (!get_ldev_if_state(mdev, D_FAILED))
-               return;
-
-       buffer = drbd_md_get_buffer(mdev);
-       if (!buffer)
-               goto out;
-
        memset(buffer, 0, sizeof(*buffer));
 
        buffer->la_size_sect = cpu_to_be64(drbd_get_capacity(mdev->this_bdev));
@@ -2937,6 +2915,35 @@ void drbd_md_sync(struct drbd_conf *mdev)
                dev_err(DEV, "meta data update failed!\n");
                drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
        }
+}
+
+/**
+ * drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set
+ * @mdev:      DRBD device.
+ */
+void drbd_md_sync(struct drbd_conf *mdev)
+{
+       struct meta_data_on_disk *buffer;
+
+       /* Don't accidentally change the DRBD meta data layout. */
+       BUILD_BUG_ON(UI_SIZE != 4);
+       BUILD_BUG_ON(sizeof(struct meta_data_on_disk) != 4096);
+
+       del_timer(&mdev->md_sync_timer);
+       /* timer may be rearmed by drbd_md_mark_dirty() now. */
+       if (!test_and_clear_bit(MD_DIRTY, &mdev->flags))
+               return;
+
+       /* We use here D_FAILED and not D_ATTACHING because we try to write
+        * metadata even if we detach due to a disk failure! */
+       if (!get_ldev_if_state(mdev, D_FAILED))
+               return;
+
+       buffer = drbd_md_get_buffer(mdev);
+       if (!buffer)
+               goto out;
+
+       drbd_md_write(mdev, buffer);
 
        /* Update mdev->ldev->md.la_size_sect,
         * since we updated it on metadata. */
index 9e3f441e7e8441e83d61273ed0f34f1c309c518b..8cc1e640f485b4620ff39d8f3de915d36a38487e 100644 (file)
@@ -417,6 +417,7 @@ static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn)
 
 bool conn_try_outdate_peer(struct drbd_tconn *tconn)
 {
+       unsigned int connect_cnt;
        union drbd_state mask = { };
        union drbd_state val = { };
        enum drbd_fencing_p fp;
@@ -428,6 +429,10 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
                return false;
        }
 
+       spin_lock_irq(&tconn->req_lock);
+       connect_cnt = tconn->connect_cnt;
+       spin_unlock_irq(&tconn->req_lock);
+
        fp = highest_fencing_policy(tconn);
        switch (fp) {
        case FP_NOT_AVAIL:
@@ -492,8 +497,14 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
           here, because we might were able to re-establish the connection in the
           meantime. */
        spin_lock_irq(&tconn->req_lock);
-       if (tconn->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &tconn->flags))
-               _conn_request_state(tconn, mask, val, CS_VERBOSE);
+       if (tconn->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &tconn->flags)) {
+               if (tconn->connect_cnt != connect_cnt)
+                       /* In case the connection was established and droped
+                          while the fence-peer handler was running, ignore it */
+                       conn_info(tconn, "Ignoring fence-peer exit code\n");
+               else
+                       _conn_request_state(tconn, mask, val, CS_VERBOSE);
+       }
        spin_unlock_irq(&tconn->req_lock);
 
        return conn_highest_pdsk(tconn) <= D_OUTDATED;
@@ -816,15 +827,20 @@ void drbd_resume_io(struct drbd_conf *mdev)
  * Returns 0 on success, negative return values indicate errors.
  * You should call drbd_md_sync() after calling this function.
  */
-enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags) __must_hold(local)
+enum determine_dev_size
+drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct resize_parms *rs) __must_hold(local)
 {
        sector_t prev_first_sect, prev_size; /* previous meta location */
        sector_t la_size_sect, u_size;
+       struct drbd_md *md = &mdev->ldev->md;
+       u32 prev_al_stripe_size_4k;
+       u32 prev_al_stripes;
        sector_t size;
        char ppb[10];
+       void *buffer;
 
        int md_moved, la_size_changed;
-       enum determine_dev_size rv = unchanged;
+       enum determine_dev_size rv = DS_UNCHANGED;
 
        /* race:
         * application request passes inc_ap_bio,
@@ -836,6 +852,11 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
         * still lock the act_log to not trigger ASSERTs there.
         */
        drbd_suspend_io(mdev);
+       buffer = drbd_md_get_buffer(mdev); /* Lock meta-data IO */
+       if (!buffer) {
+               drbd_resume_io(mdev);
+               return DS_ERROR;
+       }
 
        /* no wait necessary anymore, actually we could assert that */
        wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
@@ -844,7 +865,17 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
        prev_size = mdev->ldev->md.md_size_sect;
        la_size_sect = mdev->ldev->md.la_size_sect;
 
-       /* TODO: should only be some assert here, not (re)init... */
+       if (rs) {
+               /* rs is non NULL if we should change the AL layout only */
+
+               prev_al_stripes = md->al_stripes;
+               prev_al_stripe_size_4k = md->al_stripe_size_4k;
+
+               md->al_stripes = rs->al_stripes;
+               md->al_stripe_size_4k = rs->al_stripe_size / 4;
+               md->al_size_4k = (u64)rs->al_stripes * rs->al_stripe_size / 4;
+       }
+
        drbd_md_set_sector_offsets(mdev, mdev->ldev);
 
        rcu_read_lock();
@@ -852,6 +883,21 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
        rcu_read_unlock();
        size = drbd_new_dev_size(mdev, mdev->ldev, u_size, flags & DDSF_FORCED);
 
+       if (size < la_size_sect) {
+               if (rs && u_size == 0) {
+                       /* Remove "rs &&" later. This check should always be active, but
+                          right now the receiver expects the permissive behavior */
+                       dev_warn(DEV, "Implicit shrink not allowed. "
+                                "Use --size=%llus for explicit shrink.\n",
+                                (unsigned long long)size);
+                       rv = DS_ERROR_SHRINK;
+               }
+               if (u_size > size)
+                       rv = DS_ERROR_SPACE_MD;
+               if (rv != DS_UNCHANGED)
+                       goto err_out;
+       }
+
        if (drbd_get_capacity(mdev->this_bdev) != size ||
            drbd_bm_capacity(mdev) != size) {
                int err;
@@ -867,7 +913,7 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
                                    "Leaving size unchanged at size = %lu KB\n",
                                    (unsigned long)size);
                        }
-                       rv = dev_size_error;
+                       rv = DS_ERROR;
                }
                /* racy, see comments above. */
                drbd_set_my_capacity(mdev, size);
@@ -875,38 +921,57 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
                dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
                     (unsigned long long)size>>1);
        }
-       if (rv == dev_size_error)
-               goto out;
+       if (rv <= DS_ERROR)
+               goto err_out;
 
        la_size_changed = (la_size_sect != mdev->ldev->md.la_size_sect);
 
        md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev)
                || prev_size       != mdev->ldev->md.md_size_sect;
 
-       if (la_size_changed || md_moved) {
-               int err;
+       if (la_size_changed || md_moved || rs) {
+               u32 prev_flags;
 
                drbd_al_shrink(mdev); /* All extents inactive. */
+
+               prev_flags = md->flags;
+               md->flags &= ~MDF_PRIMARY_IND;
+               drbd_md_write(mdev, buffer);
+
                dev_info(DEV, "Writing the whole bitmap, %s\n",
                         la_size_changed && md_moved ? "size changed and md moved" :
                         la_size_changed ? "size changed" : "md moved");
                /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */
-               err = drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
-                                    "size changed", BM_LOCKED_MASK);
-               if (err) {
-                       rv = dev_size_error;
-                       goto out;
-               }
-               drbd_md_mark_dirty(mdev);
+               drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
+                              "size changed", BM_LOCKED_MASK);
+               drbd_initialize_al(mdev, buffer);
+
+               md->flags = prev_flags;
+               drbd_md_write(mdev, buffer);
+
+               if (rs)
+                       dev_info(DEV, "Changed AL layout to al-stripes = %d, al-stripe-size-kB = %d\n",
+                                md->al_stripes, md->al_stripe_size_4k * 4);
        }
 
        if (size > la_size_sect)
-               rv = grew;
+               rv = DS_GREW;
        if (size < la_size_sect)
-               rv = shrunk;
-out:
+               rv = DS_SHRUNK;
+
+       if (0) {
+       err_out:
+               if (rs) {
+                       md->al_stripes = prev_al_stripes;
+                       md->al_stripe_size_4k = prev_al_stripe_size_4k;
+                       md->al_size_4k = (u64)prev_al_stripes * prev_al_stripe_size_4k;
+
+                       drbd_md_set_sector_offsets(mdev, mdev->ldev);
+               }
+       }
        lc_unlock(mdev->act_log);
        wake_up(&mdev->al_wait);
+       drbd_md_put_buffer(mdev);
        drbd_resume_io(mdev);
 
        return rv;
@@ -1607,11 +1672,11 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
            !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
                set_bit(USE_DEGR_WFC_T, &mdev->flags);
 
-       dd = drbd_determine_dev_size(mdev, 0);
-       if (dd == dev_size_error) {
+       dd = drbd_determine_dev_size(mdev, 0, NULL);
+       if (dd <= DS_ERROR) {
                retcode = ERR_NOMEM_BITMAP;
                goto force_diskless_dec;
-       } else if (dd == grew)
+       } else if (dd == DS_GREW)
                set_bit(RESYNC_AFTER_NEG, &mdev->flags);
 
        if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC) ||
@@ -2305,6 +2370,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
        struct drbd_conf *mdev;
        enum drbd_ret_code retcode;
        enum determine_dev_size dd;
+       bool change_al_layout = false;
        enum dds_flags ddsf;
        sector_t u_size;
        int err;
@@ -2315,31 +2381,33 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto fail;
 
+       mdev = adm_ctx.mdev;
+       if (!get_ldev(mdev)) {
+               retcode = ERR_NO_DISK;
+               goto fail;
+       }
+
        memset(&rs, 0, sizeof(struct resize_parms));
+       rs.al_stripes = mdev->ldev->md.al_stripes;
+       rs.al_stripe_size = mdev->ldev->md.al_stripe_size_4k * 4;
        if (info->attrs[DRBD_NLA_RESIZE_PARMS]) {
                err = resize_parms_from_attrs(&rs, info);
                if (err) {
                        retcode = ERR_MANDATORY_TAG;
                        drbd_msg_put_info(from_attrs_err_to_txt(err));
-                       goto fail;
+                       goto fail_ldev;
                }
        }
 
-       mdev = adm_ctx.mdev;
        if (mdev->state.conn > C_CONNECTED) {
                retcode = ERR_RESIZE_RESYNC;
-               goto fail;
+               goto fail_ldev;
        }
 
        if (mdev->state.role == R_SECONDARY &&
            mdev->state.peer == R_SECONDARY) {
                retcode = ERR_NO_PRIMARY;
-               goto fail;
-       }
-
-       if (!get_ldev(mdev)) {
-               retcode = ERR_NO_DISK;
-               goto fail;
+               goto fail_ldev;
        }
 
        if (rs.no_resync && mdev->tconn->agreed_pro_version < 93) {
@@ -2358,6 +2426,28 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
+       if (mdev->ldev->md.al_stripes != rs.al_stripes ||
+           mdev->ldev->md.al_stripe_size_4k != rs.al_stripe_size / 4) {
+               u32 al_size_k = rs.al_stripes * rs.al_stripe_size;
+
+               if (al_size_k > (16 * 1024 * 1024)) {
+                       retcode = ERR_MD_LAYOUT_TOO_BIG;
+                       goto fail_ldev;
+               }
+
+               if (al_size_k < MD_32kB_SECT/2) {
+                       retcode = ERR_MD_LAYOUT_TOO_SMALL;
+                       goto fail_ldev;
+               }
+
+               if (mdev->state.conn != C_CONNECTED) {
+                       retcode = ERR_MD_LAYOUT_CONNECTED;
+                       goto fail_ldev;
+               }
+
+               change_al_layout = true;
+       }
+
        if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev))
                mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
 
@@ -2373,16 +2463,22 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
        }
 
        ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0);
-       dd = drbd_determine_dev_size(mdev, ddsf);
+       dd = drbd_determine_dev_size(mdev, ddsf, change_al_layout ? &rs : NULL);
        drbd_md_sync(mdev);
        put_ldev(mdev);
-       if (dd == dev_size_error) {
+       if (dd == DS_ERROR) {
                retcode = ERR_NOMEM_BITMAP;
                goto fail;
+       } else if (dd == DS_ERROR_SPACE_MD) {
+               retcode = ERR_MD_LAYOUT_NO_FIT;
+               goto fail;
+       } else if (dd == DS_ERROR_SHRINK) {
+               retcode = ERR_IMPLICIT_SHRINK;
+               goto fail;
        }
 
        if (mdev->state.conn == C_CONNECTED) {
-               if (dd == grew)
+               if (dd == DS_GREW)
                        set_bit(RESIZE_PENDING, &mdev->flags);
 
                drbd_send_uuids(mdev);
@@ -2658,7 +2754,6 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
                const struct sib_info *sib)
 {
        struct state_info *si = NULL; /* for sizeof(si->member); */
-       struct net_conf *nc;
        struct nlattr *nla;
        int got_ldev;
        int err = 0;
@@ -2688,13 +2783,19 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
                goto nla_put_failure;
 
        rcu_read_lock();
-       if (got_ldev)
-               if (disk_conf_to_skb(skb, rcu_dereference(mdev->ldev->disk_conf), exclude_sensitive))
-                       goto nla_put_failure;
+       if (got_ldev) {
+               struct disk_conf *disk_conf;
 
-       nc = rcu_dereference(mdev->tconn->net_conf);
-       if (nc)
-               err = net_conf_to_skb(skb, nc, exclude_sensitive);
+               disk_conf = rcu_dereference(mdev->ldev->disk_conf);
+               err = disk_conf_to_skb(skb, disk_conf, exclude_sensitive);
+       }
+       if (!err) {
+               struct net_conf *nc;
+
+               nc = rcu_dereference(mdev->tconn->net_conf);
+               if (nc)
+                       err = net_conf_to_skb(skb, nc, exclude_sensitive);
+       }
        rcu_read_unlock();
        if (err)
                goto nla_put_failure;
index 4222affff488bc15c116187e2eb382af5f2d0508..cc29cd3bf78b6a758f85255f56f6cdeca1b2cc4b 100644 (file)
@@ -1039,6 +1039,8 @@ randomize:
        rcu_read_lock();
        idr_for_each_entry(&tconn->volumes, mdev, vnr) {
                kref_get(&mdev->kref);
+               rcu_read_unlock();
+
                /* Prevent a race between resync-handshake and
                 * being promoted to Primary.
                 *
@@ -1049,8 +1051,6 @@ randomize:
                mutex_lock(mdev->state_mutex);
                mutex_unlock(mdev->state_mutex);
 
-               rcu_read_unlock();
-
                if (discard_my_data)
                        set_bit(DISCARD_MY_DATA, &mdev->flags);
                else
@@ -3545,7 +3545,7 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
 {
        struct drbd_conf *mdev;
        struct p_sizes *p = pi->data;
-       enum determine_dev_size dd = unchanged;
+       enum determine_dev_size dd = DS_UNCHANGED;
        sector_t p_size, p_usize, my_usize;
        int ldsc = 0; /* local disk size changed */
        enum dds_flags ddsf;
@@ -3617,9 +3617,9 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
 
        ddsf = be16_to_cpu(p->dds_flags);
        if (get_ldev(mdev)) {
-               dd = drbd_determine_dev_size(mdev, ddsf);
+               dd = drbd_determine_dev_size(mdev, ddsf, NULL);
                put_ldev(mdev);
-               if (dd == dev_size_error)
+               if (dd == DS_ERROR)
                        return -EIO;
                drbd_md_sync(mdev);
        } else {
@@ -3647,7 +3647,7 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
                        drbd_send_sizes(mdev, 0, ddsf);
                }
                if (test_and_clear_bit(RESIZE_PENDING, &mdev->flags) ||
-                   (dd == grew && mdev->state.conn == C_CONNECTED)) {
+                   (dd == DS_GREW && mdev->state.conn == C_CONNECTED)) {
                        if (mdev->state.pdsk >= D_INCONSISTENT &&
                            mdev->state.disk >= D_INCONSISTENT) {
                                if (ddsf & DDSF_NO_RESYNC)
index 90c5be2b1d309bf041927891f2f8be24fc491bc1..216d47b7e88b72f59e26ede29a758116adc2f687 100644 (file)
@@ -1115,8 +1115,10 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
                drbd_thread_restart_nowait(&mdev->tconn->receiver);
 
        /* Resume AL writing if we get a connection */
-       if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED)
+       if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) {
                drbd_resume_al(mdev);
+               mdev->tconn->connect_cnt++;
+       }
 
        /* remember last attach time so request_timer_fn() won't
         * kill newly established sessions while we are still trying to thaw
index 5af21f2db29cd1246397e3b4eed8627ba314adf2..6e85e21445eb13896d19f16a58a0107b4f9baa4e 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/slab.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <linux/genhd.h>
 #include <linux/idr.h>
@@ -39,8 +41,9 @@
 #include "rsxx_cfg.h"
 
 #define NO_LEGACY 0
+#define SYNC_START_TIMEOUT (10 * 60) /* 10 minutes */
 
-MODULE_DESCRIPTION("IBM FlashSystem 70/80 PCIe SSD Device Driver");
+MODULE_DESCRIPTION("IBM Flash Adapter 900GB Full Height Device Driver");
 MODULE_AUTHOR("Joshua Morris/Philip Kelleher, IBM");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRIVER_VERSION);
@@ -49,9 +52,282 @@ static unsigned int force_legacy = NO_LEGACY;
 module_param(force_legacy, uint, 0444);
 MODULE_PARM_DESC(force_legacy, "Force the use of legacy type PCI interrupts");
 
+static unsigned int sync_start = 1;
+module_param(sync_start, uint, 0444);
+MODULE_PARM_DESC(sync_start, "On by Default: Driver load will not complete "
+                            "until the card startup has completed.");
+
 static DEFINE_IDA(rsxx_disk_ida);
 static DEFINE_SPINLOCK(rsxx_ida_lock);
 
+/* --------------------Debugfs Setup ------------------- */
+
+struct rsxx_cram {
+       u32 f_pos;
+       u32 offset;
+       void *i_private;
+};
+
+static int rsxx_attr_pci_regs_show(struct seq_file *m, void *p)
+{
+       struct rsxx_cardinfo *card = m->private;
+
+       seq_printf(m, "HWID             0x%08x\n",
+                                       ioread32(card->regmap + HWID));
+       seq_printf(m, "SCRATCH          0x%08x\n",
+                                       ioread32(card->regmap + SCRATCH));
+       seq_printf(m, "IER              0x%08x\n",
+                                       ioread32(card->regmap + IER));
+       seq_printf(m, "IPR              0x%08x\n",
+                                       ioread32(card->regmap + IPR));
+       seq_printf(m, "CREG_CMD         0x%08x\n",
+                                       ioread32(card->regmap + CREG_CMD));
+       seq_printf(m, "CREG_ADD         0x%08x\n",
+                                       ioread32(card->regmap + CREG_ADD));
+       seq_printf(m, "CREG_CNT         0x%08x\n",
+                                       ioread32(card->regmap + CREG_CNT));
+       seq_printf(m, "CREG_STAT        0x%08x\n",
+                                       ioread32(card->regmap + CREG_STAT));
+       seq_printf(m, "CREG_DATA0       0x%08x\n",
+                                       ioread32(card->regmap + CREG_DATA0));
+       seq_printf(m, "CREG_DATA1       0x%08x\n",
+                                       ioread32(card->regmap + CREG_DATA1));
+       seq_printf(m, "CREG_DATA2       0x%08x\n",
+                                       ioread32(card->regmap + CREG_DATA2));
+       seq_printf(m, "CREG_DATA3       0x%08x\n",
+                                       ioread32(card->regmap + CREG_DATA3));
+       seq_printf(m, "CREG_DATA4       0x%08x\n",
+                                       ioread32(card->regmap + CREG_DATA4));
+       seq_printf(m, "CREG_DATA5       0x%08x\n",
+                                       ioread32(card->regmap + CREG_DATA5));
+       seq_printf(m, "CREG_DATA6       0x%08x\n",
+                                       ioread32(card->regmap + CREG_DATA6));
+       seq_printf(m, "CREG_DATA7       0x%08x\n",
+                                       ioread32(card->regmap + CREG_DATA7));
+       seq_printf(m, "INTR_COAL        0x%08x\n",
+                                       ioread32(card->regmap + INTR_COAL));
+       seq_printf(m, "HW_ERROR         0x%08x\n",
+                                       ioread32(card->regmap + HW_ERROR));
+       seq_printf(m, "DEBUG0           0x%08x\n",
+                                       ioread32(card->regmap + PCI_DEBUG0));
+       seq_printf(m, "DEBUG1           0x%08x\n",
+                                       ioread32(card->regmap + PCI_DEBUG1));
+       seq_printf(m, "DEBUG2           0x%08x\n",
+                                       ioread32(card->regmap + PCI_DEBUG2));
+       seq_printf(m, "DEBUG3           0x%08x\n",
+                                       ioread32(card->regmap + PCI_DEBUG3));
+       seq_printf(m, "DEBUG4           0x%08x\n",
+                                       ioread32(card->regmap + PCI_DEBUG4));
+       seq_printf(m, "DEBUG5           0x%08x\n",
+                                       ioread32(card->regmap + PCI_DEBUG5));
+       seq_printf(m, "DEBUG6           0x%08x\n",
+                                       ioread32(card->regmap + PCI_DEBUG6));
+       seq_printf(m, "DEBUG7           0x%08x\n",
+                                       ioread32(card->regmap + PCI_DEBUG7));
+       seq_printf(m, "RECONFIG         0x%08x\n",
+                                       ioread32(card->regmap + PCI_RECONFIG));
+
+       return 0;
+}
+
+static int rsxx_attr_stats_show(struct seq_file *m, void *p)
+{
+       struct rsxx_cardinfo *card = m->private;
+       int i;
+
+       for (i = 0; i < card->n_targets; i++) {
+               seq_printf(m, "Ctrl %d CRC Errors       = %d\n",
+                               i, card->ctrl[i].stats.crc_errors);
+               seq_printf(m, "Ctrl %d Hard Errors      = %d\n",
+                               i, card->ctrl[i].stats.hard_errors);
+               seq_printf(m, "Ctrl %d Soft Errors      = %d\n",
+                               i, card->ctrl[i].stats.soft_errors);
+               seq_printf(m, "Ctrl %d Writes Issued    = %d\n",
+                               i, card->ctrl[i].stats.writes_issued);
+               seq_printf(m, "Ctrl %d Writes Failed    = %d\n",
+                               i, card->ctrl[i].stats.writes_failed);
+               seq_printf(m, "Ctrl %d Reads Issued     = %d\n",
+                               i, card->ctrl[i].stats.reads_issued);
+               seq_printf(m, "Ctrl %d Reads Failed     = %d\n",
+                               i, card->ctrl[i].stats.reads_failed);
+               seq_printf(m, "Ctrl %d Reads Retried    = %d\n",
+                               i, card->ctrl[i].stats.reads_retried);
+               seq_printf(m, "Ctrl %d Discards Issued  = %d\n",
+                               i, card->ctrl[i].stats.discards_issued);
+               seq_printf(m, "Ctrl %d Discards Failed  = %d\n",
+                               i, card->ctrl[i].stats.discards_failed);
+               seq_printf(m, "Ctrl %d DMA SW Errors    = %d\n",
+                               i, card->ctrl[i].stats.dma_sw_err);
+               seq_printf(m, "Ctrl %d DMA HW Faults    = %d\n",
+                               i, card->ctrl[i].stats.dma_hw_fault);
+               seq_printf(m, "Ctrl %d DMAs Cancelled   = %d\n",
+                               i, card->ctrl[i].stats.dma_cancelled);
+               seq_printf(m, "Ctrl %d SW Queue Depth   = %d\n",
+                               i, card->ctrl[i].stats.sw_q_depth);
+               seq_printf(m, "Ctrl %d HW Queue Depth   = %d\n",
+                       i, atomic_read(&card->ctrl[i].stats.hw_q_depth));
+       }
+
+       return 0;
+}
+
+static int rsxx_attr_stats_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rsxx_attr_stats_show, inode->i_private);
+}
+
+static int rsxx_attr_pci_regs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rsxx_attr_pci_regs_show, inode->i_private);
+}
+
+static ssize_t rsxx_cram_read(struct file *fp, char __user *ubuf,
+                             size_t cnt, loff_t *ppos)
+{
+       struct rsxx_cram *info = fp->private_data;
+       struct rsxx_cardinfo *card = info->i_private;
+       char *buf;
+       int st;
+
+       buf = kzalloc(sizeof(*buf) * cnt, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       info->f_pos = (u32)*ppos + info->offset;
+
+       st = rsxx_creg_read(card, CREG_ADD_CRAM + info->f_pos, cnt, buf, 1);
+       if (st)
+               return st;
+
+       st = copy_to_user(ubuf, buf, cnt);
+       if (st)
+               return st;
+
+       info->offset += cnt;
+
+       kfree(buf);
+
+       return cnt;
+}
+
+static ssize_t rsxx_cram_write(struct file *fp, const char __user *ubuf,
+                              size_t cnt, loff_t *ppos)
+{
+       struct rsxx_cram *info = fp->private_data;
+       struct rsxx_cardinfo *card = info->i_private;
+       char *buf;
+       int st;
+
+       buf = kzalloc(sizeof(*buf) * cnt, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       st = copy_from_user(buf, ubuf, cnt);
+       if (st)
+               return st;
+
+       info->f_pos = (u32)*ppos + info->offset;
+
+       st = rsxx_creg_write(card, CREG_ADD_CRAM + info->f_pos, cnt, buf, 1);
+       if (st)
+               return st;
+
+       info->offset += cnt;
+
+       kfree(buf);
+
+       return cnt;
+}
+
+static int rsxx_cram_open(struct inode *inode, struct file *file)
+{
+       struct rsxx_cram *info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->i_private = inode->i_private;
+       info->f_pos = file->f_pos;
+       file->private_data = info;
+
+       return 0;
+}
+
+static int rsxx_cram_release(struct inode *inode, struct file *file)
+{
+       struct rsxx_cram *info = file->private_data;
+
+       if (!info)
+               return 0;
+
+       kfree(info);
+       file->private_data = NULL;
+
+       return 0;
+}
+
+static const struct file_operations debugfs_cram_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rsxx_cram_open,
+       .read           = rsxx_cram_read,
+       .write          = rsxx_cram_write,
+       .release        = rsxx_cram_release,
+};
+
+static const struct file_operations debugfs_stats_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rsxx_attr_stats_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static const struct file_operations debugfs_pci_regs_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rsxx_attr_pci_regs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void rsxx_debugfs_dev_new(struct rsxx_cardinfo *card)
+{
+       struct dentry *debugfs_stats;
+       struct dentry *debugfs_pci_regs;
+       struct dentry *debugfs_cram;
+
+       card->debugfs_dir = debugfs_create_dir(card->gendisk->disk_name, NULL);
+       if (IS_ERR_OR_NULL(card->debugfs_dir))
+               goto failed_debugfs_dir;
+
+       debugfs_stats = debugfs_create_file("stats", S_IRUGO,
+                                           card->debugfs_dir, card,
+                                           &debugfs_stats_fops);
+       if (IS_ERR_OR_NULL(debugfs_stats))
+               goto failed_debugfs_stats;
+
+       debugfs_pci_regs = debugfs_create_file("pci_regs", S_IRUGO,
+                                              card->debugfs_dir, card,
+                                              &debugfs_pci_regs_fops);
+       if (IS_ERR_OR_NULL(debugfs_pci_regs))
+               goto failed_debugfs_pci_regs;
+
+       debugfs_cram = debugfs_create_file("cram", S_IRUGO | S_IWUSR,
+                                          card->debugfs_dir, card,
+                                          &debugfs_cram_fops);
+       if (IS_ERR_OR_NULL(debugfs_cram))
+               goto failed_debugfs_cram;
+
+       return;
+failed_debugfs_cram:
+       debugfs_remove(debugfs_pci_regs);
+failed_debugfs_pci_regs:
+       debugfs_remove(debugfs_stats);
+failed_debugfs_stats:
+       debugfs_remove(card->debugfs_dir);
+failed_debugfs_dir:
+       card->debugfs_dir = NULL;
+}
+
 /*----------------- Interrupt Control & Handling -------------------*/
 
 static void rsxx_mask_interrupts(struct rsxx_cardinfo *card)
@@ -163,12 +439,13 @@ static irqreturn_t rsxx_isr(int irq, void *pdata)
                }
 
                if (isr & CR_INTR_CREG) {
-                       schedule_work(&card->creg_ctrl.done_work);
+                       queue_work(card->creg_ctrl.creg_wq,
+                                  &card->creg_ctrl.done_work);
                        handled++;
                }
 
                if (isr & CR_INTR_EVENT) {
-                       schedule_work(&card->event_work);
+                       queue_work(card->event_wq, &card->event_work);
                        rsxx_disable_ier_and_isr(card, CR_INTR_EVENT);
                        handled++;
                }
@@ -329,7 +606,7 @@ static int rsxx_eeh_frozen(struct pci_dev *dev)
        int i;
        int st;
 
-       dev_warn(&dev->dev, "IBM FlashSystem PCI: preparing for slot reset.\n");
+       dev_warn(&dev->dev, "IBM Flash Adapter PCI: preparing for slot reset.\n");
 
        card->eeh_state = 1;
        rsxx_mask_interrupts(card);
@@ -367,15 +644,26 @@ static void rsxx_eeh_failure(struct pci_dev *dev)
 {
        struct rsxx_cardinfo *card = pci_get_drvdata(dev);
        int i;
+       int cnt = 0;
 
-       dev_err(&dev->dev, "IBM FlashSystem PCI: disabling failed card.\n");
+       dev_err(&dev->dev, "IBM Flash Adapter PCI: disabling failed card.\n");
 
        card->eeh_state = 1;
+       card->halt = 1;
 
-       for (i = 0; i < card->n_targets; i++)
-               del_timer_sync(&card->ctrl[i].activity_timer);
+       for (i = 0; i < card->n_targets; i++) {
+               spin_lock_bh(&card->ctrl[i].queue_lock);
+               cnt = rsxx_cleanup_dma_queue(&card->ctrl[i],
+                                            &card->ctrl[i].queue);
+               spin_unlock_bh(&card->ctrl[i].queue_lock);
+
+               cnt += rsxx_dma_cancel(&card->ctrl[i]);
 
-       rsxx_eeh_cancel_dmas(card);
+               if (cnt)
+                       dev_info(CARD_TO_DEV(card),
+                               "Freed %d queued DMAs on channel %d\n",
+                               cnt, card->ctrl[i].id);
+       }
 }
 
 static int rsxx_eeh_fifo_flush_poll(struct rsxx_cardinfo *card)
@@ -432,7 +720,7 @@ static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev)
        int st;
 
        dev_warn(&dev->dev,
-               "IBM FlashSystem PCI: recovering from slot reset.\n");
+               "IBM Flash Adapter PCI: recovering from slot reset.\n");
 
        st = pci_enable_device(dev);
        if (st)
@@ -485,7 +773,7 @@ static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev)
                                &card->ctrl[i].issue_dma_work);
        }
 
-       dev_info(&dev->dev, "IBM FlashSystem PCI: recovery complete.\n");
+       dev_info(&dev->dev, "IBM Flash Adapter PCI: recovery complete.\n");
 
        return PCI_ERS_RESULT_RECOVERED;
 
@@ -528,6 +816,7 @@ static int rsxx_pci_probe(struct pci_dev *dev,
 {
        struct rsxx_cardinfo *card;
        int st;
+       unsigned int sync_timeout;
 
        dev_info(&dev->dev, "PCI-Flash SSD discovered\n");
 
@@ -610,7 +899,11 @@ static int rsxx_pci_probe(struct pci_dev *dev,
        }
 
        /************* Setup Processor Command Interface *************/
-       rsxx_creg_setup(card);
+       st = rsxx_creg_setup(card);
+       if (st) {
+               dev_err(CARD_TO_DEV(card), "Failed to setup creg interface.\n");
+               goto failed_creg_setup;
+       }
 
        spin_lock_irq(&card->irq_lock);
        rsxx_enable_ier_and_isr(card, CR_INTR_CREG);
@@ -650,6 +943,12 @@ static int rsxx_pci_probe(struct pci_dev *dev,
        }
 
        /************* Setup Card Event Handler *************/
+       card->event_wq = create_singlethread_workqueue(DRIVER_NAME"_event");
+       if (!card->event_wq) {
+               dev_err(CARD_TO_DEV(card), "Failed card event setup.\n");
+               goto failed_event_handler;
+       }
+
        INIT_WORK(&card->event_work, card_event_handler);
 
        st = rsxx_setup_dev(card);
@@ -676,6 +975,33 @@ static int rsxx_pci_probe(struct pci_dev *dev,
                if (st)
                        dev_crit(CARD_TO_DEV(card),
                                "Failed issuing card startup\n");
+               if (sync_start) {
+                       sync_timeout = SYNC_START_TIMEOUT;
+
+                       dev_info(CARD_TO_DEV(card),
+                                "Waiting for card to startup\n");
+
+                       do {
+                               ssleep(1);
+                               sync_timeout--;
+
+                               rsxx_get_card_state(card, &card->state);
+                       } while (sync_timeout &&
+                               (card->state == CARD_STATE_STARTING));
+
+                       if (card->state == CARD_STATE_STARTING) {
+                               dev_warn(CARD_TO_DEV(card),
+                                        "Card startup timed out\n");
+                               card->size8 = 0;
+                       } else {
+                               dev_info(CARD_TO_DEV(card),
+                                       "card state: %s\n",
+                                       rsxx_card_state_to_str(card->state));
+                               st = rsxx_get_card_size8(card, &card->size8);
+                               if (st)
+                                       card->size8 = 0;
+                       }
+               }
        } else if (card->state == CARD_STATE_GOOD ||
                   card->state == CARD_STATE_RD_ONLY_FAULT) {
                st = rsxx_get_card_size8(card, &card->size8);
@@ -685,12 +1011,21 @@ static int rsxx_pci_probe(struct pci_dev *dev,
 
        rsxx_attach_dev(card);
 
+       /************* Setup Debugfs *************/
+       rsxx_debugfs_dev_new(card);
+
        return 0;
 
 failed_create_dev:
+       destroy_workqueue(card->event_wq);
+       card->event_wq = NULL;
+failed_event_handler:
        rsxx_dma_destroy(card);
 failed_dma_setup:
 failed_compatiblity_check:
+       destroy_workqueue(card->creg_ctrl.creg_wq);
+       card->creg_ctrl.creg_wq = NULL;
+failed_creg_setup:
        spin_lock_irq(&card->irq_lock);
        rsxx_disable_ier_and_isr(card, CR_INTR_ALL);
        spin_unlock_irq(&card->irq_lock);
@@ -756,6 +1091,8 @@ static void rsxx_pci_remove(struct pci_dev *dev)
        /* Prevent work_structs from re-queuing themselves. */
        card->halt = 1;
 
+       debugfs_remove_recursive(card->debugfs_dir);
+
        free_irq(dev->irq, card);
 
        if (!force_legacy)
index 4b5c020a0a65ad8831d75bf3407dd81b2d82b306..926dce9c452faf927d79fb0b99fd1a4e473aea6e 100644 (file)
@@ -431,6 +431,15 @@ static int __issue_creg_rw(struct rsxx_cardinfo *card,
        *hw_stat = completion.creg_status;
 
        if (completion.st) {
+               /*
+               * This read is needed to verify that there has not been any
+               * extreme errors that might have occurred, i.e. EEH. The
+               * function iowrite32 will not detect EEH errors, so it is
+               * necessary that we recover if such an error is the reason
+               * for the timeout. This is a dummy read.
+               */
+               ioread32(card->regmap + SCRATCH);
+
                dev_warn(CARD_TO_DEV(card),
                        "creg command failed(%d x%08x)\n",
                        completion.st, addr);
@@ -727,6 +736,11 @@ int rsxx_creg_setup(struct rsxx_cardinfo *card)
 {
        card->creg_ctrl.active_cmd = NULL;
 
+       card->creg_ctrl.creg_wq =
+                       create_singlethread_workqueue(DRIVER_NAME"_creg");
+       if (!card->creg_ctrl.creg_wq)
+               return -ENOMEM;
+
        INIT_WORK(&card->creg_ctrl.done_work, creg_cmd_done);
        mutex_init(&card->creg_ctrl.reset_lock);
        INIT_LIST_HEAD(&card->creg_ctrl.queue);
index 4346d17d29496b65316db8fc2f1133b9e0d116cd..d7af441880befc1c6aeb7cdd4dbfc128a8014bb8 100644 (file)
@@ -155,7 +155,8 @@ static void bio_dma_done_cb(struct rsxx_cardinfo *card,
                atomic_set(&meta->error, 1);
 
        if (atomic_dec_and_test(&meta->pending_dmas)) {
-               disk_stats_complete(card, meta->bio, meta->start_time);
+               if (!card->eeh_state && card->gendisk)
+                       disk_stats_complete(card, meta->bio, meta->start_time);
 
                bio_endio(meta->bio, atomic_read(&meta->error) ? -EIO : 0);
                kmem_cache_free(bio_meta_pool, meta);
@@ -170,6 +171,12 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio)
 
        might_sleep();
 
+       if (!card)
+               goto req_err;
+
+       if (bio->bi_sector + (bio->bi_size >> 9) > get_capacity(card->gendisk))
+               goto req_err;
+
        if (unlikely(card->halt)) {
                st = -EFAULT;
                goto req_err;
@@ -196,7 +203,8 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio)
        atomic_set(&bio_meta->pending_dmas, 0);
        bio_meta->start_time = jiffies;
 
-       disk_stats_start(card, bio);
+       if (!unlikely(card->halt))
+               disk_stats_start(card, bio);
 
        dev_dbg(CARD_TO_DEV(card), "BIO[%c]: meta: %p addr8: x%llx size: %d\n",
                 bio_data_dir(bio) ? 'W' : 'R', bio_meta,
@@ -225,24 +233,6 @@ static bool rsxx_discard_supported(struct rsxx_cardinfo *card)
        return (pci_rev >= RSXX_DISCARD_SUPPORT);
 }
 
-static unsigned short rsxx_get_logical_block_size(
-                                       struct rsxx_cardinfo *card)
-{
-       u32 capabilities = 0;
-       int st;
-
-       st = rsxx_get_card_capabilities(card, &capabilities);
-       if (st)
-               dev_warn(CARD_TO_DEV(card),
-                       "Failed reading card capabilities register\n");
-
-       /* Earlier firmware did not have support for 512 byte accesses */
-       if (capabilities & CARD_CAP_SUBPAGE_WRITES)
-               return 512;
-       else
-               return RSXX_HW_BLK_SIZE;
-}
-
 int rsxx_attach_dev(struct rsxx_cardinfo *card)
 {
        mutex_lock(&card->dev_lock);
@@ -305,7 +295,7 @@ int rsxx_setup_dev(struct rsxx_cardinfo *card)
                return -ENOMEM;
        }
 
-       blk_size = rsxx_get_logical_block_size(card);
+       blk_size = card->config.data.block_size;
 
        blk_queue_make_request(card->queue, rsxx_make_request);
        blk_queue_bounce_limit(card->queue, BLK_BOUNCE_ANY);
@@ -347,6 +337,7 @@ void rsxx_destroy_dev(struct rsxx_cardinfo *card)
        card->gendisk = NULL;
 
        blk_cleanup_queue(card->queue);
+       card->queue->queuedata = NULL;
        unregister_blkdev(card->major, DRIVER_NAME);
 }
 
index 0607513cfb41fa4b2ff88bac32be0665c645a2bb..bed32f16b084bdd46f7b881b32f95775effaa499 100644 (file)
@@ -245,6 +245,22 @@ static void rsxx_complete_dma(struct rsxx_dma_ctrl *ctrl,
        kmem_cache_free(rsxx_dma_pool, dma);
 }
 
+int rsxx_cleanup_dma_queue(struct rsxx_dma_ctrl *ctrl,
+                          struct list_head *q)
+{
+       struct rsxx_dma *dma;
+       struct rsxx_dma *tmp;
+       int cnt = 0;
+
+       list_for_each_entry_safe(dma, tmp, q, list) {
+               list_del(&dma->list);
+               rsxx_complete_dma(ctrl, dma, DMA_CANCELLED);
+               cnt++;
+       }
+
+       return cnt;
+}
+
 static void rsxx_requeue_dma(struct rsxx_dma_ctrl *ctrl,
                                 struct rsxx_dma *dma)
 {
@@ -252,9 +268,10 @@ static void rsxx_requeue_dma(struct rsxx_dma_ctrl *ctrl,
         * Requeued DMAs go to the front of the queue so they are issued
         * first.
         */
-       spin_lock(&ctrl->queue_lock);
+       spin_lock_bh(&ctrl->queue_lock);
+       ctrl->stats.sw_q_depth++;
        list_add(&dma->list, &ctrl->queue);
-       spin_unlock(&ctrl->queue_lock);
+       spin_unlock_bh(&ctrl->queue_lock);
 }
 
 static void rsxx_handle_dma_error(struct rsxx_dma_ctrl *ctrl,
@@ -329,6 +346,7 @@ static void rsxx_handle_dma_error(struct rsxx_dma_ctrl *ctrl,
 static void dma_engine_stalled(unsigned long data)
 {
        struct rsxx_dma_ctrl *ctrl = (struct rsxx_dma_ctrl *)data;
+       int cnt;
 
        if (atomic_read(&ctrl->stats.hw_q_depth) == 0 ||
            unlikely(ctrl->card->eeh_state))
@@ -349,18 +367,28 @@ static void dma_engine_stalled(unsigned long data)
                        "DMA channel %d has stalled, faulting interface.\n",
                        ctrl->id);
                ctrl->card->dma_fault = 1;
+
+               /* Clean up the DMA queue */
+               spin_lock(&ctrl->queue_lock);
+               cnt = rsxx_cleanup_dma_queue(ctrl, &ctrl->queue);
+               spin_unlock(&ctrl->queue_lock);
+
+               cnt += rsxx_dma_cancel(ctrl);
+
+               if (cnt)
+                       dev_info(CARD_TO_DEV(ctrl->card),
+                               "Freed %d queued DMAs on channel %d\n",
+                               cnt, ctrl->id);
        }
 }
 
-static void rsxx_issue_dmas(struct work_struct *work)
+static void rsxx_issue_dmas(struct rsxx_dma_ctrl *ctrl)
 {
-       struct rsxx_dma_ctrl *ctrl;
        struct rsxx_dma *dma;
        int tag;
        int cmds_pending = 0;
        struct hw_cmd *hw_cmd_buf;
 
-       ctrl = container_of(work, struct rsxx_dma_ctrl, issue_dma_work);
        hw_cmd_buf = ctrl->cmd.buf;
 
        if (unlikely(ctrl->card->halt) ||
@@ -368,22 +396,22 @@ static void rsxx_issue_dmas(struct work_struct *work)
                return;
 
        while (1) {
-               spin_lock(&ctrl->queue_lock);
+               spin_lock_bh(&ctrl->queue_lock);
                if (list_empty(&ctrl->queue)) {
-                       spin_unlock(&ctrl->queue_lock);
+                       spin_unlock_bh(&ctrl->queue_lock);
                        break;
                }
-               spin_unlock(&ctrl->queue_lock);
+               spin_unlock_bh(&ctrl->queue_lock);
 
                tag = pop_tracker(ctrl->trackers);
                if (tag == -1)
                        break;
 
-               spin_lock(&ctrl->queue_lock);
+               spin_lock_bh(&ctrl->queue_lock);
                dma = list_entry(ctrl->queue.next, struct rsxx_dma, list);
                list_del(&dma->list);
                ctrl->stats.sw_q_depth--;
-               spin_unlock(&ctrl->queue_lock);
+               spin_unlock_bh(&ctrl->queue_lock);
 
                /*
                 * This will catch any DMAs that slipped in right before the
@@ -440,9 +468,8 @@ static void rsxx_issue_dmas(struct work_struct *work)
        }
 }
 
-static void rsxx_dma_done(struct work_struct *work)
+static void rsxx_dma_done(struct rsxx_dma_ctrl *ctrl)
 {
-       struct rsxx_dma_ctrl *ctrl;
        struct rsxx_dma *dma;
        unsigned long flags;
        u16 count;
@@ -450,7 +477,6 @@ static void rsxx_dma_done(struct work_struct *work)
        u8 tag;
        struct hw_status *hw_st_buf;
 
-       ctrl = container_of(work, struct rsxx_dma_ctrl, dma_done_work);
        hw_st_buf = ctrl->status.buf;
 
        if (unlikely(ctrl->card->halt) ||
@@ -520,33 +546,32 @@ static void rsxx_dma_done(struct work_struct *work)
        rsxx_enable_ier(ctrl->card, CR_INTR_DMA(ctrl->id));
        spin_unlock_irqrestore(&ctrl->card->irq_lock, flags);
 
-       spin_lock(&ctrl->queue_lock);
+       spin_lock_bh(&ctrl->queue_lock);
        if (ctrl->stats.sw_q_depth)
                queue_work(ctrl->issue_wq, &ctrl->issue_dma_work);
-       spin_unlock(&ctrl->queue_lock);
+       spin_unlock_bh(&ctrl->queue_lock);
 }
 
-static int rsxx_cleanup_dma_queue(struct rsxx_cardinfo *card,
-                                     struct list_head *q)
+static void rsxx_schedule_issue(struct work_struct *work)
 {
-       struct rsxx_dma *dma;
-       struct rsxx_dma *tmp;
-       int cnt = 0;
+       struct rsxx_dma_ctrl *ctrl;
 
-       list_for_each_entry_safe(dma, tmp, q, list) {
-               list_del(&dma->list);
+       ctrl = container_of(work, struct rsxx_dma_ctrl, issue_dma_work);
 
-               if (dma->dma_addr)
-                       pci_unmap_page(card->dev, dma->dma_addr,
-                                      get_dma_size(dma),
-                                      (dma->cmd == HW_CMD_BLK_WRITE) ?
-                                      PCI_DMA_TODEVICE :
-                                      PCI_DMA_FROMDEVICE);
-               kmem_cache_free(rsxx_dma_pool, dma);
-               cnt++;
-       }
+       mutex_lock(&ctrl->work_lock);
+       rsxx_issue_dmas(ctrl);
+       mutex_unlock(&ctrl->work_lock);
+}
 
-       return cnt;
+static void rsxx_schedule_done(struct work_struct *work)
+{
+       struct rsxx_dma_ctrl *ctrl;
+
+       ctrl = container_of(work, struct rsxx_dma_ctrl, dma_done_work);
+
+       mutex_lock(&ctrl->work_lock);
+       rsxx_dma_done(ctrl);
+       mutex_unlock(&ctrl->work_lock);
 }
 
 static int rsxx_queue_discard(struct rsxx_cardinfo *card,
@@ -698,10 +723,10 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
 
        for (i = 0; i < card->n_targets; i++) {
                if (!list_empty(&dma_list[i])) {
-                       spin_lock(&card->ctrl[i].queue_lock);
+                       spin_lock_bh(&card->ctrl[i].queue_lock);
                        card->ctrl[i].stats.sw_q_depth += dma_cnt[i];
                        list_splice_tail(&dma_list[i], &card->ctrl[i].queue);
-                       spin_unlock(&card->ctrl[i].queue_lock);
+                       spin_unlock_bh(&card->ctrl[i].queue_lock);
 
                        queue_work(card->ctrl[i].issue_wq,
                                   &card->ctrl[i].issue_dma_work);
@@ -711,8 +736,11 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
        return 0;
 
 bvec_err:
-       for (i = 0; i < card->n_targets; i++)
-               rsxx_cleanup_dma_queue(card, &dma_list[i]);
+       for (i = 0; i < card->n_targets; i++) {
+               spin_lock_bh(&card->ctrl[i].queue_lock);
+               rsxx_cleanup_dma_queue(&card->ctrl[i], &dma_list[i]);
+               spin_unlock_bh(&card->ctrl[i].queue_lock);
+       }
 
        return st;
 }
@@ -780,6 +808,7 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev,
        spin_lock_init(&ctrl->trackers->lock);
 
        spin_lock_init(&ctrl->queue_lock);
+       mutex_init(&ctrl->work_lock);
        INIT_LIST_HEAD(&ctrl->queue);
 
        setup_timer(&ctrl->activity_timer, dma_engine_stalled,
@@ -793,8 +822,8 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev,
        if (!ctrl->done_wq)
                return -ENOMEM;
 
-       INIT_WORK(&ctrl->issue_dma_work, rsxx_issue_dmas);
-       INIT_WORK(&ctrl->dma_done_work, rsxx_dma_done);
+       INIT_WORK(&ctrl->issue_dma_work, rsxx_schedule_issue);
+       INIT_WORK(&ctrl->dma_done_work, rsxx_schedule_done);
 
        st = rsxx_hw_buffers_init(dev, ctrl);
        if (st)
@@ -918,13 +947,30 @@ failed_dma_setup:
        return st;
 }
 
+int rsxx_dma_cancel(struct rsxx_dma_ctrl *ctrl)
+{
+       struct rsxx_dma *dma;
+       int i;
+       int cnt = 0;
+
+       /* Clean up issued DMAs */
+       for (i = 0; i < RSXX_MAX_OUTSTANDING_CMDS; i++) {
+               dma = get_tracker_dma(ctrl->trackers, i);
+               if (dma) {
+                       atomic_dec(&ctrl->stats.hw_q_depth);
+                       rsxx_complete_dma(ctrl, dma, DMA_CANCELLED);
+                       push_tracker(ctrl->trackers, i);
+                       cnt++;
+               }
+       }
+
+       return cnt;
+}
 
 void rsxx_dma_destroy(struct rsxx_cardinfo *card)
 {
        struct rsxx_dma_ctrl *ctrl;
-       struct rsxx_dma *dma;
-       int i, j;
-       int cnt = 0;
+       int i;
 
        for (i = 0; i < card->n_targets; i++) {
                ctrl = &card->ctrl[i];
@@ -943,33 +989,11 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card)
                        del_timer_sync(&ctrl->activity_timer);
 
                /* Clean up the DMA queue */
-               spin_lock(&ctrl->queue_lock);
-               cnt = rsxx_cleanup_dma_queue(card, &ctrl->queue);
-               spin_unlock(&ctrl->queue_lock);
-
-               if (cnt)
-                       dev_info(CARD_TO_DEV(card),
-                               "Freed %d queued DMAs on channel %d\n",
-                               cnt, i);
-
-               /* Clean up issued DMAs */
-               for (j = 0; j < RSXX_MAX_OUTSTANDING_CMDS; j++) {
-                       dma = get_tracker_dma(ctrl->trackers, j);
-                       if (dma) {
-                               pci_unmap_page(card->dev, dma->dma_addr,
-                                              get_dma_size(dma),
-                                              (dma->cmd == HW_CMD_BLK_WRITE) ?
-                                              PCI_DMA_TODEVICE :
-                                              PCI_DMA_FROMDEVICE);
-                               kmem_cache_free(rsxx_dma_pool, dma);
-                               cnt++;
-                       }
-               }
+               spin_lock_bh(&ctrl->queue_lock);
+               rsxx_cleanup_dma_queue(ctrl, &ctrl->queue);
+               spin_unlock_bh(&ctrl->queue_lock);
 
-               if (cnt)
-                       dev_info(CARD_TO_DEV(card),
-                               "Freed %d pending DMAs on channel %d\n",
-                               cnt, i);
+               rsxx_dma_cancel(ctrl);
 
                vfree(ctrl->trackers);
 
@@ -1013,7 +1037,7 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card)
                        cnt++;
                }
 
-               spin_lock(&card->ctrl[i].queue_lock);
+               spin_lock_bh(&card->ctrl[i].queue_lock);
                list_splice(&issued_dmas[i], &card->ctrl[i].queue);
 
                atomic_sub(cnt, &card->ctrl[i].stats.hw_q_depth);
@@ -1028,7 +1052,7 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card)
                                               PCI_DMA_TODEVICE :
                                               PCI_DMA_FROMDEVICE);
                }
-               spin_unlock(&card->ctrl[i].queue_lock);
+               spin_unlock_bh(&card->ctrl[i].queue_lock);
        }
 
        kfree(issued_dmas);
@@ -1036,30 +1060,13 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card)
        return 0;
 }
 
-void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card)
-{
-       struct rsxx_dma *dma;
-       struct rsxx_dma *tmp;
-       int i;
-
-       for (i = 0; i < card->n_targets; i++) {
-               spin_lock(&card->ctrl[i].queue_lock);
-               list_for_each_entry_safe(dma, tmp, &card->ctrl[i].queue, list) {
-                       list_del(&dma->list);
-
-                       rsxx_complete_dma(&card->ctrl[i], dma, DMA_CANCELLED);
-               }
-               spin_unlock(&card->ctrl[i].queue_lock);
-       }
-}
-
 int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card)
 {
        struct rsxx_dma *dma;
        int i;
 
        for (i = 0; i < card->n_targets; i++) {
-               spin_lock(&card->ctrl[i].queue_lock);
+               spin_lock_bh(&card->ctrl[i].queue_lock);
                list_for_each_entry(dma, &card->ctrl[i].queue, list) {
                        dma->dma_addr = pci_map_page(card->dev, dma->page,
                                        dma->pg_off, get_dma_size(dma),
@@ -1067,12 +1074,12 @@ int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card)
                                        PCI_DMA_TODEVICE :
                                        PCI_DMA_FROMDEVICE);
                        if (!dma->dma_addr) {
-                               spin_unlock(&card->ctrl[i].queue_lock);
+                               spin_unlock_bh(&card->ctrl[i].queue_lock);
                                kmem_cache_free(rsxx_dma_pool, dma);
                                return -ENOMEM;
                        }
                }
-               spin_unlock(&card->ctrl[i].queue_lock);
+               spin_unlock_bh(&card->ctrl[i].queue_lock);
        }
 
        return 0;
index 382e8bf5c03b73dae35fd1ae8865110cc1a85168..5ad5055a4104d9341fc1f55054d1c872c58467d1 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/vmalloc.h>
 #include <linux/timer.h>
 #include <linux/ioctl.h>
+#include <linux/delay.h>
 
 #include "rsxx.h"
 #include "rsxx_cfg.h"
@@ -114,6 +115,7 @@ struct rsxx_dma_ctrl {
        struct timer_list               activity_timer;
        struct dma_tracker_list         *trackers;
        struct rsxx_dma_stats           stats;
+       struct mutex                    work_lock;
 };
 
 struct rsxx_cardinfo {
@@ -134,6 +136,7 @@ struct rsxx_cardinfo {
                spinlock_t              lock;
                bool                    active;
                struct creg_cmd         *active_cmd;
+               struct workqueue_struct *creg_wq;
                struct work_struct      done_work;
                struct list_head        queue;
                unsigned int            q_depth;
@@ -154,6 +157,7 @@ struct rsxx_cardinfo {
                int buf_len;
        } log;
 
+       struct workqueue_struct *event_wq;
        struct work_struct      event_work;
        unsigned int            state;
        u64                     size8;
@@ -181,6 +185,8 @@ struct rsxx_cardinfo {
 
        int                     n_targets;
        struct rsxx_dma_ctrl    *ctrl;
+
+       struct dentry           *debugfs_dir;
 };
 
 enum rsxx_pci_regmap {
@@ -283,6 +289,7 @@ enum rsxx_creg_addr {
        CREG_ADD_CAPABILITIES           = 0x80001050,
        CREG_ADD_LOG                    = 0x80002000,
        CREG_ADD_NUM_TARGETS            = 0x80003000,
+       CREG_ADD_CRAM                   = 0xA0000000,
        CREG_ADD_CONFIG                 = 0xB0000000,
 };
 
@@ -372,6 +379,8 @@ typedef void (*rsxx_dma_cb)(struct rsxx_cardinfo *card,
 int rsxx_dma_setup(struct rsxx_cardinfo *card);
 void rsxx_dma_destroy(struct rsxx_cardinfo *card);
 int rsxx_dma_init(void);
+int rsxx_cleanup_dma_queue(struct rsxx_dma_ctrl *ctrl, struct list_head *q);
+int rsxx_dma_cancel(struct rsxx_dma_ctrl *ctrl);
 void rsxx_dma_cleanup(void);
 void rsxx_dma_queue_reset(struct rsxx_cardinfo *card);
 int rsxx_dma_configure(struct rsxx_cardinfo *card);
@@ -382,7 +391,6 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
                           void *cb_data);
 int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl);
 int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card);
-void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card);
 int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card);
 
 /***** cregs.c *****/
index dd5b2fed97e9ae2b7665f13ec3c42db6ee6fb462..bf4b9d282c042ec4d5b3c31a9d3192bd059afcc5 100644 (file)
 #include "common.h"
 
 /*
- * These are rather arbitrary. They are fairly large because adjacent requests
- * pulled from a communication ring are quite likely to end up being part of
- * the same scatter/gather request at the disc.
+ * Maximum number of unused free pages to keep in the internal buffer.
+ * Setting this to a value too low will reduce memory used in each backend,
+ * but can have a performance penalty.
  *
- * ** TRY INCREASING 'xen_blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
- *
- * This will increase the chances of being able to write whole tracks.
- * 64 should be enough to keep us competitive with Linux.
+ * A sane value is xen_blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST, but can
+ * be set to a lower value that might degrade performance on some intensive
+ * IO workloads.
  */
-static int xen_blkif_reqs = 64;
-module_param_named(reqs, xen_blkif_reqs, int, 0);
-MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate");
 
-/* Run-time switchable: /sys/module/blkback/parameters/ */
-static unsigned int log_stats;
-module_param(log_stats, int, 0644);
+static int xen_blkif_max_buffer_pages = 1024;
+module_param_named(max_buffer_pages, xen_blkif_max_buffer_pages, int, 0644);
+MODULE_PARM_DESC(max_buffer_pages,
+"Maximum number of free pages to keep in each block backend buffer");
 
 /*
- * Each outstanding request that we've passed to the lower device layers has a
- * 'pending_req' allocated to it. Each buffer_head that completes decrements
- * the pendcnt towards zero. When it hits zero, the specified domain has a
- * response queued for it, with the saved 'id' passed back.
+ * Maximum number of grants to map persistently in blkback. For maximum
+ * performance this should be the total numbers of grants that can be used
+ * to fill the ring, but since this might become too high, specially with
+ * the use of indirect descriptors, we set it to a value that provides good
+ * performance without using too much memory.
+ *
+ * When the list of persistent grants is full we clean it up using a LRU
+ * algorithm.
  */
-struct pending_req {
-       struct xen_blkif        *blkif;
-       u64                     id;
-       int                     nr_pages;
-       atomic_t                pendcnt;
-       unsigned short          operation;
-       int                     status;
-       struct list_head        free_list;
-       DECLARE_BITMAP(unmap_seg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-};
 
-#define BLKBACK_INVALID_HANDLE (~0)
+static int xen_blkif_max_pgrants = 1056;
+module_param_named(max_persistent_grants, xen_blkif_max_pgrants, int, 0644);
+MODULE_PARM_DESC(max_persistent_grants,
+                 "Maximum number of grants to map persistently");
 
-struct xen_blkbk {
-       struct pending_req      *pending_reqs;
-       /* List of all 'pending_req' available */
-       struct list_head        pending_free;
-       /* And its spinlock. */
-       spinlock_t              pending_free_lock;
-       wait_queue_head_t       pending_free_wq;
-       /* The list of all pages that are available. */
-       struct page             **pending_pages;
-       /* And the grant handles that are available. */
-       grant_handle_t          *pending_grant_handles;
-};
-
-static struct xen_blkbk *blkbk;
+/*
+ * The LRU mechanism to clean the lists of persistent grants needs to
+ * be executed periodically. The time interval between consecutive executions
+ * of the purge mechanism is set in ms.
+ */
+#define LRU_INTERVAL 100
 
 /*
- * Maximum number of grant pages that can be mapped in blkback.
- * BLKIF_MAX_SEGMENTS_PER_REQUEST * RING_SIZE is the maximum number of
- * pages that blkback will persistently map.
- * Currently, this is:
- * RING_SIZE = 32 (for all known ring types)
- * BLKIF_MAX_SEGMENTS_PER_REQUEST = 11
- * sizeof(struct persistent_gnt) = 48
- * So the maximum memory used to store the grants is:
- * 32 * 11 * 48 = 16896 bytes
+ * When the persistent grants list is full we will remove unused grants
+ * from the list. The percent number of grants to be removed at each LRU
+ * execution.
  */
-static inline unsigned int max_mapped_grant_pages(enum blkif_protocol protocol)
+#define LRU_PERCENT_CLEAN 5
+
+/* Run-time switchable: /sys/module/blkback/parameters/ */
+static unsigned int log_stats;
+module_param(log_stats, int, 0644);
+
+#define BLKBACK_INVALID_HANDLE (~0)
+
+/* Number of free pages to remove on each call to free_xenballooned_pages */
+#define NUM_BATCH_FREE_PAGES 10
+
+static inline int get_free_page(struct xen_blkif *blkif, struct page **page)
 {
-       switch (protocol) {
-       case BLKIF_PROTOCOL_NATIVE:
-               return __CONST_RING_SIZE(blkif, PAGE_SIZE) *
-                          BLKIF_MAX_SEGMENTS_PER_REQUEST;
-       case BLKIF_PROTOCOL_X86_32:
-               return __CONST_RING_SIZE(blkif_x86_32, PAGE_SIZE) *
-                          BLKIF_MAX_SEGMENTS_PER_REQUEST;
-       case BLKIF_PROTOCOL_X86_64:
-               return __CONST_RING_SIZE(blkif_x86_64, PAGE_SIZE) *
-                          BLKIF_MAX_SEGMENTS_PER_REQUEST;
-       default:
-               BUG();
+       unsigned long flags;
+
+       spin_lock_irqsave(&blkif->free_pages_lock, flags);
+       if (list_empty(&blkif->free_pages)) {
+               BUG_ON(blkif->free_pages_num != 0);
+               spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+               return alloc_xenballooned_pages(1, page, false);
        }
+       BUG_ON(blkif->free_pages_num == 0);
+       page[0] = list_first_entry(&blkif->free_pages, struct page, lru);
+       list_del(&page[0]->lru);
+       blkif->free_pages_num--;
+       spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+
        return 0;
 }
 
-
-/*
- * Little helpful macro to figure out the index and virtual address of the
- * pending_pages[..]. For each 'pending_req' we have have up to
- * BLKIF_MAX_SEGMENTS_PER_REQUEST (11) pages. The seg would be from 0 through
- * 10 and would index in the pending_pages[..].
- */
-static inline int vaddr_pagenr(struct pending_req *req, int seg)
+static inline void put_free_pages(struct xen_blkif *blkif, struct page **page,
+                                  int num)
 {
-       return (req - blkbk->pending_reqs) *
-               BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
-}
+       unsigned long flags;
+       int i;
 
-#define pending_page(req, seg) pending_pages[vaddr_pagenr(req, seg)]
+       spin_lock_irqsave(&blkif->free_pages_lock, flags);
+       for (i = 0; i < num; i++)
+               list_add(&page[i]->lru, &blkif->free_pages);
+       blkif->free_pages_num += num;
+       spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+}
 
-static inline unsigned long vaddr(struct pending_req *req, int seg)
+static inline void shrink_free_pagepool(struct xen_blkif *blkif, int num)
 {
-       unsigned long pfn = page_to_pfn(blkbk->pending_page(req, seg));
-       return (unsigned long)pfn_to_kaddr(pfn);
-}
+       /* Remove requested pages in batches of NUM_BATCH_FREE_PAGES */
+       struct page *page[NUM_BATCH_FREE_PAGES];
+       unsigned int num_pages = 0;
+       unsigned long flags;
 
-#define pending_handle(_req, _seg) \
-       (blkbk->pending_grant_handles[vaddr_pagenr(_req, _seg)])
+       spin_lock_irqsave(&blkif->free_pages_lock, flags);
+       while (blkif->free_pages_num > num) {
+               BUG_ON(list_empty(&blkif->free_pages));
+               page[num_pages] = list_first_entry(&blkif->free_pages,
+                                                  struct page, lru);
+               list_del(&page[num_pages]->lru);
+               blkif->free_pages_num--;
+               if (++num_pages == NUM_BATCH_FREE_PAGES) {
+                       spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+                       free_xenballooned_pages(num_pages, page);
+                       spin_lock_irqsave(&blkif->free_pages_lock, flags);
+                       num_pages = 0;
+               }
+       }
+       spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+       if (num_pages != 0)
+               free_xenballooned_pages(num_pages, page);
+}
 
+#define vaddr(page) ((unsigned long)pfn_to_kaddr(page_to_pfn(page)))
 
 static int do_block_io_op(struct xen_blkif *blkif);
 static int dispatch_rw_block_io(struct xen_blkif *blkif,
@@ -170,13 +178,29 @@ static void make_response(struct xen_blkif *blkif, u64 id,
             (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL)
 
 
-static void add_persistent_gnt(struct rb_root *root,
+/*
+ * We don't need locking around the persistent grant helpers
+ * because blkback uses a single-thread for each backed, so we
+ * can be sure that this functions will never be called recursively.
+ *
+ * The only exception to that is put_persistent_grant, that can be called
+ * from interrupt context (by xen_blkbk_unmap), so we have to use atomic
+ * bit operations to modify the flags of a persistent grant and to count
+ * the number of used grants.
+ */
+static int add_persistent_gnt(struct xen_blkif *blkif,
                               struct persistent_gnt *persistent_gnt)
 {
-       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       struct rb_node **new = NULL, *parent = NULL;
        struct persistent_gnt *this;
 
+       if (blkif->persistent_gnt_c >= xen_blkif_max_pgrants) {
+               if (!blkif->vbd.overflow_max_grants)
+                       blkif->vbd.overflow_max_grants = 1;
+               return -EBUSY;
+       }
        /* Figure out where to put new node */
+       new = &blkif->persistent_gnts.rb_node;
        while (*new) {
                this = container_of(*new, struct persistent_gnt, node);
 
@@ -186,22 +210,28 @@ static void add_persistent_gnt(struct rb_root *root,
                else if (persistent_gnt->gnt > this->gnt)
                        new = &((*new)->rb_right);
                else {
-                       pr_alert(DRV_PFX " trying to add a gref that's already in the tree\n");
-                       BUG();
+                       pr_alert_ratelimited(DRV_PFX " trying to add a gref that's already in the tree\n");
+                       return -EINVAL;
                }
        }
 
+       bitmap_zero(persistent_gnt->flags, PERSISTENT_GNT_FLAGS_SIZE);
+       set_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags);
        /* Add new node and rebalance tree. */
        rb_link_node(&(persistent_gnt->node), parent, new);
-       rb_insert_color(&(persistent_gnt->node), root);
+       rb_insert_color(&(persistent_gnt->node), &blkif->persistent_gnts);
+       blkif->persistent_gnt_c++;
+       atomic_inc(&blkif->persistent_gnt_in_use);
+       return 0;
 }
 
-static struct persistent_gnt *get_persistent_gnt(struct rb_root *root,
+static struct persistent_gnt *get_persistent_gnt(struct xen_blkif *blkif,
                                                 grant_ref_t gref)
 {
        struct persistent_gnt *data;
-       struct rb_node *node = root->rb_node;
+       struct rb_node *node = NULL;
 
+       node = blkif->persistent_gnts.rb_node;
        while (node) {
                data = container_of(node, struct persistent_gnt, node);
 
@@ -209,13 +239,31 @@ static struct persistent_gnt *get_persistent_gnt(struct rb_root *root,
                        node = node->rb_left;
                else if (gref > data->gnt)
                        node = node->rb_right;
-               else
+               else {
+                       if(test_bit(PERSISTENT_GNT_ACTIVE, data->flags)) {
+                               pr_alert_ratelimited(DRV_PFX " requesting a grant already in use\n");
+                               return NULL;
+                       }
+                       set_bit(PERSISTENT_GNT_ACTIVE, data->flags);
+                       atomic_inc(&blkif->persistent_gnt_in_use);
                        return data;
+               }
        }
        return NULL;
 }
 
-static void free_persistent_gnts(struct rb_root *root, unsigned int num)
+static void put_persistent_gnt(struct xen_blkif *blkif,
+                               struct persistent_gnt *persistent_gnt)
+{
+       if(!test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags))
+                 pr_alert_ratelimited(DRV_PFX " freeing a grant already unused");
+       set_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags);
+       clear_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags);
+       atomic_dec(&blkif->persistent_gnt_in_use);
+}
+
+static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
+                                 unsigned int num)
 {
        struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
@@ -240,7 +288,7 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
                        ret = gnttab_unmap_refs(unmap, NULL, pages,
                                segs_to_unmap);
                        BUG_ON(ret);
-                       free_xenballooned_pages(segs_to_unmap, pages);
+                       put_free_pages(blkif, pages, segs_to_unmap);
                        segs_to_unmap = 0;
                }
 
@@ -251,21 +299,148 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
        BUG_ON(num != 0);
 }
 
+static void unmap_purged_grants(struct work_struct *work)
+{
+       struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       struct persistent_gnt *persistent_gnt;
+       int ret, segs_to_unmap = 0;
+       struct xen_blkif *blkif = container_of(work, typeof(*blkif), persistent_purge_work);
+
+       while(!list_empty(&blkif->persistent_purge_list)) {
+               persistent_gnt = list_first_entry(&blkif->persistent_purge_list,
+                                                 struct persistent_gnt,
+                                                 remove_node);
+               list_del(&persistent_gnt->remove_node);
+
+               gnttab_set_unmap_op(&unmap[segs_to_unmap],
+                       vaddr(persistent_gnt->page),
+                       GNTMAP_host_map,
+                       persistent_gnt->handle);
+
+               pages[segs_to_unmap] = persistent_gnt->page;
+
+               if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+                       ret = gnttab_unmap_refs(unmap, NULL, pages,
+                               segs_to_unmap);
+                       BUG_ON(ret);
+                       put_free_pages(blkif, pages, segs_to_unmap);
+                       segs_to_unmap = 0;
+               }
+               kfree(persistent_gnt);
+       }
+       if (segs_to_unmap > 0) {
+               ret = gnttab_unmap_refs(unmap, NULL, pages, segs_to_unmap);
+               BUG_ON(ret);
+               put_free_pages(blkif, pages, segs_to_unmap);
+       }
+}
+
+static void purge_persistent_gnt(struct xen_blkif *blkif)
+{
+       struct persistent_gnt *persistent_gnt;
+       struct rb_node *n;
+       unsigned int num_clean, total;
+       bool scan_used = false, clean_used = false;
+       struct rb_root *root;
+
+       if (blkif->persistent_gnt_c < xen_blkif_max_pgrants ||
+           (blkif->persistent_gnt_c == xen_blkif_max_pgrants &&
+           !blkif->vbd.overflow_max_grants)) {
+               return;
+       }
+
+       if (work_pending(&blkif->persistent_purge_work)) {
+               pr_alert_ratelimited(DRV_PFX "Scheduled work from previous purge is still pending, cannot purge list\n");
+               return;
+       }
+
+       num_clean = (xen_blkif_max_pgrants / 100) * LRU_PERCENT_CLEAN;
+       num_clean = blkif->persistent_gnt_c - xen_blkif_max_pgrants + num_clean;
+       num_clean = min(blkif->persistent_gnt_c, num_clean);
+       if ((num_clean == 0) ||
+           (num_clean > (blkif->persistent_gnt_c - atomic_read(&blkif->persistent_gnt_in_use))))
+               return;
+
+       /*
+        * At this point, we can assure that there will be no calls
+         * to get_persistent_grant (because we are executing this code from
+         * xen_blkif_schedule), there can only be calls to put_persistent_gnt,
+         * which means that the number of currently used grants will go down,
+         * but never up, so we will always be able to remove the requested
+         * number of grants.
+        */
+
+       total = num_clean;
+
+       pr_debug(DRV_PFX "Going to purge %u persistent grants\n", num_clean);
+
+       INIT_LIST_HEAD(&blkif->persistent_purge_list);
+       root = &blkif->persistent_gnts;
+purge_list:
+       foreach_grant_safe(persistent_gnt, n, root, node) {
+               BUG_ON(persistent_gnt->handle ==
+                       BLKBACK_INVALID_HANDLE);
+
+               if (clean_used) {
+                       clear_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags);
+                       continue;
+               }
+
+               if (test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags))
+                       continue;
+               if (!scan_used &&
+                   (test_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags)))
+                       continue;
+
+               rb_erase(&persistent_gnt->node, root);
+               list_add(&persistent_gnt->remove_node,
+                        &blkif->persistent_purge_list);
+               if (--num_clean == 0)
+                       goto finished;
+       }
+       /*
+        * If we get here it means we also need to start cleaning
+        * grants that were used since last purge in order to cope
+        * with the requested num
+        */
+       if (!scan_used && !clean_used) {
+               pr_debug(DRV_PFX "Still missing %u purged frames\n", num_clean);
+               scan_used = true;
+               goto purge_list;
+       }
+finished:
+       if (!clean_used) {
+               pr_debug(DRV_PFX "Finished scanning for grants to clean, removing used flag\n");
+               clean_used = true;
+               goto purge_list;
+       }
+
+       blkif->persistent_gnt_c -= (total - num_clean);
+       blkif->vbd.overflow_max_grants = 0;
+
+       /* We can defer this work */
+       INIT_WORK(&blkif->persistent_purge_work, unmap_purged_grants);
+       schedule_work(&blkif->persistent_purge_work);
+       pr_debug(DRV_PFX "Purged %u/%u\n", (total - num_clean), total);
+       return;
+}
+
 /*
  * Retrieve from the 'pending_reqs' a free pending_req structure to be used.
  */
-static struct pending_req *alloc_req(void)
+static struct pending_req *alloc_req(struct xen_blkif *blkif)
 {
        struct pending_req *req = NULL;
        unsigned long flags;
 
-       spin_lock_irqsave(&blkbk->pending_free_lock, flags);
-       if (!list_empty(&blkbk->pending_free)) {
-               req = list_entry(blkbk->pending_free.next, struct pending_req,
+       spin_lock_irqsave(&blkif->pending_free_lock, flags);
+       if (!list_empty(&blkif->pending_free)) {
+               req = list_entry(blkif->pending_free.next, struct pending_req,
                                 free_list);
                list_del(&req->free_list);
        }
-       spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+       spin_unlock_irqrestore(&blkif->pending_free_lock, flags);
        return req;
 }
 
@@ -273,17 +448,17 @@ static struct pending_req *alloc_req(void)
  * Return the 'pending_req' structure back to the freepool. We also
  * wake up the thread if it was waiting for a free page.
  */
-static void free_req(struct pending_req *req)
+static void free_req(struct xen_blkif *blkif, struct pending_req *req)
 {
        unsigned long flags;
        int was_empty;
 
-       spin_lock_irqsave(&blkbk->pending_free_lock, flags);
-       was_empty = list_empty(&blkbk->pending_free);
-       list_add(&req->free_list, &blkbk->pending_free);
-       spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+       spin_lock_irqsave(&blkif->pending_free_lock, flags);
+       was_empty = list_empty(&blkif->pending_free);
+       list_add(&req->free_list, &blkif->pending_free);
+       spin_unlock_irqrestore(&blkif->pending_free_lock, flags);
        if (was_empty)
-               wake_up(&blkbk->pending_free_wq);
+               wake_up(&blkif->pending_free_wq);
 }
 
 /*
@@ -382,10 +557,12 @@ irqreturn_t xen_blkif_be_int(int irq, void *dev_id)
 static void print_stats(struct xen_blkif *blkif)
 {
        pr_info("xen-blkback (%s): oo %3llu  |  rd %4llu  |  wr %4llu  |  f %4llu"
-                "  |  ds %4llu\n",
+                "  |  ds %4llu | pg: %4u/%4d\n",
                 current->comm, blkif->st_oo_req,
                 blkif->st_rd_req, blkif->st_wr_req,
-                blkif->st_f_req, blkif->st_ds_req);
+                blkif->st_f_req, blkif->st_ds_req,
+                blkif->persistent_gnt_c,
+                xen_blkif_max_pgrants);
        blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
        blkif->st_rd_req = 0;
        blkif->st_wr_req = 0;
@@ -397,6 +574,8 @@ int xen_blkif_schedule(void *arg)
 {
        struct xen_blkif *blkif = arg;
        struct xen_vbd *vbd = &blkif->vbd;
+       unsigned long timeout;
+       int ret;
 
        xen_blkif_get(blkif);
 
@@ -406,27 +585,52 @@ int xen_blkif_schedule(void *arg)
                if (unlikely(vbd->size != vbd_sz(vbd)))
                        xen_vbd_resize(blkif);
 
-               wait_event_interruptible(
+               timeout = msecs_to_jiffies(LRU_INTERVAL);
+
+               timeout = wait_event_interruptible_timeout(
                        blkif->wq,
-                       blkif->waiting_reqs || kthread_should_stop());
-               wait_event_interruptible(
-                       blkbk->pending_free_wq,
-                       !list_empty(&blkbk->pending_free) ||
-                       kthread_should_stop());
+                       blkif->waiting_reqs || kthread_should_stop(),
+                       timeout);
+               if (timeout == 0)
+                       goto purge_gnt_list;
+               timeout = wait_event_interruptible_timeout(
+                       blkif->pending_free_wq,
+                       !list_empty(&blkif->pending_free) ||
+                       kthread_should_stop(),
+                       timeout);
+               if (timeout == 0)
+                       goto purge_gnt_list;
 
                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());
+
+purge_gnt_list:
+               if (blkif->vbd.feature_gnt_persistent &&
+                   time_after(jiffies, blkif->next_lru)) {
+                       purge_persistent_gnt(blkif);
+                       blkif->next_lru = jiffies + msecs_to_jiffies(LRU_INTERVAL);
+               }
+
+               /* Shrink if we have more than xen_blkif_max_buffer_pages */
+               shrink_free_pagepool(blkif, xen_blkif_max_buffer_pages);
 
                if (log_stats && time_after(jiffies, blkif->st_print))
                        print_stats(blkif);
        }
 
+       /* Since we are shutting down remove all pages from the buffer */
+       shrink_free_pagepool(blkif, 0 /* All */);
+
        /* Free all persistent grant pages */
        if (!RB_EMPTY_ROOT(&blkif->persistent_gnts))
-               free_persistent_gnts(&blkif->persistent_gnts,
+               free_persistent_gnts(blkif, &blkif->persistent_gnts,
                        blkif->persistent_gnt_c);
 
        BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts));
@@ -441,148 +645,98 @@ int xen_blkif_schedule(void *arg)
        return 0;
 }
 
-struct seg_buf {
-       unsigned int offset;
-       unsigned int nsec;
-};
 /*
  * Unmap the grant references, and also remove the M2P over-rides
  * used in the 'pending_req'.
  */
-static void xen_blkbk_unmap(struct pending_req *req)
+static void xen_blkbk_unmap(struct xen_blkif *blkif,
+                            struct grant_page *pages[],
+                            int num)
 {
        struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-       struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       struct page *unmap_pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        unsigned int i, invcount = 0;
-       grant_handle_t handle;
        int ret;
 
-       for (i = 0; i < req->nr_pages; i++) {
-               if (!test_bit(i, req->unmap_seg))
+       for (i = 0; i < num; i++) {
+               if (pages[i]->persistent_gnt != NULL) {
+                       put_persistent_gnt(blkif, pages[i]->persistent_gnt);
                        continue;
-               handle = pending_handle(req, i);
-               if (handle == BLKBACK_INVALID_HANDLE)
+               }
+               if (pages[i]->handle == BLKBACK_INVALID_HANDLE)
                        continue;
-               gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i),
-                                   GNTMAP_host_map, handle);
-               pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
-               pages[invcount] = virt_to_page(vaddr(req, i));
-               invcount++;
+               unmap_pages[invcount] = pages[i]->page;
+               gnttab_set_unmap_op(&unmap[invcount], vaddr(pages[i]->page),
+                                   GNTMAP_host_map, pages[i]->handle);
+               pages[i]->handle = BLKBACK_INVALID_HANDLE;
+               if (++invcount == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+                       ret = gnttab_unmap_refs(unmap, NULL, unmap_pages,
+                                               invcount);
+                       BUG_ON(ret);
+                       put_free_pages(blkif, unmap_pages, invcount);
+                       invcount = 0;
+               }
+       }
+       if (invcount) {
+               ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount);
+               BUG_ON(ret);
+               put_free_pages(blkif, unmap_pages, invcount);
        }
-
-       ret = gnttab_unmap_refs(unmap, NULL, pages, invcount);
-       BUG_ON(ret);
 }
 
-static int xen_blkbk_map(struct blkif_request *req,
-                        struct pending_req *pending_req,
-                        struct seg_buf seg[],
-                        struct page *pages[])
+static int xen_blkbk_map(struct xen_blkif *blkif,
+                        struct grant_page *pages[],
+                        int num, bool ro)
 {
        struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-       struct persistent_gnt *persistent_gnts[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct page *pages_to_gnt[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct persistent_gnt *persistent_gnt = NULL;
-       struct xen_blkif *blkif = pending_req->blkif;
        phys_addr_t addr = 0;
-       int i, j;
-       bool new_map;
-       int nseg = req->u.rw.nr_segments;
+       int i, seg_idx, new_map_idx;
        int segs_to_map = 0;
        int ret = 0;
+       int last_map = 0, map_until = 0;
        int use_persistent_gnts;
 
        use_persistent_gnts = (blkif->vbd.feature_gnt_persistent);
 
-       BUG_ON(blkif->persistent_gnt_c >
-                  max_mapped_grant_pages(pending_req->blkif->blk_protocol));
-
        /*
         * Fill out preq.nr_sects with proper amount of sectors, and setup
         * assign map[..] with the PFN of the page in our domain with the
         * corresponding grant reference for each page.
         */
-       for (i = 0; i < nseg; i++) {
+again:
+       for (i = map_until; i < num; i++) {
                uint32_t flags;
 
                if (use_persistent_gnts)
                        persistent_gnt = get_persistent_gnt(
-                               &blkif->persistent_gnts,
-                               req->u.rw.seg[i].gref);
+                               blkif,
+                               pages[i]->gref);
 
                if (persistent_gnt) {
                        /*
                         * We are using persistent grants and
                         * the grant is already mapped
                         */
-                       new_map = false;
-               } else if (use_persistent_gnts &&
-                          blkif->persistent_gnt_c <
-                          max_mapped_grant_pages(blkif->blk_protocol)) {
-                       /*
-                        * We are using persistent grants, the grant is
-                        * not mapped but we have room for it
-                        */
-                       new_map = true;
-                       persistent_gnt = kmalloc(
-                               sizeof(struct persistent_gnt),
-                               GFP_KERNEL);
-                       if (!persistent_gnt)
-                               return -ENOMEM;
-                       if (alloc_xenballooned_pages(1, &persistent_gnt->page,
-                           false)) {
-                               kfree(persistent_gnt);
-                               return -ENOMEM;
-                       }
-                       persistent_gnt->gnt = req->u.rw.seg[i].gref;
-                       persistent_gnt->handle = BLKBACK_INVALID_HANDLE;
-
-                       pages_to_gnt[segs_to_map] =
-                               persistent_gnt->page;
-                       addr = (unsigned long) pfn_to_kaddr(
-                               page_to_pfn(persistent_gnt->page));
-
-                       add_persistent_gnt(&blkif->persistent_gnts,
-                               persistent_gnt);
-                       blkif->persistent_gnt_c++;
-                       pr_debug(DRV_PFX " grant %u added to the tree of persistent grants, using %u/%u\n",
-                                persistent_gnt->gnt, blkif->persistent_gnt_c,
-                                max_mapped_grant_pages(blkif->blk_protocol));
+                       pages[i]->page = persistent_gnt->page;
+                       pages[i]->persistent_gnt = persistent_gnt;
                } else {
-                       /*
-                        * We are either using persistent grants and
-                        * hit the maximum limit of grants mapped,
-                        * or we are not using persistent grants.
-                        */
-                       if (use_persistent_gnts &&
-                               !blkif->vbd.overflow_max_grants) {
-                               blkif->vbd.overflow_max_grants = 1;
-                               pr_alert(DRV_PFX " domain %u, device %#x is using maximum number of persistent grants\n",
-                                        blkif->domid, blkif->vbd.handle);
-                       }
-                       new_map = true;
-                       pages[i] = blkbk->pending_page(pending_req, i);
-                       addr = vaddr(pending_req, i);
-                       pages_to_gnt[segs_to_map] =
-                               blkbk->pending_page(pending_req, i);
-               }
-
-               if (persistent_gnt) {
-                       pages[i] = persistent_gnt->page;
-                       persistent_gnts[i] = persistent_gnt;
-               } else {
-                       persistent_gnts[i] = NULL;
-               }
-
-               if (new_map) {
+                       if (get_free_page(blkif, &pages[i]->page))
+                               goto out_of_memory;
+                       addr = vaddr(pages[i]->page);
+                       pages_to_gnt[segs_to_map] = pages[i]->page;
+                       pages[i]->persistent_gnt = NULL;
                        flags = GNTMAP_host_map;
-                       if (!persistent_gnt &&
-                           (pending_req->operation != BLKIF_OP_READ))
+                       if (!use_persistent_gnts && ro)
                                flags |= GNTMAP_readonly;
                        gnttab_set_map_op(&map[segs_to_map++], addr,
-                                         flags, req->u.rw.seg[i].gref,
+                                         flags, pages[i]->gref,
                                          blkif->domid);
                }
+               map_until = i + 1;
+               if (segs_to_map == BLKIF_MAX_SEGMENTS_PER_REQUEST)
+                       break;
        }
 
        if (segs_to_map) {
@@ -595,49 +749,133 @@ static int xen_blkbk_map(struct blkif_request *req,
         * so that when we access vaddr(pending_req,i) it has the contents of
         * the page from the other domain.
         */
-       bitmap_zero(pending_req->unmap_seg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-       for (i = 0, j = 0; i < nseg; i++) {
-               if (!persistent_gnts[i] ||
-                   persistent_gnts[i]->handle == BLKBACK_INVALID_HANDLE) {
+       for (seg_idx = last_map, new_map_idx = 0; seg_idx < map_until; seg_idx++) {
+               if (!pages[seg_idx]->persistent_gnt) {
                        /* This is a newly mapped grant */
-                       BUG_ON(j >= segs_to_map);
-                       if (unlikely(map[j].status != 0)) {
+                       BUG_ON(new_map_idx >= segs_to_map);
+                       if (unlikely(map[new_map_idx].status != 0)) {
                                pr_debug(DRV_PFX "invalid buffer -- could not remap it\n");
-                               map[j].handle = BLKBACK_INVALID_HANDLE;
+                               pages[seg_idx]->handle = BLKBACK_INVALID_HANDLE;
                                ret |= 1;
-                               if (persistent_gnts[i]) {
-                                       rb_erase(&persistent_gnts[i]->node,
-                                                &blkif->persistent_gnts);
-                                       blkif->persistent_gnt_c--;
-                                       kfree(persistent_gnts[i]);
-                                       persistent_gnts[i] = NULL;
-                               }
+                               goto next;
                        }
+                       pages[seg_idx]->handle = map[new_map_idx].handle;
+               } else {
+                       continue;
                }
-               if (persistent_gnts[i]) {
-                       if (persistent_gnts[i]->handle ==
-                           BLKBACK_INVALID_HANDLE) {
+               if (use_persistent_gnts &&
+                   blkif->persistent_gnt_c < xen_blkif_max_pgrants) {
+                       /*
+                        * We are using persistent grants, the grant is
+                        * not mapped but we might have room for it.
+                        */
+                       persistent_gnt = kmalloc(sizeof(struct persistent_gnt),
+                                                GFP_KERNEL);
+                       if (!persistent_gnt) {
                                /*
-                                * If this is a new persistent grant
-                                * save the handler
+                                * If we don't have enough memory to
+                                * allocate the persistent_gnt struct
+                                * map this grant non-persistenly
                                 */
-                               persistent_gnts[i]->handle = map[j++].handle;
+                               goto next;
                        }
-                       pending_handle(pending_req, i) =
-                               persistent_gnts[i]->handle;
+                       persistent_gnt->gnt = map[new_map_idx].ref;
+                       persistent_gnt->handle = map[new_map_idx].handle;
+                       persistent_gnt->page = pages[seg_idx]->page;
+                       if (add_persistent_gnt(blkif,
+                                              persistent_gnt)) {
+                               kfree(persistent_gnt);
+                               persistent_gnt = NULL;
+                               goto next;
+                       }
+                       pages[seg_idx]->persistent_gnt = persistent_gnt;
+                       pr_debug(DRV_PFX " grant %u added to the tree of persistent grants, using %u/%u\n",
+                                persistent_gnt->gnt, blkif->persistent_gnt_c,
+                                xen_blkif_max_pgrants);
+                       goto next;
+               }
+               if (use_persistent_gnts && !blkif->vbd.overflow_max_grants) {
+                       blkif->vbd.overflow_max_grants = 1;
+                       pr_debug(DRV_PFX " domain %u, device %#x is using maximum number of persistent grants\n",
+                                blkif->domid, blkif->vbd.handle);
+               }
+               /*
+                * We could not map this grant persistently, so use it as
+                * a non-persistent grant.
+                */
+next:
+               new_map_idx++;
+       }
+       segs_to_map = 0;
+       last_map = map_until;
+       if (map_until != num)
+               goto again;
 
-                       if (ret)
-                               continue;
-               } else {
-                       pending_handle(pending_req, i) = map[j++].handle;
-                       bitmap_set(pending_req->unmap_seg, i, 1);
+       return ret;
+
+out_of_memory:
+       pr_alert(DRV_PFX "%s: out of memory\n", __func__);
+       put_free_pages(blkif, pages_to_gnt, segs_to_map);
+       return -ENOMEM;
+}
+
+static int xen_blkbk_map_seg(struct pending_req *pending_req)
+{
+       int rc;
+
+       rc = xen_blkbk_map(pending_req->blkif, pending_req->segments,
+                          pending_req->nr_pages,
+                          (pending_req->operation != BLKIF_OP_READ));
+
+       return rc;
+}
 
-                       if (ret)
-                               continue;
+static int xen_blkbk_parse_indirect(struct blkif_request *req,
+                                   struct pending_req *pending_req,
+                                   struct seg_buf seg[],
+                                   struct phys_req *preq)
+{
+       struct grant_page **pages = pending_req->indirect_pages;
+       struct xen_blkif *blkif = pending_req->blkif;
+       int indirect_grefs, rc, n, nseg, i;
+       struct blkif_request_segment_aligned *segments = NULL;
+
+       nseg = pending_req->nr_pages;
+       indirect_grefs = INDIRECT_PAGES(nseg);
+       BUG_ON(indirect_grefs > BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST);
+
+       for (i = 0; i < indirect_grefs; i++)
+               pages[i]->gref = req->u.indirect.indirect_grefs[i];
+
+       rc = xen_blkbk_map(blkif, pages, indirect_grefs, true);
+       if (rc)
+               goto unmap;
+
+       for (n = 0, i = 0; n < nseg; n++) {
+               if ((n % SEGS_PER_INDIRECT_FRAME) == 0) {
+                       /* Map indirect segments */
+                       if (segments)
+                               kunmap_atomic(segments);
+                       segments = kmap_atomic(pages[n/SEGS_PER_INDIRECT_FRAME]->page);
+               }
+               i = n % SEGS_PER_INDIRECT_FRAME;
+               pending_req->segments[n]->gref = segments[i].gref;
+               seg[n].nsec = segments[i].last_sect -
+                       segments[i].first_sect + 1;
+               seg[n].offset = (segments[i].first_sect << 9);
+               if ((segments[i].last_sect >= (PAGE_SIZE >> 9)) ||
+                   (segments[i].last_sect < segments[i].first_sect)) {
+                       rc = -EINVAL;
+                       goto unmap;
                }
-               seg[i].offset = (req->u.rw.seg[i].first_sect << 9);
+               preq->nr_sects += seg[n].nsec;
        }
-       return ret;
+
+unmap:
+       if (segments)
+               kunmap_atomic(segments);
+       xen_blkbk_unmap(blkif, pages, indirect_grefs);
+       return rc;
 }
 
 static int dispatch_discard_io(struct xen_blkif *blkif,
@@ -647,7 +885,18 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
        int status = BLKIF_RSP_OKAY;
        struct block_device *bdev = blkif->vbd.bdev;
        unsigned long secure;
+       struct phys_req preq;
+
+       preq.sector_number = req->u.discard.sector_number;
+       preq.nr_sects      = req->u.discard.nr_sectors;
 
+       err = xen_vbd_translate(&preq, blkif, WRITE);
+       if (err) {
+               pr_warn(DRV_PFX "access denied: DISCARD [%llu->%llu] on dev=%04x\n",
+                       preq.sector_number,
+                       preq.sector_number + preq.nr_sects, blkif->vbd.pdevice);
+               goto fail_response;
+       }
        blkif->st_ds_req++;
 
        xen_blkif_get(blkif);
@@ -658,7 +907,7 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
        err = blkdev_issue_discard(bdev, req->u.discard.sector_number,
                                   req->u.discard.nr_sectors,
                                   GFP_KERNEL, secure);
-
+fail_response:
        if (err == -EOPNOTSUPP) {
                pr_debug(DRV_PFX "discard op failed, not supported\n");
                status = BLKIF_RSP_EOPNOTSUPP;
@@ -674,7 +923,7 @@ static int dispatch_other_io(struct xen_blkif *blkif,
                             struct blkif_request *req,
                             struct pending_req *pending_req)
 {
-       free_req(pending_req);
+       free_req(blkif, pending_req);
        make_response(blkif, req->u.other.id, req->operation,
                      BLKIF_RSP_EOPNOTSUPP);
        return -EIO;
@@ -726,7 +975,9 @@ static void __end_block_io_op(struct pending_req *pending_req, int error)
         * the proper response on the ring.
         */
        if (atomic_dec_and_test(&pending_req->pendcnt)) {
-               xen_blkbk_unmap(pending_req);
+               xen_blkbk_unmap(pending_req->blkif,
+                               pending_req->segments,
+                               pending_req->nr_pages);
                make_response(pending_req->blkif, pending_req->id,
                              pending_req->operation, pending_req->status);
                xen_blkif_put(pending_req->blkif);
@@ -734,7 +985,7 @@ static void __end_block_io_op(struct pending_req *pending_req, int error)
                        if (atomic_read(&pending_req->blkif->drain))
                                complete(&pending_req->blkif->drain_complete);
                }
-               free_req(pending_req);
+               free_req(pending_req->blkif, pending_req);
        }
 }
 
@@ -767,6 +1018,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))
@@ -777,7 +1034,7 @@ __do_block_io_op(struct xen_blkif *blkif)
                        break;
                }
 
-               pending_req = alloc_req();
+               pending_req = alloc_req(blkif);
                if (NULL == pending_req) {
                        blkif->st_oo_req++;
                        more_to_do = 1;
@@ -807,11 +1064,12 @@ __do_block_io_op(struct xen_blkif *blkif)
                case BLKIF_OP_WRITE:
                case BLKIF_OP_WRITE_BARRIER:
                case BLKIF_OP_FLUSH_DISKCACHE:
+               case BLKIF_OP_INDIRECT:
                        if (dispatch_rw_block_io(blkif, &req, pending_req))
                                goto done;
                        break;
                case BLKIF_OP_DISCARD:
-                       free_req(pending_req);
+                       free_req(blkif, pending_req);
                        if (dispatch_discard_io(blkif, &req))
                                goto done;
                        break;
@@ -853,17 +1111,28 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
                                struct pending_req *pending_req)
 {
        struct phys_req preq;
-       struct seg_buf seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       struct seg_buf *seg = pending_req->seg;
        unsigned int nseg;
        struct bio *bio = NULL;
-       struct bio *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       struct bio **biolist = pending_req->biolist;
        int i, nbio = 0;
        int operation;
        struct blk_plug plug;
        bool drain = false;
-       struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       struct grant_page **pages = pending_req->segments;
+       unsigned short req_operation;
+
+       req_operation = req->operation == BLKIF_OP_INDIRECT ?
+                       req->u.indirect.indirect_op : req->operation;
+       if ((req->operation == BLKIF_OP_INDIRECT) &&
+           (req_operation != BLKIF_OP_READ) &&
+           (req_operation != BLKIF_OP_WRITE)) {
+               pr_debug(DRV_PFX "Invalid indirect operation (%u)\n",
+                        req_operation);
+               goto fail_response;
+       }
 
-       switch (req->operation) {
+       switch (req_operation) {
        case BLKIF_OP_READ:
                blkif->st_rd_req++;
                operation = READ;
@@ -885,33 +1154,47 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
        }
 
        /* Check that the number of segments is sane. */
-       nseg = req->u.rw.nr_segments;
+       nseg = req->operation == BLKIF_OP_INDIRECT ?
+              req->u.indirect.nr_segments : req->u.rw.nr_segments;
 
        if (unlikely(nseg == 0 && operation != WRITE_FLUSH) ||
-           unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
+           unlikely((req->operation != BLKIF_OP_INDIRECT) &&
+                    (nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) ||
+           unlikely((req->operation == BLKIF_OP_INDIRECT) &&
+                    (nseg > MAX_INDIRECT_SEGMENTS))) {
                pr_debug(DRV_PFX "Bad number of segments in request (%d)\n",
                         nseg);
                /* Haven't submitted any bio's yet. */
                goto fail_response;
        }
 
-       preq.sector_number = req->u.rw.sector_number;
        preq.nr_sects      = 0;
 
        pending_req->blkif     = blkif;
        pending_req->id        = req->u.rw.id;
-       pending_req->operation = req->operation;
+       pending_req->operation = req_operation;
        pending_req->status    = BLKIF_RSP_OKAY;
        pending_req->nr_pages  = nseg;
 
-       for (i = 0; i < nseg; i++) {
-               seg[i].nsec = req->u.rw.seg[i].last_sect -
-                       req->u.rw.seg[i].first_sect + 1;
-               if ((req->u.rw.seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
-                   (req->u.rw.seg[i].last_sect < req->u.rw.seg[i].first_sect))
+       if (req->operation != BLKIF_OP_INDIRECT) {
+               preq.dev               = req->u.rw.handle;
+               preq.sector_number     = req->u.rw.sector_number;
+               for (i = 0; i < nseg; i++) {
+                       pages[i]->gref = req->u.rw.seg[i].gref;
+                       seg[i].nsec = req->u.rw.seg[i].last_sect -
+                               req->u.rw.seg[i].first_sect + 1;
+                       seg[i].offset = (req->u.rw.seg[i].first_sect << 9);
+                       if ((req->u.rw.seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
+                           (req->u.rw.seg[i].last_sect <
+                            req->u.rw.seg[i].first_sect))
+                               goto fail_response;
+                       preq.nr_sects += seg[i].nsec;
+               }
+       } else {
+               preq.dev               = req->u.indirect.handle;
+               preq.sector_number     = req->u.indirect.sector_number;
+               if (xen_blkbk_parse_indirect(req, pending_req, seg, &preq))
                        goto fail_response;
-               preq.nr_sects += seg[i].nsec;
-
        }
 
        if (xen_vbd_translate(&preq, blkif, operation) != 0) {
@@ -948,7 +1231,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
         * the hypercall to unmap the grants - that is all done in
         * xen_blkbk_unmap.
         */
-       if (xen_blkbk_map(req, pending_req, seg, pages))
+       if (xen_blkbk_map_seg(pending_req))
                goto fail_flush;
 
        /*
@@ -960,11 +1243,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
        for (i = 0; i < nseg; i++) {
                while ((bio == NULL) ||
                       (bio_add_page(bio,
-                                    pages[i],
+                                    pages[i]->page,
                                     seg[i].nsec << 9,
                                     seg[i].offset) == 0)) {
 
-                       bio = bio_alloc(GFP_KERNEL, nseg-i);
+                       int nr_iovecs = min_t(int, (nseg-i), BIO_MAX_PAGES);
+                       bio = bio_alloc(GFP_KERNEL, nr_iovecs);
                        if (unlikely(bio == NULL))
                                goto fail_put_bio;
 
@@ -1009,11 +1293,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
        return 0;
 
  fail_flush:
-       xen_blkbk_unmap(pending_req);
+       xen_blkbk_unmap(blkif, pending_req->segments,
+                       pending_req->nr_pages);
  fail_response:
        /* Haven't submitted any bio's yet. */
-       make_response(blkif, req->u.rw.id, req->operation, BLKIF_RSP_ERROR);
-       free_req(pending_req);
+       make_response(blkif, req->u.rw.id, req_operation, BLKIF_RSP_ERROR);
+       free_req(blkif, pending_req);
        msleep(1); /* back off a bit */
        return -EIO;
 
@@ -1070,73 +1355,20 @@ static void make_response(struct xen_blkif *blkif, u64 id,
 
 static int __init xen_blkif_init(void)
 {
-       int i, mmap_pages;
        int rc = 0;
 
        if (!xen_domain())
                return -ENODEV;
 
-       blkbk = kzalloc(sizeof(struct xen_blkbk), GFP_KERNEL);
-       if (!blkbk) {
-               pr_alert(DRV_PFX "%s: out of memory!\n", __func__);
-               return -ENOMEM;
-       }
-
-       mmap_pages = xen_blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
-
-       blkbk->pending_reqs          = kzalloc(sizeof(blkbk->pending_reqs[0]) *
-                                       xen_blkif_reqs, GFP_KERNEL);
-       blkbk->pending_grant_handles = kmalloc(sizeof(blkbk->pending_grant_handles[0]) *
-                                       mmap_pages, GFP_KERNEL);
-       blkbk->pending_pages         = kzalloc(sizeof(blkbk->pending_pages[0]) *
-                                       mmap_pages, GFP_KERNEL);
-
-       if (!blkbk->pending_reqs || !blkbk->pending_grant_handles ||
-           !blkbk->pending_pages) {
-               rc = -ENOMEM;
-               goto out_of_memory;
-       }
-
-       for (i = 0; i < mmap_pages; i++) {
-               blkbk->pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
-               blkbk->pending_pages[i] = alloc_page(GFP_KERNEL);
-               if (blkbk->pending_pages[i] == NULL) {
-                       rc = -ENOMEM;
-                       goto out_of_memory;
-               }
-       }
        rc = xen_blkif_interface_init();
        if (rc)
                goto failed_init;
 
-       INIT_LIST_HEAD(&blkbk->pending_free);
-       spin_lock_init(&blkbk->pending_free_lock);
-       init_waitqueue_head(&blkbk->pending_free_wq);
-
-       for (i = 0; i < xen_blkif_reqs; i++)
-               list_add_tail(&blkbk->pending_reqs[i].free_list,
-                             &blkbk->pending_free);
-
        rc = xen_blkif_xenbus_init();
        if (rc)
                goto failed_init;
 
-       return 0;
-
- out_of_memory:
-       pr_alert(DRV_PFX "%s: out of memory\n", __func__);
  failed_init:
-       kfree(blkbk->pending_reqs);
-       kfree(blkbk->pending_grant_handles);
-       if (blkbk->pending_pages) {
-               for (i = 0; i < mmap_pages; i++) {
-                       if (blkbk->pending_pages[i])
-                               __free_page(blkbk->pending_pages[i]);
-               }
-               kfree(blkbk->pending_pages);
-       }
-       kfree(blkbk);
-       blkbk = NULL;
        return rc;
 }
 
index 60103e2517ba28ac5c946f32e1bd9e0e6eb7f668..8d8807563d9967afd28b70dcb0cd072bed35e8ec 100644 (file)
                 __func__, __LINE__, ##args)
 
 
+/*
+ * This is the maximum number of segments that would be allowed in indirect
+ * requests. This value will also be passed to the frontend.
+ */
+#define MAX_INDIRECT_SEGMENTS 256
+
+#define SEGS_PER_INDIRECT_FRAME \
+       (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned))
+#define MAX_INDIRECT_PAGES \
+       ((MAX_INDIRECT_SEGMENTS + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
+#define INDIRECT_PAGES(_segs) \
+       ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
+
 /* Not a real protocol.  Used to generate ring structs which contain
  * the elements common to all protocols only.  This way we get a
  * compiler-checkable way to use common struct elements, so we can
@@ -83,12 +96,31 @@ struct blkif_x86_32_request_other {
        uint64_t       id;           /* private guest value, echoed in resp  */
 } __attribute__((__packed__));
 
+struct blkif_x86_32_request_indirect {
+       uint8_t        indirect_op;
+       uint16_t       nr_segments;
+       uint64_t       id;
+       blkif_sector_t sector_number;
+       blkif_vdev_t   handle;
+       uint16_t       _pad1;
+       grant_ref_t    indirect_grefs[BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST];
+       /*
+        * The maximum number of indirect segments (and pages) that will
+        * be used is determined by MAX_INDIRECT_SEGMENTS, this value
+        * is also exported to the guest (via xenstore
+        * feature-max-indirect-segments entry), so the frontend knows how
+        * many indirect segments the backend supports.
+        */
+       uint64_t       _pad2;        /* make it 64 byte aligned */
+} __attribute__((__packed__));
+
 struct blkif_x86_32_request {
        uint8_t        operation;    /* BLKIF_OP_???                         */
        union {
                struct blkif_x86_32_request_rw rw;
                struct blkif_x86_32_request_discard discard;
                struct blkif_x86_32_request_other other;
+               struct blkif_x86_32_request_indirect indirect;
        } u;
 } __attribute__((__packed__));
 
@@ -127,12 +159,32 @@ struct blkif_x86_64_request_other {
        uint64_t       id;           /* private guest value, echoed in resp  */
 } __attribute__((__packed__));
 
+struct blkif_x86_64_request_indirect {
+       uint8_t        indirect_op;
+       uint16_t       nr_segments;
+       uint32_t       _pad1;        /* offsetof(blkif_..,u.indirect.id)==8   */
+       uint64_t       id;
+       blkif_sector_t sector_number;
+       blkif_vdev_t   handle;
+       uint16_t       _pad2;
+       grant_ref_t    indirect_grefs[BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST];
+       /*
+        * The maximum number of indirect segments (and pages) that will
+        * be used is determined by MAX_INDIRECT_SEGMENTS, this value
+        * is also exported to the guest (via xenstore
+        * feature-max-indirect-segments entry), so the frontend knows how
+        * many indirect segments the backend supports.
+        */
+       uint32_t       _pad3;        /* make it 64 byte aligned */
+} __attribute__((__packed__));
+
 struct blkif_x86_64_request {
        uint8_t        operation;    /* BLKIF_OP_???                         */
        union {
                struct blkif_x86_64_request_rw rw;
                struct blkif_x86_64_request_discard discard;
                struct blkif_x86_64_request_other other;
+               struct blkif_x86_64_request_indirect indirect;
        } u;
 } __attribute__((__packed__));
 
@@ -182,12 +234,26 @@ struct xen_vbd {
 
 struct backend_info;
 
+/* Number of available flags */
+#define PERSISTENT_GNT_FLAGS_SIZE      2
+/* This persistent grant is currently in use */
+#define PERSISTENT_GNT_ACTIVE          0
+/*
+ * This persistent grant has been used, this flag is set when we remove the
+ * PERSISTENT_GNT_ACTIVE, to know that this grant has been used recently.
+ */
+#define PERSISTENT_GNT_WAS_ACTIVE      1
+
+/* Number of requests that we can fit in a ring */
+#define XEN_BLKIF_REQS                 32
 
 struct persistent_gnt {
        struct page *page;
        grant_ref_t gnt;
        grant_handle_t handle;
+       DECLARE_BITMAP(flags, PERSISTENT_GNT_FLAGS_SIZE);
        struct rb_node node;
+       struct list_head remove_node;
 };
 
 struct xen_blkif {
@@ -219,6 +285,23 @@ struct xen_blkif {
        /* tree to store persistent grants */
        struct rb_root          persistent_gnts;
        unsigned int            persistent_gnt_c;
+       atomic_t                persistent_gnt_in_use;
+       unsigned long           next_lru;
+
+       /* used by the kworker that offload work from the persistent purge */
+       struct list_head        persistent_purge_list;
+       struct work_struct      persistent_purge_work;
+
+       /* buffer of free pages to map grant refs */
+       spinlock_t              free_pages_lock;
+       int                     free_pages_num;
+       struct list_head        free_pages;
+
+       /* List of all 'pending_req' available */
+       struct list_head        pending_free;
+       /* And its spinlock. */
+       spinlock_t              pending_free_lock;
+       wait_queue_head_t       pending_free_wq;
 
        /* statistics */
        unsigned long           st_print;
@@ -231,6 +314,41 @@ struct xen_blkif {
        unsigned long long                      st_wr_sect;
 
        wait_queue_head_t       waiting_to_free;
+       /* Thread shutdown wait queue. */
+       wait_queue_head_t       shutdown_wq;
+};
+
+struct seg_buf {
+       unsigned long offset;
+       unsigned int nsec;
+};
+
+struct grant_page {
+       struct page             *page;
+       struct persistent_gnt   *persistent_gnt;
+       grant_handle_t          handle;
+       grant_ref_t             gref;
+};
+
+/*
+ * Each outstanding request that we've passed to the lower device layers has a
+ * 'pending_req' allocated to it. Each buffer_head that completes decrements
+ * the pendcnt towards zero. When it hits zero, the specified domain has a
+ * response queued for it, with the saved 'id' passed back.
+ */
+struct pending_req {
+       struct xen_blkif        *blkif;
+       u64                     id;
+       int                     nr_pages;
+       atomic_t                pendcnt;
+       unsigned short          operation;
+       int                     status;
+       struct list_head        free_list;
+       struct grant_page       *segments[MAX_INDIRECT_SEGMENTS];
+       /* Indirect descriptors */
+       struct grant_page       *indirect_pages[MAX_INDIRECT_PAGES];
+       struct seg_buf          seg[MAX_INDIRECT_SEGMENTS];
+       struct bio              *biolist[MAX_INDIRECT_SEGMENTS];
 };
 
 
@@ -257,6 +375,7 @@ int xen_blkif_xenbus_init(void);
 
 irqreturn_t xen_blkif_be_int(int irq, void *dev_id);
 int xen_blkif_schedule(void *arg);
+int xen_blkif_purge_persistent(void *arg);
 
 int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
                              struct backend_info *be, int state);
@@ -268,7 +387,7 @@ struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be);
 static inline void blkif_get_x86_32_req(struct blkif_request *dst,
                                        struct blkif_x86_32_request *src)
 {
-       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
        dst->operation = src->operation;
        switch (src->operation) {
        case BLKIF_OP_READ:
@@ -291,6 +410,18 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
                dst->u.discard.sector_number = src->u.discard.sector_number;
                dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
                break;
+       case BLKIF_OP_INDIRECT:
+               dst->u.indirect.indirect_op = src->u.indirect.indirect_op;
+               dst->u.indirect.nr_segments = src->u.indirect.nr_segments;
+               dst->u.indirect.handle = src->u.indirect.handle;
+               dst->u.indirect.id = src->u.indirect.id;
+               dst->u.indirect.sector_number = src->u.indirect.sector_number;
+               barrier();
+               j = min(MAX_INDIRECT_PAGES, INDIRECT_PAGES(dst->u.indirect.nr_segments));
+               for (i = 0; i < j; i++)
+                       dst->u.indirect.indirect_grefs[i] =
+                               src->u.indirect.indirect_grefs[i];
+               break;
        default:
                /*
                 * Don't know how to translate this op. Only get the
@@ -304,7 +435,7 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
 static inline void blkif_get_x86_64_req(struct blkif_request *dst,
                                        struct blkif_x86_64_request *src)
 {
-       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
        dst->operation = src->operation;
        switch (src->operation) {
        case BLKIF_OP_READ:
@@ -327,6 +458,18 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
                dst->u.discard.sector_number = src->u.discard.sector_number;
                dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
                break;
+       case BLKIF_OP_INDIRECT:
+               dst->u.indirect.indirect_op = src->u.indirect.indirect_op;
+               dst->u.indirect.nr_segments = src->u.indirect.nr_segments;
+               dst->u.indirect.handle = src->u.indirect.handle;
+               dst->u.indirect.id = src->u.indirect.id;
+               dst->u.indirect.sector_number = src->u.indirect.sector_number;
+               barrier();
+               j = min(MAX_INDIRECT_PAGES, INDIRECT_PAGES(dst->u.indirect.nr_segments));
+               for (i = 0; i < j; i++)
+                       dst->u.indirect.indirect_grefs[i] =
+                               src->u.indirect.indirect_grefs[i];
+               break;
        default:
                /*
                 * Don't know how to translate this op. Only get the
index 04608a6502d7b25bec73a51da69e1e2748e960c4..fe5c3cd10c341045ca63aeacb15edc93c185a88b 100644 (file)
@@ -98,12 +98,17 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
                err = PTR_ERR(blkif->xenblkd);
                blkif->xenblkd = NULL;
                xenbus_dev_error(blkif->be->dev, err, "start xenblkd");
+               return;
        }
 }
 
 static struct xen_blkif *xen_blkif_alloc(domid_t domid)
 {
        struct xen_blkif *blkif;
+       struct pending_req *req, *n;
+       int i, j;
+
+       BUILD_BUG_ON(MAX_INDIRECT_PAGES > BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST);
 
        blkif = kmem_cache_zalloc(xen_blkif_cachep, GFP_KERNEL);
        if (!blkif)
@@ -118,8 +123,57 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
        blkif->st_print = jiffies;
        init_waitqueue_head(&blkif->waiting_to_free);
        blkif->persistent_gnts.rb_node = NULL;
+       spin_lock_init(&blkif->free_pages_lock);
+       INIT_LIST_HEAD(&blkif->free_pages);
+       blkif->free_pages_num = 0;
+       atomic_set(&blkif->persistent_gnt_in_use, 0);
+
+       INIT_LIST_HEAD(&blkif->pending_free);
+
+       for (i = 0; i < XEN_BLKIF_REQS; i++) {
+               req = kzalloc(sizeof(*req), GFP_KERNEL);
+               if (!req)
+                       goto fail;
+               list_add_tail(&req->free_list,
+                             &blkif->pending_free);
+               for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++) {
+                       req->segments[j] = kzalloc(sizeof(*req->segments[0]),
+                                                  GFP_KERNEL);
+                       if (!req->segments[j])
+                               goto fail;
+               }
+               for (j = 0; j < MAX_INDIRECT_PAGES; j++) {
+                       req->indirect_pages[j] = kzalloc(sizeof(*req->indirect_pages[0]),
+                                                        GFP_KERNEL);
+                       if (!req->indirect_pages[j])
+                               goto fail;
+               }
+       }
+       spin_lock_init(&blkif->pending_free_lock);
+       init_waitqueue_head(&blkif->pending_free_wq);
+       init_waitqueue_head(&blkif->shutdown_wq);
 
        return blkif;
+
+fail:
+       list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) {
+               list_del(&req->free_list);
+               for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++) {
+                       if (!req->segments[j])
+                               break;
+                       kfree(req->segments[j]);
+               }
+               for (j = 0; j < MAX_INDIRECT_PAGES; j++) {
+                       if (!req->indirect_pages[j])
+                               break;
+                       kfree(req->indirect_pages[j]);
+               }
+               kfree(req);
+       }
+
+       kmem_cache_free(xen_blkif_cachep, blkif);
+
+       return ERR_PTR(-ENOMEM);
 }
 
 static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page,
@@ -178,6 +232,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;
        }
 
@@ -198,8 +253,28 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif)
 
 static void xen_blkif_free(struct xen_blkif *blkif)
 {
+       struct pending_req *req, *n;
+       int i = 0, j;
+
        if (!atomic_dec_and_test(&blkif->refcnt))
                BUG();
+
+       /* Check that there is no request in use */
+       list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) {
+               list_del(&req->free_list);
+
+               for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++)
+                       kfree(req->segments[j]);
+
+               for (j = 0; j < MAX_INDIRECT_PAGES; j++)
+                       kfree(req->indirect_pages[j]);
+
+               kfree(req);
+               i++;
+       }
+
+       WARN_ON(i != XEN_BLKIF_REQS);
+
        kmem_cache_free(xen_blkif_cachep, blkif);
 }
 
@@ -678,6 +753,11 @@ again:
                                 dev->nodename);
                goto abort;
        }
+       err = xenbus_printf(xbt, dev->nodename, "feature-max-indirect-segments", "%u",
+                           MAX_INDIRECT_SEGMENTS);
+       if (err)
+               dev_warn(&dev->dev, "writing %s/feature-max-indirect-segments (%d)",
+                        dev->nodename, err);
 
        err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
                            (unsigned long long)vbd_sz(&be->blkif->vbd));
@@ -704,6 +784,11 @@ again:
                                 dev->nodename);
                goto abort;
        }
+       err = xenbus_printf(xbt, dev->nodename, "physical-sector-size", "%u",
+                           bdev_physical_block_size(be->blkif->vbd.bdev));
+       if (err)
+               xenbus_dev_error(dev, err, "writing %s/physical-sector-size",
+                                dev->nodename);
 
        err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN)
index d89ef86220f4a55a247083d36d5f8dd3ce74e0d5..a4660bbee8a6279bd4cc1a6def776ddc85bcf169 100644 (file)
@@ -74,12 +74,30 @@ struct grant {
 struct blk_shadow {
        struct blkif_request req;
        struct request *request;
-       struct grant *grants_used[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       struct grant **grants_used;
+       struct grant **indirect_grants;
+       struct scatterlist *sg;
+};
+
+struct split_bio {
+       struct bio *bio;
+       atomic_t pending;
+       int err;
 };
 
 static DEFINE_MUTEX(blkfront_mutex);
 static const struct block_device_operations xlvbd_block_fops;
 
+/*
+ * Maximum number of segments in indirect requests, the actual value used by
+ * the frontend driver is the minimum of this value and the value provided
+ * by the backend driver.
+ */
+
+static unsigned int xen_blkif_max_segments = 32;
+module_param_named(max, xen_blkif_max_segments, int, S_IRUGO);
+MODULE_PARM_DESC(max, "Maximum amount of segments in indirect requests (default is 32)");
+
 #define BLK_RING_SIZE __CONST_RING_SIZE(blkif, PAGE_SIZE)
 
 /*
@@ -98,7 +116,6 @@ struct blkfront_info
        enum blkif_state connected;
        int ring_ref;
        struct blkif_front_ring ring;
-       struct scatterlist sg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        unsigned int evtchn, irq;
        struct request_queue *rq;
        struct work_struct work;
@@ -114,6 +131,7 @@ struct blkfront_info
        unsigned int discard_granularity;
        unsigned int discard_alignment;
        unsigned int feature_persistent:1;
+       unsigned int max_indirect_segments;
        int is_ready;
 };
 
@@ -142,6 +160,13 @@ static DEFINE_SPINLOCK(minor_lock);
 
 #define DEV_NAME       "xvd"   /* name in /dev */
 
+#define SEGS_PER_INDIRECT_FRAME \
+       (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned))
+#define INDIRECT_GREFS(_segs) \
+       ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
+
+static int blkfront_setup_indirect(struct blkfront_info *info);
+
 static int get_id_from_freelist(struct blkfront_info *info)
 {
        unsigned long free = info->shadow_free;
@@ -358,7 +383,8 @@ static int blkif_queue_request(struct request *req)
        struct blkif_request *ring_req;
        unsigned long id;
        unsigned int fsect, lsect;
-       int i, ref;
+       int i, ref, n;
+       struct blkif_request_segment_aligned *segments = NULL;
 
        /*
         * Used to store if we are able to queue the request by just using
@@ -369,21 +395,27 @@ static int blkif_queue_request(struct request *req)
        grant_ref_t gref_head;
        struct grant *gnt_list_entry = NULL;
        struct scatterlist *sg;
+       int nseg, max_grefs;
 
        if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
                return 1;
 
-       /* Check if we have enought grants to allocate a requests */
-       if (info->persistent_gnts_c < BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+       max_grefs = info->max_indirect_segments ?
+                   info->max_indirect_segments +
+                   INDIRECT_GREFS(info->max_indirect_segments) :
+                   BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+       /* Check if we have enough grants to allocate a requests */
+       if (info->persistent_gnts_c < max_grefs) {
                new_persistent_gnts = 1;
                if (gnttab_alloc_grant_references(
-                   BLKIF_MAX_SEGMENTS_PER_REQUEST - info->persistent_gnts_c,
+                   max_grefs - info->persistent_gnts_c,
                    &gref_head) < 0) {
                        gnttab_request_free_callback(
                                &info->callback,
                                blkif_restart_queue_callback,
                                info,
-                               BLKIF_MAX_SEGMENTS_PER_REQUEST);
+                               max_grefs);
                        return 1;
                }
        } else
@@ -394,42 +426,67 @@ static int blkif_queue_request(struct request *req)
        id = get_id_from_freelist(info);
        info->shadow[id].request = req;
 
-       ring_req->u.rw.id = id;
-       ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
-       ring_req->u.rw.handle = info->handle;
-
-       ring_req->operation = rq_data_dir(req) ?
-               BLKIF_OP_WRITE : BLKIF_OP_READ;
-
-       if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
-               /*
-                * Ideally we can do an unordered flush-to-disk. In case the
-                * backend onlysupports barriers, use that. A barrier request
-                * a superset of FUA, so we can implement it the same
-                * way.  (It's also a FLUSH+FUA, since it is
-                * guaranteed ordered WRT previous writes.)
-                */
-               ring_req->operation = info->flush_op;
-       }
-
        if (unlikely(req->cmd_flags & (REQ_DISCARD | REQ_SECURE))) {
-               /* id, sector_number and handle are set above. */
                ring_req->operation = BLKIF_OP_DISCARD;
                ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
+               ring_req->u.discard.id = id;
+               ring_req->u.discard.sector_number = (blkif_sector_t)blk_rq_pos(req);
                if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard)
                        ring_req->u.discard.flag = BLKIF_DISCARD_SECURE;
                else
                        ring_req->u.discard.flag = 0;
        } else {
-               ring_req->u.rw.nr_segments = blk_rq_map_sg(req->q, req,
-                                                          info->sg);
-               BUG_ON(ring_req->u.rw.nr_segments >
-                      BLKIF_MAX_SEGMENTS_PER_REQUEST);
-
-               for_each_sg(info->sg, sg, ring_req->u.rw.nr_segments, i) {
+               BUG_ON(info->max_indirect_segments == 0 &&
+                      req->nr_phys_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
+               BUG_ON(info->max_indirect_segments &&
+                      req->nr_phys_segments > info->max_indirect_segments);
+               nseg = blk_rq_map_sg(req->q, req, info->shadow[id].sg);
+               ring_req->u.rw.id = id;
+               if (nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+                       /*
+                        * The indirect operation can only be a BLKIF_OP_READ or
+                        * BLKIF_OP_WRITE
+                        */
+                       BUG_ON(req->cmd_flags & (REQ_FLUSH | REQ_FUA));
+                       ring_req->operation = BLKIF_OP_INDIRECT;
+                       ring_req->u.indirect.indirect_op = rq_data_dir(req) ?
+                               BLKIF_OP_WRITE : BLKIF_OP_READ;
+                       ring_req->u.indirect.sector_number = (blkif_sector_t)blk_rq_pos(req);
+                       ring_req->u.indirect.handle = info->handle;
+                       ring_req->u.indirect.nr_segments = nseg;
+               } else {
+                       ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
+                       ring_req->u.rw.handle = info->handle;
+                       ring_req->operation = rq_data_dir(req) ?
+                               BLKIF_OP_WRITE : BLKIF_OP_READ;
+                       if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
+                               /*
+                                * Ideally we can do an unordered flush-to-disk. In case the
+                                * backend onlysupports barriers, use that. A barrier request
+                                * a superset of FUA, so we can implement it the same
+                                * way.  (It's also a FLUSH+FUA, since it is
+                                * guaranteed ordered WRT previous writes.)
+                                */
+                               ring_req->operation = info->flush_op;
+                       }
+                       ring_req->u.rw.nr_segments = nseg;
+               }
+               for_each_sg(info->shadow[id].sg, sg, nseg, i) {
                        fsect = sg->offset >> 9;
                        lsect = fsect + (sg->length >> 9) - 1;
 
+                       if ((ring_req->operation == BLKIF_OP_INDIRECT) &&
+                           (i % SEGS_PER_INDIRECT_FRAME == 0)) {
+                               if (segments)
+                                       kunmap_atomic(segments);
+
+                               n = i / SEGS_PER_INDIRECT_FRAME;
+                               gnt_list_entry = get_grant(&gref_head, info);
+                               info->shadow[id].indirect_grants[n] = gnt_list_entry;
+                               segments = kmap_atomic(pfn_to_page(gnt_list_entry->pfn));
+                               ring_req->u.indirect.indirect_grefs[n] = gnt_list_entry->gref;
+                       }
+
                        gnt_list_entry = get_grant(&gref_head, info);
                        ref = gnt_list_entry->gref;
 
@@ -441,8 +498,7 @@ static int blkif_queue_request(struct request *req)
 
                                BUG_ON(sg->offset + sg->length > PAGE_SIZE);
 
-                               shared_data = kmap_atomic(
-                                       pfn_to_page(gnt_list_entry->pfn));
+                               shared_data = kmap_atomic(pfn_to_page(gnt_list_entry->pfn));
                                bvec_data = kmap_atomic(sg_page(sg));
 
                                /*
@@ -461,13 +517,23 @@ static int blkif_queue_request(struct request *req)
                                kunmap_atomic(bvec_data);
                                kunmap_atomic(shared_data);
                        }
-
-                       ring_req->u.rw.seg[i] =
-                                       (struct blkif_request_segment) {
-                                               .gref       = ref,
-                                               .first_sect = fsect,
-                                               .last_sect  = lsect };
+                       if (ring_req->operation != BLKIF_OP_INDIRECT) {
+                               ring_req->u.rw.seg[i] =
+                                               (struct blkif_request_segment) {
+                                                       .gref       = ref,
+                                                       .first_sect = fsect,
+                                                       .last_sect  = lsect };
+                       } else {
+                               n = i % SEGS_PER_INDIRECT_FRAME;
+                               segments[n] =
+                                       (struct blkif_request_segment_aligned) {
+                                                       .gref       = ref,
+                                                       .first_sect = fsect,
+                                                       .last_sect  = lsect };
+                       }
                }
+               if (segments)
+                       kunmap_atomic(segments);
        }
 
        info->ring.req_prod_pvt++;
@@ -542,7 +608,9 @@ wait:
                flush_requests(info);
 }
 
-static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
+static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size,
+                               unsigned int physical_sector_size,
+                               unsigned int segments)
 {
        struct request_queue *rq;
        struct blkfront_info *info = gd->private_data;
@@ -564,14 +632,15 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
 
        /* Hard sector size and max sectors impersonate the equiv. hardware. */
        blk_queue_logical_block_size(rq, sector_size);
-       blk_queue_max_hw_sectors(rq, 512);
+       blk_queue_physical_block_size(rq, physical_sector_size);
+       blk_queue_max_hw_sectors(rq, (segments * PAGE_SIZE) / 512);
 
        /* Each segment in a request is up to an aligned page in size. */
        blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
        blk_queue_max_segment_size(rq, PAGE_SIZE);
 
        /* Ensure a merged request will fit in a single I/O ring slot. */
-       blk_queue_max_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+       blk_queue_max_segments(rq, segments);
 
        /* Make sure buffer addresses are sector-aligned. */
        blk_queue_dma_alignment(rq, 511);
@@ -588,13 +657,16 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
 static void xlvbd_flush(struct blkfront_info *info)
 {
        blk_queue_flush(info->rq, info->feature_flush);
-       printk(KERN_INFO "blkfront: %s: %s: %s %s\n",
+       printk(KERN_INFO "blkfront: %s: %s: %s %s %s %s %s\n",
               info->gd->disk_name,
               info->flush_op == BLKIF_OP_WRITE_BARRIER ?
                "barrier" : (info->flush_op == BLKIF_OP_FLUSH_DISKCACHE ?
                "flush diskcache" : "barrier or flush"),
-              info->feature_flush ? "enabled" : "disabled",
-              info->feature_persistent ? "using persistent grants" : "");
+              info->feature_flush ? "enabled;" : "disabled;",
+              "persistent grants:",
+              info->feature_persistent ? "enabled;" : "disabled;",
+              "indirect descriptors:",
+              info->max_indirect_segments ? "enabled;" : "disabled;");
 }
 
 static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset)
@@ -667,7 +739,8 @@ static char *encode_disk_name(char *ptr, unsigned int n)
 
 static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
                               struct blkfront_info *info,
-                              u16 vdisk_info, u16 sector_size)
+                              u16 vdisk_info, u16 sector_size,
+                              unsigned int physical_sector_size)
 {
        struct gendisk *gd;
        int nr_minors = 1;
@@ -734,7 +807,9 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
        gd->driverfs_dev = &(info->xbdev->dev);
        set_capacity(gd, capacity);
 
-       if (xlvbd_init_blk_queue(gd, sector_size)) {
+       if (xlvbd_init_blk_queue(gd, sector_size, physical_sector_size,
+                                info->max_indirect_segments ? :
+                                BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
                del_gendisk(gd);
                goto release;
        }
@@ -818,6 +893,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
 {
        struct grant *persistent_gnt;
        struct grant *n;
+       int i, j, segs;
 
        /* Prevent new requests being issued until we fix things up. */
        spin_lock_irq(&info->io_lock);
@@ -843,6 +919,47 @@ static void blkif_free(struct blkfront_info *info, int suspend)
        }
        BUG_ON(info->persistent_gnts_c != 0);
 
+       for (i = 0; i < BLK_RING_SIZE; i++) {
+               /*
+                * Clear persistent grants present in requests already
+                * on the shared ring
+                */
+               if (!info->shadow[i].request)
+                       goto free_shadow;
+
+               segs = info->shadow[i].req.operation == BLKIF_OP_INDIRECT ?
+                      info->shadow[i].req.u.indirect.nr_segments :
+                      info->shadow[i].req.u.rw.nr_segments;
+               for (j = 0; j < segs; j++) {
+                       persistent_gnt = info->shadow[i].grants_used[j];
+                       gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
+                       __free_page(pfn_to_page(persistent_gnt->pfn));
+                       kfree(persistent_gnt);
+               }
+
+               if (info->shadow[i].req.operation != BLKIF_OP_INDIRECT)
+                       /*
+                        * If this is not an indirect operation don't try to
+                        * free indirect segments
+                        */
+                       goto free_shadow;
+
+               for (j = 0; j < INDIRECT_GREFS(segs); j++) {
+                       persistent_gnt = info->shadow[i].indirect_grants[j];
+                       gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
+                       __free_page(pfn_to_page(persistent_gnt->pfn));
+                       kfree(persistent_gnt);
+               }
+
+free_shadow:
+               kfree(info->shadow[i].grants_used);
+               info->shadow[i].grants_used = NULL;
+               kfree(info->shadow[i].indirect_grants);
+               info->shadow[i].indirect_grants = NULL;
+               kfree(info->shadow[i].sg);
+               info->shadow[i].sg = NULL;
+       }
+
        /* No more gnttab callback work. */
        gnttab_cancel_free_callback(&info->callback);
        spin_unlock_irq(&info->io_lock);
@@ -867,12 +984,13 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
                             struct blkif_response *bret)
 {
        int i = 0;
-       struct bio_vec *bvec;
-       struct req_iterator iter;
-       unsigned long flags;
+       struct scatterlist *sg;
        char *bvec_data;
        void *shared_data;
-       unsigned int offset = 0;
+       int nseg;
+
+       nseg = s->req.operation == BLKIF_OP_INDIRECT ?
+               s->req.u.indirect.nr_segments : s->req.u.rw.nr_segments;
 
        if (bret->operation == BLKIF_OP_READ) {
                /*
@@ -881,26 +999,29 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
                 * than PAGE_SIZE, we have to keep track of the current offset,
                 * to be sure we are copying the data from the right shared page.
                 */
-               rq_for_each_segment(bvec, s->request, iter) {
-                       BUG_ON((bvec->bv_offset + bvec->bv_len) > PAGE_SIZE);
-                       if (bvec->bv_offset < offset)
-                               i++;
-                       BUG_ON(i >= s->req.u.rw.nr_segments);
+               for_each_sg(s->sg, sg, nseg, i) {
+                       BUG_ON(sg->offset + sg->length > PAGE_SIZE);
                        shared_data = kmap_atomic(
                                pfn_to_page(s->grants_used[i]->pfn));
-                       bvec_data = bvec_kmap_irq(bvec, &flags);
-                       memcpy(bvec_data, shared_data + bvec->bv_offset,
-                               bvec->bv_len);
-                       bvec_kunmap_irq(bvec_data, &flags);
+                       bvec_data = kmap_atomic(sg_page(sg));
+                       memcpy(bvec_data   + sg->offset,
+                              shared_data + sg->offset,
+                              sg->length);
+                       kunmap_atomic(bvec_data);
                        kunmap_atomic(shared_data);
-                       offset = bvec->bv_offset + bvec->bv_len;
                }
        }
        /* Add the persistent grant into the list of free grants */
-       for (i = 0; i < s->req.u.rw.nr_segments; i++) {
+       for (i = 0; i < nseg; i++) {
                list_add(&s->grants_used[i]->node, &info->persistent_gnts);
                info->persistent_gnts_c++;
        }
+       if (s->req.operation == BLKIF_OP_INDIRECT) {
+               for (i = 0; i < INDIRECT_GREFS(nseg); i++) {
+                       list_add(&s->indirect_grants[i]->node, &info->persistent_gnts);
+                       info->persistent_gnts_c++;
+               }
+       }
 }
 
 static irqreturn_t blkif_interrupt(int irq, void *dev_id)
@@ -1034,14 +1155,6 @@ static int setup_blkring(struct xenbus_device *dev,
        SHARED_RING_INIT(sring);
        FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
 
-       sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-
-       /* Allocate memory for grants */
-       err = fill_grant_buffer(info, BLK_RING_SIZE *
-                                     BLKIF_MAX_SEGMENTS_PER_REQUEST);
-       if (err)
-               goto fail;
-
        err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
        if (err < 0) {
                free_page((unsigned long)sring);
@@ -1223,13 +1336,84 @@ static int blkfront_probe(struct xenbus_device *dev,
        return 0;
 }
 
+/*
+ * This is a clone of md_trim_bio, used to split a bio into smaller ones
+ */
+static void trim_bio(struct bio *bio, int offset, int size)
+{
+       /* 'bio' is a cloned bio which we need to trim to match
+        * the given offset and size.
+        * This requires adjusting bi_sector, bi_size, and bi_io_vec
+        */
+       int i;
+       struct bio_vec *bvec;
+       int sofar = 0;
+
+       size <<= 9;
+       if (offset == 0 && size == bio->bi_size)
+               return;
+
+       bio->bi_sector += offset;
+       bio->bi_size = size;
+       offset <<= 9;
+       clear_bit(BIO_SEG_VALID, &bio->bi_flags);
+
+       while (bio->bi_idx < bio->bi_vcnt &&
+              bio->bi_io_vec[bio->bi_idx].bv_len <= offset) {
+               /* remove this whole bio_vec */
+               offset -= bio->bi_io_vec[bio->bi_idx].bv_len;
+               bio->bi_idx++;
+       }
+       if (bio->bi_idx < bio->bi_vcnt) {
+               bio->bi_io_vec[bio->bi_idx].bv_offset += offset;
+               bio->bi_io_vec[bio->bi_idx].bv_len -= offset;
+       }
+       /* avoid any complications with bi_idx being non-zero*/
+       if (bio->bi_idx) {
+               memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx,
+                       (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec));
+               bio->bi_vcnt -= bio->bi_idx;
+               bio->bi_idx = 0;
+       }
+       /* Make sure vcnt and last bv are not too big */
+       bio_for_each_segment(bvec, bio, i) {
+               if (sofar + bvec->bv_len > size)
+                       bvec->bv_len = size - sofar;
+               if (bvec->bv_len == 0) {
+                       bio->bi_vcnt = i;
+                       break;
+               }
+               sofar += bvec->bv_len;
+       }
+}
+
+static void split_bio_end(struct bio *bio, int error)
+{
+       struct split_bio *split_bio = bio->bi_private;
+
+       if (error)
+               split_bio->err = error;
+
+       if (atomic_dec_and_test(&split_bio->pending)) {
+               split_bio->bio->bi_phys_segments = 0;
+               bio_endio(split_bio->bio, split_bio->err);
+               kfree(split_bio);
+       }
+       bio_put(bio);
+}
 
 static int blkif_recover(struct blkfront_info *info)
 {
        int i;
-       struct blkif_request *req;
+       struct request *req, *n;
        struct blk_shadow *copy;
-       int j;
+       int rc;
+       struct bio *bio, *cloned_bio;
+       struct bio_list bio_list, merge_bio;
+       unsigned int segs, offset;
+       int pending, size;
+       struct split_bio *split_bio;
+       struct list_head requests;
 
        /* Stage 1: Make a safe copy of the shadow state. */
        copy = kmemdup(info->shadow, sizeof(info->shadow),
@@ -1244,36 +1428,64 @@ static int blkif_recover(struct blkfront_info *info)
        info->shadow_free = info->ring.req_prod_pvt;
        info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff;
 
-       /* Stage 3: Find pending requests and requeue them. */
+       rc = blkfront_setup_indirect(info);
+       if (rc) {
+               kfree(copy);
+               return rc;
+       }
+
+       segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST;
+       blk_queue_max_segments(info->rq, segs);
+       bio_list_init(&bio_list);
+       INIT_LIST_HEAD(&requests);
        for (i = 0; i < BLK_RING_SIZE; i++) {
                /* Not in use? */
                if (!copy[i].request)
                        continue;
 
-               /* Grab a request slot and copy shadow state into it. */
-               req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
-               *req = copy[i].req;
-
-               /* We get a new request id, and must reset the shadow state. */
-               req->u.rw.id = get_id_from_freelist(info);
-               memcpy(&info->shadow[req->u.rw.id], &copy[i], sizeof(copy[i]));
-
-               if (req->operation != BLKIF_OP_DISCARD) {
-               /* Rewrite any grant references invalidated by susp/resume. */
-                       for (j = 0; j < req->u.rw.nr_segments; j++)
-                               gnttab_grant_foreign_access_ref(
-                                       req->u.rw.seg[j].gref,
-                                       info->xbdev->otherend_id,
-                                       pfn_to_mfn(copy[i].grants_used[j]->pfn),
-                                       0);
+               /*
+                * Get the bios in the request so we can re-queue them.
+                */
+               if (copy[i].request->cmd_flags &
+                   (REQ_FLUSH | REQ_FUA | REQ_DISCARD | REQ_SECURE)) {
+                       /*
+                        * Flush operations don't contain bios, so
+                        * we need to requeue the whole request
+                        */
+                       list_add(&copy[i].request->queuelist, &requests);
+                       continue;
                }
-               info->shadow[req->u.rw.id].req = *req;
-
-               info->ring.req_prod_pvt++;
+               merge_bio.head = copy[i].request->bio;
+               merge_bio.tail = copy[i].request->biotail;
+               bio_list_merge(&bio_list, &merge_bio);
+               copy[i].request->bio = NULL;
+               blk_put_request(copy[i].request);
        }
 
        kfree(copy);
 
+       /*
+        * Empty the queue, this is important because we might have
+        * requests in the queue with more segments than what we
+        * can handle now.
+        */
+       spin_lock_irq(&info->io_lock);
+       while ((req = blk_fetch_request(info->rq)) != NULL) {
+               if (req->cmd_flags &
+                   (REQ_FLUSH | REQ_FUA | REQ_DISCARD | REQ_SECURE)) {
+                       list_add(&req->queuelist, &requests);
+                       continue;
+               }
+               merge_bio.head = req->bio;
+               merge_bio.tail = req->biotail;
+               bio_list_merge(&bio_list, &merge_bio);
+               req->bio = NULL;
+               if (req->cmd_flags & (REQ_FLUSH | REQ_FUA))
+                       pr_alert("diskcache flush request found!\n");
+               __blk_put_request(info->rq, req);
+       }
+       spin_unlock_irq(&info->io_lock);
+
        xenbus_switch_state(info->xbdev, XenbusStateConnected);
 
        spin_lock_irq(&info->io_lock);
@@ -1281,14 +1493,50 @@ static int blkif_recover(struct blkfront_info *info)
        /* Now safe for us to use the shared ring */
        info->connected = BLKIF_STATE_CONNECTED;
 
-       /* Send off requeued requests */
-       flush_requests(info);
-
        /* Kick any other new requests queued since we resumed */
        kick_pending_request_queues(info);
 
+       list_for_each_entry_safe(req, n, &requests, queuelist) {
+               /* Requeue pending requests (flush or discard) */
+               list_del_init(&req->queuelist);
+               BUG_ON(req->nr_phys_segments > segs);
+               blk_requeue_request(info->rq, req);
+       }
        spin_unlock_irq(&info->io_lock);
 
+       while ((bio = bio_list_pop(&bio_list)) != NULL) {
+               /* Traverse the list of pending bios and re-queue them */
+               if (bio_segments(bio) > segs) {
+                       /*
+                        * This bio has more segments than what we can
+                        * handle, we have to split it.
+                        */
+                       pending = (bio_segments(bio) + segs - 1) / segs;
+                       split_bio = kzalloc(sizeof(*split_bio), GFP_NOIO);
+                       BUG_ON(split_bio == NULL);
+                       atomic_set(&split_bio->pending, pending);
+                       split_bio->bio = bio;
+                       for (i = 0; i < pending; i++) {
+                               offset = (i * segs * PAGE_SIZE) >> 9;
+                               size = min((unsigned int)(segs * PAGE_SIZE) >> 9,
+                                          (unsigned int)(bio->bi_size >> 9) - offset);
+                               cloned_bio = bio_clone(bio, GFP_NOIO);
+                               BUG_ON(cloned_bio == NULL);
+                               trim_bio(cloned_bio, offset, size);
+                               cloned_bio->bi_private = split_bio;
+                               cloned_bio->bi_end_io = split_bio_end;
+                               submit_bio(cloned_bio->bi_rw, cloned_bio);
+                       }
+                       /*
+                        * Now we have to wait for all those smaller bios to
+                        * end, so we can also end the "parent" bio.
+                        */
+                       continue;
+               }
+               /* We don't need to split this bio */
+               submit_bio(bio->bi_rw, bio);
+       }
+
        return 0;
 }
 
@@ -1308,8 +1556,12 @@ static int blkfront_resume(struct xenbus_device *dev)
        blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
 
        err = talk_to_blkback(dev, info);
-       if (info->connected == BLKIF_STATE_SUSPENDED && !err)
-               err = blkif_recover(info);
+
+       /*
+        * We have to wait for the backend to switch to
+        * connected state, since we want to read which
+        * features it supports.
+        */
 
        return err;
 }
@@ -1387,6 +1639,60 @@ static void blkfront_setup_discard(struct blkfront_info *info)
        kfree(type);
 }
 
+static int blkfront_setup_indirect(struct blkfront_info *info)
+{
+       unsigned int indirect_segments, segs;
+       int err, i;
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "feature-max-indirect-segments", "%u", &indirect_segments,
+                           NULL);
+       if (err) {
+               info->max_indirect_segments = 0;
+               segs = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+       } else {
+               info->max_indirect_segments = min(indirect_segments,
+                                                 xen_blkif_max_segments);
+               segs = info->max_indirect_segments;
+       }
+
+       err = fill_grant_buffer(info, (segs + INDIRECT_GREFS(segs)) * BLK_RING_SIZE);
+       if (err)
+               goto out_of_memory;
+
+       for (i = 0; i < BLK_RING_SIZE; i++) {
+               info->shadow[i].grants_used = kzalloc(
+                       sizeof(info->shadow[i].grants_used[0]) * segs,
+                       GFP_NOIO);
+               info->shadow[i].sg = kzalloc(sizeof(info->shadow[i].sg[0]) * segs, GFP_NOIO);
+               if (info->max_indirect_segments)
+                       info->shadow[i].indirect_grants = kzalloc(
+                               sizeof(info->shadow[i].indirect_grants[0]) *
+                               INDIRECT_GREFS(segs),
+                               GFP_NOIO);
+               if ((info->shadow[i].grants_used == NULL) ||
+                       (info->shadow[i].sg == NULL) ||
+                    (info->max_indirect_segments &&
+                    (info->shadow[i].indirect_grants == NULL)))
+                       goto out_of_memory;
+               sg_init_table(info->shadow[i].sg, segs);
+       }
+
+
+       return 0;
+
+out_of_memory:
+       for (i = 0; i < BLK_RING_SIZE; i++) {
+               kfree(info->shadow[i].grants_used);
+               info->shadow[i].grants_used = NULL;
+               kfree(info->shadow[i].sg);
+               info->shadow[i].sg = NULL;
+               kfree(info->shadow[i].indirect_grants);
+               info->shadow[i].indirect_grants = NULL;
+       }
+       return -ENOMEM;
+}
+
 /*
  * Invoked when the backend is finally 'ready' (and has told produced
  * the details about the physical device - #sectors, size, etc).
@@ -1395,6 +1701,7 @@ static void blkfront_connect(struct blkfront_info *info)
 {
        unsigned long long sectors;
        unsigned long sector_size;
+       unsigned int physical_sector_size;
        unsigned int binfo;
        int err;
        int barrier, flush, discard, persistent;
@@ -1414,8 +1721,15 @@ static void blkfront_connect(struct blkfront_info *info)
                set_capacity(info->gd, sectors);
                revalidate_disk(info->gd);
 
-               /* fall through */
+               return;
        case BLKIF_STATE_SUSPENDED:
+               /*
+                * If we are recovering from suspension, we need to wait
+                * for the backend to announce it's features before
+                * reconnecting, at least we need to know if the backend
+                * supports indirect descriptors, and how many.
+                */
+               blkif_recover(info);
                return;
 
        default:
@@ -1437,6 +1751,16 @@ static void blkfront_connect(struct blkfront_info *info)
                return;
        }
 
+       /*
+        * physcial-sector-size is a newer field, so old backends may not
+        * provide this. Assume physical sector size to be the same as
+        * sector_size in that case.
+        */
+       err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                          "physical-sector-size", "%u", &physical_sector_size);
+       if (err != 1)
+               physical_sector_size = sector_size;
+
        info->feature_flush = 0;
        info->flush_op = 0;
 
@@ -1483,7 +1807,15 @@ static void blkfront_connect(struct blkfront_info *info)
        else
                info->feature_persistent = persistent;
 
-       err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
+       err = blkfront_setup_indirect(info);
+       if (err) {
+               xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
+                                info->xbdev->otherend);
+               return;
+       }
+
+       err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size,
+                                 physical_sector_size);
        if (err) {
                xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
                                 info->xbdev->otherend);
index 11f467c00d0ac836a1c6509bffd31e49b891a844..a12b923bbaca91f14b923e0b271b00ebc1be8d28 100644 (file)
@@ -91,6 +91,10 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0489, 0xe04e) },
        { USB_DEVICE(0x0489, 0xe056) },
        { USB_DEVICE(0x0489, 0xe04d) },
+       { USB_DEVICE(0x04c5, 0x1330) },
+       { USB_DEVICE(0x13d3, 0x3402) },
+       { USB_DEVICE(0x0cf3, 0x3121) },
+       { USB_DEVICE(0x0cf3, 0xe003) },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE02C) },
@@ -128,6 +132,10 @@ static struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU22 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
@@ -193,24 +201,44 @@ error:
 
 static int ath3k_get_state(struct usb_device *udev, unsigned char *state)
 {
-       int pipe = 0;
+       int ret, pipe = 0;
+       char *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        pipe = usb_rcvctrlpipe(udev, 0);
-       return usb_control_msg(udev, pipe, ATH3K_GETSTATE,
-                       USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-                       state, 0x01, USB_CTRL_SET_TIMEOUT);
+       ret = usb_control_msg(udev, pipe, ATH3K_GETSTATE,
+                             USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+                             buf, sizeof(*buf), USB_CTRL_SET_TIMEOUT);
+
+       *state = *buf;
+       kfree(buf);
+
+       return ret;
 }
 
 static int ath3k_get_version(struct usb_device *udev,
                        struct ath3k_version *version)
 {
-       int pipe = 0;
+       int ret, pipe = 0;
+       struct ath3k_version *buf;
+       const int size = sizeof(*buf);
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        pipe = usb_rcvctrlpipe(udev, 0);
-       return usb_control_msg(udev, pipe, ATH3K_GETVERSION,
-                       USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version,
-                       sizeof(struct ath3k_version),
-                       USB_CTRL_SET_TIMEOUT);
+       ret = usb_control_msg(udev, pipe, ATH3K_GETVERSION,
+                             USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+                             buf, size, USB_CTRL_SET_TIMEOUT);
+
+       memcpy(version, buf, size);
+       kfree(buf);
+
+       return ret;
 }
 
 static int ath3k_load_fwfile(struct usb_device *udev,
index de4cf4daa2f4cefa3a270ccaf8e4e8fb22af1015..8e16f0af6358872606fbe102bddc9ade2c6ab470 100644 (file)
@@ -154,6 +154,10 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -1095,7 +1099,7 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev,
        if (IS_ERR(skb)) {
                BT_ERR("%s sending Intel patch command (0x%4.4x) failed (%ld)",
                       hdev->name, cmd->opcode, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
 
        /* It ensures that the returned event matches the event data read from
@@ -1147,7 +1151,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        if (IS_ERR(skb)) {
                BT_ERR("%s sending initial HCI reset command failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
@@ -1161,7 +1165,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        if (IS_ERR(skb)) {
                BT_ERR("%s reading Intel fw version command failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
 
        if (skb->len != sizeof(*ver)) {
@@ -1219,7 +1223,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
                BT_ERR("%s entering Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
                release_firmware(fw);
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
 
        if (skb->data[0]) {
@@ -1276,7 +1280,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        if (IS_ERR(skb)) {
                BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
@@ -1292,7 +1296,7 @@ exit_mfg_disable:
        if (IS_ERR(skb)) {
                BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
@@ -1310,7 +1314,7 @@ exit_mfg_deactivate:
        if (IS_ERR(skb)) {
                BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
index bf5d2477cb77c296dac3a63b3aea2e8a2ec5ce0a..15f2e7025b78e20abcdafc61dee7718800ff1824 100644 (file)
@@ -129,7 +129,8 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
        off_t j, io_pg_start;
        int io_pg_count;
 
-       if (type != 0 || mem->type != 0) {
+       if (type != mem->type ||
+               agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
                return -EINVAL;
        }
 
@@ -175,7 +176,8 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        struct _parisc_agp_info *info = &parisc_agp_info;
        int i, io_pg_start, io_pg_count;
 
-       if (type != 0 || mem->type != 0) {
+       if (type != mem->type ||
+               agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
                return -EINVAL;
        }
 
index a4ad7339588d7122fee7f4f86271c74629980709..f0a5e2b0eb8a9584f1e1d55ffac92bfd2800fbba 100644 (file)
@@ -1177,14 +1177,11 @@ static int __cpufreq_remove_dev(struct device *dev,
                                __func__, cpu_dev->id, cpu);
        }
 
-       if ((cpus == 1) && (cpufreq_driver->target))
-               __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
-
-       pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
-       cpufreq_cpu_put(data);
-
        /* If cpu is last user of policy, free policy */
        if (cpus == 1) {
+               if (cpufreq_driver->target)
+                       __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
+
                lock_policy_rwsem_read(cpu);
                kobj = &data->kobj;
                cmp = &data->kobj_unregister;
@@ -1205,9 +1202,13 @@ static int __cpufreq_remove_dev(struct device *dev,
                free_cpumask_var(data->related_cpus);
                free_cpumask_var(data->cpus);
                kfree(data);
-       } else if (cpufreq_driver->target) {
-               __cpufreq_governor(data, CPUFREQ_GOV_START);
-               __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+       } else {
+               pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
+               cpufreq_cpu_put(data);
+               if (cpufreq_driver->target) {
+                       __cpufreq_governor(data, CPUFREQ_GOV_START);
+                       __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+               }
        }
 
        per_cpu(cpufreq_policy_cpu, cpu) = -1;
index b012d7600e1a6c4d29038ba0df98940774cf6b3e..7cde885011ed3d1b15809f6d25c1a7f3ddc3adf1 100644 (file)
@@ -103,10 +103,10 @@ struct pstate_adjust_policy {
 static struct pstate_adjust_policy default_policy = {
        .sample_rate_ms = 10,
        .deadband = 0,
-       .setpoint = 109,
-       .p_gain_pct = 17,
+       .setpoint = 97,
+       .p_gain_pct = 20,
        .d_gain_pct = 0,
-       .i_gain_pct = 4,
+       .i_gain_pct = 0,
 };
 
 struct perf_limits {
@@ -468,12 +468,12 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
 static inline int intel_pstate_get_scaled_busy(struct cpudata *cpu)
 {
        int32_t busy_scaled;
-       int32_t core_busy, turbo_pstate, current_pstate;
+       int32_t core_busy, max_pstate, current_pstate;
 
        core_busy = int_tofp(cpu->samples[cpu->sample_ptr].core_pct_busy);
-       turbo_pstate = int_tofp(cpu->pstate.turbo_pstate);
+       max_pstate = int_tofp(cpu->pstate.max_pstate);
        current_pstate = int_tofp(cpu->pstate.current_pstate);
-       busy_scaled = mul_fp(core_busy, div_fp(turbo_pstate, current_pstate));
+       busy_scaled = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
 
        return fp_toint(busy_scaled);
 }
index fe343a06b7da3278ba68c9c15c261ea14afde685..bc580b67a65298a8bf65e699d562dfd6f237b697 100644 (file)
 #define MAX_INTERESTING 50000
 #define STDDEV_THRESH 400
 
-/* 60 * 60 > STDDEV_THRESH * INTERVALS = 400 * 8 */
-#define MAX_DEVIATION 60
-
-static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer);
-static DEFINE_PER_CPU(int, hrtimer_status);
-/* menu hrtimer mode */
-enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL};
 
 /*
  * Concepts and ideas behind the menu governor
@@ -116,13 +109,6 @@ enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL};
  *
  */
 
-/*
- * The C-state residency is so long that is is worthwhile to exit
- * from the shallow C-state and re-enter into a deeper C-state.
- */
-static unsigned int perfect_cstate_ms __read_mostly = 30;
-module_param(perfect_cstate_ms, uint, 0000);
-
 struct menu_device {
        int             last_state_idx;
        int             needs_update;
@@ -205,52 +191,17 @@ static u64 div_round64(u64 dividend, u32 divisor)
        return div_u64(dividend + (divisor / 2), divisor);
 }
 
-/* Cancel the hrtimer if it is not triggered yet */
-void menu_hrtimer_cancel(void)
-{
-       int cpu = smp_processor_id();
-       struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
-
-       /* The timer is still not time out*/
-       if (per_cpu(hrtimer_status, cpu)) {
-               hrtimer_cancel(hrtmr);
-               per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
-       }
-}
-EXPORT_SYMBOL_GPL(menu_hrtimer_cancel);
-
-/* Call back for hrtimer is triggered */
-static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer)
-{
-       int cpu = smp_processor_id();
-       struct menu_device *data = &per_cpu(menu_devices, cpu);
-
-       /* In general case, the expected residency is much larger than
-        *  deepest C-state target residency, but prediction logic still
-        *  predicts a small predicted residency, so the prediction
-        *  history is totally broken if the timer is triggered.
-        *  So reset the correction factor.
-        */
-       if (per_cpu(hrtimer_status, cpu) == MENU_HRTIMER_GENERAL)
-               data->correction_factor[data->bucket] = RESOLUTION * DECAY;
-
-       per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
-
-       return HRTIMER_NORESTART;
-}
-
 /*
  * Try detecting repeating patterns by keeping track of the last 8
  * intervals, and checking if the standard deviation of that set
  * of points is below a threshold. If it is... then use the
  * average of these 8 points as the estimated value.
  */
-static u32 get_typical_interval(struct menu_device *data)
+static void get_typical_interval(struct menu_device *data)
 {
        int i = 0, divisor = 0;
        uint64_t max = 0, avg = 0, stddev = 0;
        int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */
-       unsigned int ret = 0;
 
 again:
 
@@ -291,16 +242,13 @@ again:
        if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
                                                        || stddev <= 20) {
                data->predicted_us = avg;
-               ret = 1;
-               return ret;
+               return;
 
        } else if ((divisor * 4) > INTERVALS * 3) {
                /* Exclude the max interval */
                thresh = max - 1;
                goto again;
        }
-
-       return ret;
 }
 
 /**
@@ -315,9 +263,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        int i;
        int multiplier;
        struct timespec t;
-       int repeat = 0, low_predicted = 0;
-       int cpu = smp_processor_id();
-       struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
 
        if (data->needs_update) {
                menu_update(drv, dev);
@@ -352,7 +297,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
                                         RESOLUTION * DECAY);
 
-       repeat = get_typical_interval(data);
+       get_typical_interval(data);
 
        /*
         * We want to default to C1 (hlt), not to busy polling
@@ -373,10 +318,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 
                if (s->disabled || su->disable)
                        continue;
-               if (s->target_residency > data->predicted_us) {
-                       low_predicted = 1;
+               if (s->target_residency > data->predicted_us)
                        continue;
-               }
                if (s->exit_latency > latency_req)
                        continue;
                if (s->exit_latency * multiplier > data->predicted_us)
@@ -386,44 +329,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
                data->exit_us = s->exit_latency;
        }
 
-       /* not deepest C-state chosen for low predicted residency */
-       if (low_predicted) {
-               unsigned int timer_us = 0;
-               unsigned int perfect_us = 0;
-
-               /*
-                * Set a timer to detect whether this sleep is much
-                * longer than repeat mode predicted.  If the timer
-                * triggers, the code will evaluate whether to put
-                * the CPU into a deeper C-state.
-                * The timer is cancelled on CPU wakeup.
-                */
-               timer_us = 2 * (data->predicted_us + MAX_DEVIATION);
-
-               perfect_us = perfect_cstate_ms * 1000;
-
-               if (repeat && (4 * timer_us < data->expected_us)) {
-                       RCU_NONIDLE(hrtimer_start(hrtmr,
-                               ns_to_ktime(1000 * timer_us),
-                               HRTIMER_MODE_REL_PINNED));
-                       /* In repeat case, menu hrtimer is started */
-                       per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT;
-               } else if (perfect_us < data->expected_us) {
-                       /*
-                        * The next timer is long. This could be because
-                        * we did not make a useful prediction.
-                        * In that case, it makes sense to re-enter
-                        * into a deeper C-state after some time.
-                        */
-                       RCU_NONIDLE(hrtimer_start(hrtmr,
-                               ns_to_ktime(1000 * timer_us),
-                               HRTIMER_MODE_REL_PINNED));
-                       /* In general case, menu hrtimer is started */
-                       per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_GENERAL;
-               }
-
-       }
-
        return data->last_state_idx;
 }
 
@@ -514,9 +419,6 @@ static int menu_enable_device(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev)
 {
        struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
-       struct hrtimer *t = &per_cpu(menu_hrtimer, dev->cpu);
-       hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       t->function = menu_hrtimer_notify;
 
        memset(data, 0, sizeof(struct menu_device));
 
index 5996521a1caff11068e9b2e1e417cdf729f474df..84573b4d6f92809d5cd98fa968f6dd1a617482d3 100644 (file)
@@ -429,7 +429,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in,
        dma_addr_t src_dma, dst_dma;
        int ret = 0;
 
-       desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA);
+       desc = kmalloc(CAAM_CMD_SZ * 8 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA);
        if (!desc) {
                dev_err(jrdev, "unable to allocate key input memory\n");
                return -ENOMEM;
index ce3dc3e9688c86ea30e3be7757094b78749a6ec9..0bbdea5059f3b693a8929a4d6ee82db24c90b768 100644 (file)
@@ -867,6 +867,7 @@ static int pch_dma_probe(struct pci_dev *pdev,
 
        if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
                dev_err(&pdev->dev, "Cannot find proper base address\n");
+               err = -ENODEV;
                goto err_disable_pdev;
        }
 
index 593827b3fdd4fd8556724da998934a7c191b8d49..fa645d8250091943ba8d47aa42852b99b74ca1ce 100644 (file)
@@ -2505,6 +2505,10 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
        /* Assign cookies to all nodes */
        while (!list_empty(&last->node)) {
                desc = list_entry(last->node.next, struct dma_pl330_desc, node);
+               if (pch->cyclic) {
+                       desc->txd.callback = last->txd.callback;
+                       desc->txd.callback_param = last->txd.callback_param;
+               }
 
                dma_cookie_assign(&desc->txd);
 
@@ -2688,45 +2692,82 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
                size_t period_len, enum dma_transfer_direction direction,
                unsigned long flags, void *context)
 {
-       struct dma_pl330_desc *desc;
+       struct dma_pl330_desc *desc = NULL, *first = NULL;
        struct dma_pl330_chan *pch = to_pchan(chan);
+       struct dma_pl330_dmac *pdmac = pch->dmac;
+       unsigned int i;
        dma_addr_t dst;
        dma_addr_t src;
 
-       desc = pl330_get_desc(pch);
-       if (!desc) {
-               dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
-                       __func__, __LINE__);
+       if (len % period_len != 0)
                return NULL;
-       }
 
-       switch (direction) {
-       case DMA_MEM_TO_DEV:
-               desc->rqcfg.src_inc = 1;
-               desc->rqcfg.dst_inc = 0;
-               desc->req.rqtype = MEMTODEV;
-               src = dma_addr;
-               dst = pch->fifo_addr;
-               break;
-       case DMA_DEV_TO_MEM:
-               desc->rqcfg.src_inc = 0;
-               desc->rqcfg.dst_inc = 1;
-               desc->req.rqtype = DEVTOMEM;
-               src = pch->fifo_addr;
-               dst = dma_addr;
-               break;
-       default:
+       if (!is_slave_direction(direction)) {
                dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
                __func__, __LINE__);
                return NULL;
        }
 
-       desc->rqcfg.brst_size = pch->burst_sz;
-       desc->rqcfg.brst_len = 1;
+       for (i = 0; i < len / period_len; i++) {
+               desc = pl330_get_desc(pch);
+               if (!desc) {
+                       dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+                               __func__, __LINE__);
 
-       pch->cyclic = true;
+                       if (!first)
+                               return NULL;
+
+                       spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+                       while (!list_empty(&first->node)) {
+                               desc = list_entry(first->node.next,
+                                               struct dma_pl330_desc, node);
+                               list_move_tail(&desc->node, &pdmac->desc_pool);
+                       }
+
+                       list_move_tail(&first->node, &pdmac->desc_pool);
 
-       fill_px(&desc->px, dst, src, period_len);
+                       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+
+                       return NULL;
+               }
+
+               switch (direction) {
+               case DMA_MEM_TO_DEV:
+                       desc->rqcfg.src_inc = 1;
+                       desc->rqcfg.dst_inc = 0;
+                       desc->req.rqtype = MEMTODEV;
+                       src = dma_addr;
+                       dst = pch->fifo_addr;
+                       break;
+               case DMA_DEV_TO_MEM:
+                       desc->rqcfg.src_inc = 0;
+                       desc->rqcfg.dst_inc = 1;
+                       desc->req.rqtype = DEVTOMEM;
+                       src = pch->fifo_addr;
+                       dst = dma_addr;
+                       break;
+               default:
+                       break;
+               }
+
+               desc->rqcfg.brst_size = pch->burst_sz;
+               desc->rqcfg.brst_len = 1;
+               fill_px(&desc->px, dst, src, period_len);
+
+               if (!first)
+                       first = desc;
+               else
+                       list_add_tail(&desc->node, &first->node);
+
+               dma_addr += period_len;
+       }
+
+       if (!desc)
+               return NULL;
+
+       pch->cyclic = true;
+       desc->txd.flags = flags;
 
        return &desc->txd;
 }
index b67f45f5c2712a8c16be7afad085bd745649a708..5039fbc88254eabd570e9da6d50d51ed0cff8240 100644 (file)
@@ -400,8 +400,8 @@ static size_t sh_dmae_get_partial(struct shdma_chan *schan,
                                                    shdma_chan);
        struct sh_dmae_desc *sh_desc = container_of(sdesc,
                                        struct sh_dmae_desc, shdma_desc);
-       return (sh_desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) <<
-               sh_chan->xmit_shift;
+       return sh_desc->hw.tcr -
+               (sh_dmae_readl(sh_chan, TCR) << sh_chan->xmit_shift);
 }
 
 /* Called from error IRQ or NMI */
index 27e86d93826280a62744a559332bf0cd9bc03b3b..89e109022d78a27cf506d995c1c16de2feffea0f 100644 (file)
@@ -48,6 +48,8 @@ static LIST_HEAD(mc_devices);
  */
 static void const *edac_mc_owner;
 
+static struct bus_type mc_bus[EDAC_MAX_MCS];
+
 unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
                                 unsigned len)
 {
@@ -723,6 +725,11 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
        int ret = -EINVAL;
        edac_dbg(0, "\n");
 
+       if (mci->mc_idx >= EDAC_MAX_MCS) {
+               pr_warn_once("Too many memory controllers: %d\n", mci->mc_idx);
+               return -ENODEV;
+       }
+
 #ifdef CONFIG_EDAC_DEBUG
        if (edac_debug_level >= 3)
                edac_mc_dump_mci(mci);
@@ -762,6 +769,8 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
        /* set load time so that error rate can be tracked */
        mci->start_time = jiffies;
 
+       mci->bus = &mc_bus[mci->mc_idx];
+
        if (edac_create_sysfs_mci_device(mci)) {
                edac_mc_printk(mci, KERN_WARNING,
                        "failed to create sysfs device\n");
index ef15a7e613bc6b1d1feec75733a86e20cb23efa7..e7c32c4f783737962b575a232f03b5ed19d3629b 100644 (file)
@@ -370,7 +370,7 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
                return -ENODEV;
 
        csrow->dev.type = &csrow_attr_type;
-       csrow->dev.bus = &mci->bus;
+       csrow->dev.bus = mci->bus;
        device_initialize(&csrow->dev);
        csrow->dev.parent = &mci->dev;
        csrow->mci = mci;
@@ -605,7 +605,7 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
        dimm->mci = mci;
 
        dimm->dev.type = &dimm_attr_type;
-       dimm->dev.bus = &mci->bus;
+       dimm->dev.bus = mci->bus;
        device_initialize(&dimm->dev);
 
        dimm->dev.parent = &mci->dev;
@@ -975,11 +975,13 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
         * The memory controller needs its own bus, in order to avoid
         * namespace conflicts at /sys/bus/edac.
         */
-       mci->bus.name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
-       if (!mci->bus.name)
+       mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
+       if (!mci->bus->name)
                return -ENOMEM;
-       edac_dbg(0, "creating bus %s\n", mci->bus.name);
-       err = bus_register(&mci->bus);
+
+       edac_dbg(0, "creating bus %s\n", mci->bus->name);
+
+       err = bus_register(mci->bus);
        if (err < 0)
                return err;
 
@@ -988,7 +990,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
        device_initialize(&mci->dev);
 
        mci->dev.parent = mci_pdev;
-       mci->dev.bus = &mci->bus;
+       mci->dev.bus = mci->bus;
        dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
        dev_set_drvdata(&mci->dev, mci);
        pm_runtime_forbid(&mci->dev);
@@ -997,8 +999,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
        err = device_add(&mci->dev);
        if (err < 0) {
                edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
-               bus_unregister(&mci->bus);
-               kfree(mci->bus.name);
+               bus_unregister(mci->bus);
+               kfree(mci->bus->name);
                return err;
        }
 
@@ -1064,8 +1066,8 @@ fail:
        }
 fail2:
        device_unregister(&mci->dev);
-       bus_unregister(&mci->bus);
-       kfree(mci->bus.name);
+       bus_unregister(mci->bus);
+       kfree(mci->bus->name);
        return err;
 }
 
@@ -1098,8 +1100,8 @@ void edac_unregister_sysfs(struct mem_ctl_info *mci)
 {
        edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
        device_unregister(&mci->dev);
-       bus_unregister(&mci->bus);
-       kfree(mci->bus.name);
+       bus_unregister(mci->bus);
+       kfree(mci->bus->name);
 }
 
 static void mc_attr_release(struct device *dev)
index 1b635178cc44ff31b8ed224560ebdf86851165f0..157b934e8ce3a528468e45a735ab41dee6043cea 100644 (file)
@@ -974,7 +974,7 @@ static int i5100_setup_debugfs(struct mem_ctl_info *mci)
        if (!i5100_debugfs)
                return -ENODEV;
 
-       priv->debugfs = debugfs_create_dir(mci->bus.name, i5100_debugfs);
+       priv->debugfs = debugfs_create_dir(mci->bus->name, i5100_debugfs);
 
        if (!priv->debugfs)
                return -ENOMEM;
index 7ef316fdc4d964cc8d1f87bd7be0cb9995223612..ac1b43a0428531273c4fdaefd56a0b83f1545ce2 100644 (file)
@@ -54,6 +54,7 @@
 #define FW_CDEV_KERNEL_VERSION                 5
 #define FW_CDEV_VERSION_EVENT_REQUEST2         4
 #define FW_CDEV_VERSION_ALLOCATE_REGION_END    4
+#define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW        5
 
 struct client {
        u32 version;
@@ -1005,6 +1006,8 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
                        a->channel, a->speed, a->header_size, cb, client);
        if (IS_ERR(context))
                return PTR_ERR(context);
+       if (client->version < FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW)
+               context->drop_overflow_headers = true;
 
        /* We only support one context at this time. */
        spin_lock_irq(&client->lock);
index 9e1db6490b9a3bb497b7911d94c42d9fc6190be7..afb701ec90cabd50ceb03b1298beba38e97717b4 100644 (file)
@@ -2749,8 +2749,11 @@ static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr)
 {
        u32 *ctx_hdr;
 
-       if (ctx->header_length + ctx->base.header_size > PAGE_SIZE)
+       if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) {
+               if (ctx->base.drop_overflow_headers)
+                       return;
                flush_iso_completions(ctx);
+       }
 
        ctx_hdr = ctx->header + ctx->header_length;
        ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]);
@@ -2910,8 +2913,11 @@ static int handle_it_packet(struct context *context,
 
        sync_it_packet_for_cpu(context, d);
 
-       if (ctx->header_length + 4 > PAGE_SIZE)
+       if (ctx->header_length + 4 > PAGE_SIZE) {
+               if (ctx->base.drop_overflow_headers)
+                       return 1;
                flush_iso_completions(ctx);
+       }
 
        ctx_hdr = ctx->header + ctx->header_length;
        ctx->last_timestamp = le16_to_cpu(last->res_count);
index eb760a218da4292f7c208ddc145deffb833df7ab..232fa8fce26a5d0ffddf5fdc3ee01ed3c63eed7f 100644 (file)
@@ -419,6 +419,13 @@ static void __init dmi_format_ids(char *buf, size_t len)
                            dmi_get_system_info(DMI_BIOS_DATE));
 }
 
+/*
+ * Check for DMI/SMBIOS headers in the system firmware image.  Any
+ * SMBIOS header must start 16 bytes before the DMI header, so take a
+ * 32 byte buffer and check for DMI at offset 16 and SMBIOS at offset
+ * 0.  If the DMI header is present, set dmi_ver accordingly (SMBIOS
+ * takes precedence) and return 0.  Otherwise return 1.
+ */
 static int __init dmi_present(const u8 *buf)
 {
        int smbios_ver;
@@ -506,6 +513,13 @@ void __init dmi_scan_machine(void)
                if (p == NULL)
                        goto error;
 
+               /*
+                * Iterate over all possible DMI header addresses q.
+                * Maintain the 32 bytes around q in buf.  On the
+                * first iteration, substitute zero for the
+                * out-of-range bytes so there is no chance of falsely
+                * detecting an SMBIOS header.
+                */
                memset(buf, 0, 16);
                for (q = p; q < p + 0x10000; q += 16) {
                        memcpy_fromio(buf + 16, q, 16);
index e3ceaacde45c111990c534c887a47cda3a5ec61e..73b73969d361c10a42968ee5eaaa142f72894ef6 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/err.h>
 
 #include <mach/msm_gpiomux.h>
 
index f4491a497cc8760ef59484ac2c6c264573b3b8a9..c2fa77086eb58cf9de7f2c2a453c900a9771f0b5 100644 (file)
@@ -378,7 +378,7 @@ static int msm_gpio_probe(struct platform_device *pdev)
        int ret, ngpio;
        struct resource *res;
 
-       if (!of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) {
+       if (of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) {
                dev_err(&pdev->dev, "%s: ngpio property missing\n", __func__);
                return -EINVAL;
        }
index 738a4294d820e164d7534f830dd4eed7c880aa4d..6a647493ca7f0741cd39d03134f0614c74451d48 100644 (file)
@@ -677,6 +677,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                        /* don't break so fail path works correct */
                                        fail = 1;
                                break;
+
+                               if (connector->dpms != DRM_MODE_DPMS_ON) {
+                                       DRM_DEBUG_KMS("connector dpms not on, full mode switch\n");
+                                       mode_changed = true;
+                               }
                        }
                }
 
@@ -754,6 +759,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                ret = -EINVAL;
                                goto fail;
                        }
+                       DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+                       for (i = 0; i < set->num_connectors; i++) {
+                               DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+                                             drm_get_connector_name(set->connectors[i]));
+                               set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
+                       }
                }
                drm_helper_disable_unused_functions(dev);
        } else if (fb_changed) {
@@ -771,22 +782,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                }
        }
 
-       /*
-        * crtc set_config helpers implicit set the crtc and all connected
-        * encoders to DPMS on for a full mode set. But for just an fb update it
-        * doesn't do that. To not confuse userspace, do an explicit DPMS_ON
-        * unconditionally. This will also ensure driver internal dpms state is
-        * consistent again.
-        */
-       if (set->crtc->enabled) {
-               DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
-               for (i = 0; i < set->num_connectors; i++) {
-                       DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
-                                     drm_get_connector_name(set->connectors[i]));
-                       set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
-               }
-       }
-
        kfree(save_connectors);
        kfree(save_encoders);
        kfree(save_crtcs);
index 95c75edef01a0440303a36f2692ce963fe6a135e..30ef41bcd7b8fa5ed0554adf8bc3332cf19a1320 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 
 
 #include "exynos_drm_drv.h"
index 61b094f689a72c56666decd1b6b4361d12be6291..6e047bd53e2f00dd8f0d494194be7cda4f02ceda 100644 (file)
@@ -12,7 +12,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
index 3e106beca5b6c132f1dea2407652deac449fcc59..1c263dac3c1c8ddcbee197d13143a428ac4b01a2 100644 (file)
@@ -14,7 +14,6 @@
 #include <drm/drmP.h>
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/of_device.h>
@@ -130,7 +129,6 @@ static const struct of_device_id fimd_driver_dt_match[] = {
          .data = &exynos5_fimd_driver_data },
        {},
 };
-MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
 #endif
 
 static inline struct fimd_driver_data *drm_fimd_get_driver_data(
@@ -1082,7 +1080,6 @@ static struct platform_device_id fimd_driver_ids[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(platform, fimd_driver_ids);
 
 static const struct dev_pm_ops fimd_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
index 42a5a5466075a7d2d25b8ab30fa6155383a0befa..eddea4941483228a68530513e4f04aa94cb0f84e 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
@@ -806,9 +805,20 @@ static void g2d_dma_start(struct g2d_data *g2d,
        struct g2d_cmdlist_node *node =
                                list_first_entry(&runqueue_node->run_cmdlist,
                                                struct g2d_cmdlist_node, list);
+       int ret;
+
+       ret = pm_runtime_get_sync(g2d->dev);
+       if (ret < 0) {
+               dev_warn(g2d->dev, "failed pm power on.\n");
+               return;
+       }
 
-       pm_runtime_get_sync(g2d->dev);
-       clk_enable(g2d->gate_clk);
+       ret = clk_prepare_enable(g2d->gate_clk);
+       if (ret < 0) {
+               dev_warn(g2d->dev, "failed to enable clock.\n");
+               pm_runtime_put_sync(g2d->dev);
+               return;
+       }
 
        writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR);
        writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND);
@@ -861,7 +871,7 @@ static void g2d_runqueue_worker(struct work_struct *work)
                                            runqueue_work);
 
        mutex_lock(&g2d->runqueue_mutex);
-       clk_disable(g2d->gate_clk);
+       clk_disable_unprepare(g2d->gate_clk);
        pm_runtime_put_sync(g2d->dev);
 
        complete(&g2d->runqueue_node->complete);
@@ -1521,7 +1531,6 @@ static const struct of_device_id exynos_g2d_match[] = {
        { .compatible = "samsung,exynos5250-g2d" },
        {},
 };
-MODULE_DEVICE_TABLE(of, exynos_g2d_match);
 #endif
 
 struct platform_driver g2d_driver = {
index 472e3b25e7f2cc6f5e05c1db002e5117bfca8685..90b8a1a5344cef0528b3bad82ab4b0b993002415 100644 (file)
@@ -12,7 +12,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
index aaa550d622f03c047ca2ecf7c19fec8722f52747..8d3bc01d6834f7b8fca2c2320e67b151a4df3d0c 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/wait.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
index b1ef8e7ff9c91fff7ecc11fc21cf25f7f20fbb3b..d2b6ab4def93ab7421d30fea9c9f86880a0b0e10 100644 (file)
@@ -12,7 +12,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/clk.h>
@@ -342,10 +341,10 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
                 */
                ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock,
                                                prop_list->ipp_id);
-               if (!ippdrv) {
+               if (IS_ERR(ippdrv)) {
                        DRM_ERROR("not found ipp%d driver.\n",
                                        prop_list->ipp_id);
-                       return -EINVAL;
+                       return PTR_ERR(ippdrv);
                }
 
                prop_list = ippdrv->prop_list;
@@ -970,9 +969,9 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
        /* find command node */
        c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
                qbuf->prop_id);
-       if (!c_node) {
+       if (IS_ERR(c_node)) {
                DRM_ERROR("failed to get command node.\n");
-               return -EFAULT;
+               return PTR_ERR(c_node);
        }
 
        /* buffer control */
@@ -1106,9 +1105,9 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
 
        c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
                cmd_ctrl->prop_id);
-       if (!c_node) {
+       if (IS_ERR(c_node)) {
                DRM_ERROR("invalid command node list.\n");
-               return -EINVAL;
+               return PTR_ERR(c_node);
        }
 
        if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl,
index 427640aa51481777976391fa51d856f7bbc7512f..49669aa24c4510168d003b4677b3da5548ef2b94 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
index 41cc74d83e4ec885bab33adf02182402938d27d3..c57c56519adda3d2240d57aa1fe6d90900efe680 100644 (file)
@@ -13,7 +13,6 @@
 #include <drm/drmP.h>
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include <drm/exynos_drm.h>
index 62ef5971ac3c6c40f2d269251a1d098386e024c4..2f5c6942c968bd7a1f9ed4e16adcb8f4c7a99d35 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index ef04255076c7f30bd293aa97f95fdaa7d6c5fdcd..6e320ae9afedc758b4a61282e030c099adf152db 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 
 #include "exynos_drm_drv.h"
 #include "exynos_hdmi.h"
index 42ffb71c63bca254fd5ac753b1d6dcd84c284371..c9a137caea41108a18b8c179a39110c3d64e6a5b 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index cf188ab7051a6b213e0ebb945fde92fc869b0ce6..f4669802a0fb35a6a1ae99b6f7c7cdaeb21d9df5 100644 (file)
@@ -1495,6 +1495,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev_priv->dev = dev;
        dev_priv->info = info;
 
+       spin_lock_init(&dev_priv->irq_lock);
+       spin_lock_init(&dev_priv->gpu_error.lock);
+       spin_lock_init(&dev_priv->rps.lock);
+       spin_lock_init(&dev_priv->gt_lock);
+       spin_lock_init(&dev_priv->backlight.lock);
+       mutex_init(&dev_priv->dpio_lock);
+       mutex_init(&dev_priv->rps.hw_lock);
+       mutex_init(&dev_priv->modeset_restore_lock);
+
        i915_dump_device_info(dev_priv);
 
        if (i915_get_bridge_dev(dev)) {
@@ -1585,6 +1594,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        intel_detect_pch(dev);
 
        intel_irq_init(dev);
+       intel_pm_init(dev);
+       intel_gt_sanitize(dev);
        intel_gt_init(dev);
 
        /* Try to make sure MCHBAR is enabled before poking at it */
@@ -1610,15 +1621,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (!IS_I945G(dev) && !IS_I945GM(dev))
                pci_enable_msi(dev->pdev);
 
-       spin_lock_init(&dev_priv->irq_lock);
-       spin_lock_init(&dev_priv->gpu_error.lock);
-       spin_lock_init(&dev_priv->rps.lock);
-       spin_lock_init(&dev_priv->backlight.lock);
-       mutex_init(&dev_priv->dpio_lock);
-
-       mutex_init(&dev_priv->rps.hw_lock);
-       mutex_init(&dev_priv->modeset_restore_lock);
-
        dev_priv->num_plane = 1;
        if (IS_VALLEYVIEW(dev))
                dev_priv->num_plane = 2;
@@ -1648,7 +1650,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (INTEL_INFO(dev)->num_pipes) {
                /* Must be done after probing outputs */
                intel_opregion_init(dev);
-               acpi_video_register_with_quirks();
+               acpi_video_register();
        }
 
        if (IS_GEN5(dev))
index f4af1ca0fb62d82827213d51461d9642f0cf33cf..45b3c030f48393b6921e66406e48f92e2f1d643e 100644 (file)
@@ -706,7 +706,7 @@ static int i915_drm_thaw(struct drm_device *dev)
 {
        int error = 0;
 
-       intel_gt_reset(dev);
+       intel_gt_sanitize(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                mutex_lock(&dev->struct_mutex);
@@ -732,7 +732,7 @@ int i915_resume(struct drm_device *dev)
 
        pci_set_master(dev->pdev);
 
-       intel_gt_reset(dev);
+       intel_gt_sanitize(dev);
 
        /*
         * Platforms with opregion should have sane BIOS, older ones (gen3 and
@@ -1253,21 +1253,21 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
 
 #define __i915_read(x, y) \
 u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
+       unsigned long irqflags; \
        u##x val = 0; \
+       spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
        if (IS_GEN5(dev_priv->dev)) \
                ilk_dummy_write(dev_priv); \
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
-               unsigned long irqflags; \
-               spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
                if (dev_priv->forcewake_count == 0) \
                        dev_priv->gt.force_wake_get(dev_priv); \
                val = read##y(dev_priv->regs + reg); \
                if (dev_priv->forcewake_count == 0) \
                        dev_priv->gt.force_wake_put(dev_priv); \
-               spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
        } else { \
                val = read##y(dev_priv->regs + reg); \
        } \
+       spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
        trace_i915_reg_rw(false, reg, val, sizeof(val)); \
        return val; \
 }
@@ -1280,8 +1280,10 @@ __i915_read(64, q)
 
 #define __i915_write(x, y) \
 void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
+       unsigned long irqflags; \
        u32 __fifo_ret = 0; \
        trace_i915_reg_rw(true, reg, val, sizeof(val)); \
+       spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
                __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
        } \
@@ -1293,6 +1295,7 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
                gen6_gt_check_fifodbg(dev_priv); \
        } \
        hsw_unclaimed_reg_check(dev_priv, reg); \
+       spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
 }
 __i915_write(8, b)
 __i915_write(16, w)
index a416645bcd23364bb9793100da286b7f74858794..1929bffc1c77f645a920c9b4037f0b5eb646a145 100644 (file)
@@ -555,6 +555,7 @@ enum intel_sbi_destination {
 #define QUIRK_PIPEA_FORCE (1<<0)
 #define QUIRK_LVDS_SSC_DISABLE (1<<1)
 #define QUIRK_INVERT_BRIGHTNESS (1<<2)
+#define QUIRK_NO_PCH_PWM_ENABLE (1<<3)
 
 struct intel_fbdev;
 struct intel_fbc_work;
@@ -1581,9 +1582,10 @@ void i915_hangcheck_elapsed(unsigned long data);
 void i915_handle_error(struct drm_device *dev, bool wedged);
 
 extern void intel_irq_init(struct drm_device *dev);
+extern void intel_pm_init(struct drm_device *dev);
 extern void intel_hpd_init(struct drm_device *dev);
 extern void intel_gt_init(struct drm_device *dev);
-extern void intel_gt_reset(struct drm_device *dev);
+extern void intel_gt_sanitize(struct drm_device *dev);
 
 void i915_error_state_free(struct kref *error_ref);
 
index 97afd2639fb63a1e240fce2c6f97f53fd9f82e98..d9e2208cfe98f2fdcb3957bf4ee13f0497e06dfb 100644 (file)
@@ -2258,7 +2258,17 @@ void i915_gem_restore_fences(struct drm_device *dev)
 
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
-               i915_gem_write_fence(dev, i, reg->obj);
+
+               /*
+                * Commit delayed tiling changes if we have an object still
+                * attached to the fence, otherwise just clear the fence.
+                */
+               if (reg->obj) {
+                       i915_gem_object_update_fence(reg->obj, reg,
+                                                    reg->obj->tiling_mode);
+               } else {
+                       i915_gem_write_fence(dev, i, NULL);
+               }
        }
 }
 
@@ -2795,6 +2805,10 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg,
        if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj))
                mb();
 
+       WARN(obj && (!obj->stride || !obj->tiling_mode),
+            "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
+            obj->stride, obj->tiling_mode);
+
        switch (INTEL_INFO(dev)->gen) {
        case 7:
        case 6:
@@ -2836,6 +2850,7 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
                fence->obj = NULL;
                list_del_init(&fence->lru_list);
        }
+       obj->fence_dirty = false;
 }
 
 static int
@@ -2965,7 +2980,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
                return 0;
 
        i915_gem_object_update_fence(obj, reg, enable);
-       obj->fence_dirty = false;
 
        return 0;
 }
index 324211ac9c555486d56acd36584af7468e762f01..b042ee5c40704a8beaa1e5b99f3d6a1b2082d722 100644 (file)
@@ -301,7 +301,7 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder,
                struct intel_digital_port *intel_dig_port =
                        enc_to_dig_port(encoder);
 
-               intel_dp->DP = intel_dig_port->port_reversal |
+               intel_dp->DP = intel_dig_port->saved_port_bits |
                               DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW;
                intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
 
@@ -1109,7 +1109,8 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
                 * enabling the port.
                 */
                I915_WRITE(DDI_BUF_CTL(port),
-                          intel_dig_port->port_reversal | DDI_BUF_CTL_ENABLE);
+                          intel_dig_port->saved_port_bits |
+                          DDI_BUF_CTL_ENABLE);
        } else if (type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
@@ -1347,8 +1348,9 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
        intel_encoder->get_config = intel_ddi_get_config;
 
        intel_dig_port->port = port;
-       intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) &
-                                       DDI_BUF_PORT_REVERSAL;
+       intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
+                                         (DDI_BUF_PORT_REVERSAL |
+                                          DDI_A_4_LANES);
        intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
 
        intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
index 85f3eb74d2b75dbf48f7d9afcf3d5626de4187ca..5fb305840db89ecd80b5cd42b69ff9c35dd9432b 100644 (file)
@@ -4913,22 +4913,19 @@ static void i9xx_get_pfit_config(struct intel_crtc *crtc,
        uint32_t tmp;
 
        tmp = I915_READ(PFIT_CONTROL);
+       if (!(tmp & PFIT_ENABLE))
+               return;
 
+       /* Check whether the pfit is attached to our pipe. */
        if (INTEL_INFO(dev)->gen < 4) {
                if (crtc->pipe != PIPE_B)
                        return;
-
-               /* gen2/3 store dither state in pfit control, needs to match */
-               pipe_config->gmch_pfit.control = tmp & PANEL_8TO6_DITHER_ENABLE;
        } else {
                if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT))
                        return;
        }
 
-       if (!(tmp & PFIT_ENABLE))
-               return;
-
-       pipe_config->gmch_pfit.control = I915_READ(PFIT_CONTROL);
+       pipe_config->gmch_pfit.control = tmp;
        pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS);
        if (INTEL_INFO(dev)->gen < 5)
                pipe_config->gmch_pfit.lvds_border_bits =
@@ -8317,6 +8314,8 @@ check_shared_dpll_state(struct drm_device *dev)
                     pll->active, pll->refcount);
                WARN(pll->active && !pll->on,
                     "pll in active use but not on in sw tracking\n");
+               WARN(pll->on && !pll->active,
+                    "pll in on but not on in use in sw tracking\n");
                WARN(pll->on != active,
                     "pll on state mismatch (expected %i, found %i)\n",
                     pll->on, active);
@@ -8541,15 +8540,20 @@ static void intel_set_config_restore_state(struct drm_device *dev,
 }
 
 static bool
-is_crtc_connector_off(struct drm_crtc *crtc, struct drm_connector *connectors,
-                     int num_connectors)
+is_crtc_connector_off(struct drm_mode_set *set)
 {
        int i;
 
-       for (i = 0; i < num_connectors; i++)
-               if (connectors[i].encoder &&
-                   connectors[i].encoder->crtc == crtc &&
-                   connectors[i].dpms != DRM_MODE_DPMS_ON)
+       if (set->num_connectors == 0)
+               return false;
+
+       if (WARN_ON(set->connectors == NULL))
+               return false;
+
+       for (i = 0; i < set->num_connectors; i++)
+               if (set->connectors[i]->encoder &&
+                   set->connectors[i]->encoder->crtc == set->crtc &&
+                   set->connectors[i]->dpms != DRM_MODE_DPMS_ON)
                        return true;
 
        return false;
@@ -8562,10 +8566,8 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
 
        /* We should be able to check here if the fb has the same properties
         * and then just flip_or_move it */
-       if (set->connectors != NULL &&
-           is_crtc_connector_off(set->crtc, *set->connectors,
-                                 set->num_connectors)) {
-                       config->mode_changed = true;
+       if (is_crtc_connector_off(set)) {
+               config->mode_changed = true;
        } else if (set->crtc->fb != set->fb) {
                /* If we have no fb then treat it as a full mode set */
                if (set->crtc->fb == NULL) {
@@ -9398,6 +9400,17 @@ static void quirk_invert_brightness(struct drm_device *dev)
        DRM_INFO("applying inverted panel brightness quirk\n");
 }
 
+/*
+ * Some machines (Dell XPS13) suffer broken backlight controls if
+ * BLM_PCH_PWM_ENABLE is set.
+ */
+static void quirk_no_pcm_pwm_enable(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       dev_priv->quirks |= QUIRK_NO_PCH_PWM_ENABLE;
+       DRM_INFO("applying no-PCH_PWM_ENABLE quirk\n");
+}
+
 struct intel_quirk {
        int device;
        int subsystem_vendor;
@@ -9467,6 +9480,11 @@ static struct intel_quirk intel_quirks[] = {
 
        /* Acer Aspire 4736Z */
        { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
+
+       /* Dell XPS13 HD Sandy Bridge */
+       { 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable },
+       /* Dell XPS13 HD and XPS13 FHD Ivy Bridge */
+       { 0x0166, 0x1028, 0x058b, quirk_no_pcm_pwm_enable },
 };
 
 static void intel_init_quirks(struct drm_device *dev)
@@ -9817,8 +9835,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                }
                pll->refcount = pll->active;
 
-               DRM_DEBUG_KMS("%s hw state readout: refcount %i\n",
-                             pll->name, pll->refcount);
+               DRM_DEBUG_KMS("%s hw state readout: refcount %i, on %i\n",
+                             pll->name, pll->refcount, pll->on);
        }
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list,
@@ -9869,6 +9887,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
        struct drm_plane *plane;
        struct intel_crtc *crtc;
        struct intel_encoder *encoder;
+       int i;
 
        intel_modeset_readout_hw_state(dev);
 
@@ -9884,6 +9903,18 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
        }
 
+       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+               struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
+
+               if (!pll->on || pll->active)
+                       continue;
+
+               DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name);
+
+               pll->disable(dev_priv, pll);
+               pll->on = false;
+       }
+
        if (force_restore) {
                /*
                 * We need to use raw interfaces for restoring state to avoid
index c8c9b6f48230489b0cccdf37413e5b4d8fbb28d7..b7d6e09456ce372f8a87e8f3b1ebd75df1779e70 100644 (file)
@@ -504,7 +504,7 @@ struct intel_dp {
 struct intel_digital_port {
        struct intel_encoder base;
        enum port port;
-       u32 port_reversal;
+       u32 saved_port_bits;
        struct intel_dp dp;
        struct intel_hdmi hdmi;
 };
index 98df2a0c85bdf43f9ed545489700470392b11ca1..2fd3fd5b943ee57aff93415c707798d9069cea7e 100644 (file)
@@ -785,10 +785,22 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
        }
 }
 
+static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
+{
+       struct drm_device *dev = intel_hdmi_to_dev(hdmi);
+
+       if (IS_G4X(dev))
+               return 165000;
+       else if (IS_HASWELL(dev))
+               return 300000;
+       else
+               return 225000;
+}
+
 static int intel_hdmi_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
-       if (mode->clock > 165000)
+       if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector)))
                return MODE_CLOCK_HIGH;
        if (mode->clock < 20000)
                return MODE_CLOCK_LOW;
@@ -806,6 +818,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
        struct drm_device *dev = encoder->base.dev;
        struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
        int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2;
+       int portclock_limit = hdmi_portclock_limit(intel_hdmi);
        int desired_bpp;
 
        if (intel_hdmi->color_range_auto) {
@@ -829,7 +842,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         * outputs. We also need to check that the higher clock still fits
         * within limits.
         */
-       if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000
+       if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= portclock_limit
            && HAS_PCH_SPLIT(dev)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
@@ -846,7 +859,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
                pipe_config->pipe_bpp = desired_bpp;
        }
 
-       if (adjusted_mode->clock > 225000) {
+       if (adjusted_mode->clock > portclock_limit) {
                DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n");
                return false;
        }
index 021e8daa022d34485583e53eeea71d7f9ba33fb5..61348eae2f0436a05f7b5d88fec4242db918655d 100644 (file)
@@ -109,6 +109,13 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
                flags |= DRM_MODE_FLAG_PVSYNC;
 
        pipe_config->adjusted_mode.flags |= flags;
+
+       /* gen2/3 store dither state in pfit control, needs to match */
+       if (INTEL_INFO(dev)->gen < 4) {
+               tmp = I915_READ(PFIT_CONTROL);
+
+               pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE;
+       }
 }
 
 /* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -290,14 +297,11 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
 
                intel_pch_panel_fitting(intel_crtc, pipe_config,
                                        intel_connector->panel.fitting_mode);
-               return true;
        } else {
                intel_gmch_panel_fitting(intel_crtc, pipe_config,
                                         intel_connector->panel.fitting_mode);
-       }
 
-       drm_mode_set_crtcinfo(adjusted_mode, 0);
-       pipe_config->timings_set = true;
+       }
 
        /*
         * XXX: It would be nice to support lower refresh rates on the
index 80bea1d3209fad623a9d189f5ac1b3e1c12b6f0f..67e2c1f1c9a8309b809c35f32395e26e67236992 100644 (file)
@@ -194,6 +194,9 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
            adjusted_mode->vdisplay == mode->vdisplay)
                goto out;
 
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+       pipe_config->timings_set = true;
+
        switch (fitting_mode) {
        case DRM_MODE_SCALE_CENTER:
                /*
@@ -580,7 +583,8 @@ void intel_panel_enable_backlight(struct drm_device *dev,
                POSTING_READ(reg);
                I915_WRITE(reg, tmp | BLM_PWM_ENABLE);
 
-               if (HAS_PCH_SPLIT(dev)) {
+               if (HAS_PCH_SPLIT(dev) &&
+                   !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) {
                        tmp = I915_READ(BLC_PWM_PCH_CTL1);
                        tmp |= BLM_PCH_PWM_ENABLE;
                        tmp &= ~BLM_PCH_OVERRIDE_ENABLE;
index d10e6735771fe55bd738bc3ee2d840f384d04471..f895d1508df8fbb9646ed064f1d2ce8244d4f4d0 100644 (file)
@@ -5476,7 +5476,7 @@ static void vlv_force_wake_put(struct drm_i915_private *dev_priv)
        gen6_gt_check_fifodbg(dev_priv);
 }
 
-void intel_gt_reset(struct drm_device *dev)
+void intel_gt_sanitize(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -5487,16 +5487,16 @@ void intel_gt_reset(struct drm_device *dev)
                if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
                        __gen6_gt_force_wake_mt_reset(dev_priv);
        }
+
+       /* BIOS often leaves RC6 enabled, but disable it for hw init */
+       if (INTEL_INFO(dev)->gen >= 6)
+               intel_disable_gt_powersave(dev);
 }
 
 void intel_gt_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       spin_lock_init(&dev_priv->gt_lock);
-
-       intel_gt_reset(dev);
-
        if (IS_VALLEYVIEW(dev)) {
                dev_priv->gt.force_wake_get = vlv_force_wake_get;
                dev_priv->gt.force_wake_put = vlv_force_wake_put;
@@ -5536,6 +5536,12 @@ void intel_gt_init(struct drm_device *dev)
                dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get;
                dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put;
        }
+}
+
+void intel_pm_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
        INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
                          intel_gen6_powersave_work);
 }
index 251784aa22259a44baec12749d21c9b1e2163f35..503a414cbdad2ef83db8f10c9eaadd80522c515d 100644 (file)
@@ -29,6 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
        struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct mga_device *mdev = dev->dev_private;
+       struct drm_framebuffer *fb = crtc->fb;
        int i;
 
        if (!crtc->enabled)
@@ -36,6 +37,28 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
 
        WREG8(DAC_INDEX + MGA1064_INDEX, 0);
 
+       if (fb && fb->bits_per_pixel == 16) {
+               int inc = (fb->depth == 15) ? 8 : 4;
+               u8 r, b;
+               for (i = 0; i < MGAG200_LUT_SIZE; i += inc) {
+                       if (fb->depth == 16) {
+                               if (i > (MGAG200_LUT_SIZE >> 1)) {
+                                       r = b = 0;
+                               } else {
+                                       r = mga_crtc->lut_r[i << 1];
+                                       b = mga_crtc->lut_b[i << 1];
+                               }
+                       } else {
+                               r = mga_crtc->lut_r[i];
+                               b = mga_crtc->lut_b[i];
+                       }
+                       /* VGA registers */
+                       WREG8(DAC_INDEX + MGA1064_COL_PAL, r);
+                       WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
+                       WREG8(DAC_INDEX + MGA1064_COL_PAL, b);
+               }
+               return;
+       }
        for (i = 0; i < MGAG200_LUT_SIZE; i++) {
                /* VGA registers */
                WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]);
@@ -877,7 +900,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 
        pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
        if (crtc->fb->bits_per_pixel == 24)
-               pitch = pitch >> (4 - bppshift);
+               pitch = (pitch * 3) >> (4 - bppshift);
        else
                pitch = pitch >> (4 - bppshift);
 
@@ -1251,6 +1274,24 @@ static void mga_crtc_destroy(struct drm_crtc *crtc)
        kfree(mga_crtc);
 }
 
+static void mga_crtc_disable(struct drm_crtc *crtc)
+{
+       int ret;
+       DRM_DEBUG_KMS("\n");
+       mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       if (crtc->fb) {
+               struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb);
+               struct drm_gem_object *obj = mga_fb->obj;
+               struct mgag200_bo *bo = gem_to_mga_bo(obj);
+               ret = mgag200_bo_reserve(bo, false);
+               if (ret)
+                       return;
+               mgag200_bo_push_sysram(bo);
+               mgag200_bo_unreserve(bo);
+       }
+       crtc->fb = NULL;
+}
+
 /* These provide the minimum set of functions required to handle a CRTC */
 static const struct drm_crtc_funcs mga_crtc_funcs = {
        .cursor_set = mga_crtc_cursor_set,
@@ -1261,6 +1302,7 @@ static const struct drm_crtc_funcs mga_crtc_funcs = {
 };
 
 static const struct drm_crtc_helper_funcs mga_helper_funcs = {
+       .disable = mga_crtc_disable,
        .dpms = mga_crtc_dpms,
        .mode_fixup = mga_crtc_mode_fixup,
        .mode_set = mga_crtc_mode_set,
@@ -1581,6 +1623,8 @@ static struct drm_connector *mga_vga_init(struct drm_device *dev)
 
        drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs);
 
+       drm_sysfs_connector_add(connector);
+
        mga_connector->i2c = mgag200_i2c_create(dev);
        if (!mga_connector->i2c)
                DRM_ERROR("failed to add ddc bus\n");
index 3acb2b044c7b2d626c4efb9741c39a89f92a5ebc..13878d5de063f4b08b97ee2f5735dc2e3e7cb37b 100644 (file)
@@ -353,6 +353,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr)
                bo->pin_count++;
                if (gpu_addr)
                        *gpu_addr = mgag200_bo_gpu_offset(bo);
+               return 0;
        }
 
        mgag200_ttm_placement(bo, pl_flag);
index 262c9f5f5f60b322d1a122fe44d99e86d079c818..ce860de43e614a31c73cc6a265a152cbed191233 100644 (file)
@@ -90,6 +90,7 @@ nvc0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        nv_subdev(priv)->unit = 0x00008000;
+       nv_subdev(priv)->intr = nouveau_falcon_intr;
        nv_engine(priv)->cclass = &nvc0_bsp_cclass;
        nv_engine(priv)->sclass = nvc0_bsp_sclass;
        return 0;
index c46882c8398253ceb1739d82dc31739fef8e09e4..ba6aeca0285ee14afac488166432c5d392ba9a01 100644 (file)
@@ -90,6 +90,7 @@ nve0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        nv_subdev(priv)->unit = 0x00008000;
+       nv_subdev(priv)->intr = nouveau_falcon_intr;
        nv_engine(priv)->cclass = &nve0_bsp_cclass;
        nv_engine(priv)->sclass = nve0_bsp_sclass;
        return 0;
index 373dbcc523b23a1cc5c16e3aa5d1c8ca271e8e98..a19e7d79b847b2447d7254c1c77aeac623fb44cc 100644 (file)
@@ -36,6 +36,8 @@ nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
        if (data && data[0]) {
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]);
+               for (; i < 0x60; i++)
+                       nv_wr32(priv, 0x61c440 + soff, (i << 8));
                nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
        } else
        if (data) {
index dc57e24fc1df955253d1f447d8404c4d43d29fc6..717639386ced2c3e881dbf102ba39e24a5737293 100644 (file)
@@ -41,6 +41,8 @@ nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
        if (data && data[0]) {
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]);
+               for (; i < 0x60; i++)
+                       nv_wr32(priv, 0x10ec00 + soff, (i << 8));
                nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
        } else
        if (data) {
index ab1e918469a822f76bc09f4c09eb215f97a56990..526b75242899fb6e97e0abc3bd48cd228affe151 100644 (file)
@@ -47,14 +47,8 @@ int
 nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
-       struct nouveau_bios *bios = nouveau_bios(priv);
-       const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
        const u8  head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
-       const u8  link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
        const u8    or = (mthd & NV50_DISP_SOR_MTHD_OR);
-       const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
-       struct dcb_output outp;
-       u8  ver, hdr;
        u32 data;
        int ret = -EINVAL;
 
@@ -62,8 +56,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
                return -EINVAL;
        data = *(u32 *)args;
 
-       if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
-               return -ENODEV;
 
        switch (mthd & ~0x3f) {
        case NV50_DISP_SOR_PWR:
index 3c7a31f7590edd973b84376427dfeb8d60387b0a..e03fc8e4dc1dac8c8262a93b2b0b812dcae60841 100644 (file)
 #include <engine/falcon.h>
 #include <subdev/timer.h>
 
+void
+nouveau_falcon_intr(struct nouveau_subdev *subdev)
+{
+       struct nouveau_falcon *falcon = (void *)subdev;
+       u32 dispatch = nv_ro32(falcon, 0x01c);
+       u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
+
+       if (intr & 0x00000010) {
+               nv_debug(falcon, "ucode halted\n");
+               nv_wo32(falcon, 0x004, 0x00000010);
+               intr &= ~0x00000010;
+       }
+
+       if (intr)  {
+               nv_error(falcon, "unhandled intr 0x%08x\n", intr);
+               nv_wo32(falcon, 0x004, intr);
+       }
+}
+
 u32
 _nouveau_falcon_rd32(struct nouveau_object *object, u64 addr)
 {
index 49ecbb859b251974eefd6c5767d1b31ae2b624dc..c19004301309ea0c039fe8336d7fffdb906b24e7 100644 (file)
@@ -265,8 +265,8 @@ nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 int
 nv31_mpeg_init(struct nouveau_object *object)
 {
-       struct nouveau_engine *engine = nv_engine(object->engine);
-       struct nv31_mpeg_priv *priv = (void *)engine;
+       struct nouveau_engine *engine = nv_engine(object);
+       struct nv31_mpeg_priv *priv = (void *)object;
        struct nouveau_fb *pfb = nouveau_fb(object);
        int ret, i;
 
@@ -284,7 +284,10 @@ nv31_mpeg_init(struct nouveau_object *object)
        /* PMPEG init */
        nv_wr32(priv, 0x00b32c, 0x00000000);
        nv_wr32(priv, 0x00b314, 0x00000100);
-       nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031);
+       if (nv_device(priv)->chipset >= 0x40 && nv44_graph_class(priv))
+               nv_wr32(priv, 0x00b220, 0x00000044);
+       else
+               nv_wr32(priv, 0x00b220, 0x00000031);
        nv_wr32(priv, 0x00b300, 0x02001ec1);
        nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
 
index f7c581ad1991b880b3abe6590f0250b68261a9d2..dd6196072e9c7f58062c7e500ea8c57ba19cb580 100644 (file)
@@ -61,6 +61,7 @@ nv40_mpeg_context_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
        return 0;
 }
 
index 98072c1ff3606117e477cb294435e0e75bc11116..73719aaa62d6474ea66fbe85ca252de826f6cff9 100644 (file)
@@ -90,6 +90,7 @@ nvc0_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        nv_subdev(priv)->unit = 0x00000002;
+       nv_subdev(priv)->intr = nouveau_falcon_intr;
        nv_engine(priv)->cclass = &nvc0_ppp_cclass;
        nv_engine(priv)->sclass = nvc0_ppp_sclass;
        return 0;
index 1879229b60eb8ef4e347d16c07f78fed8a8b3f82..ac1f62aace72eb99ff1ca47849aa4828a160a2b5 100644 (file)
@@ -90,6 +90,7 @@ nvc0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        nv_subdev(priv)->unit = 0x00020000;
+       nv_subdev(priv)->intr = nouveau_falcon_intr;
        nv_engine(priv)->cclass = &nvc0_vp_cclass;
        nv_engine(priv)->sclass = nvc0_vp_sclass;
        return 0;
index d28ecbf7bc49ee6c2fd521c6ab652237e04bb6ae..d4c3108479c9344967759c134a9d96802181b8ba 100644 (file)
@@ -90,6 +90,7 @@ nve0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        nv_subdev(priv)->unit = 0x00020000;
+       nv_subdev(priv)->intr = nouveau_falcon_intr;
        nv_engine(priv)->cclass = &nve0_vp_cclass;
        nv_engine(priv)->sclass = nve0_vp_sclass;
        return 0;
index 0639bc59d0a513725195ea64be7af30ed2dadbf0..5f6ede7c48928a799e3a2084371e5bb86a2388d4 100644 (file)
@@ -118,7 +118,13 @@ _nouveau_xtensa_init(struct nouveau_object *object)
                        return ret;
                }
 
-               ret = nouveau_gpuobj_new(object, NULL, fw->size, 0x1000, 0,
+               if (fw->size > 0x40000) {
+                       nv_warn(xtensa, "firmware %s too large\n", name);
+                       release_firmware(fw);
+                       return -EINVAL;
+               }
+
+               ret = nouveau_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
                                         &xtensa->gpu_fw);
                if (ret) {
                        release_firmware(fw);
index 1edec386ab36008e2a50272c2c2200d4ddb3f80b..181aa7da524dd1c05779f21da4aad367ce4c0e94 100644 (file)
@@ -72,6 +72,8 @@ int nouveau_falcon_create_(struct nouveau_object *, struct nouveau_object *,
                           struct nouveau_oclass *, u32, bool, const char *,
                           const char *, int, void **);
 
+void nouveau_falcon_intr(struct nouveau_subdev *subdev);
+
 #define _nouveau_falcon_dtor _nouveau_engine_dtor
 int  _nouveau_falcon_init(struct nouveau_object *);
 int  _nouveau_falcon_fini(struct nouveau_object *, bool);
index f2e87b105666f344c46e0c96c9870a062dd76340..fcf57fa309bfd54bbcbba86bdfc53ef5fcc481f6 100644 (file)
@@ -55,7 +55,7 @@ struct nouveau_vma {
 struct nouveau_vm {
        struct nouveau_vmmgr *vmm;
        struct nouveau_mm mm;
-       int refcount;
+       struct kref refcount;
 
        struct list_head pgd_list;
        atomic_t engref[NVDEV_SUBDEV_NR];
index 6c974dd83e8bcbe43daf5ac6e44f6b9690180e91..db9d6ddde52c31cc7395de7cca70ceaf0671d015 100644 (file)
@@ -81,7 +81,7 @@ void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
 void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
                       u32 pitch, u32 flags, struct nouveau_fb_tile *);
 
-void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
 extern int nv50_fb_memtype[0x80];
 
 #endif
index af5aa7ee8ad954a465f4b6ec3183e7091731afdb..903baff77fddcc20e8e2f18a6df808d66c0d316d 100644 (file)
 #include "priv.h"
 
 void
-nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+__nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem)
 {
        struct nouveau_mm_node *this;
-       struct nouveau_mem *mem;
 
-       mem = *pmem;
-       *pmem = NULL;
-       if (unlikely(mem == NULL))
-               return;
-
-       mutex_lock(&pfb->base.mutex);
        while (!list_empty(&mem->regions)) {
                this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
 
@@ -46,6 +39,19 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
        }
 
        nouveau_mm_free(&pfb->tags, &mem->tag);
+}
+
+void
+nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+       struct nouveau_mem *mem = *pmem;
+
+       *pmem = NULL;
+       if (unlikely(mem == NULL))
+               return;
+
+       mutex_lock(&pfb->base.mutex);
+       __nv50_ram_put(pfb, mem);
        mutex_unlock(&pfb->base.mutex);
 
        kfree(mem);
index 9c3634acbb9d8e3c404a8e251470636552d4fc6d..cf97c4de4a6b2911722da3b1799487f217cfb560 100644 (file)
@@ -33,11 +33,19 @@ void
 nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
 {
        struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+       struct nouveau_mem *mem = *pmem;
 
-       if ((*pmem)->tag)
-               ltcg->tags_free(ltcg, &(*pmem)->tag);
+       *pmem = NULL;
+       if (unlikely(mem == NULL))
+               return;
 
-       nv50_ram_put(pfb, pmem);
+       mutex_lock(&pfb->base.mutex);
+       if (mem->tag)
+               ltcg->tags_free(ltcg, &mem->tag);
+       __nv50_ram_put(pfb, mem);
+       mutex_unlock(&pfb->base.mutex);
+
+       kfree(mem);
 }
 
 int
index bf489dcf46e2796fed5e0e1b1f109ae2dcfe015b..c4c1d415e7feb871329c275e894558f44c60aff8 100644 (file)
@@ -103,7 +103,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
        int i;
 
        intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
 
        hi = (intr0 & 0x0000ffff) | (intr1 << 16);
@@ -115,7 +115,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
        }
 
        nv_wr32(priv, 0xe054, intr0);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                nv_wr32(priv, 0xe074, intr1);
 }
 
@@ -146,7 +146,7 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        int ret;
 
        ret = nouveau_gpio_create(parent, engine, oclass,
-                                 nv_device(parent)->chipset >= 0x90 ? 32 : 16,
+                                 nv_device(parent)->chipset > 0x92 ? 32 : 16,
                                  &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -182,7 +182,7 @@ nv50_gpio_init(struct nouveau_object *object)
        /* disable, and ack any pending gpio interrupts */
        nv_wr32(priv, 0xe050, 0x00000000);
        nv_wr32(priv, 0xe054, 0xffffffff);
-       if (nv_device(priv)->chipset >= 0x90) {
+       if (nv_device(priv)->chipset > 0x92) {
                nv_wr32(priv, 0xe070, 0x00000000);
                nv_wr32(priv, 0xe074, 0xffffffff);
        }
@@ -195,7 +195,7 @@ nv50_gpio_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv50_gpio_priv *priv = (void *)object;
        nv_wr32(priv, 0xe050, 0x00000000);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                nv_wr32(priv, 0xe070, 0x00000000);
        return nouveau_gpio_fini(&priv->base, suspend);
 }
index 0cb322a5e72cdaab4f29dc7f2e6306963c110ba0..f25fc5fc7dd11a773e6743a3df5d3ae5e1235532 100644 (file)
@@ -41,7 +41,7 @@ nv50_mc_intr[] = {
        { 0x04000000, NVDEV_ENGINE_DISP },
        { 0x10000000, NVDEV_SUBDEV_BUS },
        { 0x80000000, NVDEV_ENGINE_SW },
-       { 0x0000d101, NVDEV_SUBDEV_FB },
+       { 0x0002d101, NVDEV_SUBDEV_FB },
        {},
 };
 
index 67fcb6c852ac008539548f8271889998b64043d5..ef3133e7575c8eaf937520cf750bd51effcd7505 100644 (file)
@@ -361,7 +361,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
 
        INIT_LIST_HEAD(&vm->pgd_list);
        vm->vmm = vmm;
-       vm->refcount = 1;
+       kref_init(&vm->refcount);
        vm->fpde = offset >> (vmm->pgt_bits + 12);
        vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
 
@@ -441,8 +441,9 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
 }
 
 static void
-nouveau_vm_del(struct nouveau_vm *vm)
+nouveau_vm_del(struct kref *kref)
 {
+       struct nouveau_vm *vm = container_of(kref, typeof(*vm), refcount);
        struct nouveau_vm_pgd *vpgd, *tmp;
 
        list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
@@ -458,27 +459,19 @@ int
 nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
               struct nouveau_gpuobj *pgd)
 {
-       struct nouveau_vm *vm;
-       int ret;
-
-       vm = ref;
-       if (vm) {
-               ret = nouveau_vm_link(vm, pgd);
+       if (ref) {
+               int ret = nouveau_vm_link(ref, pgd);
                if (ret)
                        return ret;
 
-               vm->refcount++;
+               kref_get(&ref->refcount);
        }
 
-       vm = *ptr;
-       *ptr = ref;
-
-       if (vm) {
-               nouveau_vm_unlink(vm, pgd);
-
-               if (--vm->refcount == 0)
-                       nouveau_vm_del(vm);
+       if (*ptr) {
+               nouveau_vm_unlink(*ptr, pgd);
+               kref_put(&(*ptr)->refcount, nouveau_vm_del);
        }
 
+       *ptr = ref;
        return 0;
 }
index 4b1afb131380312bc971117635c9ac072fbdba1a..af20fba3a1a47ae441f8c587d79670d445ed6374 100644 (file)
@@ -148,6 +148,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
 
        if (unlikely(nvbo->gem))
                DRM_ERROR("bo %p still attached to GEM object\n", bo);
+       WARN_ON(nvbo->pin_refcnt > 0);
        nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
        kfree(nvbo);
 }
@@ -197,6 +198,17 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
        size_t acc_size;
        int ret;
        int type = ttm_bo_type_device;
+       int lpg_shift = 12;
+       int max_size;
+
+       if (drm->client.base.vm)
+               lpg_shift = drm->client.base.vm->vmm->lpg_shift;
+       max_size = INT_MAX & ~((1 << lpg_shift) - 1);
+
+       if (size <= 0 || size > max_size) {
+               nv_warn(drm, "skipped size %x\n", (u32)size);
+               return -EINVAL;
+       }
 
        if (sg)
                type = ttm_bo_type_sg;
@@ -340,13 +352,15 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
 {
        struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_buffer_object *bo = &nvbo->bo;
-       int ret;
+       int ret, ref;
 
        ret = ttm_bo_reserve(bo, false, false, false, 0);
        if (ret)
                return ret;
 
-       if (--nvbo->pin_refcnt)
+       ref = --nvbo->pin_refcnt;
+       WARN_ON_ONCE(ref < 0);
+       if (ref)
                goto out;
 
        nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
@@ -578,7 +592,7 @@ nve0_bo_move_init(struct nouveau_channel *chan, u32 handle)
        int ret = RING_SPACE(chan, 2);
        if (ret == 0) {
                BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1);
-               OUT_RING  (chan, handle);
+               OUT_RING  (chan, handle & 0x0000ffff);
                FIRE_RING (chan);
        }
        return ret;
@@ -973,7 +987,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
        struct ttm_mem_reg *old_mem = &bo->mem;
        int ret;
 
-       mutex_lock(&chan->cli->mutex);
+       mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING);
 
        /* create temporary vmas for the transfer and attach them to the
         * old nouveau_mem node, these will get cleaned up after ttm has
@@ -1014,7 +1028,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
                            struct ttm_mem_reg *, struct ttm_mem_reg *);
                int (*init)(struct nouveau_channel *, u32 handle);
        } _methods[] = {
-               {  "COPY", 0, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
+               {  "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
                {  "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init },
                { "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init },
                { "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init },
@@ -1034,7 +1048,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
                struct nouveau_channel *chan;
                u32 handle = (mthd->engine << 16) | mthd->oclass;
 
-               if (mthd->init == nve0_bo_move_init)
+               if (mthd->engine)
                        chan = drm->cechan;
                else
                        chan = drm->channel;
index 708b2d1c0037e689b579b860d812463c01a9bf2e..907d20ef6d4d119f81c06fe1801edf3867f01673 100644 (file)
@@ -138,7 +138,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
 {
        struct nouveau_framebuffer *nouveau_fb;
        struct drm_gem_object *gem;
-       int ret;
+       int ret = -ENOMEM;
 
        gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
        if (!gem)
@@ -146,15 +146,19 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
 
        nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
        if (!nouveau_fb)
-               return ERR_PTR(-ENOMEM);
+               goto err_unref;
 
        ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
-       if (ret) {
-               drm_gem_object_unreference(gem);
-               return ERR_PTR(ret);
-       }
+       if (ret)
+               goto err;
 
        return &nouveau_fb->base;
+
+err:
+       kfree(nouveau_fb);
+err_unref:
+       drm_gem_object_unreference(gem);
+       return ERR_PTR(ret);
 }
 
 static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
@@ -524,9 +528,12 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        struct nouveau_page_flip_state *s;
        struct nouveau_channel *chan = NULL;
        struct nouveau_fence *fence;
-       struct list_head res;
-       struct ttm_validate_buffer res_val[2];
+       struct ttm_validate_buffer resv[2] = {
+               { .bo = &old_bo->bo },
+               { .bo = &new_bo->bo },
+       };
        struct ww_acquire_ctx ticket;
+       LIST_HEAD(res);
        int ret;
 
        if (!drm->channel)
@@ -545,27 +552,19 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                chan = drm->channel;
        spin_unlock(&old_bo->bo.bdev->fence_lock);
 
-       mutex_lock(&chan->cli->mutex);
-
        if (new_bo != old_bo) {
                ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
-               if (likely(!ret)) {
-                       res_val[0].bo = &old_bo->bo;
-                       res_val[1].bo = &new_bo->bo;
-                       INIT_LIST_HEAD(&res);
-                       list_add_tail(&res_val[0].head, &res);
-                       list_add_tail(&res_val[1].head, &res);
-                       ret = ttm_eu_reserve_buffers(&ticket, &res);
-                       if (ret)
-                               nouveau_bo_unpin(new_bo);
-               }
-       } else
-               ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
+               if (ret)
+                       goto fail_free;
 
-       if (ret) {
-               mutex_unlock(&chan->cli->mutex);
-               goto fail_free;
+               list_add(&resv[1].head, &res);
        }
+       list_add(&resv[0].head, &res);
+
+       mutex_lock(&chan->cli->mutex);
+       ret = ttm_eu_reserve_buffers(&ticket, &res);
+       if (ret)
+               goto fail_unpin;
 
        /* Initialize a page flip struct */
        *s = (struct nouveau_page_flip_state)
@@ -576,10 +575,8 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        /* Emit a page flip */
        if (nv_device(drm->device)->card_type >= NV_50) {
                ret = nv50_display_flip_next(crtc, fb, chan, 0);
-               if (ret) {
-                       mutex_unlock(&chan->cli->mutex);
+               if (ret)
                        goto fail_unreserve;
-               }
        }
 
        ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
@@ -590,22 +587,18 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        /* Update the crtc struct and cleanup */
        crtc->fb = fb;
 
-       if (old_bo != new_bo) {
-               ttm_eu_fence_buffer_objects(&ticket, &res, fence);
+       ttm_eu_fence_buffer_objects(&ticket, &res, fence);
+       if (old_bo != new_bo)
                nouveau_bo_unpin(old_bo);
-       } else {
-               nouveau_bo_fence(new_bo, fence);
-               ttm_bo_unreserve(&new_bo->bo);
-       }
        nouveau_fence_unref(&fence);
        return 0;
 
 fail_unreserve:
-       if (old_bo != new_bo) {
-               ttm_eu_backoff_reservation(&ticket, &res);
+       ttm_eu_backoff_reservation(&ticket, &res);
+fail_unpin:
+       mutex_unlock(&chan->cli->mutex);
+       if (old_bo != new_bo)
                nouveau_bo_unpin(new_bo);
-       } else
-               ttm_bo_unreserve(&new_bo->bo);
 fail_free:
        kfree(s);
        return ret;
index 218a4b522fe591ecca92eee558afc2e1baf9ff0c..61972668fd0532f9f29e6ea540ab925713d5cf7d 100644 (file)
@@ -192,6 +192,18 @@ nouveau_accel_init(struct nouveau_drm *drm)
 
                arg0 = NVE0_CHANNEL_IND_ENGINE_GR;
                arg1 = 1;
+       } else
+       if (device->chipset >= 0xa3 &&
+           device->chipset != 0xaa &&
+           device->chipset != 0xac) {
+               ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE,
+                                         NVDRM_CHAN + 1, NvDmaFB, NvDmaTT,
+                                         &drm->cechan);
+               if (ret)
+                       NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
+
+               arg0 = NvDmaFB;
+               arg1 = NvDmaTT;
        } else {
                arg0 = NvDmaFB;
                arg1 = NvDmaTT;
@@ -284,8 +296,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
        return 0;
 }
 
-static struct lock_class_key drm_client_lock_class_key;
-
 static int
 nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 {
@@ -297,7 +307,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
        if (ret)
                return ret;
-       lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key);
 
        dev->dev_private = drm;
        drm->dev = dev;
index 9352010030e9fd6f885834aca9e81c769fa61e10..8f6d63d7edd314c4f6a6ff7e492c3b37be88930e 100644 (file)
@@ -385,6 +385,7 @@ out_unlock:
        mutex_unlock(&dev->struct_mutex);
        if (chan)
                nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma);
+       nouveau_bo_unmap(nvbo);
 out_unpin:
        nouveau_bo_unpin(nvbo);
 out_unref:
@@ -397,7 +398,8 @@ void
 nouveau_fbcon_output_poll_changed(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       drm_fb_helper_hotplug_event(&drm->fbcon->helper);
+       if (drm->fbcon)
+               drm_fb_helper_hotplug_event(&drm->fbcon->helper);
 }
 
 static int
index 1680d9187bab6623cc958be6f3fa603b9f9e6941..be3149932c2d4c3035a36cf40e68f04af8ffd808 100644 (file)
@@ -143,7 +143,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
        int ret;
 
        fence->channel  = chan;
-       fence->timeout  = jiffies + (3 * DRM_HZ);
+       fence->timeout  = jiffies + (15 * DRM_HZ);
        fence->sequence = ++fctx->sequence;
 
        ret = fctx->emit(fence);
index e72d09c068a8e8bcb8de4b47abd1ea0340415c12..830cb7bad922bba909a6c5129c16a786cb9ee969 100644 (file)
@@ -50,12 +50,6 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
                return;
        nvbo->gem = NULL;
 
-       /* Lockdep hates you for doing reserve with gem object lock held */
-       if (WARN_ON_ONCE(nvbo->pin_refcnt)) {
-               nvbo->pin_refcnt = 1;
-               nouveau_bo_unpin(nvbo);
-       }
-
        if (gem->import_attach)
                drm_prime_gem_destroy(gem, nvbo->bo.sg);
 
index 8e47a9bae8c301e1ac205a0140ef650ed9d7aa5f..22aa9963ea6fd46b36f28b457fa7cfeecac0372b 100644 (file)
@@ -76,7 +76,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
        struct ttm_mem_reg *mem = &priv->bo->bo.mem;
        struct nouveau_object *object;
        u32 start = mem->start * PAGE_SIZE;
-       u32 limit = mem->start + mem->size - 1;
+       u32 limit = start + mem->size - 1;
        int ret = 0;
 
        fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
index 54dc6355b0c2a02b7629440248a3cfb5e22a234c..8b40a36c1b57eb2f4e1eeac30a20478e7f563974 100644 (file)
@@ -355,6 +355,7 @@ struct nv50_oimm {
 
 struct nv50_head {
        struct nouveau_crtc base;
+       struct nouveau_bo *image;
        struct nv50_curs curs;
        struct nv50_sync sync;
        struct nv50_ovly ovly;
@@ -517,9 +518,10 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 {
        struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+       struct nv50_head *head = nv50_head(crtc);
        struct nv50_sync *sync = nv50_sync(crtc);
-       int head = nv_crtc->index, ret;
        u32 *push;
+       int ret;
 
        swap_interval <<= 4;
        if (swap_interval == 0)
@@ -537,7 +539,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                        return ret;
 
                BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
-               OUT_RING  (chan, NvEvoSema0 + head);
+               OUT_RING  (chan, NvEvoSema0 + nv_crtc->index);
                OUT_RING  (chan, sync->addr ^ 0x10);
                BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
                OUT_RING  (chan, sync->data + 1);
@@ -546,7 +548,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                OUT_RING  (chan, sync->data);
        } else
        if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
-               u64 addr = nv84_fence_crtc(chan, head) + sync->addr;
+               u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
                ret = RING_SPACE(chan, 12);
                if (ret)
                        return ret;
@@ -565,7 +567,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
        } else
        if (chan) {
-               u64 addr = nv84_fence_crtc(chan, head) + sync->addr;
+               u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
                ret = RING_SPACE(chan, 10);
                if (ret)
                        return ret;
@@ -630,6 +632,8 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        evo_mthd(push, 0x0080, 1);
        evo_data(push, 0x00000000);
        evo_kick(push, sync);
+
+       nouveau_bo_ref(nv_fb->nvbo, &head->image);
        return 0;
 }
 
@@ -1038,18 +1042,17 @@ static int
 nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
 {
        struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
+       struct nv50_head *head = nv50_head(crtc);
        int ret;
 
        ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
-       if (ret)
-               return ret;
-
-       if (old_fb) {
-               nvfb = nouveau_framebuffer(old_fb);
-               nouveau_bo_unpin(nvfb->nvbo);
+       if (ret == 0) {
+               if (head->image)
+                       nouveau_bo_unpin(head->image);
+               nouveau_bo_ref(nvfb->nvbo, &head->image);
        }
 
-       return 0;
+       return ret;
 }
 
 static int
@@ -1198,6 +1201,15 @@ nv50_crtc_lut_load(struct drm_crtc *crtc)
        }
 }
 
+static void
+nv50_crtc_disable(struct drm_crtc *crtc)
+{
+       struct nv50_head *head = nv50_head(crtc);
+       if (head->image)
+               nouveau_bo_unpin(head->image);
+       nouveau_bo_ref(NULL, &head->image);
+}
+
 static int
 nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
                     uint32_t handle, uint32_t width, uint32_t height)
@@ -1271,18 +1283,29 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct nv50_disp *disp = nv50_disp(crtc->dev);
        struct nv50_head *head = nv50_head(crtc);
+
        nv50_dmac_destroy(disp->core, &head->ovly.base);
        nv50_pioc_destroy(disp->core, &head->oimm.base);
        nv50_dmac_destroy(disp->core, &head->sync.base);
        nv50_pioc_destroy(disp->core, &head->curs.base);
+
+       /*XXX: this shouldn't be necessary, but the core doesn't call
+        *     disconnect() during the cleanup paths
+        */
+       if (head->image)
+               nouveau_bo_unpin(head->image);
+       nouveau_bo_ref(NULL, &head->image);
+
        nouveau_bo_unmap(nv_crtc->cursor.nvbo);
        if (nv_crtc->cursor.nvbo)
                nouveau_bo_unpin(nv_crtc->cursor.nvbo);
        nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
+
        nouveau_bo_unmap(nv_crtc->lut.nvbo);
        if (nv_crtc->lut.nvbo)
                nouveau_bo_unpin(nv_crtc->lut.nvbo);
        nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
+
        drm_crtc_cleanup(crtc);
        kfree(crtc);
 }
@@ -1296,6 +1319,7 @@ static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
        .mode_set_base = nv50_crtc_mode_set_base,
        .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
        .load_lut = nv50_crtc_lut_load,
+       .disable = nv50_crtc_disable,
 };
 
 static const struct drm_crtc_funcs nv50_crtc_func = {
index f9701e567db89793136c52e02bf11d59baba4ce4..0ee363840035b1e67bd3e6c6b8bb63afbf4d8ea3 100644 (file)
@@ -39,6 +39,8 @@ nv50_fence_context_new(struct nouveau_channel *chan)
        struct nv10_fence_chan *fctx;
        struct ttm_mem_reg *mem = &priv->bo->bo.mem;
        struct nouveau_object *object;
+       u32 start = mem->start * PAGE_SIZE;
+       u32 limit = start + mem->size - 1;
        int ret, i;
 
        fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
@@ -51,26 +53,28 @@ nv50_fence_context_new(struct nouveau_channel *chan)
        fctx->base.sync = nv17_fence_sync;
 
        ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
-                                NvSema, 0x0002,
+                                NvSema, 0x003d,
                                 &(struct nv_dma_class) {
                                        .flags = NV_DMA_TARGET_VRAM |
                                                 NV_DMA_ACCESS_RDWR,
-                                       .start = mem->start * PAGE_SIZE,
-                                       .limit = mem->size - 1,
+                                       .start = start,
+                                       .limit = limit,
                                 }, sizeof(struct nv_dma_class),
                                 &object);
 
        /* dma objects for display sync channel semaphore blocks */
        for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
                struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
+               u32 start = bo->bo.mem.start * PAGE_SIZE;
+               u32 limit = start + bo->bo.mem.size - 1;
 
                ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
                                         NvEvoSema0 + i, 0x003d,
                                         &(struct nv_dma_class) {
                                                .flags = NV_DMA_TARGET_VRAM |
                                                         NV_DMA_ACCESS_RDWR,
-                                               .start = bo->bo.offset,
-                                               .limit = bo->bo.offset + 0xfff,
+                                               .start = start,
+                                               .limit = limit,
                                         }, sizeof(struct nv_dma_class),
                                         &object);
        }
index 93c2f2cceb5165c25e80c6480c60c3e2e9e7fd62..eb89653a7a1710adf2842a2d2fb811cbe6c62737 100644 (file)
@@ -179,9 +179,10 @@ qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *relea
                              uint32_t type, bool interruptible)
 {
        struct qxl_command cmd;
+       struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
 
        cmd.type = type;
-       cmd.data = qxl_bo_physical_address(qdev, release->bos[0], release->release_offset);
+       cmd.data = qxl_bo_physical_address(qdev, to_qxl_bo(entry->tv.bo), release->release_offset);
 
        return qxl_ring_push(qdev->command_ring, &cmd, interruptible);
 }
@@ -191,9 +192,10 @@ qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *releas
                             uint32_t type, bool interruptible)
 {
        struct qxl_command cmd;
+       struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
 
        cmd.type = type;
-       cmd.data = qxl_bo_physical_address(qdev, release->bos[0], release->release_offset);
+       cmd.data = qxl_bo_physical_address(qdev, to_qxl_bo(entry->tv.bo), release->release_offset);
 
        return qxl_ring_push(qdev->cursor_ring, &cmd, interruptible);
 }
@@ -214,7 +216,6 @@ int qxl_garbage_collect(struct qxl_device *qdev)
        struct qxl_release *release;
        uint64_t id, next_id;
        int i = 0;
-       int ret;
        union qxl_release_info *info;
 
        while (qxl_ring_pop(qdev->release_ring, &id)) {
@@ -224,17 +225,10 @@ int qxl_garbage_collect(struct qxl_device *qdev)
                        if (release == NULL)
                                break;
 
-                       ret = qxl_release_reserve(qdev, release, false);
-                       if (ret) {
-                               qxl_io_log(qdev, "failed to reserve release on garbage collect %lld\n", id);
-                               DRM_ERROR("failed to reserve release %lld\n", id);
-                       }
-
                        info = qxl_release_map(qdev, release);
                        next_id = info->next;
                        qxl_release_unmap(qdev, release, info);
 
-                       qxl_release_unreserve(qdev, release);
                        QXL_INFO(qdev, "popped %lld, next %lld\n", id,
                                next_id);
 
@@ -259,27 +253,29 @@ int qxl_garbage_collect(struct qxl_device *qdev)
        return i;
 }
 
-int qxl_alloc_bo_reserved(struct qxl_device *qdev, unsigned long size,
+int qxl_alloc_bo_reserved(struct qxl_device *qdev,
+                         struct qxl_release *release,
+                         unsigned long size,
                          struct qxl_bo **_bo)
 {
        struct qxl_bo *bo;
        int ret;
 
        ret = qxl_bo_create(qdev, size, false /* not kernel - device */,
-                           QXL_GEM_DOMAIN_VRAM, NULL, &bo);
+                           false, QXL_GEM_DOMAIN_VRAM, NULL, &bo);
        if (ret) {
                DRM_ERROR("failed to allocate VRAM BO\n");
                return ret;
        }
-       ret = qxl_bo_reserve(bo, false);
-       if (unlikely(ret != 0))
+       ret = qxl_release_list_add(release, bo);
+       if (ret)
                goto out_unref;
 
        *_bo = bo;
        return 0;
 out_unref:
        qxl_bo_unref(&bo);
-       return 0;
+       return ret;
 }
 
 static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port, bool intr)
@@ -503,6 +499,10 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
        if (ret)
                return ret;
 
+       ret = qxl_release_reserve_list(release, true);
+       if (ret)
+               return ret;
+
        cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release);
        cmd->type = QXL_SURFACE_CMD_CREATE;
        cmd->u.surface_create.format = surf->surf.format;
@@ -524,14 +524,11 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
 
        surf->surf_create = release;
 
-       /* no need to add a release to the fence for this bo,
+       /* no need to add a release to the fence for this surface bo,
           since it is only released when we ask to destroy the surface
           and it would never signal otherwise */
-       qxl_fence_releaseable(qdev, release);
-
        qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
-
-       qxl_release_unreserve(qdev, release);
+       qxl_release_fence_buffer_objects(release);
 
        surf->hw_surf_alloc = true;
        spin_lock(&qdev->surf_id_idr_lock);
@@ -573,12 +570,9 @@ int qxl_hw_surface_dealloc(struct qxl_device *qdev,
        cmd->surface_id = id;
        qxl_release_unmap(qdev, release, &cmd->release_info);
 
-       qxl_fence_releaseable(qdev, release);
-
        qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
 
-       qxl_release_unreserve(qdev, release);
-
+       qxl_release_fence_buffer_objects(release);
 
        return 0;
 }
index f76f5dd7bfc43281b8c5fed9d06ffd6f0876eb92..835caba026d399d4e3750fbc3b47d44c7c6b7df5 100644 (file)
@@ -179,7 +179,7 @@ static void qxl_crtc_destroy(struct drm_crtc *crtc)
        kfree(qxl_crtc);
 }
 
-static void
+static int
 qxl_hide_cursor(struct qxl_device *qdev)
 {
        struct qxl_release *release;
@@ -188,14 +188,22 @@ qxl_hide_cursor(struct qxl_device *qdev)
 
        ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), QXL_RELEASE_CURSOR_CMD,
                                         &release, NULL);
+       if (ret)
+               return ret;
+
+       ret = qxl_release_reserve_list(release, true);
+       if (ret) {
+               qxl_release_free(qdev, release);
+               return ret;
+       }
 
        cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
        cmd->type = QXL_CURSOR_HIDE;
        qxl_release_unmap(qdev, release, &cmd->release_info);
 
-       qxl_fence_releaseable(qdev, release);
        qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
-       qxl_release_unreserve(qdev, release);
+       qxl_release_fence_buffer_objects(release);
+       return 0;
 }
 
 static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
@@ -216,10 +224,8 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
 
        int size = 64*64*4;
        int ret = 0;
-       if (!handle) {
-               qxl_hide_cursor(qdev);
-               return 0;
-       }
+       if (!handle)
+               return qxl_hide_cursor(qdev);
 
        obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
        if (!obj) {
@@ -234,8 +240,9 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
                goto out_unref;
 
        ret = qxl_bo_pin(user_bo, QXL_GEM_DOMAIN_CPU, NULL);
+       qxl_bo_unreserve(user_bo);
        if (ret)
-               goto out_unreserve;
+               goto out_unref;
 
        ret = qxl_bo_kmap(user_bo, &user_ptr);
        if (ret)
@@ -246,14 +253,20 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
                                         &release, NULL);
        if (ret)
                goto out_kunmap;
-       ret = qxl_alloc_bo_reserved(qdev, sizeof(struct qxl_cursor) + size,
-                                   &cursor_bo);
+
+       ret = qxl_alloc_bo_reserved(qdev, release, sizeof(struct qxl_cursor) + size,
+                          &cursor_bo);
        if (ret)
                goto out_free_release;
-       ret = qxl_bo_kmap(cursor_bo, (void **)&cursor);
+
+       ret = qxl_release_reserve_list(release, false);
        if (ret)
                goto out_free_bo;
 
+       ret = qxl_bo_kmap(cursor_bo, (void **)&cursor);
+       if (ret)
+               goto out_backoff;
+
        cursor->header.unique = 0;
        cursor->header.type = SPICE_CURSOR_TYPE_ALPHA;
        cursor->header.width = 64;
@@ -269,11 +282,7 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
 
        qxl_bo_kunmap(cursor_bo);
 
-       /* finish with the userspace bo */
        qxl_bo_kunmap(user_bo);
-       qxl_bo_unpin(user_bo);
-       qxl_bo_unreserve(user_bo);
-       drm_gem_object_unreference_unlocked(obj);
 
        cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
        cmd->type = QXL_CURSOR_SET;
@@ -281,30 +290,35 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
        cmd->u.set.position.y = qcrtc->cur_y;
 
        cmd->u.set.shape = qxl_bo_physical_address(qdev, cursor_bo, 0);
-       qxl_release_add_res(qdev, release, cursor_bo);
 
        cmd->u.set.visible = 1;
        qxl_release_unmap(qdev, release, &cmd->release_info);
 
-       qxl_fence_releaseable(qdev, release);
        qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
-       qxl_release_unreserve(qdev, release);
+       qxl_release_fence_buffer_objects(release);
+
+       /* finish with the userspace bo */
+       ret = qxl_bo_reserve(user_bo, false);
+       if (!ret) {
+               qxl_bo_unpin(user_bo);
+               qxl_bo_unreserve(user_bo);
+       }
+       drm_gem_object_unreference_unlocked(obj);
 
-       qxl_bo_unreserve(cursor_bo);
        qxl_bo_unref(&cursor_bo);
 
        return ret;
+
+out_backoff:
+       qxl_release_backoff_reserve_list(release);
 out_free_bo:
        qxl_bo_unref(&cursor_bo);
 out_free_release:
-       qxl_release_unreserve(qdev, release);
        qxl_release_free(qdev, release);
 out_kunmap:
        qxl_bo_kunmap(user_bo);
 out_unpin:
        qxl_bo_unpin(user_bo);
-out_unreserve:
-       qxl_bo_unreserve(user_bo);
 out_unref:
        drm_gem_object_unreference_unlocked(obj);
        return ret;
@@ -322,6 +336,14 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc,
 
        ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), QXL_RELEASE_CURSOR_CMD,
                                   &release, NULL);
+       if (ret)
+               return ret;
+
+       ret = qxl_release_reserve_list(release, true);
+       if (ret) {
+               qxl_release_free(qdev, release);
+               return ret;
+       }
 
        qcrtc->cur_x = x;
        qcrtc->cur_y = y;
@@ -332,9 +354,9 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc,
        cmd->u.position.y = qcrtc->cur_y;
        qxl_release_unmap(qdev, release, &cmd->release_info);
 
-       qxl_fence_releaseable(qdev, release);
        qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
-       qxl_release_unreserve(qdev, release);
+       qxl_release_fence_buffer_objects(release);
+
        return 0;
 }
 
index 3c8c3dbf93782522eac671a3d6c8cf5f1af3e4bc..56e1d633875e2772b6a3f767e3af44e013f3519d 100644 (file)
 #include "qxl_drv.h"
 #include "qxl_object.h"
 
+static int alloc_clips(struct qxl_device *qdev,
+                      struct qxl_release *release,
+                      unsigned num_clips,
+                      struct qxl_bo **clips_bo)
+{
+       int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips;
+
+       return qxl_alloc_bo_reserved(qdev, release, size, clips_bo);
+}
+
 /* returns a pointer to the already allocated qxl_rect array inside
  * the qxl_clip_rects. This is *not* the same as the memory allocated
  * on the device, it is offset to qxl_clip_rects.chunk.data */
 static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
                                              struct qxl_drawable *drawable,
                                              unsigned num_clips,
-                                             struct qxl_bo **clips_bo,
-                                             struct qxl_release *release)
+                                             struct qxl_bo *clips_bo)
 {
        struct qxl_clip_rects *dev_clips;
        int ret;
-       int size = sizeof(*dev_clips) + sizeof(struct qxl_rect) * num_clips;
-       ret = qxl_alloc_bo_reserved(qdev, size, clips_bo);
-       if (ret)
-               return NULL;
 
-       ret = qxl_bo_kmap(*clips_bo, (void **)&dev_clips);
+       ret = qxl_bo_kmap(clips_bo, (void **)&dev_clips);
        if (ret) {
-               qxl_bo_unref(clips_bo);
                return NULL;
        }
        dev_clips->num_rects = num_clips;
@@ -51,21 +55,35 @@ static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
        return (struct qxl_rect *)dev_clips->chunk.data;
 }
 
+static int
+alloc_drawable(struct qxl_device *qdev, struct qxl_release **release)
+{
+       int ret;
+       ret = qxl_alloc_release_reserved(qdev, sizeof(struct qxl_drawable),
+                                        QXL_RELEASE_DRAWABLE, release,
+                                        NULL);
+       return ret;
+}
+
+static void
+free_drawable(struct qxl_device *qdev, struct qxl_release *release)
+{
+       qxl_release_free(qdev, release);
+}
+
+/* release needs to be reserved at this point */
 static int
 make_drawable(struct qxl_device *qdev, int surface, uint8_t type,
              const struct qxl_rect *rect,
-             struct qxl_release **release)
+             struct qxl_release *release)
 {
        struct qxl_drawable *drawable;
-       int i, ret;
+       int i;
 
-       ret = qxl_alloc_release_reserved(qdev, sizeof(*drawable),
-                                        QXL_RELEASE_DRAWABLE, release,
-                                        NULL);
-       if (ret)
-               return ret;
+       drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
+       if (!drawable)
+               return -ENOMEM;
 
-       drawable = (struct qxl_drawable *)qxl_release_map(qdev, *release);
        drawable->type = type;
 
        drawable->surface_id = surface;         /* Only primary for now */
@@ -91,14 +109,23 @@ make_drawable(struct qxl_device *qdev, int surface, uint8_t type,
                drawable->bbox = *rect;
 
        drawable->mm_time = qdev->rom->mm_clock;
-       qxl_release_unmap(qdev, *release, &drawable->release_info);
+       qxl_release_unmap(qdev, release, &drawable->release_info);
        return 0;
 }
 
-static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
+static int alloc_palette_object(struct qxl_device *qdev,
+                               struct qxl_release *release,
+                               struct qxl_bo **palette_bo)
+{
+       return qxl_alloc_bo_reserved(qdev, release,
+                                    sizeof(struct qxl_palette) + sizeof(uint32_t) * 2,
+                                    palette_bo);
+}
+
+static int qxl_palette_create_1bit(struct qxl_bo *palette_bo,
+                                  struct qxl_release *release,
                                   const struct qxl_fb_image *qxl_fb_image)
 {
-       struct qxl_device *qdev = qxl_fb_image->qdev;
        const struct fb_image *fb_image = &qxl_fb_image->fb_image;
        uint32_t visual = qxl_fb_image->visual;
        const uint32_t *pseudo_palette = qxl_fb_image->pseudo_palette;
@@ -108,12 +135,7 @@ static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
        static uint64_t unique; /* we make no attempt to actually set this
                                 * correctly globaly, since that would require
                                 * tracking all of our palettes. */
-
-       ret = qxl_alloc_bo_reserved(qdev,
-                                   sizeof(struct qxl_palette) + sizeof(uint32_t) * 2,
-                                   palette_bo);
-
-       ret = qxl_bo_kmap(*palette_bo, (void **)&pal);
+       ret = qxl_bo_kmap(palette_bo, (void **)&pal);
        pal->num_ents = 2;
        pal->unique = unique++;
        if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) {
@@ -126,7 +148,7 @@ static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
        }
        pal->ents[0] = bgcolor;
        pal->ents[1] = fgcolor;
-       qxl_bo_kunmap(*palette_bo);
+       qxl_bo_kunmap(palette_bo);
        return 0;
 }
 
@@ -144,44 +166,63 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
        const char *src = fb_image->data;
        int depth = fb_image->depth;
        struct qxl_release *release;
-       struct qxl_bo *image_bo;
        struct qxl_image *image;
        int ret;
-
+       struct qxl_drm_image *dimage;
+       struct qxl_bo *palette_bo = NULL;
        if (stride == 0)
                stride = depth * width / 8;
 
+       ret = alloc_drawable(qdev, &release);
+       if (ret)
+               return;
+
+       ret = qxl_image_alloc_objects(qdev, release,
+                                     &dimage,
+                                     height, stride);
+       if (ret)
+               goto out_free_drawable;
+
+       if (depth == 1) {
+               ret = alloc_palette_object(qdev, release, &palette_bo);
+               if (ret)
+                       goto out_free_image;
+       }
+
+       /* do a reservation run over all the objects we just allocated */
+       ret = qxl_release_reserve_list(release, true);
+       if (ret)
+               goto out_free_palette;
+
        rect.left = x;
        rect.right = x + width;
        rect.top = y;
        rect.bottom = y + height;
 
-       ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, &release);
-       if (ret)
-               return;
+       ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, release);
+       if (ret) {
+               qxl_release_backoff_reserve_list(release);
+               goto out_free_palette;
+       }
 
-       ret = qxl_image_create(qdev, release, &image_bo,
-                              (const uint8_t *)src, 0, 0,
-                              width, height, depth, stride);
+       ret = qxl_image_init(qdev, release, dimage,
+                            (const uint8_t *)src, 0, 0,
+                            width, height, depth, stride);
        if (ret) {
-               qxl_release_unreserve(qdev, release);
+               qxl_release_backoff_reserve_list(release);
                qxl_release_free(qdev, release);
                return;
        }
 
        if (depth == 1) {
-               struct qxl_bo *palette_bo;
                void *ptr;
-               ret = qxl_palette_create_1bit(&palette_bo, qxl_fb_image);
-               qxl_release_add_res(qdev, release, palette_bo);
+               ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image);
 
-               ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0);
+               ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0);
                image = ptr;
                image->u.bitmap.palette =
                        qxl_bo_physical_address(qdev, palette_bo, 0);
-               qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
-               qxl_bo_unreserve(palette_bo);
-               qxl_bo_unref(&palette_bo);
+               qxl_bo_kunmap_atomic_page(qdev, dimage->bo, ptr);
        }
 
        drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
@@ -199,16 +240,20 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
        drawable->u.copy.mask.bitmap = 0;
 
        drawable->u.copy.src_bitmap =
-               qxl_bo_physical_address(qdev, image_bo, 0);
+               qxl_bo_physical_address(qdev, dimage->bo, 0);
        qxl_release_unmap(qdev, release, &drawable->release_info);
 
-       qxl_release_add_res(qdev, release, image_bo);
-       qxl_bo_unreserve(image_bo);
-       qxl_bo_unref(&image_bo);
-
-       qxl_fence_releaseable(qdev, release);
        qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
-       qxl_release_unreserve(qdev, release);
+       qxl_release_fence_buffer_objects(release);
+
+out_free_palette:
+       if (palette_bo)
+               qxl_bo_unref(&palette_bo);
+out_free_image:
+       qxl_image_free_objects(qdev, dimage);
+out_free_drawable:
+       if (ret)
+               free_drawable(qdev, release);
 }
 
 /* push a draw command using the given clipping rectangles as
@@ -243,10 +288,14 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
        int depth = qxl_fb->base.bits_per_pixel;
        uint8_t *surface_base;
        struct qxl_release *release;
-       struct qxl_bo *image_bo;
        struct qxl_bo *clips_bo;
+       struct qxl_drm_image *dimage;
        int ret;
 
+       ret = alloc_drawable(qdev, &release);
+       if (ret)
+               return;
+
        left = clips->x1;
        right = clips->x2;
        top = clips->y1;
@@ -263,36 +312,52 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
 
        width = right - left;
        height = bottom - top;
+
+       ret = alloc_clips(qdev, release, num_clips, &clips_bo);
+       if (ret)
+               goto out_free_drawable;
+
+       ret = qxl_image_alloc_objects(qdev, release,
+                                     &dimage,
+                                     height, stride);
+       if (ret)
+               goto out_free_clips;
+
+       /* do a reservation run over all the objects we just allocated */
+       ret = qxl_release_reserve_list(release, true);
+       if (ret)
+               goto out_free_image;
+
        drawable_rect.left = left;
        drawable_rect.right = right;
        drawable_rect.top = top;
        drawable_rect.bottom = bottom;
+
        ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &drawable_rect,
-                           &release);
+                           release);
        if (ret)
-               return;
+               goto out_release_backoff;
 
        ret = qxl_bo_kmap(bo, (void **)&surface_base);
        if (ret)
-               goto out_unref;
+               goto out_release_backoff;
 
-       ret = qxl_image_create(qdev, release, &image_bo, surface_base,
-                              left, top, width, height, depth, stride);
+
+       ret = qxl_image_init(qdev, release, dimage, surface_base,
+                            left, top, width, height, depth, stride);
        qxl_bo_kunmap(bo);
        if (ret)
-               goto out_unref;
+               goto out_release_backoff;
+
+       rects = drawable_set_clipping(qdev, drawable, num_clips, clips_bo);
+       if (!rects)
+               goto out_release_backoff;
 
-       rects = drawable_set_clipping(qdev, drawable, num_clips, &clips_bo, release);
-       if (!rects) {
-               qxl_bo_unref(&image_bo);
-               goto out_unref;
-       }
        drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
 
        drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
        drawable->clip.data = qxl_bo_physical_address(qdev,
                                                      clips_bo, 0);
-       qxl_release_add_res(qdev, release, clips_bo);
 
        drawable->u.copy.src_area.top = 0;
        drawable->u.copy.src_area.bottom = height;
@@ -306,11 +371,9 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
        drawable->u.copy.mask.pos.y = 0;
        drawable->u.copy.mask.bitmap = 0;
 
-       drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, image_bo, 0);
+       drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, dimage->bo, 0);
        qxl_release_unmap(qdev, release, &drawable->release_info);
-       qxl_release_add_res(qdev, release, image_bo);
-       qxl_bo_unreserve(image_bo);
-       qxl_bo_unref(&image_bo);
+
        clips_ptr = clips;
        for (i = 0; i < num_clips; i++, clips_ptr += inc) {
                rects[i].left   = clips_ptr->x1;
@@ -319,17 +382,22 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
                rects[i].bottom = clips_ptr->y2;
        }
        qxl_bo_kunmap(clips_bo);
-       qxl_bo_unreserve(clips_bo);
-       qxl_bo_unref(&clips_bo);
 
-       qxl_fence_releaseable(qdev, release);
        qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
-       qxl_release_unreserve(qdev, release);
-       return;
+       qxl_release_fence_buffer_objects(release);
+
+out_release_backoff:
+       if (ret)
+               qxl_release_backoff_reserve_list(release);
+out_free_image:
+       qxl_image_free_objects(qdev, dimage);
+out_free_clips:
+       qxl_bo_unref(&clips_bo);
+out_free_drawable:
+       /* only free drawable on error */
+       if (ret)
+               free_drawable(qdev, release);
 
-out_unref:
-       qxl_release_unreserve(qdev, release);
-       qxl_release_free(qdev, release);
 }
 
 void qxl_draw_copyarea(struct qxl_device *qdev,
@@ -342,22 +410,36 @@ void qxl_draw_copyarea(struct qxl_device *qdev,
        struct qxl_release *release;
        int ret;
 
+       ret = alloc_drawable(qdev, &release);
+       if (ret)
+               return;
+
+       /* do a reservation run over all the objects we just allocated */
+       ret = qxl_release_reserve_list(release, true);
+       if (ret)
+               goto out_free_release;
+
        rect.left = dx;
        rect.top = dy;
        rect.right = dx + width;
        rect.bottom = dy + height;
-       ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, &release);
-       if (ret)
-               return;
+       ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, release);
+       if (ret) {
+               qxl_release_backoff_reserve_list(release);
+               goto out_free_release;
+       }
 
        drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
        drawable->u.copy_bits.src_pos.x = sx;
        drawable->u.copy_bits.src_pos.y = sy;
-
        qxl_release_unmap(qdev, release, &drawable->release_info);
-       qxl_fence_releaseable(qdev, release);
+
        qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
-       qxl_release_unreserve(qdev, release);
+       qxl_release_fence_buffer_objects(release);
+
+out_free_release:
+       if (ret)
+               free_drawable(qdev, release);
 }
 
 void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
@@ -370,10 +452,21 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
        struct qxl_release *release;
        int ret;
 
-       ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, &release);
+       ret = alloc_drawable(qdev, &release);
        if (ret)
                return;
 
+       /* do a reservation run over all the objects we just allocated */
+       ret = qxl_release_reserve_list(release, true);
+       if (ret)
+               goto out_free_release;
+
+       ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, release);
+       if (ret) {
+               qxl_release_backoff_reserve_list(release);
+               goto out_free_release;
+       }
+
        drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
        drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID;
        drawable->u.fill.brush.u.color = color;
@@ -384,7 +477,11 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
        drawable->u.fill.mask.bitmap = 0;
 
        qxl_release_unmap(qdev, release, &drawable->release_info);
-       qxl_fence_releaseable(qdev, release);
+
        qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
-       qxl_release_unreserve(qdev, release);
+       qxl_release_fence_buffer_objects(release);
+
+out_free_release:
+       if (ret)
+               free_drawable(qdev, release);
 }
index aacb791464a34b770be0cd776fd7162d0fd0f344..7e96f4f117384faea9bad6b29826888f91973cf3 100644 (file)
@@ -42,6 +42,9 @@
 #include <ttm/ttm_placement.h>
 #include <ttm/ttm_module.h>
 
+/* just for ttm_validate_buffer */
+#include <ttm/ttm_execbuf_util.h>
+
 #include <drm/qxl_drm.h>
 #include "qxl_dev.h"
 
@@ -118,9 +121,9 @@ struct qxl_bo {
        uint32_t surface_id;
        struct qxl_fence fence; /* per bo fence  - list of releases */
        struct qxl_release *surf_create;
-       atomic_t reserve_count;
 };
 #define gem_to_qxl_bo(gobj) container_of((gobj), struct qxl_bo, gem_base)
+#define to_qxl_bo(tobj) container_of((tobj), struct qxl_bo, tbo)
 
 struct qxl_gem {
        struct mutex            mutex;
@@ -128,12 +131,7 @@ struct qxl_gem {
 };
 
 struct qxl_bo_list {
-       struct list_head lhead;
-       struct qxl_bo *bo;
-};
-
-struct qxl_reloc_list {
-       struct list_head bos;
+       struct ttm_validate_buffer tv;
 };
 
 struct qxl_crtc {
@@ -195,10 +193,20 @@ enum {
 struct qxl_release {
        int id;
        int type;
-       int bo_count;
        uint32_t release_offset;
        uint32_t surface_release_id;
-       struct qxl_bo *bos[QXL_MAX_RES];
+       struct ww_acquire_ctx ticket;
+       struct list_head bos;
+};
+
+struct qxl_drm_chunk {
+       struct list_head head;
+       struct qxl_bo *bo;
+};
+
+struct qxl_drm_image {
+       struct qxl_bo *bo;
+       struct list_head chunk_list;
 };
 
 struct qxl_fb_image {
@@ -314,6 +322,7 @@ struct qxl_device {
        struct workqueue_struct *gc_queue;
        struct work_struct gc_work;
 
+       struct work_struct fb_work;
 };
 
 /* forward declaration for QXL_INFO_IO */
@@ -433,12 +442,19 @@ int qxl_mmap(struct file *filp, struct vm_area_struct *vma);
 
 /* qxl image */
 
-int qxl_image_create(struct qxl_device *qdev,
-                    struct qxl_release *release,
-                    struct qxl_bo **image_bo,
-                    const uint8_t *data,
-                    int x, int y, int width, int height,
-                    int depth, int stride);
+int qxl_image_init(struct qxl_device *qdev,
+                  struct qxl_release *release,
+                  struct qxl_drm_image *dimage,
+                  const uint8_t *data,
+                  int x, int y, int width, int height,
+                  int depth, int stride);
+int
+qxl_image_alloc_objects(struct qxl_device *qdev,
+                       struct qxl_release *release,
+                       struct qxl_drm_image **image_ptr,
+                       int height, int stride);
+void qxl_image_free_objects(struct qxl_device *qdev, struct qxl_drm_image *dimage);
+
 void qxl_update_screen(struct qxl_device *qxl);
 
 /* qxl io operations (qxl_cmd.c) */
@@ -459,20 +475,15 @@ int qxl_ring_push(struct qxl_ring *ring, const void *new_elt, bool interruptible
 void qxl_io_flush_release(struct qxl_device *qdev);
 void qxl_io_flush_surfaces(struct qxl_device *qdev);
 
-int qxl_release_reserve(struct qxl_device *qdev,
-                       struct qxl_release *release, bool no_wait);
-void qxl_release_unreserve(struct qxl_device *qdev,
-                          struct qxl_release *release);
 union qxl_release_info *qxl_release_map(struct qxl_device *qdev,
                                        struct qxl_release *release);
 void qxl_release_unmap(struct qxl_device *qdev,
                       struct qxl_release *release,
                       union qxl_release_info *info);
-/*
- * qxl_bo_add_resource.
- *
- */
-void qxl_bo_add_resource(struct qxl_bo *main_bo, struct qxl_bo *resource);
+int qxl_release_list_add(struct qxl_release *release, struct qxl_bo *bo);
+int qxl_release_reserve_list(struct qxl_release *release, bool no_intr);
+void qxl_release_backoff_reserve_list(struct qxl_release *release);
+void qxl_release_fence_buffer_objects(struct qxl_release *release);
 
 int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
                                       enum qxl_surface_cmd_type surface_cmd_type,
@@ -481,15 +492,16 @@ int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
 int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
                               int type, struct qxl_release **release,
                               struct qxl_bo **rbo);
-int qxl_fence_releaseable(struct qxl_device *qdev,
-                         struct qxl_release *release);
+
 int
 qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *release,
                              uint32_t type, bool interruptible);
 int
 qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *release,
                             uint32_t type, bool interruptible);
-int qxl_alloc_bo_reserved(struct qxl_device *qdev, unsigned long size,
+int qxl_alloc_bo_reserved(struct qxl_device *qdev,
+                         struct qxl_release *release,
+                         unsigned long size,
                          struct qxl_bo **_bo);
 /* qxl drawing commands */
 
@@ -510,15 +522,9 @@ void qxl_draw_copyarea(struct qxl_device *qdev,
                       u32 sx, u32 sy,
                       u32 dx, u32 dy);
 
-uint64_t
-qxl_release_alloc(struct qxl_device *qdev, int type,
-                 struct qxl_release **ret);
-
 void qxl_release_free(struct qxl_device *qdev,
                      struct qxl_release *release);
-void qxl_release_add_res(struct qxl_device *qdev,
-                        struct qxl_release *release,
-                        struct qxl_bo *bo);
+
 /* used by qxl_debugfs_release */
 struct qxl_release *qxl_release_from_id_locked(struct qxl_device *qdev,
                                                   uint64_t id);
@@ -561,7 +567,7 @@ void qxl_surface_evict(struct qxl_device *qdev, struct qxl_bo *surf, bool freein
 int qxl_update_surface(struct qxl_device *qdev, struct qxl_bo *surf);
 
 /* qxl_fence.c */
-int qxl_fence_add_release(struct qxl_fence *qfence, uint32_t rel_id);
+void qxl_fence_add_release_locked(struct qxl_fence *qfence, uint32_t rel_id);
 int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id);
 int qxl_fence_init(struct qxl_device *qdev, struct qxl_fence *qfence);
 void qxl_fence_fini(struct qxl_fence *qfence);
index 76f39d88d684fbd979bc50ebf2047eceaa9ad632..88722f233430a3d0f7eb4e8b35ad929b709c5b35 100644 (file)
 
 #define QXL_DIRTY_DELAY (HZ / 30)
 
+#define QXL_FB_OP_FILLRECT 1
+#define QXL_FB_OP_COPYAREA 2
+#define QXL_FB_OP_IMAGEBLIT 3
+
+struct qxl_fb_op {
+       struct list_head head;
+       int op_type;
+       union {
+               struct fb_fillrect fr;
+               struct fb_copyarea ca;
+               struct fb_image ib;
+       } op;
+       void *img_data;
+};
+
 struct qxl_fbdev {
        struct drm_fb_helper helper;
        struct qxl_framebuffer  qfb;
        struct list_head        fbdev_list;
        struct qxl_device       *qdev;
 
+       spinlock_t delayed_ops_lock;
+       struct list_head delayed_ops;
        void *shadow;
        int size;
 
@@ -164,8 +181,69 @@ static struct fb_deferred_io qxl_defio = {
        .deferred_io    = qxl_deferred_io,
 };
 
-static void qxl_fb_fillrect(struct fb_info *info,
-                           const struct fb_fillrect *fb_rect)
+static void qxl_fb_delayed_fillrect(struct qxl_fbdev *qfbdev,
+                                   const struct fb_fillrect *fb_rect)
+{
+       struct qxl_fb_op *op;
+       unsigned long flags;
+
+       op = kmalloc(sizeof(struct qxl_fb_op), GFP_ATOMIC | __GFP_NOWARN);
+       if (!op)
+               return;
+
+       op->op.fr = *fb_rect;
+       op->img_data = NULL;
+       op->op_type = QXL_FB_OP_FILLRECT;
+
+       spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+       list_add_tail(&op->head, &qfbdev->delayed_ops);
+       spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
+}
+
+static void qxl_fb_delayed_copyarea(struct qxl_fbdev *qfbdev,
+                                   const struct fb_copyarea *fb_copy)
+{
+       struct qxl_fb_op *op;
+       unsigned long flags;
+
+       op = kmalloc(sizeof(struct qxl_fb_op), GFP_ATOMIC | __GFP_NOWARN);
+       if (!op)
+               return;
+
+       op->op.ca = *fb_copy;
+       op->img_data = NULL;
+       op->op_type = QXL_FB_OP_COPYAREA;
+
+       spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+       list_add_tail(&op->head, &qfbdev->delayed_ops);
+       spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
+}
+
+static void qxl_fb_delayed_imageblit(struct qxl_fbdev *qfbdev,
+                                    const struct fb_image *fb_image)
+{
+       struct qxl_fb_op *op;
+       unsigned long flags;
+       uint32_t size = fb_image->width * fb_image->height * (fb_image->depth >= 8 ? fb_image->depth / 8 : 1);
+
+       op = kmalloc(sizeof(struct qxl_fb_op) + size, GFP_ATOMIC | __GFP_NOWARN);
+       if (!op)
+               return;
+
+       op->op.ib = *fb_image;
+       op->img_data = (void *)(op + 1);
+       op->op_type = QXL_FB_OP_IMAGEBLIT;
+
+       memcpy(op->img_data, fb_image->data, size);
+
+       op->op.ib.data = op->img_data;
+       spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+       list_add_tail(&op->head, &qfbdev->delayed_ops);
+       spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
+}
+
+static void qxl_fb_fillrect_internal(struct fb_info *info,
+                                    const struct fb_fillrect *fb_rect)
 {
        struct qxl_fbdev *qfbdev = info->par;
        struct qxl_device *qdev = qfbdev->qdev;
@@ -203,17 +281,28 @@ static void qxl_fb_fillrect(struct fb_info *info,
        qxl_draw_fill_rec.rect = rect;
        qxl_draw_fill_rec.color = color;
        qxl_draw_fill_rec.rop = rop;
+
+       qxl_draw_fill(&qxl_draw_fill_rec);
+}
+
+static void qxl_fb_fillrect(struct fb_info *info,
+                           const struct fb_fillrect *fb_rect)
+{
+       struct qxl_fbdev *qfbdev = info->par;
+       struct qxl_device *qdev = qfbdev->qdev;
+
        if (!drm_can_sleep()) {
-               qxl_io_log(qdev,
-                       "%s: TODO use RCU, mysterious locks with spin_lock\n",
-                       __func__);
+               qxl_fb_delayed_fillrect(qfbdev, fb_rect);
+               schedule_work(&qdev->fb_work);
                return;
        }
-       qxl_draw_fill(&qxl_draw_fill_rec);
+       /* make sure any previous work is done */
+       flush_work(&qdev->fb_work);
+       qxl_fb_fillrect_internal(info, fb_rect);
 }
 
-static void qxl_fb_copyarea(struct fb_info *info,
-                           const struct fb_copyarea *region)
+static void qxl_fb_copyarea_internal(struct fb_info *info,
+                                    const struct fb_copyarea *region)
 {
        struct qxl_fbdev *qfbdev = info->par;
 
@@ -223,37 +312,89 @@ static void qxl_fb_copyarea(struct fb_info *info,
                          region->dx, region->dy);
 }
 
+static void qxl_fb_copyarea(struct fb_info *info,
+                           const struct fb_copyarea *region)
+{
+       struct qxl_fbdev *qfbdev = info->par;
+       struct qxl_device *qdev = qfbdev->qdev;
+
+       if (!drm_can_sleep()) {
+               qxl_fb_delayed_copyarea(qfbdev, region);
+               schedule_work(&qdev->fb_work);
+               return;
+       }
+       /* make sure any previous work is done */
+       flush_work(&qdev->fb_work);
+       qxl_fb_copyarea_internal(info, region);
+}
+
 static void qxl_fb_imageblit_safe(struct qxl_fb_image *qxl_fb_image)
 {
        qxl_draw_opaque_fb(qxl_fb_image, 0);
 }
 
+static void qxl_fb_imageblit_internal(struct fb_info *info,
+                                     const struct fb_image *image)
+{
+       struct qxl_fbdev *qfbdev = info->par;
+       struct qxl_fb_image qxl_fb_image;
+
+       /* ensure proper order  rendering operations - TODO: must do this
+        * for everything. */
+       qxl_fb_image_init(&qxl_fb_image, qfbdev->qdev, info, image);
+       qxl_fb_imageblit_safe(&qxl_fb_image);
+}
+
 static void qxl_fb_imageblit(struct fb_info *info,
                             const struct fb_image *image)
 {
        struct qxl_fbdev *qfbdev = info->par;
        struct qxl_device *qdev = qfbdev->qdev;
-       struct qxl_fb_image qxl_fb_image;
 
        if (!drm_can_sleep()) {
-               /* we cannot do any ttm_bo allocation since that will fail on
-                * ioremap_wc..__get_vm_area_node, so queue the work item
-                * instead This can happen from printk inside an interrupt
-                * context, i.e.: smp_apic_timer_interrupt..check_cpu_stall */
-               qxl_io_log(qdev,
-                       "%s: TODO use RCU, mysterious locks with spin_lock\n",
-                          __func__);
+               qxl_fb_delayed_imageblit(qfbdev, image);
+               schedule_work(&qdev->fb_work);
                return;
        }
+       /* make sure any previous work is done */
+       flush_work(&qdev->fb_work);
+       qxl_fb_imageblit_internal(info, image);
+}
 
-       /* ensure proper order of rendering operations - TODO: must do this
-        * for everything. */
-       qxl_fb_image_init(&qxl_fb_image, qfbdev->qdev, info, image);
-       qxl_fb_imageblit_safe(&qxl_fb_image);
+static void qxl_fb_work(struct work_struct *work)
+{
+       struct qxl_device *qdev = container_of(work, struct qxl_device, fb_work);
+       unsigned long flags;
+       struct qxl_fb_op *entry, *tmp;
+       struct qxl_fbdev *qfbdev = qdev->mode_info.qfbdev;
+
+       /* since the irq context just adds entries to the end of the
+          list dropping the lock should be fine, as entry isn't modified
+          in the operation code */
+       spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+       list_for_each_entry_safe(entry, tmp, &qfbdev->delayed_ops, head) {
+               spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
+               switch (entry->op_type) {
+               case QXL_FB_OP_FILLRECT:
+                       qxl_fb_fillrect_internal(qfbdev->helper.fbdev, &entry->op.fr);
+                       break;
+               case QXL_FB_OP_COPYAREA:
+                       qxl_fb_copyarea_internal(qfbdev->helper.fbdev, &entry->op.ca);
+                       break;
+               case QXL_FB_OP_IMAGEBLIT:
+                       qxl_fb_imageblit_internal(qfbdev->helper.fbdev, &entry->op.ib);
+                       break;
+               }
+               spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+               list_del(&entry->head);
+               kfree(entry);
+       }
+       spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
 }
 
 int qxl_fb_init(struct qxl_device *qdev)
 {
+       INIT_WORK(&qdev->fb_work, qxl_fb_work);
        return 0;
 }
 
@@ -536,7 +677,8 @@ int qxl_fbdev_init(struct qxl_device *qdev)
        qfbdev->qdev = qdev;
        qdev->mode_info.qfbdev = qfbdev;
        qfbdev->helper.funcs = &qxl_fb_helper_funcs;
-
+       spin_lock_init(&qfbdev->delayed_ops_lock);
+       INIT_LIST_HEAD(&qfbdev->delayed_ops);
        ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper,
                                 qxl_num_crtc /* num_crtc - QXL supports just 1 */,
                                 QXLFB_CONN_LIMIT);
index 63c6715ad38565d5ad5c04243b00d4482c54b7b5..ae59e91cfb9ab1694aee3047e094166130e7b123 100644 (file)
 
    For some reason every so often qxl hw fails to release, things go wrong.
 */
-
-
-int qxl_fence_add_release(struct qxl_fence *qfence, uint32_t rel_id)
+/* must be called with the fence lock held */
+void qxl_fence_add_release_locked(struct qxl_fence *qfence, uint32_t rel_id)
 {
-       struct qxl_bo *bo = container_of(qfence, struct qxl_bo, fence);
-
-       spin_lock(&bo->tbo.bdev->fence_lock);
        radix_tree_insert(&qfence->tree, rel_id, qfence);
        qfence->num_active_releases++;
-       spin_unlock(&bo->tbo.bdev->fence_lock);
-       return 0;
 }
 
 int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id)
index a235693aabba331284fca3017c519002789c1ab9..25e1777fb0a28551ac1d43d8a7a5b183812f54a7 100644 (file)
@@ -55,7 +55,7 @@ int qxl_gem_object_create(struct qxl_device *qdev, int size,
        /* At least align on page size */
        if (alignment < PAGE_SIZE)
                alignment = PAGE_SIZE;
-       r = qxl_bo_create(qdev, size, kernel, initial_domain, surf, &qbo);
+       r = qxl_bo_create(qdev, size, kernel, false, initial_domain, surf, &qbo);
        if (r) {
                if (r != -ERESTARTSYS)
                        DRM_ERROR(
index cf856206996b86a6b2293723faafc1c14810a64d..7fbcc35e8ad35bfa8cce9f3323a4f4e5d574f21e 100644 (file)
 #include "qxl_object.h"
 
 static int
-qxl_image_create_helper(struct qxl_device *qdev,
+qxl_allocate_chunk(struct qxl_device *qdev,
+                  struct qxl_release *release,
+                  struct qxl_drm_image *image,
+                  unsigned int chunk_size)
+{
+       struct qxl_drm_chunk *chunk;
+       int ret;
+
+       chunk = kmalloc(sizeof(struct qxl_drm_chunk), GFP_KERNEL);
+       if (!chunk)
+               return -ENOMEM;
+
+       ret = qxl_alloc_bo_reserved(qdev, release, chunk_size, &chunk->bo);
+       if (ret) {
+               kfree(chunk);
+               return ret;
+       }
+
+       list_add_tail(&chunk->head, &image->chunk_list);
+       return 0;
+}
+
+int
+qxl_image_alloc_objects(struct qxl_device *qdev,
                        struct qxl_release *release,
-                       struct qxl_bo **image_bo,
-                       const uint8_t *data,
-                       int width, int height,
-                       int depth, unsigned int hash,
-                       int stride)
+                       struct qxl_drm_image **image_ptr,
+                       int height, int stride)
+{
+       struct qxl_drm_image *image;
+       int ret;
+
+       image = kmalloc(sizeof(struct qxl_drm_image), GFP_KERNEL);
+       if (!image)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&image->chunk_list);
+
+       ret = qxl_alloc_bo_reserved(qdev, release, sizeof(struct qxl_image), &image->bo);
+       if (ret) {
+               kfree(image);
+               return ret;
+       }
+
+       ret = qxl_allocate_chunk(qdev, release, image, sizeof(struct qxl_data_chunk) + stride * height);
+       if (ret) {
+               qxl_bo_unref(&image->bo);
+               kfree(image);
+               return ret;
+       }
+       *image_ptr = image;
+       return 0;
+}
+
+void qxl_image_free_objects(struct qxl_device *qdev, struct qxl_drm_image *dimage)
 {
+       struct qxl_drm_chunk *chunk, *tmp;
+
+       list_for_each_entry_safe(chunk, tmp, &dimage->chunk_list, head) {
+               qxl_bo_unref(&chunk->bo);
+               kfree(chunk);
+       }
+
+       qxl_bo_unref(&dimage->bo);
+       kfree(dimage);
+}
+
+static int
+qxl_image_init_helper(struct qxl_device *qdev,
+                     struct qxl_release *release,
+                     struct qxl_drm_image *dimage,
+                     const uint8_t *data,
+                     int width, int height,
+                     int depth, unsigned int hash,
+                     int stride)
+{
+       struct qxl_drm_chunk *drv_chunk;
        struct qxl_image *image;
        struct qxl_data_chunk *chunk;
        int i;
        int chunk_stride;
        int linesize = width * depth / 8;
-       struct qxl_bo *chunk_bo;
-       int ret;
+       struct qxl_bo *chunk_bo, *image_bo;
        void *ptr;
        /* Chunk */
        /* FIXME: Check integer overflow */
        /* TODO: variable number of chunks */
+
+       drv_chunk = list_first_entry(&dimage->chunk_list, struct qxl_drm_chunk, head);
+
+       chunk_bo = drv_chunk->bo;
        chunk_stride = stride; /* TODO: should use linesize, but it renders
                                  wrong (check the bitmaps are sent correctly
                                  first) */
-       ret = qxl_alloc_bo_reserved(qdev, sizeof(*chunk) + height * chunk_stride,
-                                   &chunk_bo);
-       
+
        ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, 0);
        chunk = ptr;
        chunk->data_size = height * chunk_stride;
@@ -102,7 +171,6 @@ qxl_image_create_helper(struct qxl_device *qdev,
                                while (remain > 0) {
                                        page_base = out_offset & PAGE_MASK;
                                        page_offset = offset_in_page(out_offset);
-                                       
                                        size = min((int)(PAGE_SIZE - page_offset), remain);
 
                                        ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page_base);
@@ -116,14 +184,10 @@ qxl_image_create_helper(struct qxl_device *qdev,
                        }
                }
        }
-
-
        qxl_bo_kunmap(chunk_bo);
 
-       /* Image */
-       ret = qxl_alloc_bo_reserved(qdev, sizeof(*image), image_bo);
-
-       ptr = qxl_bo_kmap_atomic_page(qdev, *image_bo, 0);
+       image_bo = dimage->bo;
+       ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0);
        image = ptr;
 
        image->descriptor.id = 0;
@@ -154,23 +218,20 @@ qxl_image_create_helper(struct qxl_device *qdev,
        image->u.bitmap.stride = chunk_stride;
        image->u.bitmap.palette = 0;
        image->u.bitmap.data = qxl_bo_physical_address(qdev, chunk_bo, 0);
-       qxl_release_add_res(qdev, release, chunk_bo);
-       qxl_bo_unreserve(chunk_bo);
-       qxl_bo_unref(&chunk_bo);
 
-       qxl_bo_kunmap_atomic_page(qdev, *image_bo, ptr);
+       qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
 
        return 0;
 }
 
-int qxl_image_create(struct qxl_device *qdev,
+int qxl_image_init(struct qxl_device *qdev,
                     struct qxl_release *release,
-                    struct qxl_bo **image_bo,
+                    struct qxl_drm_image *dimage,
                     const uint8_t *data,
                     int x, int y, int width, int height,
                     int depth, int stride)
 {
        data += y * stride + x * (depth / 8);
-       return qxl_image_create_helper(qdev, release, image_bo, data,
+       return qxl_image_init_helper(qdev, release, dimage, data,
                                       width, height, depth, 0, stride);
 }
index 27f45e49250d72e48efd1bce5cc86b1f7442334e..6de33563d6f186fe56745137a7e8b3c3b324e5a8 100644 (file)
@@ -68,55 +68,60 @@ static int qxl_map_ioctl(struct drm_device *dev, void *data,
                                  &qxl_map->offset);
 }
 
+struct qxl_reloc_info {
+       int type;
+       struct qxl_bo *dst_bo;
+       uint32_t dst_offset;
+       struct qxl_bo *src_bo;
+       int src_offset;
+};
+
 /*
  * dst must be validated, i.e. whole bo on vram/surfacesram (right now all bo's
  * are on vram).
  * *(dst + dst_off) = qxl_bo_physical_address(src, src_off)
  */
 static void
-apply_reloc(struct qxl_device *qdev, struct qxl_bo *dst, uint64_t dst_off,
-           struct qxl_bo *src, uint64_t src_off)
+apply_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info)
 {
        void *reloc_page;
-
-       reloc_page = qxl_bo_kmap_atomic_page(qdev, dst, dst_off & PAGE_MASK);
-       *(uint64_t *)(reloc_page + (dst_off & ~PAGE_MASK)) = qxl_bo_physical_address(qdev,
-                                                                    src, src_off);
-       qxl_bo_kunmap_atomic_page(qdev, dst, reloc_page);
+       reloc_page = qxl_bo_kmap_atomic_page(qdev, info->dst_bo, info->dst_offset & PAGE_MASK);
+       *(uint64_t *)(reloc_page + (info->dst_offset & ~PAGE_MASK)) = qxl_bo_physical_address(qdev,
+                                                                                             info->src_bo,
+                                                                                             info->src_offset);
+       qxl_bo_kunmap_atomic_page(qdev, info->dst_bo, reloc_page);
 }
 
 static void
-apply_surf_reloc(struct qxl_device *qdev, struct qxl_bo *dst, uint64_t dst_off,
-                struct qxl_bo *src)
+apply_surf_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info)
 {
        uint32_t id = 0;
        void *reloc_page;
 
-       if (src && !src->is_primary)
-               id = src->surface_id;
+       if (info->src_bo && !info->src_bo->is_primary)
+               id = info->src_bo->surface_id;
 
-       reloc_page = qxl_bo_kmap_atomic_page(qdev, dst, dst_off & PAGE_MASK);
-       *(uint32_t *)(reloc_page + (dst_off & ~PAGE_MASK)) = id;
-       qxl_bo_kunmap_atomic_page(qdev, dst, reloc_page);
+       reloc_page = qxl_bo_kmap_atomic_page(qdev, info->dst_bo, info->dst_offset & PAGE_MASK);
+       *(uint32_t *)(reloc_page + (info->dst_offset & ~PAGE_MASK)) = id;
+       qxl_bo_kunmap_atomic_page(qdev, info->dst_bo, reloc_page);
 }
 
 /* return holding the reference to this object */
 static struct qxl_bo *qxlhw_handle_to_bo(struct qxl_device *qdev,
                                         struct drm_file *file_priv, uint64_t handle,
-                                        struct qxl_reloc_list *reloc_list)
+                                        struct qxl_release *release)
 {
        struct drm_gem_object *gobj;
        struct qxl_bo *qobj;
        int ret;
 
        gobj = drm_gem_object_lookup(qdev->ddev, file_priv, handle);
-       if (!gobj) {
-               DRM_ERROR("bad bo handle %lld\n", handle);
+       if (!gobj)
                return NULL;
-       }
+
        qobj = gem_to_qxl_bo(gobj);
 
-       ret = qxl_bo_list_add(reloc_list, qobj);
+       ret = qxl_release_list_add(release, qobj);
        if (ret)
                return NULL;
 
@@ -129,151 +134,177 @@ static struct qxl_bo *qxlhw_handle_to_bo(struct qxl_device *qdev,
  * However, the command as passed from user space must *not* contain the initial
  * QXLReleaseInfo struct (first XXX bytes)
  */
-static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
-                               struct drm_file *file_priv)
+static int qxl_process_single_command(struct qxl_device *qdev,
+                                     struct drm_qxl_command *cmd,
+                                     struct drm_file *file_priv)
 {
-       struct qxl_device *qdev = dev->dev_private;
-       struct drm_qxl_execbuffer *execbuffer = data;
-       struct drm_qxl_command user_cmd;
-       int cmd_num;
-       struct qxl_bo *reloc_src_bo;
-       struct qxl_bo *reloc_dst_bo;
-       struct drm_qxl_reloc reloc;
+       struct qxl_reloc_info *reloc_info;
+       int release_type;
+       struct qxl_release *release;
+       struct qxl_bo *cmd_bo;
        void *fb_cmd;
-       int i, ret;
-       struct qxl_reloc_list reloc_list;
+       int i, j, ret, num_relocs;
        int unwritten;
-       uint32_t reloc_dst_offset;
-       INIT_LIST_HEAD(&reloc_list.bos);
 
-       for (cmd_num = 0; cmd_num < execbuffer->commands_num; ++cmd_num) {
-               struct qxl_release *release;
-               struct qxl_bo *cmd_bo;
-               int release_type;
-               struct drm_qxl_command *commands =
-                       (struct drm_qxl_command *)(uintptr_t)execbuffer->commands;
+       switch (cmd->type) {
+       case QXL_CMD_DRAW:
+               release_type = QXL_RELEASE_DRAWABLE;
+               break;
+       case QXL_CMD_SURFACE:
+       case QXL_CMD_CURSOR:
+       default:
+               DRM_DEBUG("Only draw commands in execbuffers\n");
+               return -EINVAL;
+               break;
+       }
 
-               if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num],
-                                      sizeof(user_cmd)))
-                       return -EFAULT;
-               switch (user_cmd.type) {
-               case QXL_CMD_DRAW:
-                       release_type = QXL_RELEASE_DRAWABLE;
-                       break;
-               case QXL_CMD_SURFACE:
-               case QXL_CMD_CURSOR:
-               default:
-                       DRM_DEBUG("Only draw commands in execbuffers\n");
-                       return -EINVAL;
-                       break;
-               }
+       if (cmd->command_size > PAGE_SIZE - sizeof(union qxl_release_info))
+               return -EINVAL;
 
-               if (user_cmd.command_size > PAGE_SIZE - sizeof(union qxl_release_info))
-                       return -EINVAL;
+       if (!access_ok(VERIFY_READ,
+                      (void *)(unsigned long)cmd->command,
+                      cmd->command_size))
+               return -EFAULT;
 
-               if (!access_ok(VERIFY_READ,
-                              (void *)(unsigned long)user_cmd.command,
-                              user_cmd.command_size))
-                       return -EFAULT;
+       reloc_info = kmalloc(sizeof(struct qxl_reloc_info) * cmd->relocs_num, GFP_KERNEL);
+       if (!reloc_info)
+               return -ENOMEM;
 
-               ret = qxl_alloc_release_reserved(qdev,
-                                                sizeof(union qxl_release_info) +
-                                                user_cmd.command_size,
-                                                release_type,
-                                                &release,
-                                                &cmd_bo);
-               if (ret)
-                       return ret;
+       ret = qxl_alloc_release_reserved(qdev,
+                                        sizeof(union qxl_release_info) +
+                                        cmd->command_size,
+                                        release_type,
+                                        &release,
+                                        &cmd_bo);
+       if (ret)
+               goto out_free_reloc;
 
-               /* TODO copy slow path code from i915 */
-               fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE));
-               unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)user_cmd.command, user_cmd.command_size);
+       /* TODO copy slow path code from i915 */
+       fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE));
+       unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)cmd->command, cmd->command_size);
 
-               {
-                       struct qxl_drawable *draw = fb_cmd;
+       {
+               struct qxl_drawable *draw = fb_cmd;
+               draw->mm_time = qdev->rom->mm_clock;
+       }
 
-                       draw->mm_time = qdev->rom->mm_clock;
-               }
-               qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd);
-               if (unwritten) {
-                       DRM_ERROR("got unwritten %d\n", unwritten);
-                       qxl_release_unreserve(qdev, release);
-                       qxl_release_free(qdev, release);
-                       return -EFAULT;
+       qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd);
+       if (unwritten) {
+               DRM_ERROR("got unwritten %d\n", unwritten);
+               ret = -EFAULT;
+               goto out_free_release;
+       }
+
+       /* fill out reloc info structs */
+       num_relocs = 0;
+       for (i = 0; i < cmd->relocs_num; ++i) {
+               struct drm_qxl_reloc reloc;
+
+               if (DRM_COPY_FROM_USER(&reloc,
+                                      &((struct drm_qxl_reloc *)(uintptr_t)cmd->relocs)[i],
+                                      sizeof(reloc))) {
+                       ret = -EFAULT;
+                       goto out_free_bos;
                }
 
-               for (i = 0 ; i < user_cmd.relocs_num; ++i) {
-                       if (DRM_COPY_FROM_USER(&reloc,
-                                              &((struct drm_qxl_reloc *)(uintptr_t)user_cmd.relocs)[i],
-                                              sizeof(reloc))) {
-                               qxl_bo_list_unreserve(&reloc_list, true);
-                               qxl_release_unreserve(qdev, release);
-                               qxl_release_free(qdev, release);
-                               return -EFAULT;
-                       }
+               /* add the bos to the list of bos to validate -
+                  need to validate first then process relocs? */
+               if (reloc.reloc_type != QXL_RELOC_TYPE_BO && reloc.reloc_type != QXL_RELOC_TYPE_SURF) {
+                       DRM_DEBUG("unknown reloc type %d\n", reloc_info[i].type);
 
-                       /* add the bos to the list of bos to validate -
-                          need to validate first then process relocs? */
-                       if (reloc.dst_handle) {
-                               reloc_dst_bo = qxlhw_handle_to_bo(qdev, file_priv,
-                                                                 reloc.dst_handle, &reloc_list);
-                               if (!reloc_dst_bo) {
-                                       qxl_bo_list_unreserve(&reloc_list, true);
-                                       qxl_release_unreserve(qdev, release);
-                                       qxl_release_free(qdev, release);
-                                       return -EINVAL;
-                               }
-                               reloc_dst_offset = 0;
-                       } else {
-                               reloc_dst_bo = cmd_bo;
-                               reloc_dst_offset = release->release_offset;
+                       ret = -EINVAL;
+                       goto out_free_bos;
+               }
+               reloc_info[i].type = reloc.reloc_type;
+
+               if (reloc.dst_handle) {
+                       reloc_info[i].dst_bo = qxlhw_handle_to_bo(qdev, file_priv,
+                                                                 reloc.dst_handle, release);
+                       if (!reloc_info[i].dst_bo) {
+                               ret = -EINVAL;
+                               reloc_info[i].src_bo = NULL;
+                               goto out_free_bos;
                        }
-
-                       /* reserve and validate the reloc dst bo */
-                       if (reloc.reloc_type == QXL_RELOC_TYPE_BO || reloc.src_handle > 0) {
-                               reloc_src_bo =
-                                       qxlhw_handle_to_bo(qdev, file_priv,
-                                                          reloc.src_handle, &reloc_list);
-                               if (!reloc_src_bo) {
-                                       if (reloc_dst_bo != cmd_bo)
-                                               drm_gem_object_unreference_unlocked(&reloc_dst_bo->gem_base);
-                                       qxl_bo_list_unreserve(&reloc_list, true);
-                                       qxl_release_unreserve(qdev, release);
-                                       qxl_release_free(qdev, release);
-                                       return -EINVAL;
-                               }
-                       } else
-                               reloc_src_bo = NULL;
-                       if (reloc.reloc_type == QXL_RELOC_TYPE_BO) {
-                               apply_reloc(qdev, reloc_dst_bo, reloc_dst_offset + reloc.dst_offset,
-                                           reloc_src_bo, reloc.src_offset);
-                       } else if (reloc.reloc_type == QXL_RELOC_TYPE_SURF) {
-                               apply_surf_reloc(qdev, reloc_dst_bo, reloc_dst_offset + reloc.dst_offset, reloc_src_bo);
-                       } else {
-                               DRM_ERROR("unknown reloc type %d\n", reloc.reloc_type);
-                               return -EINVAL;
+                       reloc_info[i].dst_offset = reloc.dst_offset;
+               } else {
+                       reloc_info[i].dst_bo = cmd_bo;
+                       reloc_info[i].dst_offset = reloc.dst_offset + release->release_offset;
+               }
+               num_relocs++;
+
+               /* reserve and validate the reloc dst bo */
+               if (reloc.reloc_type == QXL_RELOC_TYPE_BO || reloc.src_handle > 0) {
+                       reloc_info[i].src_bo =
+                               qxlhw_handle_to_bo(qdev, file_priv,
+                                                  reloc.src_handle, release);
+                       if (!reloc_info[i].src_bo) {
+                               if (reloc_info[i].dst_bo != cmd_bo)
+                                       drm_gem_object_unreference_unlocked(&reloc_info[i].dst_bo->gem_base);
+                               ret = -EINVAL;
+                               goto out_free_bos;
                        }
+                       reloc_info[i].src_offset = reloc.src_offset;
+               } else {
+                       reloc_info[i].src_bo = NULL;
+                       reloc_info[i].src_offset = 0;
+               }
+       }
 
-                       if (reloc_src_bo && reloc_src_bo != cmd_bo) {
-                               qxl_release_add_res(qdev, release, reloc_src_bo);
-                               drm_gem_object_unreference_unlocked(&reloc_src_bo->gem_base);
-                       }
+       /* validate all buffers */
+       ret = qxl_release_reserve_list(release, false);
+       if (ret)
+               goto out_free_bos;
 
-                       if (reloc_dst_bo != cmd_bo)
-                               drm_gem_object_unreference_unlocked(&reloc_dst_bo->gem_base);
-               }
-               qxl_fence_releaseable(qdev, release);
+       for (i = 0; i < cmd->relocs_num; ++i) {
+               if (reloc_info[i].type == QXL_RELOC_TYPE_BO)
+                       apply_reloc(qdev, &reloc_info[i]);
+               else if (reloc_info[i].type == QXL_RELOC_TYPE_SURF)
+                       apply_surf_reloc(qdev, &reloc_info[i]);
+       }
 
-               ret = qxl_push_command_ring_release(qdev, release, user_cmd.type, true);
-               if (ret == -ERESTARTSYS) {
-                       qxl_release_unreserve(qdev, release);
-                       qxl_release_free(qdev, release);
-                       qxl_bo_list_unreserve(&reloc_list, true);
+       ret = qxl_push_command_ring_release(qdev, release, cmd->type, true);
+       if (ret)
+               qxl_release_backoff_reserve_list(release);
+       else
+               qxl_release_fence_buffer_objects(release);
+
+out_free_bos:
+       for (j = 0; j < num_relocs; j++) {
+               if (reloc_info[j].dst_bo != cmd_bo)
+                       drm_gem_object_unreference_unlocked(&reloc_info[j].dst_bo->gem_base);
+               if (reloc_info[j].src_bo && reloc_info[j].src_bo != cmd_bo)
+                       drm_gem_object_unreference_unlocked(&reloc_info[j].src_bo->gem_base);
+       }
+out_free_release:
+       if (ret)
+               qxl_release_free(qdev, release);
+out_free_reloc:
+       kfree(reloc_info);
+       return ret;
+}
+
+static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv)
+{
+       struct qxl_device *qdev = dev->dev_private;
+       struct drm_qxl_execbuffer *execbuffer = data;
+       struct drm_qxl_command user_cmd;
+       int cmd_num;
+       int ret;
+
+       for (cmd_num = 0; cmd_num < execbuffer->commands_num; ++cmd_num) {
+
+               struct drm_qxl_command *commands =
+                       (struct drm_qxl_command *)(uintptr_t)execbuffer->commands;
+
+               if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num],
+                                      sizeof(user_cmd)))
+                       return -EFAULT;
+
+               ret = qxl_process_single_command(qdev, &user_cmd, file_priv);
+               if (ret)
                        return ret;
-               }
-               qxl_release_unreserve(qdev, release);
        }
-       qxl_bo_list_unreserve(&reloc_list, 0);
        return 0;
 }
 
@@ -305,7 +336,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data,
                goto out;
 
        if (!qobj->pin_count) {
-               qxl_ttm_placement_from_domain(qobj, qobj->type);
+               qxl_ttm_placement_from_domain(qobj, qobj->type, false);
                ret = ttm_bo_validate(&qobj->tbo, &qobj->placement,
                                      true, false);
                if (unlikely(ret))
index 1191fe7788c932d6c10e678815724c1dd44b8f16..aa161cddd87e4a018c601e25e722663d4e0e3207 100644 (file)
@@ -51,20 +51,21 @@ bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo)
        return false;
 }
 
-void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain)
+void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
 {
        u32 c = 0;
+       u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0;
 
        qbo->placement.fpfn = 0;
        qbo->placement.lpfn = 0;
        qbo->placement.placement = qbo->placements;
        qbo->placement.busy_placement = qbo->placements;
        if (domain == QXL_GEM_DOMAIN_VRAM)
-               qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM;
+               qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag;
        if (domain == QXL_GEM_DOMAIN_SURFACE)
-               qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0;
+               qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0 | pflag;
        if (domain == QXL_GEM_DOMAIN_CPU)
-               qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag;
        if (!c)
                qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
        qbo->placement.num_placement = c;
@@ -73,7 +74,7 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain)
 
 
 int qxl_bo_create(struct qxl_device *qdev,
-                 unsigned long size, bool kernel, u32 domain,
+                 unsigned long size, bool kernel, bool pinned, u32 domain,
                  struct qxl_surface *surf,
                  struct qxl_bo **bo_ptr)
 {
@@ -99,15 +100,15 @@ int qxl_bo_create(struct qxl_device *qdev,
        }
        bo->gem_base.driver_private = NULL;
        bo->type = domain;
-       bo->pin_count = 0;
+       bo->pin_count = pinned ? 1 : 0;
        bo->surface_id = 0;
        qxl_fence_init(qdev, &bo->fence);
        INIT_LIST_HEAD(&bo->list);
-       atomic_set(&bo->reserve_count, 0);
+
        if (surf)
                bo->surf = *surf;
 
-       qxl_ttm_placement_from_domain(bo, domain);
+       qxl_ttm_placement_from_domain(bo, domain, pinned);
 
        r = ttm_bo_init(&qdev->mman.bdev, &bo->tbo, size, type,
                        &bo->placement, 0, !kernel, NULL, size,
@@ -228,7 +229,7 @@ struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo)
 int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr)
 {
        struct qxl_device *qdev = (struct qxl_device *)bo->gem_base.dev->dev_private;
-       int r, i;
+       int r;
 
        if (bo->pin_count) {
                bo->pin_count++;
@@ -236,9 +237,7 @@ int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr)
                        *gpu_addr = qxl_bo_gpu_offset(bo);
                return 0;
        }
-       qxl_ttm_placement_from_domain(bo, domain);
-       for (i = 0; i < bo->placement.num_placement; i++)
-               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+       qxl_ttm_placement_from_domain(bo, domain, true);
        r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
        if (likely(r == 0)) {
                bo->pin_count = 1;
@@ -317,53 +316,6 @@ int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo)
        return 0;
 }
 
-void qxl_bo_list_unreserve(struct qxl_reloc_list *reloc_list, bool failed)
-{
-       struct qxl_bo_list *entry, *sf;
-
-       list_for_each_entry_safe(entry, sf, &reloc_list->bos, lhead) {
-               qxl_bo_unreserve(entry->bo);
-               list_del(&entry->lhead);
-               kfree(entry);
-       }
-}
-
-int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo)
-{
-       struct qxl_bo_list *entry;
-       int ret;
-
-       list_for_each_entry(entry, &reloc_list->bos, lhead) {
-               if (entry->bo == bo)
-                       return 0;
-       }
-
-       entry = kmalloc(sizeof(struct qxl_bo_list), GFP_KERNEL);
-       if (!entry)
-               return -ENOMEM;
-
-       entry->bo = bo;
-       list_add(&entry->lhead, &reloc_list->bos);
-
-       ret = qxl_bo_reserve(bo, false);
-       if (ret)
-               return ret;
-
-       if (!bo->pin_count) {
-               qxl_ttm_placement_from_domain(bo, bo->type);
-               ret = ttm_bo_validate(&bo->tbo, &bo->placement,
-                                     true, false);
-               if (ret)
-                       return ret;
-       }
-
-       /* allocate a surface for reserved + validated buffers */
-       ret = qxl_bo_check_id(bo->gem_base.dev->dev_private, bo);
-       if (ret)
-               return ret;
-       return 0;
-}
-
 int qxl_surf_evict(struct qxl_device *qdev)
 {
        return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0);
index ee7ad79ce781b163fdc31836184af2b44fb10d70..8cb6167038e544625ec666a6fef7b4308d8e832d 100644 (file)
@@ -88,7 +88,7 @@ static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type,
 
 extern int qxl_bo_create(struct qxl_device *qdev,
                         unsigned long size,
-                        bool kernel, u32 domain,
+                        bool kernel, bool pinned, u32 domain,
                         struct qxl_surface *surf,
                         struct qxl_bo **bo_ptr);
 extern int qxl_bo_kmap(struct qxl_bo *bo, void **ptr);
@@ -99,9 +99,7 @@ extern struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo);
 extern void qxl_bo_unref(struct qxl_bo **bo);
 extern int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr);
 extern int qxl_bo_unpin(struct qxl_bo *bo);
-extern void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain);
+extern void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned);
 extern bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo);
 
-extern int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo);
-extern void qxl_bo_list_unreserve(struct qxl_reloc_list *reloc_list, bool failed);
 #endif
index b443d6751d5f2da675dda7fccec24b2637312ba7..b61449e52cd5695c7c024548ecedfc3340b11156 100644 (file)
@@ -38,7 +38,8 @@
 
 static const int release_size_per_bo[] = { RELEASE_SIZE, SURFACE_RELEASE_SIZE, RELEASE_SIZE };
 static const int releases_per_bo[] = { RELEASES_PER_BO, SURFACE_RELEASES_PER_BO, RELEASES_PER_BO };
-uint64_t
+
+static uint64_t
 qxl_release_alloc(struct qxl_device *qdev, int type,
                  struct qxl_release **ret)
 {
@@ -53,9 +54,9 @@ qxl_release_alloc(struct qxl_device *qdev, int type,
                return 0;
        }
        release->type = type;
-       release->bo_count = 0;
        release->release_offset = 0;
        release->surface_release_id = 0;
+       INIT_LIST_HEAD(&release->bos);
 
        idr_preload(GFP_KERNEL);
        spin_lock(&qdev->release_idr_lock);
@@ -77,20 +78,20 @@ void
 qxl_release_free(struct qxl_device *qdev,
                 struct qxl_release *release)
 {
-       int i;
-
-       QXL_INFO(qdev, "release %d, type %d, %d bos\n", release->id,
-                release->type, release->bo_count);
+       struct qxl_bo_list *entry, *tmp;
+       QXL_INFO(qdev, "release %d, type %d\n", release->id,
+                release->type);
 
        if (release->surface_release_id)
                qxl_surface_id_dealloc(qdev, release->surface_release_id);
 
-       for (i = 0 ; i < release->bo_count; ++i) {
+       list_for_each_entry_safe(entry, tmp, &release->bos, tv.head) {
+               struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
                QXL_INFO(qdev, "release %llx\n",
-                       release->bos[i]->tbo.addr_space_offset
+                       entry->tv.bo->addr_space_offset
                                                - DRM_FILE_OFFSET);
-               qxl_fence_remove_release(&release->bos[i]->fence, release->id);
-               qxl_bo_unref(&release->bos[i]);
+               qxl_fence_remove_release(&bo->fence, release->id);
+               qxl_bo_unref(&bo);
        }
        spin_lock(&qdev->release_idr_lock);
        idr_remove(&qdev->release_idr, release->id);
@@ -98,83 +99,117 @@ qxl_release_free(struct qxl_device *qdev,
        kfree(release);
 }
 
-void
-qxl_release_add_res(struct qxl_device *qdev, struct qxl_release *release,
-                   struct qxl_bo *bo)
-{
-       int i;
-       for (i = 0; i < release->bo_count; i++)
-               if (release->bos[i] == bo)
-                       return;
-
-       if (release->bo_count >= QXL_MAX_RES) {
-               DRM_ERROR("exceeded max resource on a qxl_release item\n");
-               return;
-       }
-       release->bos[release->bo_count++] = qxl_bo_ref(bo);
-}
-
 static int qxl_release_bo_alloc(struct qxl_device *qdev,
                                struct qxl_bo **bo)
 {
        int ret;
-       ret = qxl_bo_create(qdev, PAGE_SIZE, false, QXL_GEM_DOMAIN_VRAM, NULL,
+       /* pin releases bo's they are too messy to evict */
+       ret = qxl_bo_create(qdev, PAGE_SIZE, false, true,
+                           QXL_GEM_DOMAIN_VRAM, NULL,
                            bo);
        return ret;
 }
 
-int qxl_release_reserve(struct qxl_device *qdev,
-                       struct qxl_release *release, bool no_wait)
+int qxl_release_list_add(struct qxl_release *release, struct qxl_bo *bo)
+{
+       struct qxl_bo_list *entry;
+
+       list_for_each_entry(entry, &release->bos, tv.head) {
+               if (entry->tv.bo == &bo->tbo)
+                       return 0;
+       }
+
+       entry = kmalloc(sizeof(struct qxl_bo_list), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       qxl_bo_ref(bo);
+       entry->tv.bo = &bo->tbo;
+       list_add_tail(&entry->tv.head, &release->bos);
+       return 0;
+}
+
+static int qxl_release_validate_bo(struct qxl_bo *bo)
 {
        int ret;
-       if (atomic_inc_return(&release->bos[0]->reserve_count) == 1) {
-               ret = qxl_bo_reserve(release->bos[0], no_wait);
+
+       if (!bo->pin_count) {
+               qxl_ttm_placement_from_domain(bo, bo->type, false);
+               ret = ttm_bo_validate(&bo->tbo, &bo->placement,
+                                     true, false);
                if (ret)
                        return ret;
        }
+
+       /* allocate a surface for reserved + validated buffers */
+       ret = qxl_bo_check_id(bo->gem_base.dev->dev_private, bo);
+       if (ret)
+               return ret;
+       return 0;
+}
+
+int qxl_release_reserve_list(struct qxl_release *release, bool no_intr)
+{
+       int ret;
+       struct qxl_bo_list *entry;
+
+       /* if only one object on the release its the release itself
+          since these objects are pinned no need to reserve */
+       if (list_is_singular(&release->bos))
+               return 0;
+
+       ret = ttm_eu_reserve_buffers(&release->ticket, &release->bos);
+       if (ret)
+               return ret;
+
+       list_for_each_entry(entry, &release->bos, tv.head) {
+               struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
+
+               ret = qxl_release_validate_bo(bo);
+               if (ret) {
+                       ttm_eu_backoff_reservation(&release->ticket, &release->bos);
+                       return ret;
+               }
+       }
        return 0;
 }
 
-void qxl_release_unreserve(struct qxl_device *qdev,
-                         struct qxl_release *release)
+void qxl_release_backoff_reserve_list(struct qxl_release *release)
 {
-       if (atomic_dec_and_test(&release->bos[0]->reserve_count))
-               qxl_bo_unreserve(release->bos[0]);
+       /* if only one object on the release its the release itself
+          since these objects are pinned no need to reserve */
+       if (list_is_singular(&release->bos))
+               return;
+
+       ttm_eu_backoff_reservation(&release->ticket, &release->bos);
 }
 
+
 int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
                                       enum qxl_surface_cmd_type surface_cmd_type,
                                       struct qxl_release *create_rel,
                                       struct qxl_release **release)
 {
-       int ret;
-
        if (surface_cmd_type == QXL_SURFACE_CMD_DESTROY && create_rel) {
                int idr_ret;
+               struct qxl_bo_list *entry = list_first_entry(&create_rel->bos, struct qxl_bo_list, tv.head);
                struct qxl_bo *bo;
                union qxl_release_info *info;
 
                /* stash the release after the create command */
                idr_ret = qxl_release_alloc(qdev, QXL_RELEASE_SURFACE_CMD, release);
-               bo = qxl_bo_ref(create_rel->bos[0]);
+               bo = qxl_bo_ref(to_qxl_bo(entry->tv.bo));
 
                (*release)->release_offset = create_rel->release_offset + 64;
 
-               qxl_release_add_res(qdev, *release, bo);
+               qxl_release_list_add(*release, bo);
 
-               ret = qxl_release_reserve(qdev, *release, false);
-               if (ret) {
-                       DRM_ERROR("release reserve failed\n");
-                       goto out_unref;
-               }
                info = qxl_release_map(qdev, *release);
                info->id = idr_ret;
                qxl_release_unmap(qdev, *release, info);
 
-
-out_unref:
                qxl_bo_unref(&bo);
-               return ret;
+               return 0;
        }
 
        return qxl_alloc_release_reserved(qdev, sizeof(struct qxl_surface_cmd),
@@ -187,7 +222,7 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
 {
        struct qxl_bo *bo;
        int idr_ret;
-       int ret;
+       int ret = 0;
        union qxl_release_info *info;
        int cur_idx;
 
@@ -216,11 +251,6 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
                        mutex_unlock(&qdev->release_mutex);
                        return ret;
                }
-
-               /* pin releases bo's they are too messy to evict */
-               ret = qxl_bo_reserve(qdev->current_release_bo[cur_idx], false);
-               qxl_bo_pin(qdev->current_release_bo[cur_idx], QXL_GEM_DOMAIN_VRAM, NULL);
-               qxl_bo_unreserve(qdev->current_release_bo[cur_idx]);
        }
 
        bo = qxl_bo_ref(qdev->current_release_bo[cur_idx]);
@@ -231,36 +261,18 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
        if (rbo)
                *rbo = bo;
 
-       qxl_release_add_res(qdev, *release, bo);
-
-       ret = qxl_release_reserve(qdev, *release, false);
        mutex_unlock(&qdev->release_mutex);
-       if (ret)
-               goto out_unref;
+
+       qxl_release_list_add(*release, bo);
 
        info = qxl_release_map(qdev, *release);
        info->id = idr_ret;
        qxl_release_unmap(qdev, *release, info);
 
-out_unref:
        qxl_bo_unref(&bo);
        return ret;
 }
 
-int qxl_fence_releaseable(struct qxl_device *qdev,
-                         struct qxl_release *release)
-{
-       int i, ret;
-       for (i = 0; i < release->bo_count; i++) {
-               if (!release->bos[i]->tbo.sync_obj)
-                       release->bos[i]->tbo.sync_obj = &release->bos[i]->fence;
-               ret = qxl_fence_add_release(&release->bos[i]->fence, release->id);
-               if (ret)
-                       return ret;
-       }
-       return 0;
-}
-
 struct qxl_release *qxl_release_from_id_locked(struct qxl_device *qdev,
                                                   uint64_t id)
 {
@@ -273,10 +285,7 @@ struct qxl_release *qxl_release_from_id_locked(struct qxl_device *qdev,
                DRM_ERROR("failed to find id in release_idr\n");
                return NULL;
        }
-       if (release->bo_count < 1) {
-               DRM_ERROR("read a released resource with 0 bos\n");
-               return NULL;
-       }
+
        return release;
 }
 
@@ -285,9 +294,12 @@ union qxl_release_info *qxl_release_map(struct qxl_device *qdev,
 {
        void *ptr;
        union qxl_release_info *info;
-       struct qxl_bo *bo = release->bos[0];
+       struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
+       struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
 
        ptr = qxl_bo_kmap_atomic_page(qdev, bo, release->release_offset & PAGE_SIZE);
+       if (!ptr)
+               return NULL;
        info = ptr + (release->release_offset & ~PAGE_SIZE);
        return info;
 }
@@ -296,9 +308,51 @@ void qxl_release_unmap(struct qxl_device *qdev,
                       struct qxl_release *release,
                       union qxl_release_info *info)
 {
-       struct qxl_bo *bo = release->bos[0];
+       struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
+       struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
        void *ptr;
 
        ptr = ((void *)info) - (release->release_offset & ~PAGE_SIZE);
        qxl_bo_kunmap_atomic_page(qdev, bo, ptr);
 }
+
+void qxl_release_fence_buffer_objects(struct qxl_release *release)
+{
+       struct ttm_validate_buffer *entry;
+       struct ttm_buffer_object *bo;
+       struct ttm_bo_global *glob;
+       struct ttm_bo_device *bdev;
+       struct ttm_bo_driver *driver;
+       struct qxl_bo *qbo;
+
+       /* if only one object on the release its the release itself
+          since these objects are pinned no need to reserve */
+       if (list_is_singular(&release->bos))
+               return;
+
+       bo = list_first_entry(&release->bos, struct ttm_validate_buffer, head)->bo;
+       bdev = bo->bdev;
+       driver = bdev->driver;
+       glob = bo->glob;
+
+       spin_lock(&glob->lru_lock);
+       spin_lock(&bdev->fence_lock);
+
+       list_for_each_entry(entry, &release->bos, head) {
+               bo = entry->bo;
+               qbo = to_qxl_bo(bo);
+
+               if (!entry->bo->sync_obj)
+                       entry->bo->sync_obj = &qbo->fence;
+
+               qxl_fence_add_release_locked(&qbo->fence, release->id);
+
+               ttm_bo_add_to_lru(bo);
+               ww_mutex_unlock(&bo->resv->lock);
+               entry->reserved = false;
+       }
+       spin_unlock(&bdev->fence_lock);
+       spin_unlock(&glob->lru_lock);
+       ww_acquire_fini(&release->ticket);
+}
+
index 489cb8cece4da553b9f5c36c4dc9c610e617c3ea..1dfd84cda2a128e39f4e8143c43b3d0c6a99f30b 100644 (file)
@@ -206,7 +206,7 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo,
                return;
        }
        qbo = container_of(bo, struct qxl_bo, tbo);
-       qxl_ttm_placement_from_domain(qbo, QXL_GEM_DOMAIN_CPU);
+       qxl_ttm_placement_from_domain(qbo, QXL_GEM_DOMAIN_CPU, false);
        *placement = qbo->placement;
 }
 
index fb441a790f3dc5a56fa6c65bf4384f2d098906fb..15da7ef344a4e55fa11d604c21269e97ab361386 100644 (file)
@@ -1222,12 +1222,17 @@ int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
        int r;
 
        mutex_lock(&ctx->mutex);
+       /* reset data block */
+       ctx->data_block = 0;
        /* reset reg block */
        ctx->reg_block = 0;
        /* reset fb window */
        ctx->fb_base = 0;
        /* reset io mode */
        ctx->io_mode = ATOM_IO_MM;
+       /* reset divmul */
+       ctx->divmul[0] = 0;
+       ctx->divmul[1] = 0;
        r = atom_execute_table_locked(ctx, index, params);
        mutex_unlock(&ctx->mutex);
        return r;
index 064023bed480fb84eae64d505465601499ac4dfc..32501f6ec991169917af2446db4acbd37f8fbba0 100644 (file)
@@ -44,6 +44,41 @@ static char *pre_emph_names[] = {
 };
 
 /***** radeon AUX functions *****/
+
+/* Atom needs data in little endian format
+ * so swap as appropriate when copying data to
+ * or from atom. Note that atom operates on
+ * dw units.
+ */
+static void radeon_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
+{
+#ifdef __BIG_ENDIAN
+       u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */
+       u32 *dst32, *src32;
+       int i;
+
+       memcpy(src_tmp, src, num_bytes);
+       src32 = (u32 *)src_tmp;
+       dst32 = (u32 *)dst_tmp;
+       if (to_le) {
+               for (i = 0; i < ((num_bytes + 3) / 4); i++)
+                       dst32[i] = cpu_to_le32(src32[i]);
+               memcpy(dst, dst_tmp, num_bytes);
+       } else {
+               u8 dws = num_bytes & ~3;
+               for (i = 0; i < ((num_bytes + 3) / 4); i++)
+                       dst32[i] = le32_to_cpu(src32[i]);
+               memcpy(dst, dst_tmp, dws);
+               if (num_bytes % 4) {
+                       for (i = 0; i < (num_bytes % 4); i++)
+                               dst[dws+i] = dst_tmp[dws+i];
+               }
+       }
+#else
+       memcpy(dst, src, num_bytes);
+#endif
+}
+
 union aux_channel_transaction {
        PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
        PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
@@ -65,10 +100,10 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
 
        base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
 
-       memcpy(base, send, send_bytes);
+       radeon_copy_swap(base, send, send_bytes, true);
 
-       args.v1.lpAuxRequest = 0 + 4;
-       args.v1.lpDataOut = 16 + 4;
+       args.v1.lpAuxRequest = cpu_to_le16((u16)(0 + 4));
+       args.v1.lpDataOut = cpu_to_le16((u16)(16 + 4));
        args.v1.ucDataOutLen = 0;
        args.v1.ucChannelID = chan->rec.i2c_id;
        args.v1.ucDelay = delay / 10;
@@ -102,7 +137,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
                recv_bytes = recv_size;
 
        if (recv && recv_size)
-               memcpy(recv, base + 16, recv_bytes);
+               radeon_copy_swap(recv, base + 16, recv_bytes, false);
 
        return recv_bytes;
 }
index b0d3fb341417342cd06b3454fe17527cbb581e48..bb9ea3641312af1a8da0aff84486a124c629704a 100644 (file)
@@ -157,9 +157,9 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
         * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
         * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
         */
+       WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
        WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
        WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
-       WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
 }
 
 
index 559cf24d51af8dbe7304caa443e7e15118c750ca..4f9b9bc20daaccde2911de65882c5a9c32d23f15 100644 (file)
@@ -1054,10 +1054,6 @@ static int ni_restrict_performance_levels_before_switch(struct radeon_device *rd
 int ni_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level)
 {
-       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
-       struct ni_ps *ps = ni_get_ps(rps);
-       u32 levels;
-
        if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
                if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
@@ -1068,8 +1064,7 @@ int ni_dpm_force_performance_level(struct radeon_device *rdev,
                if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
 
-               levels = ps->performance_level_count - 1;
-               if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+               if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
                        return -EINVAL;
        } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
                if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
index 393880a094129d5fe54a6e6431de09798101e858..10f712e37003030e81a7770e94ca696c4c8f2c08 100644 (file)
@@ -3166,7 +3166,7 @@ int r600_copy_cpdma(struct radeon_device *rdev,
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
        num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
-       r = radeon_ring_lock(rdev, ring, num_loops * 6 + 21);
+       r = radeon_ring_lock(rdev, ring, num_loops * 6 + 24);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
@@ -3181,6 +3181,9 @@ int r600_copy_cpdma(struct radeon_device *rdev,
                radeon_semaphore_free(rdev, &sem, NULL);
        }
 
+       radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+       radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
+       radeon_ring_write(ring, WAIT_3D_IDLE_bit);
        for (i = 0; i < num_loops; i++) {
                cur_size_in_bytes = size_in_bytes;
                if (cur_size_in_bytes > 0x1fffff)
index b88f54b134abaa838b44dc0a5e614df2c06f3be5..e5c860f4ccbe4f7641745c018b6dda9650a4a5e7 100644 (file)
@@ -278,9 +278,9 @@ bool r600_dynamicpm_enabled(struct radeon_device *rdev)
 void r600_enable_sclk_control(struct radeon_device *rdev, bool enable)
 {
        if (enable)
-               WREG32_P(GENERAL_PWRMGT, 0, ~SCLK_PWRMGT_OFF);
+               WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
        else
-               WREG32_P(GENERAL_PWRMGT, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+               WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
 }
 
 void r600_enable_mclk_control(struct radeon_device *rdev, bool enable)
index 78bec1a58ed1a70be65e9bd11bc235fcded90df6..f8f8b3113dddd140bb6bc51455dc86307cc267e3 100644 (file)
@@ -1161,6 +1161,7 @@ static struct radeon_asic rv6xx_asic = {
                .get_mclk = &rv6xx_dpm_get_mclk,
                .print_power_state = &rv6xx_dpm_print_power_state,
                .debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
+               .force_performance_level = &rv6xx_dpm_force_performance_level,
        },
        .pflip = {
                .pre_page_flip = &rs600_pre_page_flip,
index ca1895709908b428bdc078c36abc5e40a19e6d73..902479fa737ff62c1b2917b4d0bfce0c34176d74 100644 (file)
@@ -421,6 +421,8 @@ void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
                                 struct radeon_ps *ps);
 void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                       struct seq_file *m);
+int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
+                                     enum radeon_dpm_forced_level level);
 /* rs780 dpm */
 int rs780_dpm_init(struct radeon_device *rdev);
 int rs780_dpm_enable(struct radeon_device *rdev);
index e3f3e8841789a5c7a0234f73fb089dc0cf204687..4ccd61f60eb6cd23849940c3c25ed0e9eec675fd 100644 (file)
@@ -2782,7 +2782,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
                                                             ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
                                dividers->enable_dithen = (args.v3.ucCntlFlag &
                                                           ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
-                               dividers->fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
+                               dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
                                dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
                                dividers->ref_div = args.v3.ucRefDiv;
                                dividers->vco_mode = (args.v3.ucCntlFlag &
index 78edadc9e86b22b8ec64d5877f4b98365cafcffd..68ce360560190af6505856452658e450d3f6878a 100644 (file)
@@ -147,7 +147,7 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
                                         enum radeon_combios_table_offset table)
 {
        struct radeon_device *rdev = dev->dev_private;
-       int rev;
+       int rev, size;
        uint16_t offset = 0, check_offset;
 
        if (!rdev->bios)
@@ -156,174 +156,106 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
        switch (table) {
                /* absolute offset tables */
        case COMBIOS_ASIC_INIT_1_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0xc);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0xc;
                break;
        case COMBIOS_BIOS_SUPPORT_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x14);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x14;
                break;
        case COMBIOS_DAC_PROGRAMMING_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x2a);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x2a;
                break;
        case COMBIOS_MAX_COLOR_DEPTH_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x2c);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x2c;
                break;
        case COMBIOS_CRTC_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x2e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x2e;
                break;
        case COMBIOS_PLL_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x30);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x30;
                break;
        case COMBIOS_TV_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x32);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x32;
                break;
        case COMBIOS_DFP_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x34);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x34;
                break;
        case COMBIOS_HW_CONFIG_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x36);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x36;
                break;
        case COMBIOS_MULTIMEDIA_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x38);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x38;
                break;
        case COMBIOS_TV_STD_PATCH_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x3e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x3e;
                break;
        case COMBIOS_LCD_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x40);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x40;
                break;
        case COMBIOS_MOBILE_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x42);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x42;
                break;
        case COMBIOS_PLL_INIT_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x46);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x46;
                break;
        case COMBIOS_MEM_CONFIG_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x48);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x48;
                break;
        case COMBIOS_SAVE_MASK_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x4a);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x4a;
                break;
        case COMBIOS_HARDCODED_EDID_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x4c);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x4c;
                break;
        case COMBIOS_ASIC_INIT_2_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x4e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x4e;
                break;
        case COMBIOS_CONNECTOR_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x50);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x50;
                break;
        case COMBIOS_DYN_CLK_1_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x52);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x52;
                break;
        case COMBIOS_RESERVED_MEM_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x54);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x54;
                break;
        case COMBIOS_EXT_TMDS_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x58);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x58;
                break;
        case COMBIOS_MEM_CLK_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x5a);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x5a;
                break;
        case COMBIOS_EXT_DAC_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x5c);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x5c;
                break;
        case COMBIOS_MISC_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x5e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x5e;
                break;
        case COMBIOS_CRT_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x60);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x60;
                break;
        case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x62);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x62;
                break;
        case COMBIOS_COMPONENT_VIDEO_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x64);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x64;
                break;
        case COMBIOS_FAN_SPEED_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x66);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x66;
                break;
        case COMBIOS_OVERDRIVE_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x68);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x68;
                break;
        case COMBIOS_OEM_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x6a);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x6a;
                break;
        case COMBIOS_DYN_CLK_2_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x6c);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x6c;
                break;
        case COMBIOS_POWER_CONNECTOR_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x6e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x6e;
                break;
        case COMBIOS_I2C_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x70);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x70;
                break;
                /* relative offset tables */
        case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */
@@ -439,11 +371,16 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
                }
                break;
        default:
+               check_offset = 0;
                break;
        }
 
-       return offset;
+       size = RBIOS8(rdev->bios_header_start + 0x6);
+       /* check absolute offset tables */
+       if (table < COMBIOS_ASIC_INIT_3_TABLE && check_offset && check_offset < size)
+               offset = RBIOS16(rdev->bios_header_start + check_offset);
 
+       return offset;
 }
 
 bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
@@ -965,16 +902,22 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
                        dac = RBIOS8(dac_info + 0x3) & 0xf;
                        p_dac->ps2_pdac_adj = (bg << 8) | (dac);
                }
-               /* if the values are all zeros, use the table */
-               if (p_dac->ps2_pdac_adj)
+               /* if the values are zeros, use the table */
+               if ((dac == 0) || (bg == 0))
+                       found = 0;
+               else
                        found = 1;
        }
 
        /* 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;
        }
index d9d31a3832769d0363b2d0a728f9e3d7a76add98..6a51d943ccf44d8301758a4b99e3aba35e4c2668 100644 (file)
@@ -466,7 +466,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev)
                size += rdev->vm_manager.max_pfn * 8;
                size *= 2;
                r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager,
-                                             RADEON_VM_PTB_ALIGN(size),
+                                             RADEON_GPU_PAGE_ALIGN(size),
                                              RADEON_VM_PTB_ALIGN_SIZE,
                                              RADEON_GEM_DOMAIN_VRAM);
                if (r) {
@@ -621,7 +621,7 @@ int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm)
        }
 
 retry:
-       pd_size = RADEON_VM_PTB_ALIGN(radeon_vm_directory_size(rdev));
+       pd_size = radeon_vm_directory_size(rdev);
        r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
                             &vm->page_directory, pd_size,
                             RADEON_VM_PTB_ALIGN_SIZE, false);
@@ -953,8 +953,8 @@ static int radeon_vm_update_pdes(struct radeon_device *rdev,
 retry:
                r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
                                     &vm->page_tables[pt_idx],
-                                    RADEON_VM_PTB_ALIGN(RADEON_VM_PTE_COUNT * 8),
-                                    RADEON_VM_PTB_ALIGN_SIZE, false);
+                                    RADEON_VM_PTE_COUNT * 8,
+                                    RADEON_GPU_PAGE_SIZE, false);
 
                if (r == -ENOMEM) {
                        r = radeon_vm_evict(rdev, vm);
index 65e33f38734130043dbdc061c57c70d9006b2e6e..363018c60412c1d7374ee60a176abe2f5c49dce7 100644 (file)
@@ -819,7 +819,7 @@ static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev)
                 POWERMODE1(calculate_memory_refresh_rate(rdev,
                                                          pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
                 POWERMODE2(calculate_memory_refresh_rate(rdev,
-                                                         pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
+                                                         pi->hw.sclks[R600_POWER_LEVEL_HIGH])) |
                 POWERMODE3(calculate_memory_refresh_rate(rdev,
                                                          pi->hw.sclks[R600_POWER_LEVEL_HIGH])));
        WREG32(ARB_RFSH_RATE, arb_refresh_rate);
@@ -1182,10 +1182,10 @@ static void rv6xx_program_display_gap(struct radeon_device *rdev)
        u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
 
        tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
-       if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) {
+       if (rdev->pm.dpm.new_active_crtcs & 1) {
                tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
                tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
-       } else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) {
+       } else if (rdev->pm.dpm.new_active_crtcs & 2) {
                tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
                tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
        } else {
@@ -1670,6 +1670,8 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
        struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
        int ret;
 
+       pi->restricted_levels = 0;
+
        rv6xx_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 
        rv6xx_clear_vc(rdev);
@@ -1756,6 +1758,8 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
 
        rv6xx_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
+       rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
+
        return 0;
 }
 
@@ -2085,3 +2089,34 @@ u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low)
        else
                return requested_state->high.mclk;
 }
+
+int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
+                                     enum radeon_dpm_forced_level level)
+{
+       struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+       if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+               pi->restricted_levels = 3;
+       } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+               pi->restricted_levels = 2;
+       } else {
+               pi->restricted_levels = 0;
+       }
+
+       rv6xx_clear_vc(rdev);
+       r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+       r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
+       r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
+       r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+       r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+       rv6xx_enable_medium(rdev);
+       rv6xx_enable_high(rdev);
+       if (pi->restricted_levels == 3)
+               r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false);
+       rv6xx_program_vc(rdev);
+       rv6xx_program_at(rdev);
+
+       rdev->pm.dpm.forced_level = level;
+
+       return 0;
+}
index d325280e2f9ffcc94b2260e802f6533c242f6546..6ca904673a4fa7046cee901d26c2b049546f2234 100644 (file)
@@ -5215,14 +5215,12 @@ static void si_enable_mc_ls(struct radeon_device *rdev,
 
 static void si_init_cg(struct radeon_device *rdev)
 {
-       bool has_uvd = true;
-
        si_enable_mgcg(rdev, true);
-       si_enable_cgcg(rdev, true);
+       si_enable_cgcg(rdev, false);
        /* disable MC LS on Tahiti */
        if (rdev->family == CHIP_TAHITI)
                si_enable_mc_ls(rdev, false);
-       if (has_uvd) {
+       if (rdev->has_uvd) {
                si_enable_uvd_mgcg(rdev, true);
                si_init_uvd_internal_cg(rdev);
        }
@@ -5230,9 +5228,7 @@ static void si_init_cg(struct radeon_device *rdev)
 
 static void si_fini_cg(struct radeon_device *rdev)
 {
-       bool has_uvd = true;
-
-       if (has_uvd)
+       if (rdev->has_uvd)
                si_enable_uvd_mgcg(rdev, false);
        si_enable_cgcg(rdev, false);
        si_enable_mgcg(rdev, false);
@@ -5241,11 +5237,11 @@ static void si_fini_cg(struct radeon_device *rdev)
 static void si_init_pg(struct radeon_device *rdev)
 {
        bool has_pg = false;
-
+#if 0
        /* only cape verde supports PG */
        if (rdev->family == CHIP_VERDE)
                has_pg = true;
-
+#endif
        if (has_pg) {
                si_init_ao_cu_mask(rdev);
                si_init_dma_pg(rdev);
index 73aaa2e4c31272b6f4a28341f05e700e0c7bf42c..41825575b403bab2b5e16b3fba33a33d3187f4f7 100644 (file)
@@ -37,8 +37,6 @@
 
 #define SMC_RAM_END                 0x20000
 
-#define DDR3_DRAM_ROWS              0x2000
-
 #define SCLK_MIN_DEEPSLEEP_FREQ     1350
 
 static const struct si_cac_config_reg cac_weights_tahiti[] =
@@ -1767,8 +1765,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe
 {
        s64 kt, kv, leakage_w, i_leakage, vddc;
        s64 temperature, t_slope, t_intercept, av, bv, t_ref;
+       s64 tmp;
 
-       i_leakage = drm_int2fixp(ileakage / 100);
+       i_leakage = div64_s64(drm_int2fixp(ileakage), 100);
        vddc = div64_s64(drm_int2fixp(v), 1000);
        temperature = div64_s64(drm_int2fixp(t), 1000);
 
@@ -1778,8 +1777,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe
        bv = div64_s64(drm_int2fixp(coeff->bv), 100000000);
        t_ref = drm_int2fixp(coeff->t_ref);
 
-       kt = drm_fixp_div(drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, temperature)),
-                         drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, t_ref)));
+       tmp = drm_fixp_mul(t_slope, vddc) + t_intercept;
+       kt = drm_fixp_exp(drm_fixp_mul(tmp, temperature));
+       kt = drm_fixp_div(kt, drm_fixp_exp(drm_fixp_mul(tmp, t_ref)));
        kv = drm_fixp_mul(av, drm_fixp_exp(drm_fixp_mul(bv, vddc)));
 
        leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);
@@ -1931,6 +1931,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)
                        si_pi->cac_override = cac_override_pitcairn;
                        si_pi->powertune_data = &powertune_data_pitcairn;
                        si_pi->dte_data = dte_data_pitcairn;
+                       break;
                }
        } else if (rdev->family == CHIP_VERDE) {
                si_pi->lcac_config = lcac_cape_verde;
@@ -1941,6 +1942,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)
                case 0x683B:
                case 0x683F:
                case 0x6829:
+               case 0x6835:
                        si_pi->cac_weights = cac_weights_cape_verde_pro;
                        si_pi->dte_data = dte_data_cape_verde;
                        break;
@@ -3237,10 +3239,10 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
 {
        struct radeon_ps *rps = rdev->pm.dpm.current_ps;
        struct ni_ps *ps = ni_get_ps(rps);
-       u32 levels;
+       u32 levels = ps->performance_level_count;
 
        if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
-               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
                        return -EINVAL;
 
                if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
@@ -3249,14 +3251,13 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
                if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
 
-               levels = ps->performance_level_count - 1;
-               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
                        return -EINVAL;
        } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
                if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
 
-               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
                        return -EINVAL;
        }
 
@@ -3620,8 +3621,12 @@ static void si_enable_display_gap(struct radeon_device *rdev)
 {
        u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
 
+       tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+       tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
+               DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE));
+
        tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
-       tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+       tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) |
                DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
        WREG32(CG_DISPLAY_GAP_CNTL, tmp);
 }
@@ -4036,16 +4041,15 @@ static int si_force_switch_to_arb_f0(struct radeon_device *rdev)
 static u32 si_calculate_memory_refresh_rate(struct radeon_device *rdev,
                                            u32 engine_clock)
 {
-       struct rv7xx_power_info *pi = rv770_get_pi(rdev);
        u32 dram_rows;
        u32 dram_refresh_rate;
        u32 mc_arb_rfsh_rate;
        u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
 
-       if (pi->mem_gddr5)
-               dram_rows = 1 << (tmp + 10);
+       if (tmp >= 4)
+               dram_rows = 16384;
        else
-               dram_rows = DDR3_DRAM_ROWS;
+               dram_rows = 1 << (tmp + 10);
 
        dram_refresh_rate = 1 << ((RREG32(MC_SEQ_MISC0) & 0x3) + 3);
        mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
@@ -6013,16 +6017,11 @@ int si_dpm_set_power_state(struct radeon_device *rdev)
                return ret;
        }
 
-#if 0
-       /* XXX */
        ret = si_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
        if (ret) {
                DRM_ERROR("si_dpm_force_performance_level failed\n");
                return ret;
        }
-#else
-       rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
-#endif
 
        return 0;
 }
index 5207591a598c05944a348be2252c4a346e0e5cfa..7a5764843bfb646d2b90526a2e9f6619931b48f9 100644 (file)
@@ -192,6 +192,7 @@ static struct hid_ll_driver logi_dj_ll_driver;
 static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
                                        size_t count,
                                        unsigned char report_type);
+static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
 
 static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
                                                struct dj_report *dj_report)
@@ -232,6 +233,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
        if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
            SPFUNCTION_DEVICE_LIST_EMPTY) {
                dbg_hid("%s: device list is empty\n", __func__);
+               djrcv_dev->querying_devices = false;
                return;
        }
 
@@ -242,6 +244,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
                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__);
+               return;
+       }
+
        dj_hiddev = hid_allocate_device();
        if (IS_ERR(dj_hiddev)) {
                dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
@@ -305,6 +313,7 @@ static void delayedwork_callback(struct work_struct *work)
        struct dj_report dj_report;
        unsigned long flags;
        int count;
+       int retval;
 
        dbg_hid("%s\n", __func__);
 
@@ -337,6 +346,25 @@ static void delayedwork_callback(struct work_struct *work)
                logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
                break;
        default:
+       /* A normal report (i. e. not belonging to a pair/unpair notification)
+        * arriving here, means that the report arrived but we did not have a
+        * paired dj_device associated to the report's device_index, this
+        * means that the original "device paired" notification corresponding
+        * to this dj_device never arrived to this driver. The reason is that
+        * hid-core discards all packets coming from a device while probe() is
+        * executing. */
+       if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
+               /* ok, we don't know the device, just re-ask the
+                * receiver for the list of connected devices. */
+               retval = logi_dj_recv_query_paired_devices(djrcv_dev);
+               if (!retval) {
+                       /* everything went fine, so just leave */
+                       break;
+               }
+               dev_err(&djrcv_dev->hdev->dev,
+                       "%s:logi_dj_recv_query_paired_devices "
+                       "error:%d\n", __func__, retval);
+               }
                dbg_hid("%s: unexpected report type\n", __func__);
        }
 }
@@ -367,6 +395,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
        if (!djdev) {
                dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
                        " is NULL, index %d\n", dj_report->device_index);
+               kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+
+               if (schedule_work(&djrcv_dev->work) == 0) {
+                       dbg_hid("%s: did not schedule the work item, was already "
+                       "queued\n", __func__);
+               }
                return;
        }
 
@@ -397,6 +431,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
        if (dj_device == NULL) {
                dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
                        " is NULL, index %d\n", dj_report->device_index);
+               kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+
+               if (schedule_work(&djrcv_dev->work) == 0) {
+                       dbg_hid("%s: did not schedule the work item, was already "
+                       "queued\n", __func__);
+               }
                return;
        }
 
@@ -444,6 +484,12 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
        struct dj_report *dj_report;
        int retval;
 
+       /* no need to protect djrcv_dev->querying_devices */
+       if (djrcv_dev->querying_devices)
+               return 0;
+
+       djrcv_dev->querying_devices = true;
+
        dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
        if (!dj_report)
                return -ENOMEM;
@@ -455,6 +501,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
        return retval;
 }
 
+
 static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
                                          unsigned timeout)
 {
index fd28a5e0ca3b84b8407791421b25f8b17bf7815a..4a4000340ce1ed8cf6be1f81ee8e0f21d8ba5f5a 100644 (file)
@@ -101,6 +101,7 @@ struct dj_receiver_dev {
        struct work_struct work;
        struct kfifo notif_fifo;
        spinlock_t lock;
+       bool querying_devices;
 };
 
 struct dj_device {
index ecbc74923d063d6494aaa4648f08d91a6c44e686..87fbe2924cfac3852ee8b202b8aaeb8500de0080 100644 (file)
@@ -369,7 +369,8 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
        if (sc->quirks & PS3REMOTE)
                return ps3remote_mapping(hdev, hi, field, usage, bit, max);
 
-       return -1;
+       /* Let hid-core decide for the others */
+       return 0;
 }
 
 /*
index a7451632ceb46bad87845c444fc1897973e94ef9..6f1feb2c2e97b5defb0628d92bfc98a719449685 100644 (file)
@@ -518,7 +518,6 @@ int hidraw_connect(struct hid_device *hid)
                goto out;
        }
 
-       mutex_unlock(&minors_lock);
        init_waitqueue_head(&dev->wait);
        INIT_LIST_HEAD(&dev->list);
 
@@ -528,6 +527,7 @@ int hidraw_connect(struct hid_device *hid)
        dev->exist = 1;
        hid->hidraw = dev;
 
+       mutex_unlock(&minors_lock);
 out:
        return result;
 
index 4c605c70ebf9ed858d014d94383ebfab86851b1f..deb5c25305aff4622ceb8f84a1598902e484a6ce 100644 (file)
@@ -562,7 +562,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
                                struct hv_hotadd_state *has)
 {
        int ret = 0;
-       int i, nid, t;
+       int i, nid;
        unsigned long start_pfn;
        unsigned long processed_pfn;
        unsigned long total_pfn = pfn_count;
@@ -607,14 +607,11 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
 
                /*
                 * Wait for the memory block to be onlined.
+                * Since the hot add has succeeded, it is ok to
+                * proceed even if the pages in the hot added region
+                * have not been "onlined" within the allowed time.
                 */
-               t = wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
-               if (t == 0) {
-                       pr_info("hot_add memory timedout\n");
-                       has->ha_end_pfn -= HA_CHUNK;
-                       has->covered_end_pfn -=  processed_pfn;
-                       break;
-               }
+               wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
 
        }
 
@@ -978,6 +975,14 @@ static void post_status(struct hv_dynmem_device *dm)
                                dm->num_pages_ballooned +
                                compute_balloon_floor();
 
+       /*
+        * If our transaction ID is no longer current, just don't
+        * send the status. This can happen if we were interrupted
+        * after we picked our transaction ID.
+        */
+       if (status.hdr.trans_id != atomic_read(&trans_id))
+               return;
+
        vmbus_sendpacket(dm->dev->channel, &status,
                                sizeof(struct dm_status),
                                (unsigned long)NULL,
index a2464bf07c49b03342c0dfcd79852cc0a232a703..e8e071fc1d6d1ab265d858772fc94bbd5cd8930c 100644 (file)
@@ -690,7 +690,7 @@ int vmbus_device_register(struct hv_device *child_device_obj)
        if (ret)
                pr_err("Unable to register child device\n");
        else
-               pr_info("child device %s registered\n",
+               pr_debug("child device %s registered\n",
                        dev_name(&child_device_obj->device));
 
        return ret;
@@ -702,14 +702,14 @@ int vmbus_device_register(struct hv_device *child_device_obj)
  */
 void vmbus_device_unregister(struct hv_device *device_obj)
 {
+       pr_debug("child device %s unregistered\n",
+               dev_name(&device_obj->device));
+
        /*
         * Kick off the process of unregistering the device.
         * This will call vmbus_remove() and eventually vmbus_device_release()
         */
        device_unregister(&device_obj->device);
-
-       pr_info("child device %s unregistered\n",
-               dev_name(&device_obj->device));
 }
 
 
index 328fb0353c171a1b879af1040185afa1be109ea4..a41b5f3fc5069596d7c9a0c0c164dcefefc7e621 100644 (file)
@@ -605,12 +605,12 @@ static int max6697_init_chip(struct i2c_client *client)
                if (ret < 0)
                        return ret;
                ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY,
-                                               pdata->ideality_mask >> 1);
+                                               pdata->ideality_value);
                if (ret < 0)
                        return ret;
                ret = i2c_smbus_write_byte_data(client,
                                                MAX6581_REG_IDEALITY_SELECT,
-                                               pdata->ideality_value);
+                                               pdata->ideality_mask >> 1);
                if (ret < 0)
                        return ret;
        }
index f1c279fabe646f80d3962f3354475087f9c37bf8..7c0f9535fb7d443bf2c4b1647b3494816292020a 100644 (file)
@@ -423,7 +423,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
        struct sockaddr_ib *addr;
        union ib_gid gid, sgid, *dgid;
        u16 pkey, index;
-       u8 port, p;
+       u8 p;
        int i;
 
        cma_dev = NULL;
@@ -443,7 +443,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
                                if (!memcmp(&gid, dgid, sizeof(gid))) {
                                        cma_dev = cur_dev;
                                        sgid = gid;
-                                       port = p;
+                                       id_priv->id.port_num = p;
                                        goto found;
                                }
 
@@ -451,7 +451,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
                                                 dgid->global.subnet_prefix)) {
                                        cma_dev = cur_dev;
                                        sgid = gid;
-                                       port = p;
+                                       id_priv->id.port_num = p;
                                }
                        }
                }
@@ -462,7 +462,6 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
 
 found:
        cma_attach_to_dev(id_priv, cma_dev);
-       id_priv->id.port_num = port;
        addr = (struct sockaddr_ib *) cma_src_addr(id_priv);
        memcpy(&addr->sib_addr, &sgid, sizeof sgid);
        cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr);
@@ -880,7 +879,8 @@ static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id
 {
        struct cma_hdr *hdr;
 
-       if (listen_id->route.addr.src_addr.ss_family == AF_IB) {
+       if ((listen_id->route.addr.src_addr.ss_family == AF_IB) &&
+           (ib_event->event == IB_CM_REQ_RECEIVED)) {
                cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
                return 0;
        }
@@ -2677,29 +2677,32 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
 {
        struct ib_cm_sidr_req_param req;
        struct ib_cm_id *id;
+       void *private_data;
        int offset, ret;
 
+       memset(&req, 0, sizeof req);
        offset = cma_user_data_offset(id_priv);
        req.private_data_len = offset + conn_param->private_data_len;
        if (req.private_data_len < conn_param->private_data_len)
                return -EINVAL;
 
        if (req.private_data_len) {
-               req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
-               if (!req.private_data)
+               private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+               if (!private_data)
                        return -ENOMEM;
        } else {
-               req.private_data = NULL;
+               private_data = NULL;
        }
 
        if (conn_param->private_data && conn_param->private_data_len)
-               memcpy((void *) req.private_data + offset,
-                      conn_param->private_data, conn_param->private_data_len);
+               memcpy(private_data + offset, conn_param->private_data,
+                      conn_param->private_data_len);
 
-       if (req.private_data) {
-               ret = cma_format_hdr((void *) req.private_data, id_priv);
+       if (private_data) {
+               ret = cma_format_hdr(private_data, id_priv);
                if (ret)
                        goto out;
+               req.private_data = private_data;
        }
 
        id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
@@ -2721,7 +2724,7 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
                id_priv->cm_id.ib = NULL;
        }
 out:
-       kfree(req.private_data);
+       kfree(private_data);
        return ret;
 }
 
index dc3fd1e8af07f0f8f4c6da455c38e315074a8e1e..4c837e66516b894f88f689d93c9a84c501fa6b47 100644 (file)
@@ -2663,6 +2663,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
        int ret, i;
        struct ib_qp_attr *attr;
        struct ib_qp *qp;
+       u16 pkey_index;
 
        attr = kmalloc(sizeof *attr, GFP_KERNEL);
        if (!attr) {
@@ -2670,6 +2671,11 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
                return -ENOMEM;
        }
 
+       ret = ib_find_pkey(port_priv->device, port_priv->port_num,
+                          IB_DEFAULT_PKEY_FULL, &pkey_index);
+       if (ret)
+               pkey_index = 0;
+
        for (i = 0; i < IB_MAD_QPS_CORE; i++) {
                qp = port_priv->qp_info[i].qp;
                if (!qp)
@@ -2680,7 +2686,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
                 * one is needed for the Reset to Init transition
                 */
                attr->qp_state = IB_QPS_INIT;
-               attr->pkey_index = 0;
+               attr->pkey_index = pkey_index;
                attr->qkey = (qp->qp_num == 0) ? 0 : IB_QP1_QKEY;
                ret = ib_modify_qp(qp, attr, IB_QP_STATE |
                                             IB_QP_PKEY_INDEX | IB_QP_QKEY);
index e87f2201b220673030ca18a3957642b623d065a7..d2283837d45168070707eba5ac11aab4c2fe9c5e 100644 (file)
@@ -226,6 +226,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
                        mm->len = PAGE_ALIGN(((1UL << uresp.size_log2) + 1) *
                                             sizeof(struct t3_cqe));
                        uresp.memsize = mm->len;
+                       uresp.reserved = 0;
                        resplen = sizeof uresp;
                }
                if (ib_copy_to_udata(udata, &uresp, resplen)) {
index 232040447e8a23803cc73e64c203734d36492c2e..a4975e1654a639960b214114648593564fcb0b27 100644 (file)
@@ -1657,6 +1657,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                if (mm5) {
                        uresp.ma_sync_key = ucontext->key;
                        ucontext->key += PAGE_SIZE;
+               } else {
+                       uresp.ma_sync_key =  0;
                }
                uresp.sq_key = ucontext->key;
                ucontext->key += PAGE_SIZE;
index 4d599cedbb0b1ccceab997a4945be0d8d6e89fde..f2a3f48107e71e1d53b0abb61757f1f0ba38bb59 100644 (file)
@@ -1511,8 +1511,14 @@ static int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx,
 
        memset(&attr, 0, sizeof attr);
        attr.qp_state = IB_QPS_INIT;
-       attr.pkey_index =
-               to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0];
+       ret = 0;
+       if (create_tun)
+               ret = find_slave_port_pkey_ix(to_mdev(ctx->ib_dev), ctx->slave,
+                                             ctx->port, IB_DEFAULT_PKEY_FULL,
+                                             &attr.pkey_index);
+       if (ret || !create_tun)
+               attr.pkey_index =
+                       to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0];
        attr.qkey = IB_QP1_QKEY;
        attr.port_num = ctx->port;
        ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT);
index 8000fff4d4444168ac4091a78112593d11b212dd..3f831de9a4d8a901607afc26c81827cc5c1e3bd5 100644 (file)
@@ -619,7 +619,8 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
 
        resp.tot_uuars = req.total_num_uuars;
        resp.num_ports = dev->mdev.caps.num_ports;
-       err = ib_copy_to_udata(udata, &resp, sizeof(resp));
+       err = ib_copy_to_udata(udata, &resp,
+                              sizeof(resp) - sizeof(resp.reserved));
        if (err)
                goto out_uars;
 
@@ -1426,7 +1427,8 @@ static int init_one(struct pci_dev *pdev,
        if (err)
                goto err_eqs;
 
-       if (ib_register_device(&dev->ib_dev, NULL))
+       err = ib_register_device(&dev->ib_dev, NULL);
+       if (err)
                goto err_rsrc;
 
        err = create_umr_res(dev);
@@ -1434,8 +1436,9 @@ static int init_one(struct pci_dev *pdev,
                goto err_dev;
 
        for (i = 0; i < ARRAY_SIZE(mlx5_class_attributes); i++) {
-               if (device_create_file(&dev->ib_dev.dev,
-                                      mlx5_class_attributes[i]))
+               err = device_create_file(&dev->ib_dev.dev,
+                                        mlx5_class_attributes[i]);
+               if (err)
                        goto err_umrc;
        }
 
index 16ac54c9819f24c113ad02f594a47608a004a828..045f8cdbd303deba81e60c5f1f52330b536b9617 100644 (file)
@@ -199,7 +199,7 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
 
 static int sq_overhead(enum ib_qp_type qp_type)
 {
-       int size;
+       int size = 0;
 
        switch (qp_type) {
        case IB_QPT_XRC_INI:
index 418004c93feb772c641dde6b102620fc2be45900..90200245c5ebfd5fe71000d17b78e52bfa8d4734 100644 (file)
@@ -3570,10 +3570,10 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
        tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
        iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
        nes_debug(NES_DBG_AEQ, "aeid = 0x%04X, qp-cq id = %d, aeqe = %p,"
-                       " Tcp state = %d, iWARP state = %d\n",
+                       " Tcp state = %s, iWARP state = %s\n",
                        async_event_id,
                        le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
-                       tcp_state, iwarp_state);
+                       nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
 
        aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
        if (aeq_info & NES_AEQE_QP) {
index 8f67fe2e91e623a87878a8790ff9f2e28db0c0b8..5b53ca5a22840c14e31ddb0d7e978dfac5c179b7 100644 (file)
@@ -1384,6 +1384,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
 
                        if (ibpd->uobject) {
                                uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index;
+                               uresp.mmap_rq_db_index = 0;
                                uresp.actual_sq_size = sq_size;
                                uresp.actual_rq_size = rq_size;
                                uresp.qp_id = nesqp->hwqp.qp_id;
@@ -1767,7 +1768,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
                resp.cq_id = nescq->hw_cq.cq_number;
                resp.cq_size = nescq->hw_cq.cq_size;
                resp.mmap_db_index = 0;
-               if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+               if (ib_copy_to_udata(udata, &resp, sizeof resp - sizeof resp.reserved)) {
                        nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
                        kfree(nescq);
                        return ERR_PTR(-EFAULT);
index a877a8ed79077dbd085d28d1fd834b3f1e01d019..f4c587c68f648055546deafce7f8708798f4d109 100644 (file)
@@ -29,7 +29,6 @@
 #include <net/netevent.h>
 
 #include <rdma/ib_addr.h>
-#include <rdma/ib_cache.h>
 
 #include "ocrdma.h"
 #include "ocrdma_verbs.h"
index dcfbab177faa63eee063a428ac7848e5763f8125..f36630e4b6be182c735b7aa81d357b4207266c82 100644 (file)
@@ -242,6 +242,7 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,
        memset(ctx->ah_tbl.va, 0, map_len);
        ctx->ah_tbl.len = map_len;
 
+       memset(&resp, 0, sizeof(resp));
        resp.ah_tbl_len = ctx->ah_tbl.len;
        resp.ah_tbl_page = ctx->ah_tbl.pa;
 
@@ -253,7 +254,6 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,
        resp.wqe_size = dev->attr.wqe_size;
        resp.rqe_size = dev->attr.rqe_size;
        resp.dpp_wqe_size = dev->attr.wqe_size;
-       resp.rsvd = 0;
 
        memcpy(resp.fw_ver, dev->attr.fw_ver, sizeof(resp.fw_ver));
        status = ib_copy_to_udata(udata, &resp, sizeof(resp));
@@ -338,6 +338,7 @@ static int ocrdma_copy_pd_uresp(struct ocrdma_pd *pd,
        struct ocrdma_alloc_pd_uresp rsp;
        struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ib_ctx);
 
+       memset(&rsp, 0, sizeof(rsp));
        rsp.id = pd->id;
        rsp.dpp_enabled = pd->dpp_enabled;
        db_page_addr = pd->dev->nic_info.unmapped_db +
@@ -692,6 +693,7 @@ static int ocrdma_copy_cq_uresp(struct ocrdma_cq *cq, struct ib_udata *udata,
        struct ocrdma_ucontext *uctx;
        struct ocrdma_create_cq_uresp uresp;
 
+       memset(&uresp, 0, sizeof(uresp));
        uresp.cq_id = cq->id;
        uresp.page_size = cq->len;
        uresp.num_pages = 1;
@@ -1460,6 +1462,7 @@ static int ocrdma_copy_srq_uresp(struct ocrdma_srq *srq, struct ib_udata *udata)
        int status;
        struct ocrdma_create_srq_uresp uresp;
 
+       memset(&uresp, 0, sizeof(uresp));
        uresp.rq_dbid = srq->rq.dbid;
        uresp.num_rq_pages = 1;
        uresp.rq_page_addr[0] = srq->rq.pa;
index 21e8b09d4bf87687a9c569ac87dae42108b7cd8a..016e7429adf66b9ffb945cb4fed168e358c57742 100644 (file)
@@ -1596,6 +1596,8 @@ static void sdma_7322_p_errors(struct qib_pportdata *ppd, u64 errs)
        struct qib_devdata *dd = ppd->dd;
 
        errs &= QIB_E_P_SDMAERRS;
+       err_decode(ppd->cpspec->sdmamsgbuf, sizeof(ppd->cpspec->sdmamsgbuf),
+                  errs, qib_7322p_error_msgs);
 
        if (errs & QIB_E_P_SDMAUNEXPDATA)
                qib_dev_err(dd, "IB%u:%u SDmaUnexpData\n", dd->unit,
index 32162d355370f95b56970b19da33783052c24c36..9b5322d8cd5accca85737745ba06973ca7212efe 100644 (file)
@@ -717,7 +717,7 @@ void dump_sdma_state(struct qib_pportdata *ppd)
        struct qib_sdma_txreq *txp, *txpnext;
        __le64 *descqp;
        u64 desc[2];
-       dma_addr_t addr;
+       u64 addr;
        u16 gen, dwlen, dwoffset;
        u16 head, tail, cnt;
 
index 2cfa76f5d99eac87bf788eb41bb2a7c3815ec700..196b1d13cbcbc09548e92a4be6c9a18cdc6aae36 100644 (file)
@@ -932,12 +932,47 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
        return 0;
 }
 
+/*
+ * Takes whatever value which is in pkey index 0 and updates priv->pkey
+ * returns 0 if the pkey value was changed.
+ */
+static inline int update_parent_pkey(struct ipoib_dev_priv *priv)
+{
+       int result;
+       u16 prev_pkey;
+
+       prev_pkey = priv->pkey;
+       result = ib_query_pkey(priv->ca, priv->port, 0, &priv->pkey);
+       if (result) {
+               ipoib_warn(priv, "ib_query_pkey port %d failed (ret = %d)\n",
+                          priv->port, result);
+               return result;
+       }
+
+       priv->pkey |= 0x8000;
+
+       if (prev_pkey != priv->pkey) {
+               ipoib_dbg(priv, "pkey changed from 0x%x to 0x%x\n",
+                         prev_pkey, priv->pkey);
+               /*
+                * Update the pkey in the broadcast address, while making sure to set
+                * the full membership bit, so that we join the right broadcast group.
+                */
+               priv->dev->broadcast[8] = priv->pkey >> 8;
+               priv->dev->broadcast[9] = priv->pkey & 0xff;
+               return 0;
+       }
+
+       return 1;
+}
+
 static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
                                enum ipoib_flush_level level)
 {
        struct ipoib_dev_priv *cpriv;
        struct net_device *dev = priv->dev;
        u16 new_index;
+       int result;
 
        mutex_lock(&priv->vlan_mutex);
 
@@ -951,6 +986,10 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
        mutex_unlock(&priv->vlan_mutex);
 
        if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) {
+               /* for non-child devices must check/update the pkey value here */
+               if (level == IPOIB_FLUSH_HEAVY &&
+                   !test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags))
+                       update_parent_pkey(priv);
                ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n");
                return;
        }
@@ -961,21 +1000,32 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
        }
 
        if (level == IPOIB_FLUSH_HEAVY) {
-               if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
-                       clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
-                       ipoib_ib_dev_down(dev, 0);
-                       ipoib_ib_dev_stop(dev, 0);
-                       if (ipoib_pkey_dev_delay_open(dev))
+               /* child devices chase their origin pkey value, while non-child
+                * (parent) devices should always takes what present in pkey index 0
+                */
+               if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
+                       if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
+                               clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
+                               ipoib_ib_dev_down(dev, 0);
+                               ipoib_ib_dev_stop(dev, 0);
+                               if (ipoib_pkey_dev_delay_open(dev))
+                                       return;
+                       }
+                       /* restart QP only if P_Key index is changed */
+                       if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
+                           new_index == priv->pkey_index) {
+                               ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
                                return;
+                       }
+                       priv->pkey_index = new_index;
+               } else {
+                       result = update_parent_pkey(priv);
+                       /* restart QP only if P_Key value changed */
+                       if (result) {
+                               ipoib_dbg(priv, "Not flushing - P_Key value not changed.\n");
+                               return;
+                       }
                }
-
-               /* restart QP only if P_Key index is changed */
-               if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
-                   new_index == priv->pkey_index) {
-                       ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
-                       return;
-               }
-               priv->pkey_index = new_index;
        }
 
        if (level == IPOIB_FLUSH_LIGHT) {
index b6e049a3c7a853b92d5c9d126c61a2d850f290cb..c6f71a88c55ca9649b6098cc81d64de229857055 100644 (file)
@@ -1461,7 +1461,7 @@ static ssize_t create_child(struct device *dev,
        if (sscanf(buf, "%i", &pkey) != 1)
                return -EINVAL;
 
-       if (pkey < 0 || pkey > 0xffff)
+       if (pkey <= 0 || pkey > 0xffff || pkey == 0x8000)
                return -EINVAL;
 
        /*
index 74685936c9482be96c09a09e5af6f314bdc2b741..f81abe16cf093d6c74ad31dd179f03f7dc90b997 100644 (file)
@@ -119,6 +119,15 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
        } else
                child_pkey  = nla_get_u16(data[IFLA_IPOIB_PKEY]);
 
+       if (child_pkey == 0 || child_pkey == 0x8000)
+               return -EINVAL;
+
+       /*
+        * Set the full membership bit, so that we join the right
+        * broadcast group, etc.
+        */
+       child_pkey |= 0x8000;
+
        err = __ipoib_vlan_add(ppriv, netdev_priv(dev), child_pkey, IPOIB_RTNL_CHILD);
 
        if (!err && data)
index 0b9a79b2f48aaded2397762ce500b032f25f77e1..82fc86a90c1a436d94ab8500334b62f4cce47dbc 100644 (file)
@@ -439,15 +439,15 @@ static void backside_setup_pid(void)
 
 /* Slots fan */
 static const struct wf_pid_param slots_param = {
-       .interval       = 5,
-       .history_len    = 2,
-       .gd             = 30 << 20,
-       .gp             = 5 << 20,
-       .gr             = 0,
-       .itarget        = 40 << 16,
-       .additive       = 1,
-       .min            = 300,
-       .max            = 4000,
+       .interval       = 1,
+       .history_len    = 20,
+       .gd             = 0,
+       .gp             = 0,
+       .gr             = 0x00100000,
+       .itarget        = 3200000,
+       .additive       = 0,
+       .min            = 20,
+       .max            = 100,
 };
 
 static void slots_fan_tick(void)
index 048f2947e08b1721a6ffab0de2ba5dd24d1a23de..e45f5575fd4dde8d2768daaa553ab57b9d0023b1 100644 (file)
 #include "bcache.h"
 #include "btree.h"
 
+#include <linux/freezer.h>
+#include <linux/kthread.h>
 #include <linux/random.h>
+#include <trace/events/bcache.h>
 
 #define MAX_IN_FLIGHT_DISCARDS         8U
 
@@ -151,7 +154,7 @@ static void discard_finish(struct work_struct *w)
        mutex_unlock(&ca->set->bucket_lock);
 
        closure_wake_up(&ca->set->bucket_wait);
-       wake_up(&ca->set->alloc_wait);
+       wake_up_process(ca->alloc_thread);
 
        closure_put(&ca->set->cl);
 }
@@ -350,38 +353,30 @@ static void invalidate_buckets(struct cache *ca)
                break;
        }
 
-       pr_debug("free %zu/%zu free_inc %zu/%zu unused %zu/%zu",
-                fifo_used(&ca->free), ca->free.size,
-                fifo_used(&ca->free_inc), ca->free_inc.size,
-                fifo_used(&ca->unused), ca->unused.size);
+       trace_bcache_alloc_invalidate(ca);
 }
 
 #define allocator_wait(ca, cond)                                       \
 do {                                                                   \
-       DEFINE_WAIT(__wait);                                            \
-                                                                       \
        while (1) {                                                     \
-               prepare_to_wait(&ca->set->alloc_wait,                   \
-                               &__wait, TASK_INTERRUPTIBLE);           \
+               set_current_state(TASK_INTERRUPTIBLE);                  \
                if (cond)                                               \
                        break;                                          \
                                                                        \
                mutex_unlock(&(ca)->set->bucket_lock);                  \
-               if (test_bit(CACHE_SET_STOPPING_2, &ca->set->flags)) {  \
-                       finish_wait(&ca->set->alloc_wait, &__wait);     \
-                       closure_return(cl);                             \
-               }                                                       \
+               if (kthread_should_stop())                              \
+                       return 0;                                       \
                                                                        \
+               try_to_freeze();                                        \
                schedule();                                             \
                mutex_lock(&(ca)->set->bucket_lock);                    \
        }                                                               \
-                                                                       \
-       finish_wait(&ca->set->alloc_wait, &__wait);                     \
+       __set_current_state(TASK_RUNNING);                              \
 } while (0)
 
-void bch_allocator_thread(struct closure *cl)
+static int bch_allocator_thread(void *arg)
 {
-       struct cache *ca = container_of(cl, struct cache, alloc);
+       struct cache *ca = arg;
 
        mutex_lock(&ca->set->bucket_lock);
 
@@ -442,7 +437,7 @@ long bch_bucket_alloc(struct cache *ca, unsigned watermark, struct closure *cl)
 {
        long r = -1;
 again:
-       wake_up(&ca->set->alloc_wait);
+       wake_up_process(ca->alloc_thread);
 
        if (fifo_used(&ca->free) > ca->watermark[watermark] &&
            fifo_pop(&ca->free, r)) {
@@ -476,9 +471,7 @@ again:
                return r;
        }
 
-       pr_debug("alloc failure: blocked %i free %zu free_inc %zu unused %zu",
-                atomic_read(&ca->set->prio_blocked), fifo_used(&ca->free),
-                fifo_used(&ca->free_inc), fifo_used(&ca->unused));
+       trace_bcache_alloc_fail(ca);
 
        if (cl) {
                closure_wait(&ca->set->bucket_wait, cl);
@@ -552,6 +545,17 @@ int bch_bucket_alloc_set(struct cache_set *c, unsigned watermark,
 
 /* Init */
 
+int bch_cache_allocator_start(struct cache *ca)
+{
+       struct task_struct *k = kthread_run(bch_allocator_thread,
+                                           ca, "bcache_allocator");
+       if (IS_ERR(k))
+               return PTR_ERR(k);
+
+       ca->alloc_thread = k;
+       return 0;
+}
+
 void bch_cache_allocator_exit(struct cache *ca)
 {
        struct discard *d;
index d3e15b42a4ab97655d989c3fe8240b09613acdc4..b39f6f0b45f27b89f29e580844e41d8d315d9c18 100644 (file)
 #define pr_fmt(fmt) "bcache: %s() " fmt "\n", __func__
 
 #include <linux/bio.h>
-#include <linux/blktrace_api.h>
 #include <linux/kobject.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
@@ -388,8 +387,6 @@ struct keybuf_key {
 typedef bool (keybuf_pred_fn)(struct keybuf *, struct bkey *);
 
 struct keybuf {
-       keybuf_pred_fn          *key_predicate;
-
        struct bkey             last_scanned;
        spinlock_t              lock;
 
@@ -437,9 +434,12 @@ struct bcache_device {
 
        /* If nonzero, we're detaching/unregistering from cache set */
        atomic_t                detaching;
+       int                     flush_done;
+
+       uint64_t                nr_stripes;
+       unsigned                stripe_size_bits;
+       atomic_t                *stripe_sectors_dirty;
 
-       atomic_long_t           sectors_dirty;
-       unsigned long           sectors_dirty_gc;
        unsigned long           sectors_dirty_last;
        long                    sectors_dirty_derivative;
 
@@ -531,6 +531,7 @@ struct cached_dev {
        unsigned                sequential_merge:1;
        unsigned                verify:1;
 
+       unsigned                partial_stripes_expensive:1;
        unsigned                writeback_metadata:1;
        unsigned                writeback_running:1;
        unsigned char           writeback_percent;
@@ -565,8 +566,7 @@ struct cache {
 
        unsigned                watermark[WATERMARK_MAX];
 
-       struct closure          alloc;
-       struct workqueue_struct *alloc_workqueue;
+       struct task_struct      *alloc_thread;
 
        struct closure          prio;
        struct prio_set         *disk_buckets;
@@ -664,13 +664,9 @@ struct gc_stat {
  * CACHE_SET_STOPPING always gets set first when we're closing down a cache set;
  * we'll continue to run normally for awhile with CACHE_SET_STOPPING set (i.e.
  * flushing dirty data).
- *
- * CACHE_SET_STOPPING_2 gets set at the last phase, when it's time to shut down
- * the allocation thread.
  */
 #define CACHE_SET_UNREGISTERING                0
 #define        CACHE_SET_STOPPING              1
-#define        CACHE_SET_STOPPING_2            2
 
 struct cache_set {
        struct closure          cl;
@@ -703,9 +699,6 @@ struct cache_set {
        /* For the btree cache */
        struct shrinker         shrink;
 
-       /* For the allocator itself */
-       wait_queue_head_t       alloc_wait;
-
        /* For the btree cache and anything allocation related */
        struct mutex            bucket_lock;
 
@@ -823,10 +816,9 @@ struct cache_set {
 
        /*
         * A btree node on disk could have too many bsets for an iterator to fit
-        * on the stack - this is a single element mempool for btree_read_work()
+        * on the stack - have to dynamically allocate them
         */
-       struct mutex            fill_lock;
-       struct btree_iter       *fill_iter;
+       mempool_t               *fill_iter;
 
        /*
         * btree_sort() is a merge sort and requires temporary space - single
@@ -834,6 +826,7 @@ struct cache_set {
         */
        struct mutex            sort_lock;
        struct bset             *sort;
+       unsigned                sort_crit_factor;
 
        /* List of buckets we're currently writing data to */
        struct list_head        data_buckets;
@@ -906,8 +899,6 @@ static inline unsigned local_clock_us(void)
        return local_clock() >> 10;
 }
 
-#define MAX_BSETS              4U
-
 #define BTREE_PRIO             USHRT_MAX
 #define INITIAL_PRIO           32768
 
@@ -1112,23 +1103,6 @@ static inline void __bkey_put(struct cache_set *c, struct bkey *k)
                atomic_dec_bug(&PTR_BUCKET(c, k, i)->pin);
 }
 
-/* Blktrace macros */
-
-#define blktrace_msg(c, fmt, ...)                                      \
-do {                                                                   \
-       struct request_queue *q = bdev_get_queue(c->bdev);              \
-       if (q)                                                          \
-               blk_add_trace_msg(q, fmt, ##__VA_ARGS__);               \
-} while (0)
-
-#define blktrace_msg_all(s, fmt, ...)                                  \
-do {                                                                   \
-       struct cache *_c;                                               \
-       unsigned i;                                                     \
-       for_each_cache(_c, (s), i)                                      \
-               blktrace_msg(_c, fmt, ##__VA_ARGS__);                   \
-} while (0)
-
 static inline void cached_dev_put(struct cached_dev *dc)
 {
        if (atomic_dec_and_test(&dc->count))
@@ -1173,10 +1147,16 @@ static inline uint8_t bucket_disk_gen(struct bucket *b)
        static struct kobj_attribute ksysfs_##n =                       \
                __ATTR(n, S_IWUSR|S_IRUSR, show, store)
 
-/* Forward declarations */
+static inline void wake_up_allocators(struct cache_set *c)
+{
+       struct cache *ca;
+       unsigned i;
+
+       for_each_cache(ca, c, i)
+               wake_up_process(ca->alloc_thread);
+}
 
-void bch_writeback_queue(struct cached_dev *);
-void bch_writeback_add(struct cached_dev *, unsigned);
+/* Forward declarations */
 
 void bch_count_io_errors(struct cache *, int, const char *);
 void bch_bbio_count_io_errors(struct cache_set *, struct bio *,
@@ -1193,7 +1173,6 @@ void bch_submit_bbio(struct bio *, struct cache_set *, struct bkey *, unsigned);
 uint8_t bch_inc_gen(struct cache *, struct bucket *);
 void bch_rescale_priorities(struct cache_set *, int);
 bool bch_bucket_add_unused(struct cache *, struct bucket *);
-void bch_allocator_thread(struct closure *);
 
 long bch_bucket_alloc(struct cache *, unsigned, struct closure *);
 void bch_bucket_free(struct cache_set *, struct bkey *);
@@ -1241,9 +1220,9 @@ void bch_cache_set_stop(struct cache_set *);
 struct cache_set *bch_cache_set_alloc(struct cache_sb *);
 void bch_btree_cache_free(struct cache_set *);
 int bch_btree_cache_alloc(struct cache_set *);
-void bch_cached_dev_writeback_init(struct cached_dev *);
 void bch_moving_init_cache_set(struct cache_set *);
 
+int bch_cache_allocator_start(struct cache *ca);
 void bch_cache_allocator_exit(struct cache *ca);
 int bch_cache_allocator_init(struct cache *ca);
 
index 1d27d3af32514055e7512a677395c709a713c28c..8010eed06a51c8320786a1c49463c98c8aa70555 100644 (file)
@@ -78,6 +78,7 @@ struct bkey *bch_keylist_pop(struct keylist *l)
 bool __bch_ptr_invalid(struct cache_set *c, int level, const struct bkey *k)
 {
        unsigned i;
+       char buf[80];
 
        if (level && (!KEY_PTRS(k) || !KEY_SIZE(k) || KEY_DIRTY(k)))
                goto bad;
@@ -102,7 +103,8 @@ bool __bch_ptr_invalid(struct cache_set *c, int level, const struct bkey *k)
 
        return false;
 bad:
-       cache_bug(c, "spotted bad key %s: %s", pkey(k), bch_ptr_status(c, k));
+       bch_bkey_to_text(buf, sizeof(buf), k);
+       cache_bug(c, "spotted bad key %s: %s", buf, bch_ptr_status(c, k));
        return true;
 }
 
@@ -162,10 +164,16 @@ bool bch_ptr_bad(struct btree *b, const struct bkey *k)
 #ifdef CONFIG_BCACHE_EDEBUG
 bug:
        mutex_unlock(&b->c->bucket_lock);
-       btree_bug(b,
+
+       {
+               char buf[80];
+
+               bch_bkey_to_text(buf, sizeof(buf), k);
+               btree_bug(b,
 "inconsistent pointer %s: bucket %zu pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
-                 pkey(k), PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin),
-                 g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
+                         buf, PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin),
+                         g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
+       }
        return true;
 #endif
 }
@@ -1084,33 +1092,39 @@ void bch_btree_sort_into(struct btree *b, struct btree *new)
        new->sets->size = 0;
 }
 
+#define SORT_CRIT      (4096 / sizeof(uint64_t))
+
 void bch_btree_sort_lazy(struct btree *b)
 {
-       if (b->nsets) {
-               unsigned i, j, keys = 0, total;
+       unsigned crit = SORT_CRIT;
+       int i;
 
-               for (i = 0; i <= b->nsets; i++)
-                       keys += b->sets[i].data->keys;
-
-               total = keys;
+       /* Don't sort if nothing to do */
+       if (!b->nsets)
+               goto out;
 
-               for (j = 0; j < b->nsets; j++) {
-                       if (keys * 2 < total ||
-                           keys < 1000) {
-                               bch_btree_sort_partial(b, j);
-                               return;
-                       }
+       /* If not a leaf node, always sort */
+       if (b->level) {
+               bch_btree_sort(b);
+               return;
+       }
 
-                       keys -= b->sets[j].data->keys;
-               }
+       for (i = b->nsets - 1; i >= 0; --i) {
+               crit *= b->c->sort_crit_factor;
 
-               /* Must sort if b->nsets == 3 or we'll overflow */
-               if (b->nsets >= (MAX_BSETS - 1) - b->level) {
-                       bch_btree_sort(b);
+               if (b->sets[i].data->keys < crit) {
+                       bch_btree_sort_partial(b, i);
                        return;
                }
        }
 
+       /* Sort if we'd overflow */
+       if (b->nsets + 1 == MAX_BSETS) {
+               bch_btree_sort(b);
+               return;
+       }
+
+out:
        bset_build_written_tree(b);
 }
 
index 57a9cff4154613900f31307ee33015527f953d87..ae115a253d7312f81422a4b162e2ca4952556a44 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _BCACHE_BSET_H
 #define _BCACHE_BSET_H
 
+#include <linux/slab.h>
+
 /*
  * BKEYS:
  *
 
 /* Btree key comparison/iteration */
 
+#define MAX_BSETS              4U
+
 struct btree_iter {
        size_t size, used;
        struct btree_iter_set {
index 7a5658f04e62092610b2144faab12ae5fa3976a0..ee372884c405444886671901e45c3834626f383a 100644 (file)
@@ -24,6 +24,7 @@
 #include "btree.h"
 #include "debug.h"
 #include "request.h"
+#include "writeback.h"
 
 #include <linux/slab.h>
 #include <linux/bitops.h>
@@ -134,44 +135,17 @@ static uint64_t btree_csum_set(struct btree *b, struct bset *i)
        return crc ^ 0xffffffffffffffffULL;
 }
 
-static void btree_bio_endio(struct bio *bio, int error)
+static void bch_btree_node_read_done(struct btree *b)
 {
-       struct closure *cl = bio->bi_private;
-       struct btree *b = container_of(cl, struct btree, io.cl);
-
-       if (error)
-               set_btree_node_io_error(b);
-
-       bch_bbio_count_io_errors(b->c, bio, error, (bio->bi_rw & WRITE)
-                                ? "writing btree" : "reading btree");
-       closure_put(cl);
-}
-
-static void btree_bio_init(struct btree *b)
-{
-       BUG_ON(b->bio);
-       b->bio = bch_bbio_alloc(b->c);
-
-       b->bio->bi_end_io       = btree_bio_endio;
-       b->bio->bi_private      = &b->io.cl;
-}
-
-void bch_btree_read_done(struct closure *cl)
-{
-       struct btree *b = container_of(cl, struct btree, io.cl);
-       struct bset *i = b->sets[0].data;
-       struct btree_iter *iter = b->c->fill_iter;
        const char *err = "bad btree header";
-       BUG_ON(b->nsets || b->written);
-
-       bch_bbio_free(b->bio, b->c);
-       b->bio = NULL;
+       struct bset *i = b->sets[0].data;
+       struct btree_iter *iter;
 
-       mutex_lock(&b->c->fill_lock);
+       iter = mempool_alloc(b->c->fill_iter, GFP_NOWAIT);
+       iter->size = b->c->sb.bucket_size / b->c->sb.block_size;
        iter->used = 0;
 
-       if (btree_node_io_error(b) ||
-           !i->seq)
+       if (!i->seq)
                goto err;
 
        for (;
@@ -228,17 +202,8 @@ void bch_btree_read_done(struct closure *cl)
        if (b->written < btree_blocks(b))
                bch_bset_init_next(b);
 out:
-
-       mutex_unlock(&b->c->fill_lock);
-
-       spin_lock(&b->c->btree_read_time_lock);
-       bch_time_stats_update(&b->c->btree_read_time, b->io_start_time);
-       spin_unlock(&b->c->btree_read_time_lock);
-
-       smp_wmb(); /* read_done is our write lock */
-       set_btree_node_read_done(b);
-
-       closure_return(cl);
+       mempool_free(iter, b->c->fill_iter);
+       return;
 err:
        set_btree_node_io_error(b);
        bch_cache_set_error(b->c, "%s at bucket %zu, block %zu, %u keys",
@@ -247,48 +212,69 @@ err:
        goto out;
 }
 
-void bch_btree_read(struct btree *b)
+static void btree_node_read_endio(struct bio *bio, int error)
+{
+       struct closure *cl = bio->bi_private;
+       closure_put(cl);
+}
+
+void bch_btree_node_read(struct btree *b)
 {
-       BUG_ON(b->nsets || b->written);
+       uint64_t start_time = local_clock();
+       struct closure cl;
+       struct bio *bio;
+
+       trace_bcache_btree_read(b);
+
+       closure_init_stack(&cl);
+
+       bio = bch_bbio_alloc(b->c);
+       bio->bi_rw      = REQ_META|READ_SYNC;
+       bio->bi_size    = KEY_SIZE(&b->key) << 9;
+       bio->bi_end_io  = btree_node_read_endio;
+       bio->bi_private = &cl;
+
+       bch_bio_map(bio, b->sets[0].data);
+
+       bch_submit_bbio(bio, b->c, &b->key, 0);
+       closure_sync(&cl);
 
-       if (!closure_trylock(&b->io.cl, &b->c->cl))
-               BUG();
+       if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+               set_btree_node_io_error(b);
 
-       b->io_start_time = local_clock();
+       bch_bbio_free(bio, b->c);
 
-       btree_bio_init(b);
-       b->bio->bi_rw   = REQ_META|READ_SYNC;
-       b->bio->bi_size = KEY_SIZE(&b->key) << 9;
+       if (btree_node_io_error(b))
+               goto err;
 
-       bch_bio_map(b->bio, b->sets[0].data);
+       bch_btree_node_read_done(b);
 
-       pr_debug("%s", pbtree(b));
-       trace_bcache_btree_read(b->bio);
-       bch_submit_bbio(b->bio, b->c, &b->key, 0);
+       spin_lock(&b->c->btree_read_time_lock);
+       bch_time_stats_update(&b->c->btree_read_time, start_time);
+       spin_unlock(&b->c->btree_read_time_lock);
 
-       continue_at(&b->io.cl, bch_btree_read_done, system_wq);
+       return;
+err:
+       bch_cache_set_error(b->c, "io error reading bucket %lu",
+                           PTR_BUCKET_NR(b->c, &b->key, 0));
 }
 
 static void btree_complete_write(struct btree *b, struct btree_write *w)
 {
        if (w->prio_blocked &&
            !atomic_sub_return(w->prio_blocked, &b->c->prio_blocked))
-               wake_up(&b->c->alloc_wait);
+               wake_up_allocators(b->c);
 
        if (w->journal) {
                atomic_dec_bug(w->journal);
                __closure_wake_up(&b->c->journal.wait);
        }
 
-       if (w->owner)
-               closure_put(w->owner);
-
        w->prio_blocked = 0;
        w->journal      = NULL;
-       w->owner        = NULL;
 }
 
-static void __btree_write_done(struct closure *cl)
+static void __btree_node_write_done(struct closure *cl)
 {
        struct btree *b = container_of(cl, struct btree, io.cl);
        struct btree_write *w = btree_prev_write(b);
@@ -304,7 +290,7 @@ static void __btree_write_done(struct closure *cl)
        closure_return(cl);
 }
 
-static void btree_write_done(struct closure *cl)
+static void btree_node_write_done(struct closure *cl)
 {
        struct btree *b = container_of(cl, struct btree, io.cl);
        struct bio_vec *bv;
@@ -313,10 +299,22 @@ static void btree_write_done(struct closure *cl)
        __bio_for_each_segment(bv, b->bio, n, 0)
                __free_page(bv->bv_page);
 
-       __btree_write_done(cl);
+       __btree_node_write_done(cl);
 }
 
-static void do_btree_write(struct btree *b)
+static void btree_node_write_endio(struct bio *bio, int error)
+{
+       struct closure *cl = bio->bi_private;
+       struct btree *b = container_of(cl, struct btree, io.cl);
+
+       if (error)
+               set_btree_node_io_error(b);
+
+       bch_bbio_count_io_errors(b->c, bio, error, "writing btree");
+       closure_put(cl);
+}
+
+static void do_btree_node_write(struct btree *b)
 {
        struct closure *cl = &b->io.cl;
        struct bset *i = b->sets[b->nsets].data;
@@ -325,15 +323,34 @@ static void do_btree_write(struct btree *b)
        i->version      = BCACHE_BSET_VERSION;
        i->csum         = btree_csum_set(b, i);
 
-       btree_bio_init(b);
-       b->bio->bi_rw   = REQ_META|WRITE_SYNC;
-       b->bio->bi_size = set_blocks(i, b->c) * block_bytes(b->c);
+       BUG_ON(b->bio);
+       b->bio = bch_bbio_alloc(b->c);
+
+       b->bio->bi_end_io       = btree_node_write_endio;
+       b->bio->bi_private      = &b->io.cl;
+       b->bio->bi_rw           = REQ_META|WRITE_SYNC|REQ_FUA;
+       b->bio->bi_size         = set_blocks(i, b->c) * block_bytes(b->c);
        bch_bio_map(b->bio, i);
 
+       /*
+        * If we're appending to a leaf node, we don't technically need FUA -
+        * this write just needs to be persisted before the next journal write,
+        * which will be marked FLUSH|FUA.
+        *
+        * Similarly if we're writing a new btree root - the pointer is going to
+        * be in the next journal entry.
+        *
+        * But if we're writing a new btree node (that isn't a root) or
+        * appending to a non leaf btree node, we need either FUA or a flush
+        * when we write the parent with the new pointer. FUA is cheaper than a
+        * flush, and writes appending to leaf nodes aren't blocking anything so
+        * just make all btree node writes FUA to keep things sane.
+        */
+
        bkey_copy(&k.key, &b->key);
        SET_PTR_OFFSET(&k.key, 0, PTR_OFFSET(&k.key, 0) + bset_offset(b, i));
 
-       if (!bch_bio_alloc_pages(b->bio, GFP_NOIO)) {
+       if (!bio_alloc_pages(b->bio, GFP_NOIO)) {
                int j;
                struct bio_vec *bv;
                void *base = (void *) ((unsigned long) i & ~(PAGE_SIZE - 1));
@@ -342,40 +359,41 @@ static void do_btree_write(struct btree *b)
                        memcpy(page_address(bv->bv_page),
                               base + j * PAGE_SIZE, PAGE_SIZE);
 
-               trace_bcache_btree_write(b->bio);
                bch_submit_bbio(b->bio, b->c, &k.key, 0);
 
-               continue_at(cl, btree_write_done, NULL);
+               continue_at(cl, btree_node_write_done, NULL);
        } else {
                b->bio->bi_vcnt = 0;
                bch_bio_map(b->bio, i);
 
-               trace_bcache_btree_write(b->bio);
                bch_submit_bbio(b->bio, b->c, &k.key, 0);
 
                closure_sync(cl);
-               __btree_write_done(cl);
+               __btree_node_write_done(cl);
        }
 }
 
-static void __btree_write(struct btree *b)
+void bch_btree_node_write(struct btree *b, struct closure *parent)
 {
        struct bset *i = b->sets[b->nsets].data;
 
+       trace_bcache_btree_write(b);
+
        BUG_ON(current->bio_list);
+       BUG_ON(b->written >= btree_blocks(b));
+       BUG_ON(b->written && !i->keys);
+       BUG_ON(b->sets->data->seq != i->seq);
+       bch_check_key_order(b, i);
 
-       closure_lock(&b->io, &b->c->cl);
        cancel_delayed_work(&b->work);
 
+       /* If caller isn't waiting for write, parent refcount is cache set */
+       closure_lock(&b->io, parent ?: &b->c->cl);
+
        clear_bit(BTREE_NODE_dirty,      &b->flags);
        change_bit(BTREE_NODE_write_idx, &b->flags);
 
-       bch_check_key_order(b, i);
-       BUG_ON(b->written && !i->keys);
-
-       do_btree_write(b);
-
-       pr_debug("%s block %i keys %i", pbtree(b), b->written, i->keys);
+       do_btree_node_write(b);
 
        b->written += set_blocks(i, b->c);
        atomic_long_add(set_blocks(i, b->c) * b->c->sb.block_size,
@@ -387,37 +405,31 @@ static void __btree_write(struct btree *b)
                bch_bset_init_next(b);
 }
 
-static void btree_write_work(struct work_struct *w)
+static void btree_node_write_work(struct work_struct *w)
 {
        struct btree *b = container_of(to_delayed_work(w), struct btree, work);
 
-       down_write(&b->lock);
+       rw_lock(true, b, b->level);
 
        if (btree_node_dirty(b))
-               __btree_write(b);
-       up_write(&b->lock);
+               bch_btree_node_write(b, NULL);
+       rw_unlock(true, b);
 }
 
-void bch_btree_write(struct btree *b, bool now, struct btree_op *op)
+static void bch_btree_leaf_dirty(struct btree *b, struct btree_op *op)
 {
        struct bset *i = b->sets[b->nsets].data;
        struct btree_write *w = btree_current_write(b);
 
-       BUG_ON(b->written &&
-              (b->written >= btree_blocks(b) ||
-               i->seq != b->sets[0].data->seq ||
-               !i->keys));
+       BUG_ON(!b->written);
+       BUG_ON(!i->keys);
 
-       if (!btree_node_dirty(b)) {
-               set_btree_node_dirty(b);
-               queue_delayed_work(btree_io_wq, &b->work,
-                                  msecs_to_jiffies(30000));
-       }
+       if (!btree_node_dirty(b))
+               queue_delayed_work(btree_io_wq, &b->work, 30 * HZ);
 
-       w->prio_blocked += b->prio_blocked;
-       b->prio_blocked = 0;
+       set_btree_node_dirty(b);
 
-       if (op && op->journal && !b->level) {
+       if (op && op->journal) {
                if (w->journal &&
                    journal_pin_cmp(b->c, w, op)) {
                        atomic_dec_bug(w->journal);
@@ -430,23 +442,10 @@ void bch_btree_write(struct btree *b, bool now, struct btree_op *op)
                }
        }
 
-       if (current->bio_list)
-               return;
-
        /* Force write if set is too big */
-       if (now ||
-           b->level ||
-           set_bytes(i) > PAGE_SIZE - 48) {
-               if (op && now) {
-                       /* Must wait on multiple writes */
-                       BUG_ON(w->owner);
-                       w->owner = &op->cl;
-                       closure_get(&op->cl);
-               }
-
-               __btree_write(b);
-       }
-       BUG_ON(!b->written);
+       if (set_bytes(i) > PAGE_SIZE - 48 &&
+           !current->bio_list)
+               bch_btree_node_write(b, NULL);
 }
 
 /*
@@ -559,7 +558,7 @@ static struct btree *mca_bucket_alloc(struct cache_set *c,
        init_rwsem(&b->lock);
        lockdep_set_novalidate_class(&b->lock);
        INIT_LIST_HEAD(&b->list);
-       INIT_DELAYED_WORK(&b->work, btree_write_work);
+       INIT_DELAYED_WORK(&b->work, btree_node_write_work);
        b->c = c;
        closure_init_unlocked(&b->io);
 
@@ -582,7 +581,7 @@ static int mca_reap(struct btree *b, struct closure *cl, unsigned min_order)
        BUG_ON(btree_node_dirty(b) && !b->sets[0].data);
 
        if (cl && btree_node_dirty(b))
-               bch_btree_write(b, true, NULL);
+               bch_btree_node_write(b, NULL);
 
        if (cl)
                closure_wait_event_async(&b->io.wait, cl,
@@ -623,6 +622,13 @@ static int bch_mca_shrink(struct shrinker *shrink, struct shrink_control *sc)
        else if (!mutex_trylock(&c->bucket_lock))
                return -1;
 
+       /*
+        * It's _really_ critical that we don't free too many btree nodes - we
+        * have to always leave ourselves a reserve. The reserve is how we
+        * guarantee that allocating memory for a new btree node can always
+        * succeed, so that inserting keys into the btree can always succeed and
+        * IO can always make forward progress:
+        */
        nr /= c->btree_pages;
        nr = min_t(unsigned long, nr, mca_can_free(c));
 
@@ -766,6 +772,8 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k,
        int ret = -ENOMEM;
        struct btree *i;
 
+       trace_bcache_btree_cache_cannibalize(c);
+
        if (!cl)
                return ERR_PTR(-ENOMEM);
 
@@ -784,7 +792,6 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k,
                return ERR_PTR(-EAGAIN);
        }
 
-       /* XXX: tracepoint */
        c->try_harder = cl;
        c->try_harder_start = local_clock();
 retry:
@@ -905,6 +912,9 @@ retry:
        b = mca_find(c, k);
 
        if (!b) {
+               if (current->bio_list)
+                       return ERR_PTR(-EAGAIN);
+
                mutex_lock(&c->bucket_lock);
                b = mca_alloc(c, k, level, &op->cl);
                mutex_unlock(&c->bucket_lock);
@@ -914,7 +924,7 @@ retry:
                if (IS_ERR(b))
                        return b;
 
-               bch_btree_read(b);
+               bch_btree_node_read(b);
 
                if (!write)
                        downgrade_write(&b->lock);
@@ -937,15 +947,12 @@ retry:
        for (; i <= b->nsets; i++)
                prefetch(b->sets[i].data);
 
-       if (!closure_wait_event(&b->io.wait, &op->cl,
-                               btree_node_read_done(b))) {
-               rw_unlock(write, b);
-               b = ERR_PTR(-EAGAIN);
-       } else if (btree_node_io_error(b)) {
+       if (btree_node_io_error(b)) {
                rw_unlock(write, b);
-               b = ERR_PTR(-EIO);
-       } else
-               BUG_ON(!b->written);
+               return ERR_PTR(-EIO);
+       }
+
+       BUG_ON(!b->written);
 
        return b;
 }
@@ -959,7 +966,7 @@ static void btree_node_prefetch(struct cache_set *c, struct bkey *k, int level)
        mutex_unlock(&c->bucket_lock);
 
        if (!IS_ERR_OR_NULL(b)) {
-               bch_btree_read(b);
+               bch_btree_node_read(b);
                rw_unlock(true, b);
        }
 }
@@ -970,24 +977,19 @@ static void btree_node_free(struct btree *b, struct btree_op *op)
 {
        unsigned i;
 
+       trace_bcache_btree_node_free(b);
+
        /*
         * The BUG_ON() in btree_node_get() implies that we must have a write
         * lock on parent to free or even invalidate a node
         */
        BUG_ON(op->lock <= b->level);
        BUG_ON(b == b->c->root);
-       pr_debug("bucket %s", pbtree(b));
 
        if (btree_node_dirty(b))
                btree_complete_write(b, btree_current_write(b));
        clear_bit(BTREE_NODE_dirty, &b->flags);
 
-       if (b->prio_blocked &&
-           !atomic_sub_return(b->prio_blocked, &b->c->prio_blocked))
-               wake_up(&b->c->alloc_wait);
-
-       b->prio_blocked = 0;
-
        cancel_delayed_work(&b->work);
 
        mutex_lock(&b->c->bucket_lock);
@@ -1028,17 +1030,20 @@ retry:
                goto retry;
        }
 
-       set_btree_node_read_done(b);
        b->accessed = 1;
        bch_bset_init_next(b);
 
        mutex_unlock(&c->bucket_lock);
+
+       trace_bcache_btree_node_alloc(b);
        return b;
 err_free:
        bch_bucket_free(c, &k.key);
        __bkey_put(c, &k.key);
 err:
        mutex_unlock(&c->bucket_lock);
+
+       trace_bcache_btree_node_alloc_fail(b);
        return b;
 }
 
@@ -1137,11 +1142,8 @@ static int btree_gc_mark_node(struct btree *b, unsigned *keys,
                gc->nkeys++;
 
                gc->data += KEY_SIZE(k);
-               if (KEY_DIRTY(k)) {
+               if (KEY_DIRTY(k))
                        gc->dirty += KEY_SIZE(k);
-                       if (d)
-                               d->sectors_dirty_gc += KEY_SIZE(k);
-               }
        }
 
        for (t = b->sets; t <= &b->sets[b->nsets]; t++)
@@ -1166,14 +1168,11 @@ static struct btree *btree_gc_alloc(struct btree *b, struct bkey *k,
 
        if (!IS_ERR_OR_NULL(n)) {
                swap(b, n);
+               __bkey_put(b->c, &b->key);
 
                memcpy(k->ptr, b->key.ptr,
                       sizeof(uint64_t) * KEY_PTRS(&b->key));
 
-               __bkey_put(b->c, &b->key);
-               atomic_inc(&b->c->prio_blocked);
-               b->prio_blocked++;
-
                btree_node_free(n, op);
                up_write(&n->lock);
        }
@@ -1278,7 +1277,7 @@ static void btree_gc_coalesce(struct btree *b, struct btree_op *op,
        btree_node_free(r->b, op);
        up_write(&r->b->lock);
 
-       pr_debug("coalesced %u nodes", nodes);
+       trace_bcache_btree_gc_coalesce(nodes);
 
        gc->nodes--;
        nodes--;
@@ -1293,14 +1292,9 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
        void write(struct btree *r)
        {
                if (!r->written)
-                       bch_btree_write(r, true, op);
-               else if (btree_node_dirty(r)) {
-                       BUG_ON(btree_current_write(r)->owner);
-                       btree_current_write(r)->owner = writes;
-                       closure_get(writes);
-
-                       bch_btree_write(r, true, NULL);
-               }
+                       bch_btree_node_write(r, &op->cl);
+               else if (btree_node_dirty(r))
+                       bch_btree_node_write(r, writes);
 
                up_write(&r->lock);
        }
@@ -1386,9 +1380,7 @@ static int bch_btree_gc_root(struct btree *b, struct btree_op *op,
                ret = btree_gc_recurse(b, op, writes, gc);
 
        if (!b->written || btree_node_dirty(b)) {
-               atomic_inc(&b->c->prio_blocked);
-               b->prio_blocked++;
-               bch_btree_write(b, true, n ? op : NULL);
+               bch_btree_node_write(b, n ? &op->cl : NULL);
        }
 
        if (!IS_ERR_OR_NULL(n)) {
@@ -1405,7 +1397,6 @@ static void btree_gc_start(struct cache_set *c)
 {
        struct cache *ca;
        struct bucket *b;
-       struct bcache_device **d;
        unsigned i;
 
        if (!c->gc_mark_valid)
@@ -1419,16 +1410,12 @@ static void btree_gc_start(struct cache_set *c)
        for_each_cache(ca, c, i)
                for_each_bucket(b, ca) {
                        b->gc_gen = b->gen;
-                       if (!atomic_read(&b->pin))
+                       if (!atomic_read(&b->pin)) {
                                SET_GC_MARK(b, GC_MARK_RECLAIMABLE);
+                               SET_GC_SECTORS_USED(b, 0);
+                       }
                }
 
-       for (d = c->devices;
-            d < c->devices + c->nr_uuids;
-            d++)
-               if (*d)
-                       (*d)->sectors_dirty_gc = 0;
-
        mutex_unlock(&c->bucket_lock);
 }
 
@@ -1437,7 +1424,6 @@ size_t bch_btree_gc_finish(struct cache_set *c)
        size_t available = 0;
        struct bucket *b;
        struct cache *ca;
-       struct bcache_device **d;
        unsigned i;
 
        mutex_lock(&c->bucket_lock);
@@ -1480,22 +1466,6 @@ size_t bch_btree_gc_finish(struct cache_set *c)
                }
        }
 
-       for (d = c->devices;
-            d < c->devices + c->nr_uuids;
-            d++)
-               if (*d) {
-                       unsigned long last =
-                               atomic_long_read(&((*d)->sectors_dirty));
-                       long difference = (*d)->sectors_dirty_gc - last;
-
-                       pr_debug("sectors dirty off by %li", difference);
-
-                       (*d)->sectors_dirty_last += difference;
-
-                       atomic_long_set(&((*d)->sectors_dirty),
-                                       (*d)->sectors_dirty_gc);
-               }
-
        mutex_unlock(&c->bucket_lock);
        return available;
 }
@@ -1508,10 +1478,9 @@ static void bch_btree_gc(struct closure *cl)
        struct gc_stat stats;
        struct closure writes;
        struct btree_op op;
-
        uint64_t start_time = local_clock();
-       trace_bcache_gc_start(c->sb.set_uuid);
-       blktrace_msg_all(c, "Starting gc");
+
+       trace_bcache_gc_start(c);
 
        memset(&stats, 0, sizeof(struct gc_stat));
        closure_init_stack(&writes);
@@ -1520,14 +1489,14 @@ static void bch_btree_gc(struct closure *cl)
 
        btree_gc_start(c);
 
+       atomic_inc(&c->prio_blocked);
+
        ret = btree_root(gc_root, c, &op, &writes, &stats);
        closure_sync(&op.cl);
        closure_sync(&writes);
 
        if (ret) {
-               blktrace_msg_all(c, "Stopped gc");
                pr_warn("gc failed!");
-
                continue_at(cl, bch_btree_gc, bch_gc_wq);
        }
 
@@ -1537,6 +1506,9 @@ static void bch_btree_gc(struct closure *cl)
 
        available = bch_btree_gc_finish(c);
 
+       atomic_dec(&c->prio_blocked);
+       wake_up_allocators(c);
+
        bch_time_stats_update(&c->btree_gc_time, start_time);
 
        stats.key_bytes *= sizeof(uint64_t);
@@ -1544,10 +1516,8 @@ static void bch_btree_gc(struct closure *cl)
        stats.data      <<= 9;
        stats.in_use    = (c->nbuckets - available) * 100 / c->nbuckets;
        memcpy(&c->gc_stats, &stats, sizeof(struct gc_stat));
-       blktrace_msg_all(c, "Finished gc");
 
-       trace_bcache_gc_end(c->sb.set_uuid);
-       wake_up(&c->alloc_wait);
+       trace_bcache_gc_end(c);
 
        continue_at(cl, bch_moving_gc, bch_gc_wq);
 }
@@ -1654,14 +1624,14 @@ static bool fix_overlapping_extents(struct btree *b,
                                    struct btree_iter *iter,
                                    struct btree_op *op)
 {
-       void subtract_dirty(struct bkey *k, int sectors)
+       void subtract_dirty(struct bkey *k, uint64_t offset, int sectors)
        {
-               struct bcache_device *d = b->c->devices[KEY_INODE(k)];
-
-               if (KEY_DIRTY(k) && d)
-                       atomic_long_sub(sectors, &d->sectors_dirty);
+               if (KEY_DIRTY(k))
+                       bcache_dev_sectors_dirty_add(b->c, KEY_INODE(k),
+                                                    offset, -sectors);
        }
 
+       uint64_t old_offset;
        unsigned old_size, sectors_found = 0;
 
        while (1) {
@@ -1673,6 +1643,7 @@ static bool fix_overlapping_extents(struct btree *b,
                if (bkey_cmp(k, &START_KEY(insert)) <= 0)
                        continue;
 
+               old_offset = KEY_START(k);
                old_size = KEY_SIZE(k);
 
                /*
@@ -1728,7 +1699,7 @@ static bool fix_overlapping_extents(struct btree *b,
 
                        struct bkey *top;
 
-                       subtract_dirty(k, KEY_SIZE(insert));
+                       subtract_dirty(k, KEY_START(insert), KEY_SIZE(insert));
 
                        if (bkey_written(b, k)) {
                                /*
@@ -1775,7 +1746,7 @@ static bool fix_overlapping_extents(struct btree *b,
                        }
                }
 
-               subtract_dirty(k, old_size - KEY_SIZE(k));
+               subtract_dirty(k, old_offset, old_size - KEY_SIZE(k));
        }
 
 check_failed:
@@ -1798,7 +1769,7 @@ static bool btree_insert_key(struct btree *b, struct btree_op *op,
 {
        struct bset *i = b->sets[b->nsets].data;
        struct bkey *m, *prev;
-       const char *status = "insert";
+       unsigned status = BTREE_INSERT_STATUS_INSERT;
 
        BUG_ON(bkey_cmp(k, &b->key) > 0);
        BUG_ON(b->level && !KEY_PTRS(k));
@@ -1831,17 +1802,17 @@ static bool btree_insert_key(struct btree *b, struct btree_op *op,
                        goto insert;
 
                /* prev is in the tree, if we merge we're done */
-               status = "back merging";
+               status = BTREE_INSERT_STATUS_BACK_MERGE;
                if (prev &&
                    bch_bkey_try_merge(b, prev, k))
                        goto merged;
 
-               status = "overwrote front";
+               status = BTREE_INSERT_STATUS_OVERWROTE;
                if (m != end(i) &&
                    KEY_PTRS(m) == KEY_PTRS(k) && !KEY_SIZE(m))
                        goto copy;
 
-               status = "front merge";
+               status = BTREE_INSERT_STATUS_FRONT_MERGE;
                if (m != end(i) &&
                    bch_bkey_try_merge(b, k, m))
                        goto copy;
@@ -1851,21 +1822,21 @@ static bool btree_insert_key(struct btree *b, struct btree_op *op,
 insert:        shift_keys(b, m, k);
 copy:  bkey_copy(m, k);
 merged:
-       bch_check_keys(b, "%s for %s at %s: %s", status,
-                      op_type(op), pbtree(b), pkey(k));
-       bch_check_key_order_msg(b, i, "%s for %s at %s: %s", status,
-                               op_type(op), pbtree(b), pkey(k));
+       if (KEY_DIRTY(k))
+               bcache_dev_sectors_dirty_add(b->c, KEY_INODE(k),
+                                            KEY_START(k), KEY_SIZE(k));
+
+       bch_check_keys(b, "%u for %s", status, op_type(op));
 
        if (b->level && !KEY_OFFSET(k))
-               b->prio_blocked++;
+               btree_current_write(b)->prio_blocked++;
 
-       pr_debug("%s for %s at %s: %s", status,
-                op_type(op), pbtree(b), pkey(k));
+       trace_bcache_btree_insert_key(b, k, op->type, status);
 
        return true;
 }
 
-bool bch_btree_insert_keys(struct btree *b, struct btree_op *op)
+static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op)
 {
        bool ret = false;
        struct bkey *k;
@@ -1896,7 +1867,7 @@ bool bch_btree_insert_check_key(struct btree *b, struct btree_op *op,
            should_split(b))
                goto out;
 
-       op->replace = KEY(op->inode, bio_end(bio), bio_sectors(bio));
+       op->replace = KEY(op->inode, bio_end_sector(bio), bio_sectors(bio));
 
        SET_KEY_PTRS(&op->replace, 1);
        get_random_bytes(&op->replace.ptr[0], sizeof(uint64_t));
@@ -1907,7 +1878,6 @@ bool bch_btree_insert_check_key(struct btree *b, struct btree_op *op,
 
        BUG_ON(op->type != BTREE_INSERT);
        BUG_ON(!btree_insert_key(b, op, &tmp.k));
-       bch_btree_write(b, false, NULL);
        ret = true;
 out:
        downgrade_write(&b->lock);
@@ -1929,12 +1899,11 @@ static int btree_split(struct btree *b, struct btree_op *op)
 
        split = set_blocks(n1->sets[0].data, n1->c) > (btree_blocks(b) * 4) / 5;
 
-       pr_debug("%ssplitting at %s keys %i", split ? "" : "not ",
-                pbtree(b), n1->sets[0].data->keys);
-
        if (split) {
                unsigned keys = 0;
 
+               trace_bcache_btree_node_split(b, n1->sets[0].data->keys);
+
                n2 = bch_btree_node_alloc(b->c, b->level, &op->cl);
                if (IS_ERR(n2))
                        goto err_free1;
@@ -1967,18 +1936,21 @@ static int btree_split(struct btree *b, struct btree_op *op)
                bkey_copy_key(&n2->key, &b->key);
 
                bch_keylist_add(&op->keys, &n2->key);
-               bch_btree_write(n2, true, op);
+               bch_btree_node_write(n2, &op->cl);
                rw_unlock(true, n2);
-       } else
+       } else {
+               trace_bcache_btree_node_compact(b, n1->sets[0].data->keys);
+
                bch_btree_insert_keys(n1, op);
+       }
 
        bch_keylist_add(&op->keys, &n1->key);
-       bch_btree_write(n1, true, op);
+       bch_btree_node_write(n1, &op->cl);
 
        if (n3) {
                bkey_copy_key(&n3->key, &MAX_KEY);
                bch_btree_insert_keys(n3, op);
-               bch_btree_write(n3, true, op);
+               bch_btree_node_write(n3, &op->cl);
 
                closure_sync(&op->cl);
                bch_btree_set_root(n3);
@@ -2082,8 +2054,12 @@ static int bch_btree_insert_recurse(struct btree *b, struct btree_op *op,
 
                BUG_ON(write_block(b) != b->sets[b->nsets].data);
 
-               if (bch_btree_insert_keys(b, op))
-                       bch_btree_write(b, false, op);
+               if (bch_btree_insert_keys(b, op)) {
+                       if (!b->level)
+                               bch_btree_leaf_dirty(b, op);
+                       else
+                               bch_btree_node_write(b, &op->cl);
+               }
        }
 
        return 0;
@@ -2140,6 +2116,11 @@ int bch_btree_insert(struct btree_op *op, struct cache_set *c)
 void bch_btree_set_root(struct btree *b)
 {
        unsigned i;
+       struct closure cl;
+
+       closure_init_stack(&cl);
+
+       trace_bcache_btree_set_root(b);
 
        BUG_ON(!b->written);
 
@@ -2153,8 +2134,8 @@ void bch_btree_set_root(struct btree *b)
        b->c->root = b;
        __bkey_put(b->c, &b->key);
 
-       bch_journal_meta(b->c, NULL);
-       pr_debug("%s for %pf", pbtree(b), __builtin_return_address(0));
+       bch_journal_meta(b->c, &cl);
+       closure_sync(&cl);
 }
 
 /* Cache lookup */
@@ -2215,9 +2196,6 @@ static int submit_partial_cache_hit(struct btree *b, struct btree_op *op,
                                         KEY_OFFSET(k) - bio->bi_sector);
 
                n = bch_bio_split(bio, sectors, GFP_NOIO, s->d->bio_split);
-               if (!n)
-                       return -EAGAIN;
-
                if (n == bio)
                        op->lookup_done = true;
 
@@ -2240,7 +2218,6 @@ static int submit_partial_cache_hit(struct btree *b, struct btree_op *op,
                n->bi_end_io    = bch_cache_read_endio;
                n->bi_private   = &s->cl;
 
-               trace_bcache_cache_hit(n);
                __bch_submit_bbio(n, b->c);
        }
 
@@ -2257,9 +2234,6 @@ int bch_btree_search_recurse(struct btree *b, struct btree_op *op)
        struct btree_iter iter;
        bch_btree_iter_init(b, &iter, &KEY(op->inode, bio->bi_sector, 0));
 
-       pr_debug("at %s searching for %u:%llu", pbtree(b), op->inode,
-                (uint64_t) bio->bi_sector);
-
        do {
                k = bch_btree_iter_next_filter(&iter, b, bch_ptr_bad);
                if (!k) {
@@ -2303,7 +2277,8 @@ static inline int keybuf_nonoverlapping_cmp(struct keybuf_key *l,
 }
 
 static int bch_btree_refill_keybuf(struct btree *b, struct btree_op *op,
-                                  struct keybuf *buf, struct bkey *end)
+                                  struct keybuf *buf, struct bkey *end,
+                                  keybuf_pred_fn *pred)
 {
        struct btree_iter iter;
        bch_btree_iter_init(b, &iter, &buf->last_scanned);
@@ -2322,11 +2297,9 @@ static int bch_btree_refill_keybuf(struct btree *b, struct btree_op *op,
                        if (bkey_cmp(&buf->last_scanned, end) >= 0)
                                break;
 
-                       if (buf->key_predicate(buf, k)) {
+                       if (pred(buf, k)) {
                                struct keybuf_key *w;
 
-                               pr_debug("%s", pkey(k));
-
                                spin_lock(&buf->lock);
 
                                w = array_alloc(&buf->freelist);
@@ -2343,7 +2316,7 @@ static int bch_btree_refill_keybuf(struct btree *b, struct btree_op *op,
                        if (!k)
                                break;
 
-                       btree(refill_keybuf, k, b, op, buf, end);
+                       btree(refill_keybuf, k, b, op, buf, end, pred);
                        /*
                         * Might get an error here, but can't really do anything
                         * and it'll get logged elsewhere. Just read what we
@@ -2361,7 +2334,7 @@ static int bch_btree_refill_keybuf(struct btree *b, struct btree_op *op,
 }
 
 void bch_refill_keybuf(struct cache_set *c, struct keybuf *buf,
-                         struct bkey *end)
+                      struct bkey *end, keybuf_pred_fn *pred)
 {
        struct bkey start = buf->last_scanned;
        struct btree_op op;
@@ -2369,7 +2342,7 @@ void bch_refill_keybuf(struct cache_set *c, struct keybuf *buf,
 
        cond_resched();
 
-       btree_root(refill_keybuf, c, &op, buf, end);
+       btree_root(refill_keybuf, c, &op, buf, end, pred);
        closure_sync(&op.cl);
 
        pr_debug("found %s keys from %llu:%llu to %llu:%llu",
@@ -2455,7 +2428,8 @@ struct keybuf_key *bch_keybuf_next(struct keybuf *buf)
 
 struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *c,
                                             struct keybuf *buf,
-                                            struct bkey *end)
+                                            struct bkey *end,
+                                            keybuf_pred_fn *pred)
 {
        struct keybuf_key *ret;
 
@@ -2469,15 +2443,14 @@ struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *c,
                        break;
                }
 
-               bch_refill_keybuf(c, buf, end);
+               bch_refill_keybuf(c, buf, end, pred);
        }
 
        return ret;
 }
 
-void bch_keybuf_init(struct keybuf *buf, keybuf_pred_fn *fn)
+void bch_keybuf_init(struct keybuf *buf)
 {
-       buf->key_predicate      = fn;
        buf->last_scanned       = MAX_KEY;
        buf->keys               = RB_ROOT;
 
index af4a7092a28c89d47bf2b4165312b7988f1921a6..3333d3723633c424e0a22d51d7475969392c1130 100644 (file)
 #include "debug.h"
 
 struct btree_write {
-       struct closure          *owner;
        atomic_t                *journal;
 
        /* If btree_split() frees a btree node, it writes a new pointer to that
@@ -142,16 +141,12 @@ struct btree {
         */
        struct bset_tree        sets[MAX_BSETS];
 
-       /* Used to refcount bio splits, also protects b->bio */
+       /* For outstanding btree writes, used as a lock - protects write_idx */
        struct closure_with_waitlist    io;
 
-       /* Gets transferred to w->prio_blocked - see the comment there */
-       int                     prio_blocked;
-
        struct list_head        list;
        struct delayed_work     work;
 
-       uint64_t                io_start_time;
        struct btree_write      writes[2];
        struct bio              *bio;
 };
@@ -164,13 +159,11 @@ static inline void set_btree_node_ ## flag(struct btree *b)               \
 {      set_bit(BTREE_NODE_ ## flag, &b->flags); }                      \
 
 enum btree_flags {
-       BTREE_NODE_read_done,
        BTREE_NODE_io_error,
        BTREE_NODE_dirty,
        BTREE_NODE_write_idx,
 };
 
-BTREE_FLAG(read_done);
 BTREE_FLAG(io_error);
 BTREE_FLAG(dirty);
 BTREE_FLAG(write_idx);
@@ -278,6 +271,13 @@ struct btree_op {
        BKEY_PADDED(replace);
 };
 
+enum {
+       BTREE_INSERT_STATUS_INSERT,
+       BTREE_INSERT_STATUS_BACK_MERGE,
+       BTREE_INSERT_STATUS_OVERWROTE,
+       BTREE_INSERT_STATUS_FRONT_MERGE,
+};
+
 void bch_btree_op_init_stack(struct btree_op *);
 
 static inline void rw_lock(bool w, struct btree *b, int level)
@@ -293,9 +293,7 @@ static inline void rw_unlock(bool w, struct btree *b)
 #ifdef CONFIG_BCACHE_EDEBUG
        unsigned i;
 
-       if (w &&
-           b->key.ptr[0] &&
-           btree_node_read_done(b))
+       if (w && b->key.ptr[0])
                for (i = 0; i <= b->nsets; i++)
                        bch_check_key_order(b, b->sets[i].data);
 #endif
@@ -370,9 +368,8 @@ static inline bool should_split(struct btree *b)
                 > btree_blocks(b));
 }
 
-void bch_btree_read_done(struct closure *);
-void bch_btree_read(struct btree *);
-void bch_btree_write(struct btree *b, bool now, struct btree_op *op);
+void bch_btree_node_read(struct btree *);
+void bch_btree_node_write(struct btree *, struct closure *);
 
 void bch_cannibalize_unlock(struct cache_set *, struct closure *);
 void bch_btree_set_root(struct btree *);
@@ -380,7 +377,6 @@ struct btree *bch_btree_node_alloc(struct cache_set *, int, struct closure *);
 struct btree *bch_btree_node_get(struct cache_set *, struct bkey *,
                                int, struct btree_op *);
 
-bool bch_btree_insert_keys(struct btree *, struct btree_op *);
 bool bch_btree_insert_check_key(struct btree *, struct btree_op *,
                                   struct bio *);
 int bch_btree_insert(struct btree_op *, struct cache_set *);
@@ -393,13 +389,14 @@ void bch_moving_gc(struct closure *);
 int bch_btree_check(struct cache_set *, struct btree_op *);
 uint8_t __bch_btree_mark_key(struct cache_set *, int, struct bkey *);
 
-void bch_keybuf_init(struct keybuf *, keybuf_pred_fn *);
-void bch_refill_keybuf(struct cache_set *, struct keybuf *, struct bkey *);
+void bch_keybuf_init(struct keybuf *);
+void bch_refill_keybuf(struct cache_set *, struct keybuf *, struct bkey *,
+                      keybuf_pred_fn *);
 bool bch_keybuf_check_overlapping(struct keybuf *, struct bkey *,
                                  struct bkey *);
 void bch_keybuf_del(struct keybuf *, struct keybuf_key *);
 struct keybuf_key *bch_keybuf_next(struct keybuf *);
-struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *,
-                                         struct keybuf *, struct bkey *);
+struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *, struct keybuf *,
+                                         struct bkey *, keybuf_pred_fn *);
 
 #endif
index bd05a9a8c7cf933e028be5eefbd1cd178681e495..9aba2017f0d1685ac5858ccf716c1f829681c853 100644 (file)
@@ -66,16 +66,18 @@ static inline void closure_put_after_sub(struct closure *cl, int flags)
                } else {
                        struct closure *parent = cl->parent;
                        struct closure_waitlist *wait = closure_waitlist(cl);
+                       closure_fn *destructor = cl->fn;
 
                        closure_debug_destroy(cl);
 
+                       smp_mb();
                        atomic_set(&cl->remaining, -1);
 
                        if (wait)
                                closure_wake_up(wait);
 
-                       if (cl->fn)
-                               cl->fn(cl);
+                       if (destructor)
+                               destructor(cl);
 
                        if (parent)
                                closure_put(parent);
index 89fd5204924e88bc2486d0616c291279161c51bb..88e6411eab4f15829ba22c535a7b100b370bc5a6 100644 (file)
@@ -47,11 +47,10 @@ const char *bch_ptr_status(struct cache_set *c, const struct bkey *k)
        return "";
 }
 
-struct keyprint_hack bch_pkey(const struct bkey *k)
+int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k)
 {
        unsigned i = 0;
-       struct keyprint_hack r;
-       char *out = r.s, *end = r.s + KEYHACK_SIZE;
+       char *out = buf, *end = buf + size;
 
 #define p(...) (out += scnprintf(out, end - out, __VA_ARGS__))
 
@@ -75,16 +74,14 @@ struct keyprint_hack bch_pkey(const struct bkey *k)
        if (KEY_CSUM(k))
                p(" cs%llu %llx", KEY_CSUM(k), k->ptr[1]);
 #undef p
-       return r;
+       return out - buf;
 }
 
-struct keyprint_hack bch_pbtree(const struct btree *b)
+int bch_btree_to_text(char *buf, size_t size, const struct btree *b)
 {
-       struct keyprint_hack r;
-
-       snprintf(r.s, 40, "%zu level %i/%i", PTR_BUCKET_NR(b->c, &b->key, 0),
-                b->level, b->c->root ? b->c->root->level : -1);
-       return r;
+       return scnprintf(buf, size, "%zu level %i/%i",
+                        PTR_BUCKET_NR(b->c, &b->key, 0),
+                        b->level, b->c->root ? b->c->root->level : -1);
 }
 
 #if defined(CONFIG_BCACHE_DEBUG) || defined(CONFIG_BCACHE_EDEBUG)
@@ -100,10 +97,12 @@ static void dump_bset(struct btree *b, struct bset *i)
 {
        struct bkey *k;
        unsigned j;
+       char buf[80];
 
        for (k = i->start; k < end(i); k = bkey_next(k)) {
+               bch_bkey_to_text(buf, sizeof(buf), k);
                printk(KERN_ERR "block %zu key %zi/%u: %s", index(i, b),
-                      (uint64_t *) k - i->d, i->keys, pkey(k));
+                      (uint64_t *) k - i->d, i->keys, buf);
 
                for (j = 0; j < KEY_PTRS(k); j++) {
                        size_t n = PTR_BUCKET_NR(b->c, k, j);
@@ -144,7 +143,7 @@ void bch_btree_verify(struct btree *b, struct bset *new)
        v->written = 0;
        v->level = b->level;
 
-       bch_btree_read(v);
+       bch_btree_node_read(v);
        closure_wait_event(&v->io.wait, &cl,
                           atomic_read(&b->io.cl.remaining) == -1);
 
@@ -200,7 +199,7 @@ void bch_data_verify(struct search *s)
        if (!check)
                return;
 
-       if (bch_bio_alloc_pages(check, GFP_NOIO))
+       if (bio_alloc_pages(check, GFP_NOIO))
                goto out_put;
 
        check->bi_rw            = READ_SYNC;
@@ -252,6 +251,7 @@ static void vdump_bucket_and_panic(struct btree *b, const char *fmt,
                                   va_list args)
 {
        unsigned i;
+       char buf[80];
 
        console_lock();
 
@@ -262,7 +262,8 @@ static void vdump_bucket_and_panic(struct btree *b, const char *fmt,
 
        console_unlock();
 
-       panic("at %s\n", pbtree(b));
+       bch_btree_to_text(buf, sizeof(buf), b);
+       panic("at %s\n", buf);
 }
 
 void bch_check_key_order_msg(struct btree *b, struct bset *i,
@@ -337,6 +338,7 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf,
 {
        struct dump_iterator *i = file->private_data;
        ssize_t ret = 0;
+       char kbuf[80];
 
        while (size) {
                struct keybuf_key *w;
@@ -355,11 +357,12 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf,
                if (i->bytes)
                        break;
 
-               w = bch_keybuf_next_rescan(i->c, &i->keys, &MAX_KEY);
+               w = bch_keybuf_next_rescan(i->c, &i->keys, &MAX_KEY, dump_pred);
                if (!w)
                        break;
 
-               i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", pkey(&w->key));
+               bch_bkey_to_text(kbuf, sizeof(kbuf), &w->key);
+               i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", kbuf);
                bch_keybuf_del(&i->keys, w);
        }
 
@@ -377,7 +380,7 @@ static int bch_dump_open(struct inode *inode, struct file *file)
 
        file->private_data = i;
        i->c = c;
-       bch_keybuf_init(&i->keys, dump_pred);
+       bch_keybuf_init(&i->keys);
        i->keys.last_scanned = KEY(0, 0, 0);
 
        return 0;
@@ -409,142 +412,6 @@ void bch_debug_init_cache_set(struct cache_set *c)
 
 #endif
 
-/* Fuzz tester has rotted: */
-#if 0
-
-static ssize_t btree_fuzz(struct kobject *k, struct kobj_attribute *a,
-                         const char *buffer, size_t size)
-{
-       void dump(struct btree *b)
-       {
-               struct bset *i;
-
-               for (i = b->sets[0].data;
-                    index(i, b) < btree_blocks(b) &&
-                    i->seq == b->sets[0].data->seq;
-                    i = ((void *) i) + set_blocks(i, b->c) * block_bytes(b->c))
-                       dump_bset(b, i);
-       }
-
-       struct cache_sb *sb;
-       struct cache_set *c;
-       struct btree *all[3], *b, *fill, *orig;
-       int j;
-
-       struct btree_op op;
-       bch_btree_op_init_stack(&op);
-
-       sb = kzalloc(sizeof(struct cache_sb), GFP_KERNEL);
-       if (!sb)
-               return -ENOMEM;
-
-       sb->bucket_size = 128;
-       sb->block_size = 4;
-
-       c = bch_cache_set_alloc(sb);
-       if (!c)
-               return -ENOMEM;
-
-       for (j = 0; j < 3; j++) {
-               BUG_ON(list_empty(&c->btree_cache));
-               all[j] = list_first_entry(&c->btree_cache, struct btree, list);
-               list_del_init(&all[j]->list);
-
-               all[j]->key = KEY(0, 0, c->sb.bucket_size);
-               bkey_copy_key(&all[j]->key, &MAX_KEY);
-       }
-
-       b = all[0];
-       fill = all[1];
-       orig = all[2];
-
-       while (1) {
-               for (j = 0; j < 3; j++)
-                       all[j]->written = all[j]->nsets = 0;
-
-               bch_bset_init_next(b);
-
-               while (1) {
-                       struct bset *i = write_block(b);
-                       struct bkey *k = op.keys.top;
-                       unsigned rand;
-
-                       bkey_init(k);
-                       rand = get_random_int();
-
-                       op.type = rand & 1
-                               ? BTREE_INSERT
-                               : BTREE_REPLACE;
-                       rand >>= 1;
-
-                       SET_KEY_SIZE(k, bucket_remainder(c, rand));
-                       rand >>= c->bucket_bits;
-                       rand &= 1024 * 512 - 1;
-                       rand += c->sb.bucket_size;
-                       SET_KEY_OFFSET(k, rand);
-#if 0
-                       SET_KEY_PTRS(k, 1);
-#endif
-                       bch_keylist_push(&op.keys);
-                       bch_btree_insert_keys(b, &op);
-
-                       if (should_split(b) ||
-                           set_blocks(i, b->c) !=
-                           __set_blocks(i, i->keys + 15, b->c)) {
-                               i->csum = csum_set(i);
-
-                               memcpy(write_block(fill),
-                                      i, set_bytes(i));
-
-                               b->written += set_blocks(i, b->c);
-                               fill->written = b->written;
-                               if (b->written == btree_blocks(b))
-                                       break;
-
-                               bch_btree_sort_lazy(b);
-                               bch_bset_init_next(b);
-                       }
-               }
-
-               memcpy(orig->sets[0].data,
-                      fill->sets[0].data,
-                      btree_bytes(c));
-
-               bch_btree_sort(b);
-               fill->written = 0;
-               bch_btree_read_done(&fill->io.cl);
-
-               if (b->sets[0].data->keys != fill->sets[0].data->keys ||
-                   memcmp(b->sets[0].data->start,
-                          fill->sets[0].data->start,
-                          b->sets[0].data->keys * sizeof(uint64_t))) {
-                       struct bset *i = b->sets[0].data;
-                       struct bkey *k, *l;
-
-                       for (k = i->start,
-                            l = fill->sets[0].data->start;
-                            k < end(i);
-                            k = bkey_next(k), l = bkey_next(l))
-                               if (bkey_cmp(k, l) ||
-                                   KEY_SIZE(k) != KEY_SIZE(l))
-                                       pr_err("key %zi differs: %s != %s",
-                                              (uint64_t *) k - i->d,
-                                              pkey(k), pkey(l));
-
-                       for (j = 0; j < 3; j++) {
-                               pr_err("**** Set %i ****", j);
-                               dump(all[j]);
-                       }
-                       panic("\n");
-               }
-
-               pr_info("fuzz complete: %i keys", b->sets[0].data->keys);
-       }
-}
-
-kobj_attribute_write(fuzz, btree_fuzz);
-#endif
-
 void bch_debug_exit(void)
 {
        if (!IS_ERR_OR_NULL(debug))
@@ -554,11 +421,6 @@ void bch_debug_exit(void)
 int __init bch_debug_init(struct kobject *kobj)
 {
        int ret = 0;
-#if 0
-       ret = sysfs_create_file(kobj, &ksysfs_fuzz.attr);
-       if (ret)
-               return ret;
-#endif
 
        debug = debugfs_create_dir("bcache", NULL);
        return ret;
index f9378a21814871033a9bc2218d184e6e422d2bd4..1c39b5a2489bd1158782f0afb1a28ef4fcb0a7a4 100644 (file)
@@ -3,15 +3,8 @@
 
 /* Btree/bkey debug printing */
 
-#define KEYHACK_SIZE 80
-struct keyprint_hack {
-       char s[KEYHACK_SIZE];
-};
-
-struct keyprint_hack bch_pkey(const struct bkey *k);
-struct keyprint_hack bch_pbtree(const struct btree *b);
-#define pkey(k)                (&bch_pkey(k).s[0])
-#define pbtree(b)      (&bch_pbtree(b).s[0])
+int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k);
+int bch_btree_to_text(char *buf, size_t size, const struct btree *b);
 
 #ifdef CONFIG_BCACHE_EDEBUG
 
index 48efd4dea645bde1b12cf69927e9f628fd1ae077..9056632995b1b8a2de9de607c60cd693704c9c65 100644 (file)
@@ -9,6 +9,8 @@
 #include "bset.h"
 #include "debug.h"
 
+#include <linux/blkdev.h>
+
 static void bch_bi_idx_hack_endio(struct bio *bio, int error)
 {
        struct bio *p = bio->bi_private;
@@ -66,13 +68,6 @@ static void bch_generic_make_request_hack(struct bio *bio)
  * The newly allocated bio will point to @bio's bi_io_vec, if the split was on a
  * bvec boundry; it is the caller's responsibility to ensure that @bio is not
  * freed before the split.
- *
- * If bch_bio_split() is running under generic_make_request(), it's not safe to
- * allocate more than one bio from the same bio set. Therefore, if it is running
- * under generic_make_request() it masks out __GFP_WAIT when doing the
- * allocation. The caller must check for failure if there's any possibility of
- * it being called from under generic_make_request(); it is then the caller's
- * responsibility to retry from a safe context (by e.g. punting to workqueue).
  */
 struct bio *bch_bio_split(struct bio *bio, int sectors,
                          gfp_t gfp, struct bio_set *bs)
@@ -83,20 +78,13 @@ struct bio *bch_bio_split(struct bio *bio, int sectors,
 
        BUG_ON(sectors <= 0);
 
-       /*
-        * If we're being called from underneath generic_make_request() and we
-        * already allocated any bios from this bio set, we risk deadlock if we
-        * use the mempool. So instead, we possibly fail and let the caller punt
-        * to workqueue or somesuch and retry in a safe context.
-        */
-       if (current->bio_list)
-               gfp &= ~__GFP_WAIT;
-
        if (sectors >= bio_sectors(bio))
                return bio;
 
        if (bio->bi_rw & REQ_DISCARD) {
                ret = bio_alloc_bioset(gfp, 1, bs);
+               if (!ret)
+                       return NULL;
                idx = 0;
                goto out;
        }
@@ -160,17 +148,18 @@ static unsigned bch_bio_max_sectors(struct bio *bio)
        struct request_queue *q = bdev_get_queue(bio->bi_bdev);
        unsigned max_segments = min_t(unsigned, BIO_MAX_PAGES,
                                      queue_max_segments(q));
-       struct bio_vec *bv, *end = bio_iovec(bio) +
-               min_t(int, bio_segments(bio), max_segments);
 
        if (bio->bi_rw & REQ_DISCARD)
                return min(ret, q->limits.max_discard_sectors);
 
        if (bio_segments(bio) > max_segments ||
            q->merge_bvec_fn) {
+               struct bio_vec *bv;
+               int i, seg = 0;
+
                ret = 0;
 
-               for (bv = bio_iovec(bio); bv < end; bv++) {
+               bio_for_each_segment(bv, bio, i) {
                        struct bvec_merge_data bvm = {
                                .bi_bdev        = bio->bi_bdev,
                                .bi_sector      = bio->bi_sector,
@@ -178,10 +167,14 @@ static unsigned bch_bio_max_sectors(struct bio *bio)
                                .bi_rw          = bio->bi_rw,
                        };
 
+                       if (seg == max_segments)
+                               break;
+
                        if (q->merge_bvec_fn &&
                            q->merge_bvec_fn(q, &bvm, bv) < (int) bv->bv_len)
                                break;
 
+                       seg++;
                        ret += bv->bv_len >> 9;
                }
        }
@@ -218,30 +211,10 @@ static void bch_bio_submit_split_endio(struct bio *bio, int error)
        closure_put(cl);
 }
 
-static void __bch_bio_submit_split(struct closure *cl)
-{
-       struct bio_split_hook *s = container_of(cl, struct bio_split_hook, cl);
-       struct bio *bio = s->bio, *n;
-
-       do {
-               n = bch_bio_split(bio, bch_bio_max_sectors(bio),
-                                 GFP_NOIO, s->p->bio_split);
-               if (!n)
-                       continue_at(cl, __bch_bio_submit_split, system_wq);
-
-               n->bi_end_io    = bch_bio_submit_split_endio;
-               n->bi_private   = cl;
-
-               closure_get(cl);
-               bch_generic_make_request_hack(n);
-       } while (n != bio);
-
-       continue_at(cl, bch_bio_submit_split_done, NULL);
-}
-
 void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p)
 {
        struct bio_split_hook *s;
+       struct bio *n;
 
        if (!bio_has_data(bio) && !(bio->bi_rw & REQ_DISCARD))
                goto submit;
@@ -250,6 +223,7 @@ void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p)
                goto submit;
 
        s = mempool_alloc(p->bio_split_hook, GFP_NOIO);
+       closure_init(&s->cl, NULL);
 
        s->bio          = bio;
        s->p            = p;
@@ -257,8 +231,18 @@ void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p)
        s->bi_private   = bio->bi_private;
        bio_get(bio);
 
-       closure_call(&s->cl, __bch_bio_submit_split, NULL, NULL);
-       return;
+       do {
+               n = bch_bio_split(bio, bch_bio_max_sectors(bio),
+                                 GFP_NOIO, s->p->bio_split);
+
+               n->bi_end_io    = bch_bio_submit_split_endio;
+               n->bi_private   = &s->cl;
+
+               closure_get(&s->cl);
+               bch_generic_make_request_hack(n);
+       } while (n != bio);
+
+       continue_at(&s->cl, bch_bio_submit_split_done, NULL);
 submit:
        bch_generic_make_request_hack(bio);
 }
index 8c8dfdcd9d4cc9bc4a3d0799b98401855b280bcc..ba95ab84b2be5a5a32292625d229bb29e051a53d 100644 (file)
@@ -9,6 +9,8 @@
 #include "debug.h"
 #include "request.h"
 
+#include <trace/events/bcache.h>
+
 /*
  * Journal replay/recovery:
  *
@@ -182,9 +184,14 @@ bsearch:
                pr_debug("starting binary search, l %u r %u", l, r);
 
                while (l + 1 < r) {
+                       seq = list_entry(list->prev, struct journal_replay,
+                                        list)->j.seq;
+
                        m = (l + r) >> 1;
+                       read_bucket(m);
 
-                       if (read_bucket(m))
+                       if (seq != list_entry(list->prev, struct journal_replay,
+                                             list)->j.seq)
                                l = m;
                        else
                                r = m;
@@ -300,7 +307,8 @@ int bch_journal_replay(struct cache_set *s, struct list_head *list,
                for (k = i->j.start;
                     k < end(&i->j);
                     k = bkey_next(k)) {
-                       pr_debug("%s", pkey(k));
+                       trace_bcache_journal_replay_key(k);
+
                        bkey_copy(op->keys.top, k);
                        bch_keylist_push(&op->keys);
 
@@ -384,7 +392,7 @@ out:
                return;
 found:
        if (btree_node_dirty(best))
-               bch_btree_write(best, true, NULL);
+               bch_btree_node_write(best, NULL);
        rw_unlock(true, best);
 }
 
@@ -617,7 +625,7 @@ static void journal_write_unlocked(struct closure *cl)
                bio_reset(bio);
                bio->bi_sector  = PTR_OFFSET(k, i);
                bio->bi_bdev    = ca->bdev;
-               bio->bi_rw      = REQ_WRITE|REQ_SYNC|REQ_META|REQ_FLUSH;
+               bio->bi_rw      = REQ_WRITE|REQ_SYNC|REQ_META|REQ_FLUSH|REQ_FUA;
                bio->bi_size    = sectors << 9;
 
                bio->bi_end_io  = journal_write_endio;
@@ -712,7 +720,8 @@ void bch_journal(struct closure *cl)
        spin_lock(&c->journal.lock);
 
        if (journal_full(&c->journal)) {
-               /* XXX: tracepoint */
+               trace_bcache_journal_full(c);
+
                closure_wait(&c->journal.wait, cl);
 
                journal_reclaim(c);
@@ -728,13 +737,15 @@ void bch_journal(struct closure *cl)
 
        if (b * c->sb.block_size > PAGE_SECTORS << JSET_BITS ||
            b > c->journal.blocks_free) {
-               /* XXX: If we were inserting so many keys that they won't fit in
+               trace_bcache_journal_entry_full(c);
+
+               /*
+                * XXX: If we were inserting so many keys that they won't fit in
                 * an _empty_ journal write, we'll deadlock. For now, handle
                 * this in bch_keylist_realloc() - but something to think about.
                 */
                BUG_ON(!w->data->keys);
 
-               /* XXX: tracepoint */
                BUG_ON(!closure_wait(&w->wait, cl));
 
                closure_flush(&c->journal.io);
index 8589512c972e3cfd1e973d53783313802b4db6ca..1a3b4f4786c3cee411d16c3a9a453e1fcd33b681 100644 (file)
@@ -9,6 +9,8 @@
 #include "debug.h"
 #include "request.h"
 
+#include <trace/events/bcache.h>
+
 struct moving_io {
        struct keybuf_key       *w;
        struct search           s;
@@ -44,14 +46,14 @@ static void write_moving_finish(struct closure *cl)
 {
        struct moving_io *io = container_of(cl, struct moving_io, s.cl);
        struct bio *bio = &io->bio.bio;
-       struct bio_vec *bv = bio_iovec_idx(bio, bio->bi_vcnt);
+       struct bio_vec *bv;
+       int i;
 
-       while (bv-- != bio->bi_io_vec)
+       bio_for_each_segment_all(bv, bio, i)
                __free_page(bv->bv_page);
 
-       pr_debug("%s %s", io->s.op.insert_collision
-                ? "collision moving" : "moved",
-                pkey(&io->w->key));
+       if (io->s.op.insert_collision)
+               trace_bcache_gc_copy_collision(&io->w->key);
 
        bch_keybuf_del(&io->s.op.c->moving_gc_keys, io->w);
 
@@ -94,8 +96,6 @@ static void write_moving(struct closure *cl)
        struct moving_io *io = container_of(s, struct moving_io, s);
 
        if (!s->error) {
-               trace_bcache_write_moving(&io->bio.bio);
-
                moving_init(io);
 
                io->bio.bio.bi_sector   = KEY_START(&io->w->key);
@@ -122,7 +122,6 @@ static void read_moving_submit(struct closure *cl)
        struct moving_io *io = container_of(s, struct moving_io, s);
        struct bio *bio = &io->bio.bio;
 
-       trace_bcache_read_moving(bio);
        bch_submit_bbio(bio, s->op.c, &io->w->key, 0);
 
        continue_at(cl, write_moving, bch_gc_wq);
@@ -138,7 +137,8 @@ static void read_moving(struct closure *cl)
        /* XXX: if we error, background writeback could stall indefinitely */
 
        while (!test_bit(CACHE_SET_STOPPING, &c->flags)) {
-               w = bch_keybuf_next_rescan(c, &c->moving_gc_keys, &MAX_KEY);
+               w = bch_keybuf_next_rescan(c, &c->moving_gc_keys,
+                                          &MAX_KEY, moving_pred);
                if (!w)
                        break;
 
@@ -159,10 +159,10 @@ static void read_moving(struct closure *cl)
                bio->bi_rw      = READ;
                bio->bi_end_io  = read_moving_endio;
 
-               if (bch_bio_alloc_pages(bio, GFP_KERNEL))
+               if (bio_alloc_pages(bio, GFP_KERNEL))
                        goto err;
 
-               pr_debug("%s", pkey(&w->key));
+               trace_bcache_gc_copy(&w->key);
 
                closure_call(&io->s.cl, read_moving_submit, NULL, &c->gc.cl);
 
@@ -250,5 +250,5 @@ void bch_moving_gc(struct closure *cl)
 
 void bch_moving_init_cache_set(struct cache_set *c)
 {
-       bch_keybuf_init(&c->moving_gc_keys, moving_pred);
+       bch_keybuf_init(&c->moving_gc_keys);
 }
index e5ff12e52d5b277bea9cc4fa4aa5eb5bdf23540a..786a1a4f74d853fafe3ab2ae263d2ecf780134aa 100644 (file)
@@ -10,6 +10,7 @@
 #include "btree.h"
 #include "debug.h"
 #include "request.h"
+#include "writeback.h"
 
 #include <linux/cgroup.h>
 #include <linux/module.h>
@@ -21,8 +22,6 @@
 
 #define CUTOFF_CACHE_ADD       95
 #define CUTOFF_CACHE_READA     90
-#define CUTOFF_WRITEBACK       50
-#define CUTOFF_WRITEBACK_SYNC  75
 
 struct kmem_cache *bch_search_cache;
 
@@ -489,6 +488,12 @@ static void bch_insert_data_loop(struct closure *cl)
                bch_queue_gc(op->c);
        }
 
+       /*
+        * Journal writes are marked REQ_FLUSH; if the original write was a
+        * flush, it'll wait on the journal write.
+        */
+       bio->bi_rw &= ~(REQ_FLUSH|REQ_FUA);
+
        do {
                unsigned i;
                struct bkey *k;
@@ -510,10 +515,6 @@ static void bch_insert_data_loop(struct closure *cl)
                        goto err;
 
                n = bch_bio_split(bio, KEY_SIZE(k), GFP_NOIO, split);
-               if (!n) {
-                       __bkey_put(op->c, k);
-                       continue_at(cl, bch_insert_data_loop, bcache_wq);
-               }
 
                n->bi_end_io    = bch_insert_data_endio;
                n->bi_private   = cl;
@@ -530,10 +531,9 @@ static void bch_insert_data_loop(struct closure *cl)
                if (KEY_CSUM(k))
                        bio_csum(n, k);
 
-               pr_debug("%s", pkey(k));
+               trace_bcache_cache_insert(k);
                bch_keylist_push(&op->keys);
 
-               trace_bcache_cache_insert(n, n->bi_sector, n->bi_bdev);
                n->bi_rw |= REQ_WRITE;
                bch_submit_bbio(n, op->c, k, 0);
        } while (n != bio);
@@ -716,7 +716,7 @@ static struct search *search_alloc(struct bio *bio, struct bcache_device *d)
        s->task                 = current;
        s->orig_bio             = bio;
        s->write                = (bio->bi_rw & REQ_WRITE) != 0;
-       s->op.flush_journal     = (bio->bi_rw & REQ_FLUSH) != 0;
+       s->op.flush_journal     = (bio->bi_rw & (REQ_FLUSH|REQ_FUA)) != 0;
        s->op.skip              = (bio->bi_rw & REQ_DISCARD) != 0;
        s->recoverable          = 1;
        s->start_time           = jiffies;
@@ -784,11 +784,8 @@ static void request_read_error(struct closure *cl)
        int i;
 
        if (s->recoverable) {
-               /* The cache read failed, but we can retry from the backing
-                * device.
-                */
-               pr_debug("recovering at sector %llu",
-                        (uint64_t) s->orig_bio->bi_sector);
+               /* Retry from the backing device: */
+               trace_bcache_read_retry(s->orig_bio);
 
                s->error = 0;
                bv = s->bio.bio.bi_io_vec;
@@ -806,7 +803,6 @@ static void request_read_error(struct closure *cl)
 
                /* XXX: invalidate cache */
 
-               trace_bcache_read_retry(&s->bio.bio);
                closure_bio_submit(&s->bio.bio, &s->cl, s->d);
        }
 
@@ -827,53 +823,13 @@ static void request_read_done(struct closure *cl)
         */
 
        if (s->op.cache_bio) {
-               struct bio_vec *src, *dst;
-               unsigned src_offset, dst_offset, bytes;
-               void *dst_ptr;
-
                bio_reset(s->op.cache_bio);
                s->op.cache_bio->bi_sector      = s->cache_miss->bi_sector;
                s->op.cache_bio->bi_bdev        = s->cache_miss->bi_bdev;
                s->op.cache_bio->bi_size        = s->cache_bio_sectors << 9;
                bch_bio_map(s->op.cache_bio, NULL);
 
-               src = bio_iovec(s->op.cache_bio);
-               dst = bio_iovec(s->cache_miss);
-               src_offset = src->bv_offset;
-               dst_offset = dst->bv_offset;
-               dst_ptr = kmap(dst->bv_page);
-
-               while (1) {
-                       if (dst_offset == dst->bv_offset + dst->bv_len) {
-                               kunmap(dst->bv_page);
-                               dst++;
-                               if (dst == bio_iovec_idx(s->cache_miss,
-                                               s->cache_miss->bi_vcnt))
-                                       break;
-
-                               dst_offset = dst->bv_offset;
-                               dst_ptr = kmap(dst->bv_page);
-                       }
-
-                       if (src_offset == src->bv_offset + src->bv_len) {
-                               src++;
-                               if (src == bio_iovec_idx(s->op.cache_bio,
-                                                s->op.cache_bio->bi_vcnt))
-                                       BUG();
-
-                               src_offset = src->bv_offset;
-                       }
-
-                       bytes = min(dst->bv_offset + dst->bv_len - dst_offset,
-                                   src->bv_offset + src->bv_len - src_offset);
-
-                       memcpy(dst_ptr + dst_offset,
-                              page_address(src->bv_page) + src_offset,
-                              bytes);
-
-                       src_offset      += bytes;
-                       dst_offset      += bytes;
-               }
+               bio_copy_data(s->cache_miss, s->op.cache_bio);
 
                bio_put(s->cache_miss);
                s->cache_miss = NULL;
@@ -899,6 +855,7 @@ static void request_read_done_bh(struct closure *cl)
        struct cached_dev *dc = container_of(s->d, struct cached_dev, disk);
 
        bch_mark_cache_accounting(s, !s->cache_miss, s->op.skip);
+       trace_bcache_read(s->orig_bio, !s->cache_miss, s->op.skip);
 
        if (s->error)
                continue_at_nobarrier(cl, request_read_error, bcache_wq);
@@ -917,9 +874,6 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
        struct bio *miss;
 
        miss = bch_bio_split(bio, sectors, GFP_NOIO, s->d->bio_split);
-       if (!miss)
-               return -EAGAIN;
-
        if (miss == bio)
                s->op.lookup_done = true;
 
@@ -938,8 +892,9 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
                reada = min(dc->readahead >> 9,
                            sectors - bio_sectors(miss));
 
-               if (bio_end(miss) + reada > bdev_sectors(miss->bi_bdev))
-                       reada = bdev_sectors(miss->bi_bdev) - bio_end(miss);
+               if (bio_end_sector(miss) + reada > bdev_sectors(miss->bi_bdev))
+                       reada = bdev_sectors(miss->bi_bdev) -
+                               bio_end_sector(miss);
        }
 
        s->cache_bio_sectors = bio_sectors(miss) + reada;
@@ -963,13 +918,12 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
                goto out_put;
 
        bch_bio_map(s->op.cache_bio, NULL);
-       if (bch_bio_alloc_pages(s->op.cache_bio, __GFP_NOWARN|GFP_NOIO))
+       if (bio_alloc_pages(s->op.cache_bio, __GFP_NOWARN|GFP_NOIO))
                goto out_put;
 
        s->cache_miss = miss;
        bio_get(s->op.cache_bio);
 
-       trace_bcache_cache_miss(s->orig_bio);
        closure_bio_submit(s->op.cache_bio, &s->cl, s->d);
 
        return ret;
@@ -1002,24 +956,13 @@ static void cached_dev_write_complete(struct closure *cl)
        cached_dev_bio_complete(cl);
 }
 
-static bool should_writeback(struct cached_dev *dc, struct bio *bio)
-{
-       unsigned threshold = (bio->bi_rw & REQ_SYNC)
-               ? CUTOFF_WRITEBACK_SYNC
-               : CUTOFF_WRITEBACK;
-
-       return !atomic_read(&dc->disk.detaching) &&
-               cache_mode(dc, bio) == CACHE_MODE_WRITEBACK &&
-               dc->disk.c->gc_stats.in_use < threshold;
-}
-
 static void request_write(struct cached_dev *dc, struct search *s)
 {
        struct closure *cl = &s->cl;
        struct bio *bio = &s->bio.bio;
        struct bkey start, end;
        start = KEY(dc->disk.id, bio->bi_sector, 0);
-       end = KEY(dc->disk.id, bio_end(bio), 0);
+       end = KEY(dc->disk.id, bio_end_sector(bio), 0);
 
        bch_keybuf_check_overlapping(&s->op.c->moving_gc_keys, &start, &end);
 
@@ -1034,22 +977,37 @@ static void request_write(struct cached_dev *dc, struct search *s)
        if (bio->bi_rw & REQ_DISCARD)
                goto skip;
 
+       if (should_writeback(dc, s->orig_bio,
+                            cache_mode(dc, bio),
+                            s->op.skip)) {
+               s->op.skip = false;
+               s->writeback = true;
+       }
+
        if (s->op.skip)
                goto skip;
 
-       if (should_writeback(dc, s->orig_bio))
-               s->writeback = true;
+       trace_bcache_write(s->orig_bio, s->writeback, s->op.skip);
 
        if (!s->writeback) {
                s->op.cache_bio = bio_clone_bioset(bio, GFP_NOIO,
                                                   dc->disk.bio_split);
 
-               trace_bcache_writethrough(s->orig_bio);
                closure_bio_submit(bio, cl, s->d);
        } else {
-               s->op.cache_bio = bio;
-               trace_bcache_writeback(s->orig_bio);
-               bch_writeback_add(dc, bio_sectors(bio));
+               bch_writeback_add(dc);
+
+               if (s->op.flush_journal) {
+                       /* Also need to send a flush to the backing device */
+                       s->op.cache_bio = bio_clone_bioset(bio, GFP_NOIO,
+                                                          dc->disk.bio_split);
+
+                       bio->bi_size = 0;
+                       bio->bi_vcnt = 0;
+                       closure_bio_submit(bio, cl, s->d);
+               } else {
+                       s->op.cache_bio = bio;
+               }
        }
 out:
        closure_call(&s->op.cl, bch_insert_data, NULL, cl);
@@ -1058,7 +1016,6 @@ skip:
        s->op.skip = true;
        s->op.cache_bio = s->orig_bio;
        bio_get(s->op.cache_bio);
-       trace_bcache_write_skip(s->orig_bio);
 
        if ((bio->bi_rw & REQ_DISCARD) &&
            !blk_queue_discard(bdev_get_queue(dc->bdev)))
@@ -1088,9 +1045,10 @@ static void request_nodata(struct cached_dev *dc, struct search *s)
 
 /* Cached devices - read & write stuff */
 
-int bch_get_congested(struct cache_set *c)
+unsigned bch_get_congested(struct cache_set *c)
 {
        int i;
+       long rand;
 
        if (!c->congested_read_threshold_us &&
            !c->congested_write_threshold_us)
@@ -1106,7 +1064,13 @@ int bch_get_congested(struct cache_set *c)
 
        i += CONGESTED_MAX;
 
-       return i <= 0 ? 1 : fract_exp_two(i, 6);
+       if (i > 0)
+               i = fract_exp_two(i, 6);
+
+       rand = get_random_int();
+       i -= bitmap_weight(&rand, BITS_PER_LONG);
+
+       return i > 0 ? i : 1;
 }
 
 static void add_sequential(struct task_struct *t)
@@ -1126,10 +1090,8 @@ static void check_should_skip(struct cached_dev *dc, struct search *s)
 {
        struct cache_set *c = s->op.c;
        struct bio *bio = &s->bio.bio;
-
-       long rand;
-       int cutoff = bch_get_congested(c);
        unsigned mode = cache_mode(dc, bio);
+       unsigned sectors, congested = bch_get_congested(c);
 
        if (atomic_read(&dc->disk.detaching) ||
            c->gc_stats.in_use > CUTOFF_CACHE_ADD ||
@@ -1147,17 +1109,14 @@ static void check_should_skip(struct cached_dev *dc, struct search *s)
                goto skip;
        }
 
-       if (!cutoff) {
-               cutoff = dc->sequential_cutoff >> 9;
+       if (!congested && !dc->sequential_cutoff)
+               goto rescale;
 
-               if (!cutoff)
-                       goto rescale;
-
-               if (mode == CACHE_MODE_WRITEBACK &&
-                   (bio->bi_rw & REQ_WRITE) &&
-                   (bio->bi_rw & REQ_SYNC))
-                       goto rescale;
-       }
+       if (!congested &&
+           mode == CACHE_MODE_WRITEBACK &&
+           (bio->bi_rw & REQ_WRITE) &&
+           (bio->bi_rw & REQ_SYNC))
+               goto rescale;
 
        if (dc->sequential_merge) {
                struct io *i;
@@ -1177,7 +1136,7 @@ found:
                if (i->sequential + bio->bi_size > i->sequential)
                        i->sequential   += bio->bi_size;
 
-               i->last                  = bio_end(bio);
+               i->last                  = bio_end_sector(bio);
                i->jiffies               = jiffies + msecs_to_jiffies(5000);
                s->task->sequential_io   = i->sequential;
 
@@ -1192,12 +1151,19 @@ found:
                add_sequential(s->task);
        }
 
-       rand = get_random_int();
-       cutoff -= bitmap_weight(&rand, BITS_PER_LONG);
+       sectors = max(s->task->sequential_io,
+                     s->task->sequential_io_avg) >> 9;
 
-       if (cutoff <= (int) (max(s->task->sequential_io,
-                                s->task->sequential_io_avg) >> 9))
+       if (dc->sequential_cutoff &&
+           sectors >= dc->sequential_cutoff >> 9) {
+               trace_bcache_bypass_sequential(s->orig_bio);
                goto skip;
+       }
+
+       if (congested && sectors >= congested) {
+               trace_bcache_bypass_congested(s->orig_bio);
+               goto skip;
+       }
 
 rescale:
        bch_rescale_priorities(c, bio_sectors(bio));
@@ -1288,30 +1254,25 @@ void bch_cached_dev_request_init(struct cached_dev *dc)
 static int flash_dev_cache_miss(struct btree *b, struct search *s,
                                struct bio *bio, unsigned sectors)
 {
+       struct bio_vec *bv;
+       int i;
+
        /* Zero fill bio */
 
-       while (bio->bi_idx != bio->bi_vcnt) {
-               struct bio_vec *bv = bio_iovec(bio);
+       bio_for_each_segment(bv, bio, i) {
                unsigned j = min(bv->bv_len >> 9, sectors);
 
                void *p = kmap(bv->bv_page);
                memset(p + bv->bv_offset, 0, j << 9);
                kunmap(bv->bv_page);
 
-               bv->bv_len      -= j << 9;
-               bv->bv_offset   += j << 9;
-
-               if (bv->bv_len)
-                       return 0;
-
-               bio->bi_sector  += j;
-               bio->bi_size    -= j << 9;
-
-               bio->bi_idx++;
-               sectors         -= j;
+               sectors -= j;
        }
 
-       s->op.lookup_done = true;
+       bio_advance(bio, min(sectors << 9, bio->bi_size));
+
+       if (!bio->bi_size)
+               s->op.lookup_done = true;
 
        return 0;
 }
@@ -1338,8 +1299,8 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio)
                closure_call(&s->op.cl, btree_read_async, NULL, cl);
        } else if (bio_has_data(bio) || s->op.skip) {
                bch_keybuf_check_overlapping(&s->op.c->moving_gc_keys,
-                                            &KEY(d->id, bio->bi_sector, 0),
-                                            &KEY(d->id, bio_end(bio), 0));
+                                       &KEY(d->id, bio->bi_sector, 0),
+                                       &KEY(d->id, bio_end_sector(bio), 0));
 
                s->writeback    = true;
                s->op.cache_bio = bio;
index 254d9ab5707cf4629e186d512d5f43e7eca3f94a..57dc4784f4f48c06b6816232d352d4992e45cee1 100644 (file)
@@ -30,7 +30,7 @@ struct search {
 };
 
 void bch_cache_read_endio(struct bio *, int);
-int bch_get_congested(struct cache_set *);
+unsigned bch_get_congested(struct cache_set *);
 void bch_insert_data(struct closure *cl);
 void bch_btree_insert_async(struct closure *);
 void bch_cache_read_endio(struct bio *, int);
index f88e2b653a3fc9c82a7b308c8988cd10eda0c96b..547c4c57b052efbb6fcd3df67c4b52c505023606 100644 (file)
 #include "btree.h"
 #include "debug.h"
 #include "request.h"
+#include "writeback.h"
 
+#include <linux/blkdev.h>
 #include <linux/buffer_head.h>
 #include <linux/debugfs.h>
 #include <linux/genhd.h>
+#include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/reboot.h>
@@ -342,6 +345,7 @@ static void uuid_io(struct cache_set *c, unsigned long rw,
        struct closure *cl = &c->uuid_write.cl;
        struct uuid_entry *u;
        unsigned i;
+       char buf[80];
 
        BUG_ON(!parent);
        closure_lock(&c->uuid_write, parent);
@@ -362,8 +366,8 @@ static void uuid_io(struct cache_set *c, unsigned long rw,
                        break;
        }
 
-       pr_debug("%s UUIDs at %s", rw & REQ_WRITE ? "wrote" : "read",
-                pkey(&c->uuid_bucket));
+       bch_bkey_to_text(buf, sizeof(buf), k);
+       pr_debug("%s UUIDs at %s", rw & REQ_WRITE ? "wrote" : "read", buf);
 
        for (u = c->uuids; u < c->uuids + c->nr_uuids; u++)
                if (!bch_is_zero(u->uuid, 16))
@@ -543,7 +547,6 @@ void bch_prio_write(struct cache *ca)
 
        pr_debug("free %zu, free_inc %zu, unused %zu", fifo_used(&ca->free),
                 fifo_used(&ca->free_inc), fifo_used(&ca->unused));
-       blktrace_msg(ca, "Starting priorities: " buckets_free(ca));
 
        for (i = prio_buckets(ca) - 1; i >= 0; --i) {
                long bucket;
@@ -704,7 +707,8 @@ static void bcache_device_detach(struct bcache_device *d)
                atomic_set(&d->detaching, 0);
        }
 
-       bcache_device_unlink(d);
+       if (!d->flush_done)
+               bcache_device_unlink(d);
 
        d->c->devices[d->id] = NULL;
        closure_put(&d->c->caching);
@@ -743,13 +747,35 @@ static void bcache_device_free(struct bcache_device *d)
                mempool_destroy(d->unaligned_bvec);
        if (d->bio_split)
                bioset_free(d->bio_split);
+       if (is_vmalloc_addr(d->stripe_sectors_dirty))
+               vfree(d->stripe_sectors_dirty);
+       else
+               kfree(d->stripe_sectors_dirty);
 
        closure_debug_destroy(&d->cl);
 }
 
-static int bcache_device_init(struct bcache_device *d, unsigned block_size)
+static int bcache_device_init(struct bcache_device *d, unsigned block_size,
+                             sector_t sectors)
 {
        struct request_queue *q;
+       size_t n;
+
+       if (!d->stripe_size_bits)
+               d->stripe_size_bits = 31;
+
+       d->nr_stripes = round_up(sectors, 1 << d->stripe_size_bits) >>
+               d->stripe_size_bits;
+
+       if (!d->nr_stripes || d->nr_stripes > SIZE_MAX / sizeof(atomic_t))
+               return -ENOMEM;
+
+       n = d->nr_stripes * sizeof(atomic_t);
+       d->stripe_sectors_dirty = n < PAGE_SIZE << 6
+               ? kzalloc(n, GFP_KERNEL)
+               : vzalloc(n);
+       if (!d->stripe_sectors_dirty)
+               return -ENOMEM;
 
        if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
            !(d->unaligned_bvec = mempool_create_kmalloc_pool(1,
@@ -759,6 +785,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size)
            !(q = blk_alloc_queue(GFP_KERNEL)))
                return -ENOMEM;
 
+       set_capacity(d->disk, sectors);
        snprintf(d->disk->disk_name, DISK_NAME_LEN, "bcache%i", bcache_minor);
 
        d->disk->major          = bcache_major;
@@ -781,6 +808,8 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size)
        set_bit(QUEUE_FLAG_NONROT,      &d->disk->queue->queue_flags);
        set_bit(QUEUE_FLAG_DISCARD,     &d->disk->queue->queue_flags);
 
+       blk_queue_flush(q, REQ_FLUSH|REQ_FUA);
+
        return 0;
 }
 
@@ -800,6 +829,17 @@ static void calc_cached_dev_sectors(struct cache_set *c)
 void bch_cached_dev_run(struct cached_dev *dc)
 {
        struct bcache_device *d = &dc->disk;
+       char buf[SB_LABEL_SIZE + 1];
+       char *env[] = {
+               "DRIVER=bcache",
+               kasprintf(GFP_KERNEL, "CACHED_UUID=%pU", dc->sb.uuid),
+               NULL,
+               NULL,
+       };
+
+       memcpy(buf, dc->sb.label, SB_LABEL_SIZE);
+       buf[SB_LABEL_SIZE] = '\0';
+       env[2] = kasprintf(GFP_KERNEL, "CACHED_LABEL=%s", buf);
 
        if (atomic_xchg(&dc->running, 1))
                return;
@@ -816,10 +856,12 @@ void bch_cached_dev_run(struct cached_dev *dc)
 
        add_disk(d->disk);
        bd_link_disk_holder(dc->bdev, dc->disk.disk);
-#if 0
-       char *env[] = { "SYMLINK=label" , NULL };
+       /* won't show up in the uevent file, use udevadm monitor -e instead
+        * only class / kset properties are persistent */
        kobject_uevent_env(&disk_to_dev(d->disk)->kobj, KOBJ_CHANGE, env);
-#endif
+       kfree(env[1]);
+       kfree(env[2]);
+
        if (sysfs_create_link(&d->kobj, &disk_to_dev(d->disk)->kobj, "dev") ||
            sysfs_create_link(&disk_to_dev(d->disk)->kobj, &d->kobj, "bcache"))
                pr_debug("error creating sysfs link");
@@ -960,6 +1002,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
        atomic_set(&dc->count, 1);
 
        if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
+               bch_sectors_dirty_init(dc);
                atomic_set(&dc->has_dirty, 1);
                atomic_inc(&dc->count);
                bch_writeback_queue(dc);
@@ -1014,6 +1057,14 @@ static void cached_dev_flush(struct closure *cl)
        struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl);
        struct bcache_device *d = &dc->disk;
 
+       mutex_lock(&bch_register_lock);
+       d->flush_done = 1;
+
+       if (d->c)
+               bcache_device_unlink(d);
+
+       mutex_unlock(&bch_register_lock);
+
        bch_cache_accounting_destroy(&dc->accounting);
        kobject_del(&d->kobj);
 
@@ -1045,7 +1096,8 @@ static int cached_dev_init(struct cached_dev *dc, unsigned block_size)
                hlist_add_head(&io->hash, dc->io_hash + RECENT_IO);
        }
 
-       ret = bcache_device_init(&dc->disk, block_size);
+       ret = bcache_device_init(&dc->disk, block_size,
+                        dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
        if (ret)
                return ret;
 
@@ -1144,11 +1196,10 @@ static int flash_dev_run(struct cache_set *c, struct uuid_entry *u)
 
        kobject_init(&d->kobj, &bch_flash_dev_ktype);
 
-       if (bcache_device_init(d, block_bytes(c)))
+       if (bcache_device_init(d, block_bytes(c), u->sectors))
                goto err;
 
        bcache_device_attach(d, c, u - c->uuids);
-       set_capacity(d->disk, u->sectors);
        bch_flash_dev_request_init(d);
        add_disk(d->disk);
 
@@ -1255,9 +1306,10 @@ static void cache_set_free(struct closure *cl)
        free_pages((unsigned long) c->uuids, ilog2(bucket_pages(c)));
        free_pages((unsigned long) c->sort, ilog2(bucket_pages(c)));
 
-       kfree(c->fill_iter);
        if (c->bio_split)
                bioset_free(c->bio_split);
+       if (c->fill_iter)
+               mempool_destroy(c->fill_iter);
        if (c->bio_meta)
                mempool_destroy(c->bio_meta);
        if (c->search)
@@ -1278,11 +1330,9 @@ static void cache_set_free(struct closure *cl)
 static void cache_set_flush(struct closure *cl)
 {
        struct cache_set *c = container_of(cl, struct cache_set, caching);
+       struct cache *ca;
        struct btree *b;
-
-       /* Shut down allocator threads */
-       set_bit(CACHE_SET_STOPPING_2, &c->flags);
-       wake_up(&c->alloc_wait);
+       unsigned i;
 
        bch_cache_accounting_destroy(&c->accounting);
 
@@ -1295,7 +1345,11 @@ static void cache_set_flush(struct closure *cl)
        /* Should skip this if we're unregistering because of an error */
        list_for_each_entry(b, &c->btree_cache, list)
                if (btree_node_dirty(b))
-                       bch_btree_write(b, true, NULL);
+                       bch_btree_node_write(b, NULL);
+
+       for_each_cache(ca, c, i)
+               if (ca->alloc_thread)
+                       kthread_stop(ca->alloc_thread);
 
        closure_return(cl);
 }
@@ -1303,18 +1357,22 @@ static void cache_set_flush(struct closure *cl)
 static void __cache_set_unregister(struct closure *cl)
 {
        struct cache_set *c = container_of(cl, struct cache_set, caching);
-       struct cached_dev *dc, *t;
+       struct cached_dev *dc;
        size_t i;
 
        mutex_lock(&bch_register_lock);
 
-       if (test_bit(CACHE_SET_UNREGISTERING, &c->flags))
-               list_for_each_entry_safe(dc, t, &c->cached_devs, list)
-                       bch_cached_dev_detach(dc);
-
        for (i = 0; i < c->nr_uuids; i++)
-               if (c->devices[i] && UUID_FLASH_ONLY(&c->uuids[i]))
-                       bcache_device_stop(c->devices[i]);
+               if (c->devices[i]) {
+                       if (!UUID_FLASH_ONLY(&c->uuids[i]) &&
+                           test_bit(CACHE_SET_UNREGISTERING, &c->flags)) {
+                               dc = container_of(c->devices[i],
+                                                 struct cached_dev, disk);
+                               bch_cached_dev_detach(dc);
+                       } else {
+                               bcache_device_stop(c->devices[i]);
+                       }
+               }
 
        mutex_unlock(&bch_register_lock);
 
@@ -1373,9 +1431,9 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
                c->btree_pages = max_t(int, c->btree_pages / 4,
                                       BTREE_MAX_PAGES);
 
-       init_waitqueue_head(&c->alloc_wait);
+       c->sort_crit_factor = int_sqrt(c->btree_pages);
+
        mutex_init(&c->bucket_lock);
-       mutex_init(&c->fill_lock);
        mutex_init(&c->sort_lock);
        spin_lock_init(&c->sort_time_lock);
        closure_init_unlocked(&c->sb_write);
@@ -1401,8 +1459,8 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
            !(c->bio_meta = mempool_create_kmalloc_pool(2,
                                sizeof(struct bbio) + sizeof(struct bio_vec) *
                                bucket_pages(c))) ||
+           !(c->fill_iter = mempool_create_kmalloc_pool(1, iter_size)) ||
            !(c->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
-           !(c->fill_iter = kmalloc(iter_size, GFP_KERNEL)) ||
            !(c->sort = alloc_bucket_pages(GFP_KERNEL, c)) ||
            !(c->uuids = alloc_bucket_pages(GFP_KERNEL, c)) ||
            bch_journal_alloc(c) ||
@@ -1410,8 +1468,6 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
            bch_open_buckets_alloc(c))
                goto err;
 
-       c->fill_iter->size = sb->bucket_size / sb->block_size;
-
        c->congested_read_threshold_us  = 2000;
        c->congested_write_threshold_us = 20000;
        c->error_limit  = 8 << IO_ERROR_SHIFT;
@@ -1496,9 +1552,10 @@ static void run_cache_set(struct cache_set *c)
                 */
                bch_journal_next(&c->journal);
 
+               err = "error starting allocator thread";
                for_each_cache(ca, c, i)
-                       closure_call(&ca->alloc, bch_allocator_thread,
-                                    system_wq, &c->cl);
+                       if (bch_cache_allocator_start(ca))
+                               goto err;
 
                /*
                 * First place it's safe to allocate: btree_check() and
@@ -1531,17 +1588,16 @@ static void run_cache_set(struct cache_set *c)
 
                bch_btree_gc_finish(c);
 
+               err = "error starting allocator thread";
                for_each_cache(ca, c, i)
-                       closure_call(&ca->alloc, bch_allocator_thread,
-                                    ca->alloc_workqueue, &c->cl);
+                       if (bch_cache_allocator_start(ca))
+                               goto err;
 
                mutex_lock(&c->bucket_lock);
                for_each_cache(ca, c, i)
                        bch_prio_write(ca);
                mutex_unlock(&c->bucket_lock);
 
-               wake_up(&c->alloc_wait);
-
                err = "cannot allocate new UUID bucket";
                if (__uuid_write(c))
                        goto err_unlock_gc;
@@ -1552,7 +1608,7 @@ static void run_cache_set(struct cache_set *c)
                        goto err_unlock_gc;
 
                bkey_copy_key(&c->root->key, &MAX_KEY);
-               bch_btree_write(c->root, true, &op);
+               bch_btree_node_write(c->root, &op.cl);
 
                bch_btree_set_root(c->root);
                rw_unlock(true, c->root);
@@ -1673,9 +1729,6 @@ void bch_cache_release(struct kobject *kobj)
 
        bio_split_pool_free(&ca->bio_split_hook);
 
-       if (ca->alloc_workqueue)
-               destroy_workqueue(ca->alloc_workqueue);
-
        free_pages((unsigned long) ca->disk_buckets, ilog2(bucket_pages(ca)));
        kfree(ca->prio_buckets);
        vfree(ca->buckets);
@@ -1723,7 +1776,6 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
            !(ca->prio_buckets  = kzalloc(sizeof(uint64_t) * prio_buckets(ca) *
                                          2, GFP_KERNEL)) ||
            !(ca->disk_buckets  = alloc_bucket_pages(GFP_KERNEL, ca)) ||
-           !(ca->alloc_workqueue = alloc_workqueue("bch_allocator", 0, 1)) ||
            bio_split_pool_init(&ca->bio_split_hook))
                return -ENOMEM;
 
@@ -1786,6 +1838,36 @@ static ssize_t register_bcache(struct kobject *, struct kobj_attribute *,
 kobj_attribute_write(register,         register_bcache);
 kobj_attribute_write(register_quiet,   register_bcache);
 
+static bool bch_is_open_backing(struct block_device *bdev) {
+       struct cache_set *c, *tc;
+       struct cached_dev *dc, *t;
+
+       list_for_each_entry_safe(c, tc, &bch_cache_sets, list)
+               list_for_each_entry_safe(dc, t, &c->cached_devs, list)
+                       if (dc->bdev == bdev)
+                               return true;
+       list_for_each_entry_safe(dc, t, &uncached_devices, list)
+               if (dc->bdev == bdev)
+                       return true;
+       return false;
+}
+
+static bool bch_is_open_cache(struct block_device *bdev) {
+       struct cache_set *c, *tc;
+       struct cache *ca;
+       unsigned i;
+
+       list_for_each_entry_safe(c, tc, &bch_cache_sets, list)
+               for_each_cache(ca, c, i)
+                       if (ca->bdev == bdev)
+                               return true;
+       return false;
+}
+
+static bool bch_is_open(struct block_device *bdev) {
+       return bch_is_open_cache(bdev) || bch_is_open_backing(bdev);
+}
+
 static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
                               const char *buffer, size_t size)
 {
@@ -1810,8 +1892,13 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
                                  FMODE_READ|FMODE_WRITE|FMODE_EXCL,
                                  sb);
        if (IS_ERR(bdev)) {
-               if (bdev == ERR_PTR(-EBUSY))
-                       err = "device busy";
+               if (bdev == ERR_PTR(-EBUSY)) {
+                       bdev = lookup_bdev(strim(path));
+                       if (!IS_ERR(bdev) && bch_is_open(bdev))
+                               err = "device already registered";
+                       else
+                               err = "device busy";
+               }
                goto err;
        }
 
index 4d9cca47e4c6006cd20919080410007f75c3bc60..12a2c2846f994a1e2d51bf79374426df96893418 100644 (file)
@@ -9,7 +9,9 @@
 #include "sysfs.h"
 #include "btree.h"
 #include "request.h"
+#include "writeback.h"
 
+#include <linux/blkdev.h>
 #include <linux/sort.h>
 
 static const char * const cache_replacement_policies[] = {
@@ -79,6 +81,9 @@ rw_attribute(writeback_rate_p_term_inverse);
 rw_attribute(writeback_rate_d_smooth);
 read_attribute(writeback_rate_debug);
 
+read_attribute(stripe_size);
+read_attribute(partial_stripes_expensive);
+
 rw_attribute(synchronous);
 rw_attribute(journal_delay_ms);
 rw_attribute(discard);
@@ -127,7 +132,7 @@ SHOW(__bch_cached_dev)
                char derivative[20];
                char target[20];
                bch_hprint(dirty,
-                      atomic_long_read(&dc->disk.sectors_dirty) << 9);
+                          bcache_dev_sectors_dirty(&dc->disk) << 9);
                bch_hprint(derivative,  dc->writeback_rate_derivative << 9);
                bch_hprint(target,      dc->writeback_rate_target << 9);
 
@@ -143,7 +148,10 @@ SHOW(__bch_cached_dev)
        }
 
        sysfs_hprint(dirty_data,
-                    atomic_long_read(&dc->disk.sectors_dirty) << 9);
+                    bcache_dev_sectors_dirty(&dc->disk) << 9);
+
+       sysfs_hprint(stripe_size,       (1 << dc->disk.stripe_size_bits) << 9);
+       var_printf(partial_stripes_expensive,   "%u");
 
        var_printf(sequential_merge,    "%i");
        var_hprint(sequential_cutoff);
@@ -170,6 +178,7 @@ STORE(__cached_dev)
                                             disk.kobj);
        unsigned v = size;
        struct cache_set *c;
+       struct kobj_uevent_env *env;
 
 #define d_strtoul(var)         sysfs_strtoul(var, dc->var)
 #define d_strtoi_h(var)                sysfs_hatoi(var, dc->var)
@@ -214,6 +223,7 @@ STORE(__cached_dev)
        }
 
        if (attr == &sysfs_label) {
+               /* note: endlines are preserved */
                memcpy(dc->sb.label, buf, SB_LABEL_SIZE);
                bch_write_bdev_super(dc, NULL);
                if (dc->disk.c) {
@@ -221,6 +231,15 @@ STORE(__cached_dev)
                               buf, SB_LABEL_SIZE);
                        bch_uuid_write(dc->disk.c);
                }
+               env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+               if (!env)
+                       return -ENOMEM;
+               add_uevent_var(env, "DRIVER=bcache");
+               add_uevent_var(env, "CACHED_UUID=%pU", dc->sb.uuid),
+               add_uevent_var(env, "CACHED_LABEL=%s", buf);
+               kobject_uevent_env(
+                       &disk_to_dev(dc->disk.disk)->kobj, KOBJ_CHANGE, env->envp);
+               kfree(env);
        }
 
        if (attr == &sysfs_attach) {
@@ -284,6 +303,8 @@ static struct attribute *bch_cached_dev_files[] = {
        &sysfs_writeback_rate_d_smooth,
        &sysfs_writeback_rate_debug,
        &sysfs_dirty_data,
+       &sysfs_stripe_size,
+       &sysfs_partial_stripes_expensive,
        &sysfs_sequential_cutoff,
        &sysfs_sequential_merge,
        &sysfs_clear_stats,
@@ -665,12 +686,10 @@ SHOW(__bch_cache)
                int cmp(const void *l, const void *r)
                {       return *((uint16_t *) r) - *((uint16_t *) l); }
 
-               /* Number of quantiles we compute */
-               const unsigned nq = 31;
-
                size_t n = ca->sb.nbuckets, i, unused, btree;
                uint64_t sum = 0;
-               uint16_t q[nq], *p, *cached;
+               /* Compute 31 quantiles */
+               uint16_t q[31], *p, *cached;
                ssize_t ret;
 
                cached = p = vmalloc(ca->sb.nbuckets * sizeof(uint16_t));
@@ -703,26 +722,29 @@ SHOW(__bch_cache)
                if (n)
                        do_div(sum, n);
 
-               for (i = 0; i < nq; i++)
-                       q[i] = INITIAL_PRIO - cached[n * (i + 1) / (nq + 1)];
+               for (i = 0; i < ARRAY_SIZE(q); i++)
+                       q[i] = INITIAL_PRIO - cached[n * (i + 1) /
+                               (ARRAY_SIZE(q) + 1)];
 
                vfree(p);
 
-               ret = snprintf(buf, PAGE_SIZE,
-                              "Unused:         %zu%%\n"
-                              "Metadata:       %zu%%\n"
-                              "Average:        %llu\n"
-                              "Sectors per Q:  %zu\n"
-                              "Quantiles:      [",
-                              unused * 100 / (size_t) ca->sb.nbuckets,
-                              btree * 100 / (size_t) ca->sb.nbuckets, sum,
-                              n * ca->sb.bucket_size / (nq + 1));
-
-               for (i = 0; i < nq && ret < (ssize_t) PAGE_SIZE; i++)
-                       ret += snprintf(buf + ret, PAGE_SIZE - ret,
-                                       i < nq - 1 ? "%u " : "%u]\n", q[i]);
-
-               buf[PAGE_SIZE - 1] = '\0';
+               ret = scnprintf(buf, PAGE_SIZE,
+                               "Unused:                %zu%%\n"
+                               "Metadata:      %zu%%\n"
+                               "Average:       %llu\n"
+                               "Sectors per Q: %zu\n"
+                               "Quantiles:     [",
+                               unused * 100 / (size_t) ca->sb.nbuckets,
+                               btree * 100 / (size_t) ca->sb.nbuckets, sum,
+                               n * ca->sb.bucket_size / (ARRAY_SIZE(q) + 1));
+
+               for (i = 0; i < ARRAY_SIZE(q); i++)
+                       ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+                                        "%u ", q[i]);
+               ret--;
+
+               ret += scnprintf(buf + ret, PAGE_SIZE - ret, "]\n");
+
                return ret;
        }
 
index 983f9bb411bc13e73be8d98cf6ef2fc0a48b07b8..f7b6c197f90f94f6aeb8ec59159265962af663c1 100644 (file)
@@ -2,6 +2,7 @@
 #include "btree.h"
 #include "request.h"
 
+#include <linux/blktrace_api.h>
 #include <linux/module.h>
 
 #define CREATE_TRACE_POINTS
 
 EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_request_start);
 EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_request_end);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_passthrough);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_cache_hit);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_cache_miss);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_bypass_sequential);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_bypass_congested);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_read);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_write);
 EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_read_retry);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writethrough);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writeback);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_write_skip);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_cache_insert);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_replay_key);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_write);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_full);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_entry_full);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_cache_cannibalize);
+
 EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_read);
 EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_write);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_write_dirty);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_read_dirty);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_write);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_cache_insert);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_alloc);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_alloc_fail);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_free);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_gc_coalesce);
 EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_gc_start);
 EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_gc_end);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_gc_copy);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_gc_copy_collision);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_insert_key);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_split);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_compact);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_set_root);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_alloc_invalidate);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_alloc_fail);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writeback);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writeback_collision);
index da3a99e85b1e0db79a35a2735769b7595f2be159..98eb81159a22ba9f9e88fec53127e2e338ae3d4d 100644 (file)
@@ -228,23 +228,6 @@ start:             bv->bv_len      = min_t(size_t, PAGE_SIZE - bv->bv_offset,
        }
 }
 
-int bch_bio_alloc_pages(struct bio *bio, gfp_t gfp)
-{
-       int i;
-       struct bio_vec *bv;
-
-       bio_for_each_segment(bv, bio, i) {
-               bv->bv_page = alloc_page(gfp);
-               if (!bv->bv_page) {
-                       while (bv-- != bio->bi_io_vec + bio->bi_idx)
-                               __free_page(bv->bv_page);
-                       return -ENOMEM;
-               }
-       }
-
-       return 0;
-}
-
 /*
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group (Any
  * use permitted, subject to terms of PostgreSQL license; see.)
index 577393e38c3ac3c05076d7a24ce0707a946a0402..1ae2a73ad85f5628b5292b769d79b0f28252f4ca 100644 (file)
@@ -15,8 +15,6 @@
 
 struct closure;
 
-#include <trace/events/bcache.h>
-
 #ifdef CONFIG_BCACHE_EDEBUG
 
 #define atomic_dec_bug(v)      BUG_ON(atomic_dec_return(v) < 0)
@@ -566,12 +564,8 @@ static inline unsigned fract_exp_two(unsigned x, unsigned fract_bits)
        return x;
 }
 
-#define bio_end(bio)   ((bio)->bi_sector + bio_sectors(bio))
-
 void bch_bio_map(struct bio *bio, void *base);
 
-int bch_bio_alloc_pages(struct bio *bio, gfp_t gfp);
-
 static inline sector_t bdev_sectors(struct block_device *bdev)
 {
        return bdev->bd_inode->i_size >> 9;
index 2714ed3991d1b747518aeb22d70222d1653d5e40..22cbff551628f3c9cff87ccc35563c09974f03b3 100644 (file)
@@ -9,6 +9,9 @@
 #include "bcache.h"
 #include "btree.h"
 #include "debug.h"
+#include "writeback.h"
+
+#include <trace/events/bcache.h>
 
 static struct workqueue_struct *dirty_wq;
 
@@ -36,7 +39,7 @@ static void __update_writeback_rate(struct cached_dev *dc)
 
        int change = 0;
        int64_t error;
-       int64_t dirty = atomic_long_read(&dc->disk.sectors_dirty);
+       int64_t dirty = bcache_dev_sectors_dirty(&dc->disk);
        int64_t derivative = dirty - dc->disk.sectors_dirty_last;
 
        dc->disk.sectors_dirty_last = dirty;
@@ -105,6 +108,31 @@ static bool dirty_pred(struct keybuf *buf, struct bkey *k)
        return KEY_DIRTY(k);
 }
 
+static bool dirty_full_stripe_pred(struct keybuf *buf, struct bkey *k)
+{
+       uint64_t stripe;
+       unsigned nr_sectors = KEY_SIZE(k);
+       struct cached_dev *dc = container_of(buf, struct cached_dev,
+                                            writeback_keys);
+       unsigned stripe_size = 1 << dc->disk.stripe_size_bits;
+
+       if (!KEY_DIRTY(k))
+               return false;
+
+       stripe = KEY_START(k) >> dc->disk.stripe_size_bits;
+       while (1) {
+               if (atomic_read(dc->disk.stripe_sectors_dirty + stripe) !=
+                   stripe_size)
+                       return false;
+
+               if (nr_sectors <= stripe_size)
+                       return true;
+
+               nr_sectors -= stripe_size;
+               stripe++;
+       }
+}
+
 static void dirty_init(struct keybuf_key *w)
 {
        struct dirty_io *io = w->private;
@@ -149,7 +177,22 @@ static void refill_dirty(struct closure *cl)
                searched_from_start = true;
        }
 
-       bch_refill_keybuf(dc->disk.c, buf, &end);
+       if (dc->partial_stripes_expensive) {
+               uint64_t i;
+
+               for (i = 0; i < dc->disk.nr_stripes; i++)
+                       if (atomic_read(dc->disk.stripe_sectors_dirty + i) ==
+                           1 << dc->disk.stripe_size_bits)
+                               goto full_stripes;
+
+               goto normal_refill;
+full_stripes:
+               bch_refill_keybuf(dc->disk.c, buf, &end,
+                                 dirty_full_stripe_pred);
+       } else {
+normal_refill:
+               bch_refill_keybuf(dc->disk.c, buf, &end, dirty_pred);
+       }
 
        if (bkey_cmp(&buf->last_scanned, &end) >= 0 && searched_from_start) {
                /* Searched the entire btree  - delay awhile */
@@ -181,10 +224,8 @@ void bch_writeback_queue(struct cached_dev *dc)
        }
 }
 
-void bch_writeback_add(struct cached_dev *dc, unsigned sectors)
+void bch_writeback_add(struct cached_dev *dc)
 {
-       atomic_long_add(sectors, &dc->disk.sectors_dirty);
-
        if (!atomic_read(&dc->has_dirty) &&
            !atomic_xchg(&dc->has_dirty, 1)) {
                atomic_inc(&dc->count);
@@ -203,6 +244,34 @@ void bch_writeback_add(struct cached_dev *dc, unsigned sectors)
        }
 }
 
+void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode,
+                                 uint64_t offset, int nr_sectors)
+{
+       struct bcache_device *d = c->devices[inode];
+       unsigned stripe_size, stripe_offset;
+       uint64_t stripe;
+
+       if (!d)
+               return;
+
+       stripe_size = 1 << d->stripe_size_bits;
+       stripe = offset >> d->stripe_size_bits;
+       stripe_offset = offset & (stripe_size - 1);
+
+       while (nr_sectors) {
+               int s = min_t(unsigned, abs(nr_sectors),
+                             stripe_size - stripe_offset);
+
+               if (nr_sectors < 0)
+                       s = -s;
+
+               atomic_add(s, d->stripe_sectors_dirty + stripe);
+               nr_sectors -= s;
+               stripe_offset = 0;
+               stripe++;
+       }
+}
+
 /* Background writeback - IO loop */
 
 static void dirty_io_destructor(struct closure *cl)
@@ -216,9 +285,10 @@ static void write_dirty_finish(struct closure *cl)
        struct dirty_io *io = container_of(cl, struct dirty_io, cl);
        struct keybuf_key *w = io->bio.bi_private;
        struct cached_dev *dc = io->dc;
-       struct bio_vec *bv = bio_iovec_idx(&io->bio, io->bio.bi_vcnt);
+       struct bio_vec *bv;
+       int i;
 
-       while (bv-- != io->bio.bi_io_vec)
+       bio_for_each_segment_all(bv, &io->bio, i)
                __free_page(bv->bv_page);
 
        /* This is kind of a dumb way of signalling errors. */
@@ -236,10 +306,12 @@ static void write_dirty_finish(struct closure *cl)
                for (i = 0; i < KEY_PTRS(&w->key); i++)
                        atomic_inc(&PTR_BUCKET(dc->disk.c, &w->key, i)->pin);
 
-               pr_debug("clearing %s", pkey(&w->key));
                bch_btree_insert(&op, dc->disk.c);
                closure_sync(&op.cl);
 
+               if (op.insert_collision)
+                       trace_bcache_writeback_collision(&w->key);
+
                atomic_long_inc(op.insert_collision
                                ? &dc->disk.c->writeback_keys_failed
                                : &dc->disk.c->writeback_keys_done);
@@ -275,7 +347,6 @@ static void write_dirty(struct closure *cl)
        io->bio.bi_bdev         = io->dc->bdev;
        io->bio.bi_end_io       = dirty_endio;
 
-       trace_bcache_write_dirty(&io->bio);
        closure_bio_submit(&io->bio, cl, &io->dc->disk);
 
        continue_at(cl, write_dirty_finish, dirty_wq);
@@ -296,7 +367,6 @@ static void read_dirty_submit(struct closure *cl)
 {
        struct dirty_io *io = container_of(cl, struct dirty_io, cl);
 
-       trace_bcache_read_dirty(&io->bio);
        closure_bio_submit(&io->bio, cl, &io->dc->disk);
 
        continue_at(cl, write_dirty, dirty_wq);
@@ -349,10 +419,10 @@ static void read_dirty(struct closure *cl)
                io->bio.bi_rw           = READ;
                io->bio.bi_end_io       = read_dirty_endio;
 
-               if (bch_bio_alloc_pages(&io->bio, GFP_KERNEL))
+               if (bio_alloc_pages(&io->bio, GFP_KERNEL))
                        goto err_free;
 
-               pr_debug("%s", pkey(&w->key));
+               trace_bcache_writeback(&w->key);
 
                closure_call(&io->cl, read_dirty_submit, NULL, &dc->disk.cl);
 
@@ -375,12 +445,49 @@ err:
        refill_dirty(cl);
 }
 
+/* Init */
+
+static int bch_btree_sectors_dirty_init(struct btree *b, struct btree_op *op,
+                                       struct cached_dev *dc)
+{
+       struct bkey *k;
+       struct btree_iter iter;
+
+       bch_btree_iter_init(b, &iter, &KEY(dc->disk.id, 0, 0));
+       while ((k = bch_btree_iter_next_filter(&iter, b, bch_ptr_bad)))
+               if (!b->level) {
+                       if (KEY_INODE(k) > dc->disk.id)
+                               break;
+
+                       if (KEY_DIRTY(k))
+                               bcache_dev_sectors_dirty_add(b->c, dc->disk.id,
+                                                            KEY_START(k),
+                                                            KEY_SIZE(k));
+               } else {
+                       btree(sectors_dirty_init, k, b, op, dc);
+                       if (KEY_INODE(k) > dc->disk.id)
+                               break;
+
+                       cond_resched();
+               }
+
+       return 0;
+}
+
+void bch_sectors_dirty_init(struct cached_dev *dc)
+{
+       struct btree_op op;
+
+       bch_btree_op_init_stack(&op);
+       btree_root(sectors_dirty_init, dc->disk.c, &op, dc);
+}
+
 void bch_cached_dev_writeback_init(struct cached_dev *dc)
 {
        closure_init_unlocked(&dc->writeback);
        init_rwsem(&dc->writeback_lock);
 
-       bch_keybuf_init(&dc->writeback_keys, dirty_pred);
+       bch_keybuf_init(&dc->writeback_keys);
 
        dc->writeback_metadata          = true;
        dc->writeback_running           = true;
diff --git a/drivers/md/bcache/writeback.h b/drivers/md/bcache/writeback.h
new file mode 100644 (file)
index 0000000..c91f61b
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _BCACHE_WRITEBACK_H
+#define _BCACHE_WRITEBACK_H
+
+#define CUTOFF_WRITEBACK       40
+#define CUTOFF_WRITEBACK_SYNC  70
+
+static inline uint64_t bcache_dev_sectors_dirty(struct bcache_device *d)
+{
+       uint64_t i, ret = 0;
+
+       for (i = 0; i < d->nr_stripes; i++)
+               ret += atomic_read(d->stripe_sectors_dirty + i);
+
+       return ret;
+}
+
+static inline bool bcache_dev_stripe_dirty(struct bcache_device *d,
+                                          uint64_t offset,
+                                          unsigned nr_sectors)
+{
+       uint64_t stripe = offset >> d->stripe_size_bits;
+
+       while (1) {
+               if (atomic_read(d->stripe_sectors_dirty + stripe))
+                       return true;
+
+               if (nr_sectors <= 1 << d->stripe_size_bits)
+                       return false;
+
+               nr_sectors -= 1 << d->stripe_size_bits;
+               stripe++;
+       }
+}
+
+static inline bool should_writeback(struct cached_dev *dc, struct bio *bio,
+                                   unsigned cache_mode, bool would_skip)
+{
+       unsigned in_use = dc->disk.c->gc_stats.in_use;
+
+       if (cache_mode != CACHE_MODE_WRITEBACK ||
+           atomic_read(&dc->disk.detaching) ||
+           in_use > CUTOFF_WRITEBACK_SYNC)
+               return false;
+
+       if (dc->partial_stripes_expensive &&
+           bcache_dev_stripe_dirty(&dc->disk, bio->bi_sector,
+                                   bio_sectors(bio)))
+               return true;
+
+       if (would_skip)
+               return false;
+
+       return bio->bi_rw & REQ_SYNC ||
+               in_use <= CUTOFF_WRITEBACK;
+}
+
+void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int);
+void bch_writeback_queue(struct cached_dev *);
+void bch_writeback_add(struct cached_dev *);
+
+void bch_sectors_dirty_init(struct cached_dev *dc);
+void bch_cached_dev_writeback_init(struct cached_dev *);
+
+#endif
index 957a719e8c2f1545073d2d897a00ffdf17321878..df7b0a06b0ea2d820aec6ad5a752a13bb64e13e8 100644 (file)
@@ -2290,12 +2290,18 @@ static void recovery_request_write(struct mddev *mddev, struct r10bio *r10_bio)
        d = r10_bio->devs[1].devnum;
        wbio = r10_bio->devs[1].bio;
        wbio2 = r10_bio->devs[1].repl_bio;
+       /* Need to test wbio2->bi_end_io before we call
+        * generic_make_request as if the former is NULL,
+        * the latter is free to free wbio2.
+        */
+       if (wbio2 && !wbio2->bi_end_io)
+               wbio2 = NULL;
        if (wbio->bi_end_io) {
                atomic_inc(&conf->mirrors[d].rdev->nr_pending);
                md_sync_acct(conf->mirrors[d].rdev->bdev, bio_sectors(wbio));
                generic_make_request(wbio);
        }
-       if (wbio2 && wbio2->bi_end_io) {
+       if (wbio2) {
                atomic_inc(&conf->mirrors[d].replacement->nr_pending);
                md_sync_acct(conf->mirrors[d].replacement->bdev,
                             bio_sectors(wbio2));
index 2bf094a587cb8ff2efb7e1bcabe6f40cd7b52602..78ea44336e75e06d5769b4a6158f2a1e506214e0 100644 (file)
@@ -3462,6 +3462,7 @@ static void handle_stripe(struct stripe_head *sh)
                    test_and_clear_bit(STRIPE_SYNC_REQUESTED, &sh->state)) {
                        set_bit(STRIPE_SYNCING, &sh->state);
                        clear_bit(STRIPE_INSYNC, &sh->state);
+                       clear_bit(STRIPE_REPLACED, &sh->state);
                }
                spin_unlock(&sh->stripe_lock);
        }
@@ -3607,19 +3608,23 @@ static void handle_stripe(struct stripe_head *sh)
                        handle_parity_checks5(conf, sh, &s, disks);
        }
 
-       if (s.replacing && s.locked == 0
-           && !test_bit(STRIPE_INSYNC, &sh->state)) {
+       if ((s.replacing || s.syncing) && s.locked == 0
+           && !test_bit(STRIPE_COMPUTE_RUN, &sh->state)
+           && !test_bit(STRIPE_REPLACED, &sh->state)) {
                /* Write out to replacement devices where possible */
                for (i = 0; i < conf->raid_disks; i++)
-                       if (test_bit(R5_UPTODATE, &sh->dev[i].flags) &&
-                           test_bit(R5_NeedReplace, &sh->dev[i].flags)) {
+                       if (test_bit(R5_NeedReplace, &sh->dev[i].flags)) {
+                               WARN_ON(!test_bit(R5_UPTODATE, &sh->dev[i].flags));
                                set_bit(R5_WantReplace, &sh->dev[i].flags);
                                set_bit(R5_LOCKED, &sh->dev[i].flags);
                                s.locked++;
                        }
-               set_bit(STRIPE_INSYNC, &sh->state);
+               if (s.replacing)
+                       set_bit(STRIPE_INSYNC, &sh->state);
+               set_bit(STRIPE_REPLACED, &sh->state);
        }
        if ((s.syncing || s.replacing) && s.locked == 0 &&
+           !test_bit(STRIPE_COMPUTE_RUN, &sh->state) &&
            test_bit(STRIPE_INSYNC, &sh->state)) {
                md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
                clear_bit(STRIPE_SYNCING, &sh->state);
index b0b663b119a8f324ba7fa3b58953b42c81030fa4..70c49329ca9a23fbbad73061477ac0a0cfe80e6e 100644 (file)
@@ -306,6 +306,7 @@ enum {
        STRIPE_SYNC_REQUESTED,
        STRIPE_SYNCING,
        STRIPE_INSYNC,
+       STRIPE_REPLACED,
        STRIPE_PREREAD_ACTIVE,
        STRIPE_DELAYED,
        STRIPE_DEGRADED,
index f7b90661e3213668310274b445f51d972ef4b9a5..e068a76a5f6f268bf183097007efb3aa571acb89 100644 (file)
@@ -66,14 +66,19 @@ EXPORT_SYMBOL(ssc_request);
 
 void ssc_free(struct ssc_device *ssc)
 {
+       bool disable_clk = true;
+
        spin_lock(&user_lock);
-       if (ssc->user) {
+       if (ssc->user)
                ssc->user--;
-               clk_disable_unprepare(ssc->clk);
-       } else {
+       else {
+               disable_clk = false;
                dev_dbg(&ssc->pdev->dev, "device already free\n");
        }
        spin_unlock(&user_lock);
+
+       if (disable_clk)
+               clk_disable_unprepare(ssc->clk);
 }
 EXPORT_SYMBOL(ssc_free);
 
index f9296abcf02ad88dd2b2fd6675c8c27bd7e0eda7..6127ab64bb399323e57e418e9742c2f5b8a9d86d 100644 (file)
@@ -167,7 +167,7 @@ int mei_hbm_start_req(struct mei_device *dev)
 
        dev->hbm_state = MEI_HBM_IDLE;
        if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
-               dev_err(&dev->pdev->dev, "version message writet failed\n");
+               dev_err(&dev->pdev->dev, "version message write failed\n");
                dev->dev_state = MEI_DEV_RESETTING;
                mei_reset(dev, 1);
                return -ENODEV;
index e4f8dec4dc3ccf134317abbd70594f503e9a5344..b22c7e2472254b89dbacc20c20772dfd297d575e 100644 (file)
@@ -239,14 +239,18 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
        if (mei_me_hw_is_ready(dev))
                return 0;
 
+       dev->recvd_hw_ready = false;
        mutex_unlock(&dev->device_lock);
        err = wait_event_interruptible_timeout(dev->wait_hw_ready,
-                       dev->recvd_hw_ready, MEI_INTEROP_TIMEOUT);
+                       dev->recvd_hw_ready,
+                       mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
        mutex_lock(&dev->device_lock);
        if (!err && !dev->recvd_hw_ready) {
+               if (!err)
+                       err = -ETIMEDOUT;
                dev_err(&dev->pdev->dev,
-                       "wait hw ready failed. status = 0x%x\n", err);
-               return -ETIMEDOUT;
+                       "wait hw ready failed. status = %d\n", err);
+               return err;
        }
 
        dev->recvd_hw_ready = false;
@@ -483,7 +487,9 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
        /* check if ME wants a reset */
        if (!mei_hw_is_ready(dev) &&
            dev->dev_state != MEI_DEV_RESETTING &&
-           dev->dev_state != MEI_DEV_INITIALIZING) {
+           dev->dev_state != MEI_DEV_INITIALIZING &&
+           dev->dev_state != MEI_DEV_POWER_DOWN &&
+           dev->dev_state != MEI_DEV_POWER_UP) {
                dev_dbg(&dev->pdev->dev, "FW not ready.\n");
                mei_reset(dev, 1);
                mutex_unlock(&dev->device_lock);
index ed1d75203af6e702de1e7a5c3fbdb6b6e8a765d6..e6f16f83ecdee479bfd679f169e078866bd3354a 100644 (file)
@@ -148,7 +148,8 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
 
        dev->hbm_state = MEI_HBM_IDLE;
 
-       if (dev->dev_state != MEI_DEV_INITIALIZING) {
+       if (dev->dev_state != MEI_DEV_INITIALIZING &&
+           dev->dev_state != MEI_DEV_POWER_UP) {
                if (dev->dev_state != MEI_DEV_DISABLED &&
                    dev->dev_state != MEI_DEV_POWER_DOWN)
                        dev->dev_state = MEI_DEV_RESETTING;
index 847b1996ce8ea105eeec31366dad87621a320ee2..2c5a91bb8ec3dbcf1433e114625e94b7d4c3cfe6 100644 (file)
@@ -128,7 +128,7 @@ static inline int pxamci_set_power(struct pxamci_host *host,
                               !!on ^ host->pdata->gpio_power_invert);
        }
        if (!host->vcc && host->pdata && host->pdata->setpower)
-               host->pdata->setpower(mmc_dev(host->mmc), vdd);
+               return host->pdata->setpower(mmc_dev(host->mmc), vdd);
 
        return 0;
 }
index a746ba272f04b5e3b77a4e45f65809a398c73585..a956053608f9f6a9fdb94c877917150e6a25680e 100644 (file)
@@ -1007,7 +1007,7 @@ static void arcnet_rx(struct net_device *dev, int bufnum)
 
        soft = &pkt.soft.rfc1201;
 
-       lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE));
+       lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE);
        if (pkt.hard.offset[0]) {
                ofs = pkt.hard.offset[0];
                length = 256 - ofs;
index 6aa7b3266c80904d8d2f2106869085a8b19d5248..ac6177d3befca611242f26906a9168f11ad3c23c 100644 (file)
@@ -412,10 +412,20 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
 
                switch (msg->msg.hdr.cmd) {
                case CMD_CAN_RX:
+                       if (msg->msg.rx.net >= dev->net_count) {
+                               dev_err(dev->udev->dev.parent, "format error\n");
+                               break;
+                       }
+
                        esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
                        break;
 
                case CMD_CAN_TX:
+                       if (msg->msg.txdone.net >= dev->net_count) {
+                               dev_err(dev->udev->dev.parent, "format error\n");
+                               break;
+                       }
+
                        esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
                                             msg);
                        break;
index cbd388eea68271c8ab7eaa2581ffb9145a4be429..8becd3d838b5eab2a520be8835c9fba3f3703482 100644 (file)
@@ -779,6 +779,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)
                        usb_unanchor_urb(urb);
                        usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
                                          urb->transfer_dma);
+                       usb_free_urb(urb);
                        break;
                }
 
index 53ad213e865ba350176ac8b59d83bac0dc58ca09..d8d95d4cd45a9ef00ffa7c9c919188bc66d39465 100644 (file)
@@ -3,19 +3,20 @@
 #
 
 config NET_VENDOR_ALLWINNER
-       bool "Allwinner devices"
-       default y
-       depends on ARCH_SUNXI
-       ---help---
-         If you have a network (Ethernet) card belonging to this
-        class, say Y and read the Ethernet-HOWTO, available from
-        <http://www.tldp.org/docs.html#howto>.
+       bool "Allwinner devices"
+       default y
 
-        Note that the answer to this question doesn't directly
-        affect the kernel: saying N will just cause the configurator
-        to skip all the questions about Allwinner cards. If you say Y,
-        you will be asked for your specific card in the following
-        questions.
+       depends on ARCH_SUNXI
+       ---help---
+         If you have a network (Ethernet) card belonging to this
+         class, say Y and read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         Note that the answer to this question doesn't directly
+         affect the kernel: saying N will just cause the configurator
+         to skip all the questions about Allwinner cards. If you say Y,
+         you will be asked for your specific card in the following
+         questions.
 
 if NET_VENDOR_ALLWINNER
 
@@ -26,6 +27,7 @@ config SUN4I_EMAC
        select CRC32
        select MII
        select PHYLIB
+       select MDIO_SUN4I
         ---help---
           Support for Allwinner A10 EMAC ethernet driver.
 
index b2bf324631dc89f7902f9d7322c549331daa1c78..0f0556526ba90bff7f764c4005d6f6e850220dd7 100644 (file)
@@ -520,6 +520,9 @@ struct atl1c_adapter {
        struct net_device   *netdev;
        struct pci_dev      *pdev;
        struct napi_struct  napi;
+       struct page         *rx_page;
+       unsigned int        rx_page_offset;
+       unsigned int        rx_frag_size;
        struct atl1c_hw        hw;
        struct atl1c_hw_stats  hw_stats;
        struct mii_if_info  mii;    /* MII interface info */
index 786a87483298ea400733b987da389144e297824b..a36a760ada28af64272a5132a60648c543963bed 100644 (file)
@@ -481,10 +481,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
 static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
                                struct net_device *dev)
 {
+       unsigned int head_size;
        int mtu = dev->mtu;
 
        adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ?
                roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
+
+       head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) +
+                   SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       adapter->rx_frag_size = roundup_pow_of_two(head_size);
 }
 
 static netdev_features_t atl1c_fix_features(struct net_device *netdev,
@@ -952,6 +957,10 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
                kfree(adapter->tpd_ring[0].buffer_info);
                adapter->tpd_ring[0].buffer_info = NULL;
        }
+       if (adapter->rx_page) {
+               put_page(adapter->rx_page);
+               adapter->rx_page = NULL;
+       }
 }
 
 /**
@@ -1639,6 +1648,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
        skb_checksum_none_assert(skb);
 }
 
+static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter)
+{
+       struct sk_buff *skb;
+       struct page *page;
+
+       if (adapter->rx_frag_size > PAGE_SIZE)
+               return netdev_alloc_skb(adapter->netdev,
+                                       adapter->rx_buffer_len);
+
+       page = adapter->rx_page;
+       if (!page) {
+               adapter->rx_page = page = alloc_page(GFP_ATOMIC);
+               if (unlikely(!page))
+                       return NULL;
+               adapter->rx_page_offset = 0;
+       }
+
+       skb = build_skb(page_address(page) + adapter->rx_page_offset,
+                       adapter->rx_frag_size);
+       if (likely(skb)) {
+               adapter->rx_page_offset += adapter->rx_frag_size;
+               if (adapter->rx_page_offset >= PAGE_SIZE)
+                       adapter->rx_page = NULL;
+               else
+                       get_page(page);
+       }
+       return skb;
+}
+
 static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
 {
        struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
@@ -1660,7 +1698,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
        while (next_info->flags & ATL1C_BUFFER_FREE) {
                rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
 
-               skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len);
+               skb = atl1c_alloc_skb(adapter);
                if (unlikely(!skb)) {
                        if (netif_msg_rx_err(adapter))
                                dev_warn(&pdev->dev, "alloc rx buffer failed\n");
index dedbd76c033ede4d695e3c7498f99ff263ca860b..d80e34b8285ff4457b6660e1e2fe6fe338f2e63e 100644 (file)
@@ -486,7 +486,7 @@ struct bnx2x_fastpath {
 
        struct napi_struct      napi;
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int state;
 #define BNX2X_FP_STATE_IDLE                  0
 #define BNX2X_FP_STATE_NAPI            (1 << 0)    /* NAPI owns this FP */
@@ -498,7 +498,7 @@ struct bnx2x_fastpath {
 #define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD)
        /* protect state */
        spinlock_t lock;
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
        union host_hc_status_block      status_blk;
        /* chip independent shortcuts into sb structure */
@@ -572,7 +572,7 @@ struct bnx2x_fastpath {
 #define bnx2x_fp_stats(bp, fp) (&((bp)->fp_stats[(fp)->index]))
 #define bnx2x_fp_qstats(bp, fp)        (&((bp)->fp_stats[(fp)->index].eth_q_stats))
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp)
 {
        spin_lock_init(&fp->lock);
@@ -680,7 +680,7 @@ static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp)
 {
        return false;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 /* Use 2500 as a mini-jumbo MTU for FCoE */
 #define BNX2X_FCOE_MINI_JUMBO_MTU      2500
index ee350bde1818cc38c4a20a0db70a466bf158ee2e..f2d1ff10054b28ccaa9b7baddfa408821c7409af 100644 (file)
@@ -3117,7 +3117,7 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
        return work_done;
 }
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 /* must be called with local_bh_disable()d */
 int bnx2x_low_latency_recv(struct napi_struct *napi)
 {
index e5da07858a2f0d5dca0747e1b7fe58992b799d5e..e06186c305d8f88d584a184175abcfd829300d4d 100644 (file)
@@ -12026,7 +12026,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
        .ndo_fcoe_get_wwn       = bnx2x_fcoe_get_wwn,
 #endif
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = bnx2x_low_latency_recv,
 #endif
 };
index d964f302ac94163f32780c4d1ed6667d4fb4165f..ddebc7a5dda0d14f32e8df6b7066b2d75c752a72 100644 (file)
@@ -17625,7 +17625,8 @@ err_out_free_res:
        pci_release_regions(pdev);
 
 err_out_disable_pdev:
-       pci_disable_device(pdev);
+       if (pci_is_enabled(pdev))
+               pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
        return err;
 }
@@ -17773,7 +17774,8 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
 
        rtnl_lock();
 
-       if (!netif_running(netdev))
+       /* We probably don't have netdev yet */
+       if (!netdev || !netif_running(netdev))
                goto done;
 
        tg3_phy_stop(tp);
index 2b0a0ea4f8e7eab210535c703b2a3d4987546d1d..ae236009f1a8c5dc857326751ce28ea68b2a4681 100644 (file)
@@ -259,6 +259,7 @@ struct bufdesc_ex {
 struct fec_enet_delayed_work {
        struct delayed_work delay_work;
        bool timeout;
+       bool trig_tx;
 };
 
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
index d3ad5ea711d316e1455cbe7d8eab61ecad8cb3d4..77ea0db0bbfc3e326d8137a26623de8fba1c4945 100644 (file)
@@ -93,6 +93,20 @@ static void set_multicast_list(struct net_device *ndev);
 #define FEC_QUIRK_HAS_CSUM             (1 << 5)
 /* Controller has hardware vlan support */
 #define FEC_QUIRK_HAS_VLAN             (1 << 6)
+/* ENET IP errata ERR006358
+ *
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * frames not being transmitted until there is a 0-to-1 transition on
+ * ENET_TDAR[TDAR].
+ */
+#define FEC_QUIRK_ERR006358            (1 << 7)
 
 static struct platform_device_id fec_devtype[] = {
        {
@@ -112,7 +126,7 @@ static struct platform_device_id fec_devtype[] = {
                .name = "imx6q-fec",
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
                                FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
-                               FEC_QUIRK_HAS_VLAN,
+                               FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358,
        }, {
                .name = "mvf600-fec",
                .driver_data = FEC_QUIRK_ENET_MAC,
@@ -275,16 +289,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        const struct platform_device_id *id_entry =
                                platform_get_device_id(fep->pdev);
-       struct bufdesc *bdp;
+       struct bufdesc *bdp, *bdp_pre;
        void *bufaddr;
        unsigned short  status;
        unsigned int index;
 
-       if (!fep->link) {
-               /* Link is down or auto-negotiation is in progress. */
-               return NETDEV_TX_BUSY;
-       }
-
        /* Fill in a Tx ring entry */
        bdp = fep->cur_tx;
 
@@ -370,6 +379,15 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                ebdp->cbd_esc |= BD_ENET_TX_PINS;
                }
        }
+
+       bdp_pre = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
+       if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
+           !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
+               fep->delay_work.trig_tx = true;
+               schedule_delayed_work(&(fep->delay_work.delay_work),
+                                       msecs_to_jiffies(1));
+       }
+
        /* If this was the last BD in the ring, start at the beginning again. */
        if (status & BD_ENET_TX_WRAP)
                bdp = fep->tx_bd_base;
@@ -689,6 +707,11 @@ static void fec_enet_work(struct work_struct *work)
                fec_restart(fep->netdev, fep->full_duplex);
                netif_wake_queue(fep->netdev);
        }
+
+       if (fep->delay_work.trig_tx) {
+               fep->delay_work.trig_tx = false;
+               writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+       }
 }
 
 static void
@@ -2279,4 +2302,5 @@ static struct platform_driver fec_driver = {
 
 module_platform_driver(fec_driver);
 
+MODULE_ALIAS("platform:"DRIVER_NAME);
 MODULE_LICENSE("GPL");
index 6a0c1b66ce54116b88a8aaf33bcf0518a7ef7ca3..c1d72c03cb5932f83e9f8a397a55227fee981d9f 100644 (file)
@@ -3739,9 +3739,8 @@ static void igb_set_rx_mode(struct net_device *netdev)
        rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE);
 
        if (netdev->flags & IFF_PROMISC) {
-               u32 mrqc = rd32(E1000_MRQC);
                /* retain VLAN HW filtering if in VT mode */
-               if (mrqc & E1000_MRQC_ENABLE_VMDQ)
+               if (adapter->vfs_allocated_count)
                        rctl |= E1000_RCTL_VFE;
                rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
                vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME);
index 7be725cdfea8d3b3c7f414a500dd83b965f24d99..a6494e5daffe9d4b26171b570251b9a97d78991d 100644 (file)
@@ -54,7 +54,7 @@
 
 #include <net/busy_poll.h>
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 #define LL_EXTENDED_STATS
 #endif
 /* common prefix used by pr_<> macros */
@@ -366,7 +366,7 @@ struct ixgbe_q_vector {
        struct rcu_head rcu;    /* to avoid race with update stats on free */
        char name[IFNAMSIZ + 9];
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int state;
 #define IXGBE_QV_STATE_IDLE        0
 #define IXGBE_QV_STATE_NAPI       1    /* NAPI owns this QV */
@@ -377,12 +377,12 @@ struct ixgbe_q_vector {
 #define IXGBE_QV_YIELD (IXGBE_QV_STATE_NAPI_YIELD | IXGBE_QV_STATE_POLL_YIELD)
 #define IXGBE_QV_USER_PEND (IXGBE_QV_STATE_POLL | IXGBE_QV_STATE_POLL_YIELD)
        spinlock_t lock;
-#endif  /* CONFIG_NET_LL_RX_POLL */
+#endif  /* CONFIG_NET_RX_BUSY_POLL */
 
        /* for dynamic allocation of rings associated with this q_vector */
        struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp;
 };
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
 {
 
@@ -462,7 +462,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
        WARN_ON(!(q_vector->state & IXGBE_QV_LOCKED));
        return q_vector->state & IXGBE_QV_USER_PEND;
 }
-#else /* CONFIG_NET_LL_RX_POLL */
+#else /* CONFIG_NET_RX_BUSY_POLL */
 static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
 {
 }
@@ -491,7 +491,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
 {
        return false;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 #ifdef CONFIG_IXGBE_HWMON
 
index ac780770863dfb3a338f3dfe4550f5bd87d2e66e..7a77f37a7cbcbd6b7b5b87dd78e9e50b677e778c 100644 (file)
@@ -108,9 +108,8 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
 
        /* Enable arbiter */
        reg &= ~IXGBE_DPMCS_ARBDIS;
-       /* Enable DFP and Recycle mode */
-       reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM);
        reg |= IXGBE_DPMCS_TSOEF;
+
        /* Configure Max TSO packet size 34KB including payload and headers */
        reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT);
 
index bad8f14b194107b7d77ac5f89f194998c4c0f514..be4b1fb3d0d2c38b62bcabdb2dc80a8332634cba 100644 (file)
@@ -1998,7 +1998,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
        return total_rx_packets;
 }
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 /* must be called with local_bh_disable()d */
 static int ixgbe_low_latency_recv(struct napi_struct *napi)
 {
@@ -2030,7 +2030,7 @@ static int ixgbe_low_latency_recv(struct napi_struct *napi)
 
        return found;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 /**
  * ixgbe_configure_msix - Configure MSI-X hardware
@@ -7227,7 +7227,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = ixgbe_netpoll,
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = ixgbe_low_latency_recv,
 #endif
 #ifdef IXGBE_FCOE
index 712779fb12b7d80416db0a4349257f046ae0d11d..b017818bccae1a06bc0c85e88d29733f9a1365e6 100644 (file)
@@ -88,6 +88,8 @@
 #define      MVNETA_TX_IN_PRGRS                  BIT(1)
 #define      MVNETA_TX_FIFO_EMPTY                BIT(8)
 #define MVNETA_RX_MIN_FRAME_SIZE                 0x247c
+#define MVNETA_SGMII_SERDES_CFG                         0x24A0
+#define      MVNETA_SGMII_SERDES_PROTO          0x0cc7
 #define MVNETA_TYPE_PRIO                         0x24bc
 #define      MVNETA_FORCE_UNI                    BIT(21)
 #define MVNETA_TXQ_CMD_1                         0x24e4
@@ -655,6 +657,8 @@ static void mvneta_port_sgmii_config(struct mvneta_port *pp)
        val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
        val |= MVNETA_GMAC2_PSC_ENABLE;
        mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
+
+       mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
 }
 
 /* Start the Ethernet port RX and TX activity */
@@ -2728,28 +2732,24 @@ static int mvneta_probe(struct platform_device *pdev)
 
        pp = netdev_priv(dev);
 
-       pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
-       init_timer(&pp->tx_done_timer);
-       clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
-
        pp->weight = MVNETA_RX_POLL_WEIGHT;
        pp->phy_node = phy_node;
        pp->phy_interface = phy_mode;
 
-       pp->base = of_iomap(dn, 0);
-       if (pp->base == NULL) {
-               err = -ENOMEM;
-               goto err_free_irq;
-       }
-
        pp->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(pp->clk)) {
                err = PTR_ERR(pp->clk);
-               goto err_unmap;
+               goto err_free_irq;
        }
 
        clk_prepare_enable(pp->clk);
 
+       pp->base = of_iomap(dn, 0);
+       if (pp->base == NULL) {
+               err = -ENOMEM;
+               goto err_clk;
+       }
+
        dt_mac_addr = of_get_mac_address(dn);
        if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) {
                mac_from = "device tree";
@@ -2766,6 +2766,9 @@ static int mvneta_probe(struct platform_device *pdev)
        }
 
        pp->tx_done_timer.data = (unsigned long)dev;
+       pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
+       init_timer(&pp->tx_done_timer);
+       clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
 
        pp->tx_ring_size = MVNETA_MAX_TXD;
        pp->rx_ring_size = MVNETA_MAX_RXD;
@@ -2776,7 +2779,7 @@ static int mvneta_probe(struct platform_device *pdev)
        err = mvneta_init(pp, phy_addr);
        if (err < 0) {
                dev_err(&pdev->dev, "can't init eth hal\n");
-               goto err_clk;
+               goto err_unmap;
        }
        mvneta_port_power_up(pp, phy_mode);
 
@@ -2806,10 +2809,10 @@ static int mvneta_probe(struct platform_device *pdev)
 
 err_deinit:
        mvneta_deinit(pp);
-err_clk:
-       clk_disable_unprepare(pp->clk);
 err_unmap:
        iounmap(pp->base);
+err_clk:
+       clk_disable_unprepare(pp->clk);
 err_free_irq:
        irq_dispose_mapping(dev->irq);
 err_free_netdev:
index 727874f575cedc80e65d52d4918007151feb3c09..a28cd801a236e5a674de67009a5b872ed29e9e71 100644 (file)
@@ -223,7 +223,7 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
        case ETH_SS_STATS:
                return (priv->stats_bitmap ? bit_count : NUM_ALL_STATS) +
                        (priv->tx_ring_num * 2) +
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
                        (priv->rx_ring_num * 5);
 #else
                        (priv->rx_ring_num * 2);
@@ -276,7 +276,7 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
        for (i = 0; i < priv->rx_ring_num; i++) {
                data[index++] = priv->rx_ring[i].packets;
                data[index++] = priv->rx_ring[i].bytes;
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
                data[index++] = priv->rx_ring[i].yields;
                data[index++] = priv->rx_ring[i].misses;
                data[index++] = priv->rx_ring[i].cleaned;
@@ -344,7 +344,7 @@ static void mlx4_en_get_strings(struct net_device *dev,
                                "rx%d_packets", i);
                        sprintf(data + (index++) * ETH_GSTRING_LEN,
                                "rx%d_bytes", i);
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
                        sprintf(data + (index++) * ETH_GSTRING_LEN,
                                "rx%d_napi_yield", i);
                        sprintf(data + (index++) * ETH_GSTRING_LEN,
index 5eac871399d8ecedf4fcffff06ed4372753df77f..fa37b7a612133c739263346a5d6f372af0fd9dda 100644 (file)
@@ -68,7 +68,7 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up)
        return 0;
 }
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 /* must be called with local_bh_disable()d */
 static int mlx4_en_low_latency_recv(struct napi_struct *napi)
 {
@@ -94,7 +94,7 @@ static int mlx4_en_low_latency_recv(struct napi_struct *napi)
 
        return done;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 #ifdef CONFIG_RFS_ACCEL
 
@@ -2140,7 +2140,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
 #ifdef CONFIG_RFS_ACCEL
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = mlx4_en_low_latency_recv,
 #endif
 };
index 8873d6802c80dd8c5359f7c1e19834236f2c9ae6..6fc6dabc78d542a3fbe9c6b470913e6744e5d196 100644 (file)
@@ -845,16 +845,7 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
                           MLX4_CMD_NATIVE);
 
        if (!err && dev->caps.function != slave) {
-               /* if config MAC in DB use it */
-               if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac)
-                       def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
-               else {
-                       /* set slave default_mac address */
-                       MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET);
-                       def_mac += slave << 8;
-                       priv->mfunc.master.vf_admin[slave].vport[vhcr->in_modifier].mac = def_mac;
-               }
-
+               def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
                MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET);
 
                /* get port type - currently only eth is enabled */
index e85af922dcdcc237ea5e7c7f227088fe77e90802..36be3208786a69ac5ae40ddd5111f79116db3f95 100644 (file)
@@ -371,7 +371,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 
        dev->caps.sqp_demux = (mlx4_is_master(dev)) ? MLX4_MAX_NUM_SLAVES : 0;
 
-       if (!enable_64b_cqe_eqe) {
+       if (!enable_64b_cqe_eqe && !mlx4_is_slave(dev)) {
                if (dev_cap->flags &
                    (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) {
                        mlx4_warn(dev, "64B EQEs/CQEs supported by the device but not enabled\n");
index 35fb60e2320c2a896e8b241c2c9dbbe575a2dd02..5e0aa569306aab2f6c8185cd1574cdd4abeb4aab 100644 (file)
@@ -292,7 +292,7 @@ struct mlx4_en_rx_ring {
        void *rx_info;
        unsigned long bytes;
        unsigned long packets;
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned long yields;
        unsigned long misses;
        unsigned long cleaned;
@@ -318,7 +318,7 @@ struct mlx4_en_cq {
        struct mlx4_cqe *buf;
 #define MLX4_EN_OPCODE_ERROR   0x1e
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int state;
 #define MLX4_EN_CQ_STATE_IDLE        0
 #define MLX4_EN_CQ_STATE_NAPI     1    /* NAPI owns this CQ */
@@ -329,7 +329,7 @@ struct mlx4_en_cq {
 #define CQ_YIELD (MLX4_EN_CQ_STATE_NAPI_YIELD | MLX4_EN_CQ_STATE_POLL_YIELD)
 #define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD)
        spinlock_t poll_lock; /* protects from LLS/napi conflicts */
-#endif  /* CONFIG_NET_LL_RX_POLL */
+#endif  /* CONFIG_NET_RX_BUSY_POLL */
 };
 
 struct mlx4_en_port_profile {
@@ -580,7 +580,7 @@ struct mlx4_mac_entry {
        struct rcu_head rcu;
 };
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
 {
        spin_lock_init(&cq->poll_lock);
@@ -687,7 +687,7 @@ static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
 {
        return false;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
 
index 205753a04cfcb22e8904dbe2e3e203d82df32552..c571de85d0f995bb2c302210cfbd979b9e1bec9e 100644 (file)
@@ -46,7 +46,7 @@
 #include "mlx5_core.h"
 
 enum {
-       CMD_IF_REV = 3,
+       CMD_IF_REV = 4,
 };
 
 enum {
@@ -282,6 +282,12 @@ const char *mlx5_command_str(int command)
        case MLX5_CMD_OP_TEARDOWN_HCA:
                return "TEARDOWN_HCA";
 
+       case MLX5_CMD_OP_ENABLE_HCA:
+               return "MLX5_CMD_OP_ENABLE_HCA";
+
+       case MLX5_CMD_OP_DISABLE_HCA:
+               return "MLX5_CMD_OP_DISABLE_HCA";
+
        case MLX5_CMD_OP_QUERY_PAGES:
                return "QUERY_PAGES";
 
@@ -1113,7 +1119,13 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
 
        for (i = 0; i < (1 << cmd->log_sz); i++) {
                if (test_bit(i, &vector)) {
+                       struct semaphore *sem;
+
                        ent = cmd->ent_arr[i];
+                       if (ent->page_queue)
+                               sem = &cmd->pages_sem;
+                       else
+                               sem = &cmd->sem;
                        ktime_get_ts(&ent->ts2);
                        memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
                        dump_command(dev, ent, 0);
@@ -1136,10 +1148,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
                        } else {
                                complete(&ent->done);
                        }
-                       if (ent->page_queue)
-                               up(&cmd->pages_sem);
-                       else
-                               up(&cmd->sem);
+                       up(sem);
                }
        }
 }
index 12242de2b0e3ec7950a01f966def239e4b1ce74f..b47739b0b5f6dfb34139ad74e02ac10db1d4fbbd 100644 (file)
@@ -249,6 +249,44 @@ static int set_hca_ctrl(struct mlx5_core_dev *dev)
        return err;
 }
 
+static int mlx5_core_enable_hca(struct mlx5_core_dev *dev)
+{
+       int err;
+       struct mlx5_enable_hca_mbox_in in;
+       struct mlx5_enable_hca_mbox_out out;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ENABLE_HCA);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       return 0;
+}
+
+static int mlx5_core_disable_hca(struct mlx5_core_dev *dev)
+{
+       int err;
+       struct mlx5_disable_hca_mbox_in in;
+       struct mlx5_disable_hca_mbox_out out;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DISABLE_HCA);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       return 0;
+}
+
 int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
 {
        struct mlx5_priv *priv = &dev->priv;
@@ -304,28 +342,41 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
        }
 
        mlx5_pagealloc_init(dev);
+
+       err = mlx5_core_enable_hca(dev);
+       if (err) {
+               dev_err(&pdev->dev, "enable hca failed\n");
+               goto err_pagealloc_cleanup;
+       }
+
+       err = mlx5_satisfy_startup_pages(dev, 1);
+       if (err) {
+               dev_err(&pdev->dev, "failed to allocate boot pages\n");
+               goto err_disable_hca;
+       }
+
        err = set_hca_ctrl(dev);
        if (err) {
                dev_err(&pdev->dev, "set_hca_ctrl failed\n");
-               goto err_pagealloc_cleanup;
+               goto reclaim_boot_pages;
        }
 
        err = handle_hca_cap(dev);
        if (err) {
                dev_err(&pdev->dev, "handle_hca_cap failed\n");
-               goto err_pagealloc_cleanup;
+               goto reclaim_boot_pages;
        }
 
-       err = mlx5_satisfy_startup_pages(dev);
+       err = mlx5_satisfy_startup_pages(dev, 0);
        if (err) {
-               dev_err(&pdev->dev, "failed to allocate startup pages\n");
-               goto err_pagealloc_cleanup;
+               dev_err(&pdev->dev, "failed to allocate init pages\n");
+               goto reclaim_boot_pages;
        }
 
        err = mlx5_pagealloc_start(dev);
        if (err) {
                dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n");
-               goto err_reclaim_pages;
+               goto reclaim_boot_pages;
        }
 
        err = mlx5_cmd_init_hca(dev);
@@ -396,9 +447,12 @@ err_stop_poll:
 err_pagealloc_stop:
        mlx5_pagealloc_stop(dev);
 
-err_reclaim_pages:
+reclaim_boot_pages:
        mlx5_reclaim_startup_pages(dev);
 
+err_disable_hca:
+       mlx5_core_disable_hca(dev);
+
 err_pagealloc_cleanup:
        mlx5_pagealloc_cleanup(dev);
        mlx5_cmd_cleanup(dev);
@@ -434,6 +488,7 @@ void mlx5_dev_cleanup(struct mlx5_core_dev *dev)
        mlx5_cmd_teardown_hca(dev);
        mlx5_pagealloc_stop(dev);
        mlx5_reclaim_startup_pages(dev);
+       mlx5_core_disable_hca(dev);
        mlx5_pagealloc_cleanup(dev);
        mlx5_cmd_cleanup(dev);
        iounmap(dev->iseg);
index f0bf46339b2805d745c89eca8a413a5cd002efb8..4a3e137931a38b898468061ae8334016e4e2f23e 100644 (file)
@@ -64,7 +64,7 @@ struct mlx5_query_pages_inbox {
 
 struct mlx5_query_pages_outbox {
        struct mlx5_outbox_hdr  hdr;
-       u8                      reserved[2];
+       __be16                  num_boot_pages;
        __be16                  func_id;
        __be16                  init_pages;
        __be16                  num_pages;
@@ -146,7 +146,7 @@ static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr)
 }
 
 static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
-                               s16 *pages, s16 *init_pages)
+                               s16 *pages, s16 *init_pages, u16 *boot_pages)
 {
        struct mlx5_query_pages_inbox   in;
        struct mlx5_query_pages_outbox  out;
@@ -164,8 +164,13 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
 
        if (pages)
                *pages = be16_to_cpu(out.num_pages);
+
        if (init_pages)
                *init_pages = be16_to_cpu(out.init_pages);
+
+       if (boot_pages)
+               *boot_pages = be16_to_cpu(out.num_boot_pages);
+
        *func_id = be16_to_cpu(out.func_id);
 
        return err;
@@ -357,19 +362,22 @@ void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
        queue_work(dev->priv.pg_wq, &req->work);
 }
 
-int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev)
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)
 {
+       u16 uninitialized_var(boot_pages);
        s16 uninitialized_var(init_pages);
        u16 uninitialized_var(func_id);
        int err;
 
-       err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages);
+       err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages,
+                                  &boot_pages);
        if (err)
                return err;
 
-       mlx5_core_dbg(dev, "requested %d init pages for func_id 0x%x\n", init_pages, func_id);
 
-       return give_pages(dev, func_id, init_pages, 0);
+       mlx5_core_dbg(dev, "requested %d init pages and %d boot pages for func_id 0x%x\n",
+                     init_pages, boot_pages, func_id);
+       return give_pages(dev, func_id, boot ? boot_pages : init_pages, 0);
 }
 
 static int optimal_reclaimed_pages(void)
index 71d4a39372009847b7d03b11c58e8ccf695e61b3..68f5d9c77c7b13b9038cf5bc4e920e09ac3c33a9 100644 (file)
@@ -164,6 +164,7 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
                uuari->uars[i].map = ioremap(addr, PAGE_SIZE);
                if (!uuari->uars[i].map) {
                        mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+                       err = -ENOMEM;
                        goto out_count;
                }
                mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n",
index cb22341a14a8c03fd7627c0d2d2a31f9f68ce126..a588ffde970041def37cae92b215011d88b6eea6 100644 (file)
@@ -4,7 +4,7 @@
 
 config PCH_GBE
        tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE"
-       depends on PCI
+       depends on PCI && (X86 || COMPILE_TEST)
        select MII
        select PTP_1588_CLOCK_PCH
        ---help---
index b00cf5665eabee735b1e218e6aeda7111380fe69..221645e9f182052fc7641155e1db37ef5044cb2f 100644 (file)
@@ -1400,8 +1400,8 @@ void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64);
 #define ADDR_IN_RANGE(addr, low, high) \
        (((addr) < (high)) && ((addr) >= (low)))
 
-#define QLCRD32(adapter, off) \
-       (adapter->ahw->hw_ops->read_reg)(adapter, off)
+#define QLCRD32(adapter, off, err) \
+       (adapter->ahw->hw_ops->read_reg)(adapter, off, err)
 
 #define QLCWR32(adapter, off, val) \
        adapter->ahw->hw_ops->write_reg(adapter, off, val)
@@ -1604,7 +1604,7 @@ struct qlcnic_nic_template {
 struct qlcnic_hardware_ops {
        void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
        void (*write_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
-       int (*read_reg) (struct qlcnic_adapter *, ulong);
+       int (*read_reg) (struct qlcnic_adapter *, ulong, int *);
        int (*write_reg) (struct qlcnic_adapter *, ulong, u32);
        void (*get_ocm_win) (struct qlcnic_hardware_context *);
        int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
@@ -1662,12 +1662,6 @@ static inline void qlcnic_write_crb(struct qlcnic_adapter *adapter, char *buf,
        adapter->ahw->hw_ops->write_crb(adapter, buf, offset, size);
 }
 
-static inline int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter,
-                                      ulong off)
-{
-       return adapter->ahw->hw_ops->read_reg(adapter, off);
-}
-
 static inline int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter,
                                        ulong off, u32 data)
 {
@@ -1869,7 +1863,8 @@ static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
 
 static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter)
 {
-       adapter->ahw->hw_ops->set_mac_filter_count(adapter);
+       if (adapter->ahw->hw_ops->set_mac_filter_count)
+               adapter->ahw->hw_ops->set_mac_filter_count(adapter);
 }
 
 static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
index 0913c623a67efd238e7d989d50cb2b1c7238cefa..92da9980a0a0a2b86ed2189313c7105ad693354a 100644 (file)
@@ -228,17 +228,17 @@ static int __qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr)
        return 0;
 }
 
-int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr)
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,
+                               int *err)
 {
-       int ret;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       ret = __qlcnic_set_win_base(adapter, (u32) addr);
-       if (!ret) {
+       *err = __qlcnic_set_win_base(adapter, (u32) addr);
+       if (!*err) {
                return QLCRDX(ahw, QLCNIC_WILDCARD);
        } else {
                dev_err(&adapter->pdev->dev,
-                       "%s failed, addr = 0x%x\n", __func__, (int)addr);
+                       "%s failed, addr = 0x%lx\n", __func__, addr);
                return -EIO;
        }
 }
@@ -561,7 +561,7 @@ void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter)
 void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                          loff_t offset, size_t size)
 {
-       int ret;
+       int ret = 0;
        u32 data;
 
        if (qlcnic_api_lock(adapter)) {
@@ -571,7 +571,7 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                return;
        }
 
-       ret = qlcnic_83xx_rd_reg_indirect(adapter, (u32) offset);
+       data = QLCRD32(adapter, (u32) offset, &ret);
        qlcnic_api_unlock(adapter);
 
        if (ret == -EIO) {
@@ -580,7 +580,6 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                        __func__, (u32)offset);
                return;
        }
-       data = ret;
        memcpy(buf, &data, size);
 }
 
@@ -2075,18 +2074,25 @@ void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
 static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
                                        u32 data[])
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        u8 link_status, duplex;
        /* link speed */
        link_status = LSB(data[3]) & 1;
-       adapter->ahw->link_speed = MSW(data[2]);
-       adapter->ahw->link_autoneg = MSB(MSW(data[3]));
-       adapter->ahw->module_type = MSB(LSW(data[3]));
-       duplex = LSB(MSW(data[3]));
-       if (duplex)
-               adapter->ahw->link_duplex = DUPLEX_FULL;
-       else
-               adapter->ahw->link_duplex = DUPLEX_HALF;
-       adapter->ahw->has_link_events = 1;
+       if (link_status) {
+               ahw->link_speed = MSW(data[2]);
+               duplex = LSB(MSW(data[3]));
+               if (duplex)
+                       ahw->link_duplex = DUPLEX_FULL;
+               else
+                       ahw->link_duplex = DUPLEX_HALF;
+       } else {
+               ahw->link_speed = SPEED_UNKNOWN;
+               ahw->link_duplex = DUPLEX_UNKNOWN;
+       }
+
+       ahw->link_autoneg = MSB(MSW(data[3]));
+       ahw->module_type = MSB(LSW(data[3]));
+       ahw->has_link_events = 1;
        qlcnic_advert_link_change(adapter, link_status);
 }
 
@@ -2384,9 +2390,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
                                      u32 flash_addr, u8 *p_data,
                                      int count)
 {
-       int i, ret;
-       u32 word, range, flash_offset, addr = flash_addr;
+       u32 word, range, flash_offset, addr = flash_addr, ret;
        ulong indirect_add, direct_window;
+       int i, err = 0;
 
        flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1);
        if (addr & 0x3) {
@@ -2404,10 +2410,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
                /* Multi sector read */
                for (i = 0; i < count; i++) {
                        indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
-                       ret = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                         indirect_add);
-                       if (ret == -EIO)
-                               return -EIO;
+                       ret = QLCRD32(adapter, indirect_add, &err);
+                       if (err == -EIO)
+                               return err;
 
                        word = ret;
                        *(u32 *)p_data  = word;
@@ -2428,10 +2433,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
                /* Single sector read */
                for (i = 0; i < count; i++) {
                        indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
-                       ret = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                         indirect_add);
-                       if (ret == -EIO)
-                               return -EIO;
+                       ret = QLCRD32(adapter, indirect_add, &err);
+                       if (err == -EIO)
+                               return err;
 
                        word = ret;
                        *(u32 *)p_data  = word;
@@ -2447,10 +2451,13 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
 {
        u32 status;
        int retries = QLC_83XX_FLASH_READ_RETRY_COUNT;
+       int err = 0;
 
        do {
-               status = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                    QLC_83XX_FLASH_STATUS);
+               status = QLCRD32(adapter, QLC_83XX_FLASH_STATUS, &err);
+               if (err == -EIO)
+                       return err;
+
                if ((status & QLC_83XX_FLASH_STATUS_READY) ==
                    QLC_83XX_FLASH_STATUS_READY)
                        break;
@@ -2502,7 +2509,8 @@ int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *adapter)
 
 int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
 {
-       int ret, mfg_id;
+       int ret, err = 0;
+       u32 mfg_id;
 
        if (qlcnic_83xx_lock_flash(adapter))
                return -EIO;
@@ -2517,9 +2525,11 @@ int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
                return -EIO;
        }
 
-       mfg_id = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
-       if (mfg_id == -EIO)
-               return -EIO;
+       mfg_id = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err);
+       if (err == -EIO) {
+               qlcnic_83xx_unlock_flash(adapter);
+               return err;
+       }
 
        adapter->flash_mfg_id = (mfg_id & 0xFF);
        qlcnic_83xx_unlock_flash(adapter);
@@ -2636,7 +2646,7 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
                                 u32 *p_data, int count)
 {
        u32 temp;
-       int ret = -EIO;
+       int ret = -EIO, err = 0;
 
        if ((count < QLC_83XX_FLASH_WRITE_MIN) ||
            (count > QLC_83XX_FLASH_WRITE_MAX)) {
@@ -2645,8 +2655,10 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
                return -EIO;
        }
 
-       temp = qlcnic_83xx_rd_reg_indirect(adapter,
-                                          QLC_83XX_FLASH_SPI_CONTROL);
+       temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err);
+       if (err == -EIO)
+               return err;
+
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL,
                                     (temp | QLC_83XX_FLASH_SPI_CTRL));
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
@@ -2695,13 +2707,18 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
                return -EIO;
        }
 
-       ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_SPI_STATUS);
+       ret = QLCRD32(adapter, QLC_83XX_FLASH_SPI_STATUS, &err);
+       if (err == -EIO)
+               return err;
+
        if ((ret & QLC_83XX_FLASH_SPI_CTRL) == QLC_83XX_FLASH_SPI_CTRL) {
                dev_err(&adapter->pdev->dev, "%s: failed at %d\n",
                        __func__, __LINE__);
                /* Operation failed, clear error bit */
-               temp = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                  QLC_83XX_FLASH_SPI_CONTROL);
+               temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err);
+               if (err == -EIO)
+                       return err;
+
                qlcnic_83xx_wrt_reg_indirect(adapter,
                                             QLC_83XX_FLASH_SPI_CONTROL,
                                             (temp | QLC_83XX_FLASH_SPI_CTRL));
@@ -2823,6 +2840,7 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
 {
        int i, j, ret = 0;
        u32 temp;
+       int err = 0;
 
        /* Check alignment */
        if (addr & 0xF)
@@ -2855,8 +2873,12 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
                                             QLCNIC_TA_WRITE_START);
 
                for (j = 0; j < MAX_CTL_CHECK; j++) {
-                       temp = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                          QLCNIC_MS_CTRL);
+                       temp = QLCRD32(adapter, QLCNIC_MS_CTRL, &err);
+                       if (err == -EIO) {
+                               mutex_unlock(&adapter->ahw->mem_lock);
+                               return err;
+                       }
+
                        if ((temp & TA_CTL_BUSY) == 0)
                                break;
                }
@@ -2878,9 +2900,9 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
 int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
                             u8 *p_data, int count)
 {
-       int i, ret;
-       u32 word, addr = flash_addr;
+       u32 word, addr = flash_addr, ret;
        ulong  indirect_addr;
+       int i, err = 0;
 
        if (qlcnic_83xx_lock_flash(adapter) != 0)
                return -EIO;
@@ -2900,10 +2922,10 @@ int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
                }
 
                indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr);
-               ret = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                 indirect_addr);
-               if (ret == -EIO)
-                       return -EIO;
+               ret = QLCRD32(adapter, indirect_addr, &err);
+               if (err == -EIO)
+                       return err;
+
                word = ret;
                *(u32 *)p_data  = word;
                p_data = p_data + 4;
@@ -3014,8 +3036,8 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
        }
 
        if (ahw->port_type == QLCNIC_XGBE) {
-               ecmd->supported = SUPPORTED_1000baseT_Full;
-               ecmd->advertising = ADVERTISED_1000baseT_Full;
+               ecmd->supported = SUPPORTED_10000baseT_Full;
+               ecmd->advertising = ADVERTISED_10000baseT_Full;
        } else {
                ecmd->supported = (SUPPORTED_10baseT_Half |
                                   SUPPORTED_10baseT_Full |
@@ -3369,7 +3391,8 @@ int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,
 
 static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
 {
-       int ret;
+       int ret, err = 0;
+       u32 temp;
 
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
                                     QLC_83XX_FLASH_OEM_READ_SIG);
@@ -3379,8 +3402,11 @@ static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
        if (ret)
                return -EIO;
 
-       ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
-       return ret & 0xFF;
+       temp = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err);
+       if (err == -EIO)
+               return err;
+
+       return temp & 0xFF;
 }
 
 int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)
index 2548d1403d75a7668434d53db5013f3969dd8f78..272f56a2e14b10b14ff97714c063b3f62ba4c7f8 100644 (file)
@@ -508,7 +508,7 @@ void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *);
 void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *);
 void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
 void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
-int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong);
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong, int *);
 int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32);
 void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []);
 int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32);
index f41dfab1e9a35d3fc4b3d72c820b2d5db84f59e0..9f4b8d5f08657d04fff6f0996b46313a1eea75dd 100644 (file)
@@ -1303,8 +1303,11 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
 {
        int i, j;
        u32 val = 0, val1 = 0, reg = 0;
+       int err = 0;
 
-       val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG);
+       val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG, &err);
+       if (err == -EIO)
+               return;
        dev_info(&adapter->pdev->dev, "SRE-Shim Ctrl:0x%x\n", val);
 
        for (j = 0; j < 2; j++) {
@@ -1318,7 +1321,9 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
                        reg = QLC_83XX_PORT1_THRESHOLD;
                }
                for (i = 0; i < 8; i++) {
-                       val = QLCRD32(adapter, reg + (i * 0x4));
+                       val = QLCRD32(adapter, reg + (i * 0x4), &err);
+                       if (err == -EIO)
+                               return;
                        dev_info(&adapter->pdev->dev, "0x%x  ", val);
                }
                dev_info(&adapter->pdev->dev, "\n");
@@ -1335,8 +1340,10 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
                        reg = QLC_83XX_PORT1_TC_MC_REG;
                }
                for (i = 0; i < 4; i++) {
-                       val = QLCRD32(adapter, reg + (i * 0x4));
-                        dev_info(&adapter->pdev->dev, "0x%x  ", val);
+                       val = QLCRD32(adapter, reg + (i * 0x4), &err);
+                       if (err == -EIO)
+                               return;
+                       dev_info(&adapter->pdev->dev, "0x%x  ", val);
                }
                dev_info(&adapter->pdev->dev, "\n");
        }
@@ -1352,17 +1359,25 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
                        reg = QLC_83XX_PORT1_TC_STATS;
                }
                for (i = 7; i >= 0; i--) {
-                       val = QLCRD32(adapter, reg);
+                       val = QLCRD32(adapter, reg, &err);
+                       if (err == -EIO)
+                               return;
                        val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
                        QLCWR32(adapter, reg, (val | (i << 29)));
-                       val = QLCRD32(adapter, reg);
+                       val = QLCRD32(adapter, reg, &err);
+                       if (err == -EIO)
+                               return;
                        dev_info(&adapter->pdev->dev, "0x%x  ", val);
                }
                dev_info(&adapter->pdev->dev, "\n");
        }
 
-       val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD);
-       val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD);
+       val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, &err);
+       if (err == -EIO)
+               return;
+       val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, &err);
+       if (err == -EIO)
+               return;
        dev_info(&adapter->pdev->dev,
                 "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
                 val, val1);
@@ -1425,7 +1440,7 @@ static void qlcnic_83xx_take_eport_out_of_reset(struct qlcnic_adapter *adapter)
 static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
 {
        u32 heartbeat, peg_status;
-       int retries, ret = -EIO;
+       int retries, ret = -EIO, err = 0;
 
        retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
        p_dev->heartbeat = QLC_SHARED_REG_RD32(p_dev,
@@ -1453,11 +1468,11 @@ static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
                         "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
                         "PEG_NET_4_PC: 0x%x\n", peg_status,
                         QLC_SHARED_REG_RD32(p_dev, QLCNIC_PEG_HALT_STATUS2),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4));
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0, &err),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1, &err),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2, &err),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3, &err),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4, &err));
 
                if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
                        dev_err(&p_dev->pdev->dev,
@@ -1501,18 +1516,22 @@ int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
 static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr,
                                int duration, u32 mask, u32 status)
 {
+       int timeout_error, err = 0;
        u32 value;
-       int timeout_error;
        u8 retries;
 
-       value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+       value = QLCRD32(p_dev, addr, &err);
+       if (err == -EIO)
+               return err;
        retries = duration / 10;
 
        do {
                if ((value & mask) != status) {
                        timeout_error = 1;
                        msleep(duration / 10);
-                       value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+                       value = QLCRD32(p_dev, addr, &err);
+                       if (err == -EIO)
+                               return err;
                } else {
                        timeout_error = 0;
                        break;
@@ -1606,9 +1625,12 @@ int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
 static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev,
                                           u32 raddr, u32 waddr)
 {
-       int value;
+       int err = 0;
+       u32 value;
 
-       value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+       value = QLCRD32(p_dev, raddr, &err);
+       if (err == -EIO)
+               return;
        qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
 }
 
@@ -1617,12 +1639,16 @@ static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
                                    u32 raddr, u32 waddr,
                                    struct qlc_83xx_rmw *p_rmw_hdr)
 {
-       int value;
+       int err = 0;
+       u32 value;
 
-       if (p_rmw_hdr->index_a)
+       if (p_rmw_hdr->index_a) {
                value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
-       else
-               value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+       } else {
+               value = QLCRD32(p_dev, raddr, &err);
+               if (err == -EIO)
+                       return;
+       }
 
        value &= p_rmw_hdr->mask;
        value <<= p_rmw_hdr->shl;
@@ -1675,7 +1701,7 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
        long delay;
        struct qlc_83xx_entry *entry;
        struct qlc_83xx_poll *poll;
-       int i;
+       int i, err = 0;
        unsigned long arg1, arg2;
 
        poll = (struct qlc_83xx_poll *)((char *)p_hdr +
@@ -1699,10 +1725,12 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
                                                         arg1, delay,
                                                         poll->mask,
                                                         poll->status)){
-                                       qlcnic_83xx_rd_reg_indirect(p_dev,
-                                                                   arg1);
-                                       qlcnic_83xx_rd_reg_indirect(p_dev,
-                                                                   arg2);
+                                       QLCRD32(p_dev, arg1, &err);
+                                       if (err == -EIO)
+                                               return;
+                                       QLCRD32(p_dev, arg2, &err);
+                                       if (err == -EIO)
+                                               return;
                                }
                        }
                }
@@ -1768,7 +1796,7 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
                                       struct qlc_83xx_entry_hdr *p_hdr)
 {
        long delay;
-       int index, i, j;
+       int index, i, j, err;
        struct qlc_83xx_quad_entry *entry;
        struct qlc_83xx_poll *poll;
        unsigned long addr;
@@ -1788,7 +1816,10 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
                                                  poll->mask, poll->status)){
                                index = p_dev->ahw->reset.array_index;
                                addr = entry->dr_addr;
-                               j = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+                               j = QLCRD32(p_dev, addr, &err);
+                               if (err == -EIO)
+                                       return;
+
                                p_dev->ahw->reset.array[index++] = j;
 
                                if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
@@ -2123,6 +2154,8 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
        qlcnic_83xx_clear_function_resources(adapter);
 
+       INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
        /* register for NIC IDC AEN Events */
        qlcnic_83xx_register_nic_idc_func(adapter, 1);
 
@@ -2140,8 +2173,6 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        if (adapter->nic_ops->init_driver(adapter))
                return -EIO;
 
-       INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
-
        /* Periodically monitor device status */
        qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
 
index 0581a484ceb519dc8e6b11b6d08b06e4461bab46..d09389b33474d7c9ae730385e6fa3478fd77c832 100644 (file)
@@ -104,7 +104,7 @@ static u32
 qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
 {
        u32 rsp;
-       int timeout = 0;
+       int timeout = 0, err = 0;
 
        do {
                /* give atleast 1ms for firmware to respond */
@@ -113,7 +113,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
                if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT)
                        return QLCNIC_CDRP_RSP_TIMEOUT;
 
-               rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET);
+               rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET, &err);
        } while (!QLCNIC_CDRP_IS_RSP(rsp));
 
        return rsp;
@@ -122,7 +122,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
 int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
                          struct qlcnic_cmd_args *cmd)
 {
-       int i;
+       int i, err = 0;
        u32 rsp;
        u32 signature;
        struct pci_dev *pdev = adapter->pdev;
@@ -148,7 +148,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
                dev_err(&pdev->dev, "card response timeout.\n");
                cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
        } else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
-               cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1));
+               cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1), &err);
                switch (cmd->rsp.arg[0]) {
                case QLCNIC_RCODE_INVALID_ARGS:
                        fmt = "CDRP invalid args: [%d]\n";
@@ -175,7 +175,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
                cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;
 
        for (i = 1; i < cmd->rsp.num; i++)
-               cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i));
+               cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i), &err);
 
        /* Release semaphore */
        qlcnic_api_unlock(adapter);
@@ -210,10 +210,10 @@ int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter, u32 fw_cmd)
        if (err) {
                dev_info(&adapter->pdev->dev,
                         "Failed to set driver version in firmware\n");
-               return -EIO;
+               err = -EIO;
        }
-
-       return 0;
+       qlcnic_free_mbx_args(&cmd);
+       return err;
 }
 
 int
index 700a46324d09230b8d8ba6e6fc820bc0e56b9526..7aac23ab31d1bb26b9ac3c069580a114b5dff299 100644 (file)
@@ -150,6 +150,7 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
        "Link_Test_on_offline",
        "Interrupt_Test_offline",
        "Internal_Loopback_offline",
+       "External_Loopback_offline",
        "EEPROM_Test_offline"
 };
 
@@ -266,7 +267,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
 {
        struct qlcnic_hardware_context *ahw = adapter->ahw;
        u32 speed, reg;
-       int check_sfp_module = 0;
+       int check_sfp_module = 0, err = 0;
        u16 pcifn = ahw->pci_func;
 
        /* read which mode */
@@ -289,7 +290,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
 
        } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
                u32 val = 0;
-               val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
+               val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err);
 
                if (val == QLCNIC_PORT_MODE_802_3_AP) {
                        ecmd->supported = SUPPORTED_1000baseT_Full;
@@ -300,9 +301,13 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
                }
 
                if (netif_running(adapter->netdev) && ahw->has_link_events) {
-                       reg = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
-                       speed = P3P_LINK_SPEED_VAL(pcifn, reg);
-                       ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+                       if (ahw->linkup) {
+                               reg = QLCRD32(adapter,
+                                             P3P_LINK_SPEED_REG(pcifn), &err);
+                               speed = P3P_LINK_SPEED_VAL(pcifn, reg);
+                               ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+                       }
+
                        ethtool_cmd_speed_set(ecmd, ahw->link_speed);
                        ecmd->autoneg = ahw->link_autoneg;
                        ecmd->duplex = ahw->link_duplex;
@@ -463,13 +468,14 @@ static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
                                     u32 *regs_buff)
 {
-       int i, j = 0;
+       int i, j = 0, err = 0;
 
        for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
                regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
        j = 0;
        while (ext_diag_registers[j] != -1)
-               regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]);
+               regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++],
+                                        &err);
        return i;
 }
 
@@ -519,13 +525,16 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 static u32 qlcnic_test_link(struct net_device *dev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
+       int err = 0;
        u32 val;
 
        if (qlcnic_83xx_check(adapter)) {
                val = qlcnic_83xx_test_link(adapter);
                return (val & 1) ? 0 : 1;
        }
-       val = QLCRD32(adapter, CRB_XG_STATE_P3P);
+       val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err);
+       if (err == -EIO)
+               return err;
        val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
        return (val == XG_LINK_UP_P3P) ? 0 : 1;
 }
@@ -658,6 +667,7 @@ qlcnic_get_pauseparam(struct net_device *netdev,
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        int port = adapter->ahw->physical_port;
+       int err = 0;
        __u32 val;
 
        if (qlcnic_83xx_check(adapter)) {
@@ -668,9 +678,13 @@ qlcnic_get_pauseparam(struct net_device *netdev,
                if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
                        return;
                /* get flow control settings */
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
+               if (err == -EIO)
+                       return;
                pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
+               if (err == -EIO)
+                       return;
                switch (port) {
                case 0:
                        pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
@@ -690,7 +704,9 @@ qlcnic_get_pauseparam(struct net_device *netdev,
                if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
                        return;
                pause->rx_pause = 1;
-               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
+               if (err == -EIO)
+                       return;
                if (port == 0)
                        pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
                else
@@ -707,6 +723,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        int port = adapter->ahw->physical_port;
+       int err = 0;
        __u32 val;
 
        if (qlcnic_83xx_check(adapter))
@@ -717,7 +734,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
                if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
                        return -EIO;
                /* set flow control */
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
+               if (err == -EIO)
+                       return err;
 
                if (pause->rx_pause)
                        qlcnic_gb_rx_flowctl(val);
@@ -728,7 +747,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
                                val);
                QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
                /* set autoneg */
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
+               if (err == -EIO)
+                       return err;
                switch (port) {
                case 0:
                        if (pause->tx_pause)
@@ -764,7 +785,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
                if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
                        return -EIO;
 
-               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
+               if (err == -EIO)
+                       return err;
                if (port == 0) {
                        if (pause->tx_pause)
                                qlcnic_xg_unset_xg0_mask(val);
@@ -788,11 +811,14 @@ static int qlcnic_reg_test(struct net_device *dev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 data_read;
+       int err = 0;
 
        if (qlcnic_83xx_check(adapter))
                return qlcnic_83xx_reg_test(adapter);
 
-       data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
+       data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err);
+       if (err == -EIO)
+               return err;
        if ((data_read & 0xffff) != adapter->pdev->vendor)
                return 1;
 
@@ -1026,8 +1052,15 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
                if (data[3])
                        eth_test->flags |= ETH_TEST_FL_FAILED;
 
-               data[4] = qlcnic_eeprom_test(dev);
-               if (data[4])
+               if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
+                       data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
+                       if (data[4])
+                               eth_test->flags |= ETH_TEST_FL_FAILED;
+                       eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
+               }
+
+               data[5] = qlcnic_eeprom_test(dev);
+               if (data[5])
                        eth_test->flags |= ETH_TEST_FL_FAILED;
        }
 }
@@ -1257,17 +1290,20 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 wol_cfg;
+       int err = 0;
 
        if (qlcnic_83xx_check(adapter))
                return;
        wol->supported = 0;
        wol->wolopts = 0;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
+       if (err == -EIO)
+               return;
        if (wol_cfg & (1UL << adapter->portnum))
                wol->supported |= WAKE_MAGIC;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
        if (wol_cfg & (1UL << adapter->portnum))
                wol->wolopts |= WAKE_MAGIC;
 }
@@ -1277,17 +1313,22 @@ qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 wol_cfg;
+       int err = 0;
 
        if (qlcnic_83xx_check(adapter))
                return -EOPNOTSUPP;
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EINVAL;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
+       if (err == -EIO)
+               return err;
        if (!(wol_cfg & (1 << adapter->portnum)))
                return -EOPNOTSUPP;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
+       if (err == -EIO)
+               return err;
        if (wol->wolopts & WAKE_MAGIC)
                wol_cfg |= 1UL << adapter->portnum;
        else
@@ -1540,7 +1581,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
                return 0;
        case QLCNIC_SET_QUIESCENT:
        case QLCNIC_RESET_QUIESCENT:
-               state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+               state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
                if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
                        netdev_info(netdev, "Device in FAILED state\n");
                return 0;
index 5b5d2edf125d9f93920b13d83fbfa802c96140fc..4d5f59b2d153f55579bd3c3f2a64f3c96b9ca66e 100644 (file)
@@ -317,16 +317,20 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data)
 int
 qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
 {
-       int done = 0, timeout = 0;
+       int timeout = 0;
+       int err = 0;
+       u32 done = 0;
 
        while (!done) {
-               done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)));
+               done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)),
+                              &err);
                if (done == 1)
                        break;
                if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
                        dev_err(&adapter->pdev->dev,
                                "Failed to acquire sem=%d lock; holdby=%d\n",
-                               sem, id_reg ? QLCRD32(adapter, id_reg) : -1);
+                               sem,
+                               id_reg ? QLCRD32(adapter, id_reg, &err) : -1);
                        return -EIO;
                }
                msleep(1);
@@ -341,19 +345,22 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
 void
 qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
 {
-       QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
+       int err = 0;
+
+       QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)), &err);
 }
 
 int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
 {
+       int err = 0;
        u32 data;
 
        if (qlcnic_82xx_check(adapter))
                qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data);
        else {
-               data = qlcnic_83xx_rd_reg_indirect(adapter, addr);
-               if (data == -EIO)
-                       return -EIO;
+               data = QLCRD32(adapter, addr, &err);
+               if (err == -EIO)
+                       return err;
        }
        return data;
 }
@@ -516,20 +523,18 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
        if (netdev->flags & IFF_PROMISC) {
                if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
                        mode = VPORT_MISS_MODE_ACCEPT_ALL;
-       } else if (netdev->flags & IFF_ALLMULTI) {
-               if (netdev_mc_count(netdev) > ahw->max_mc_count) {
-                       mode = VPORT_MISS_MODE_ACCEPT_MULTI;
-               } else if (!netdev_mc_empty(netdev) &&
-                          !qlcnic_sriov_vf_check(adapter)) {
-                               netdev_for_each_mc_addr(ha, netdev)
-                                       qlcnic_nic_add_mac(adapter, ha->addr,
-                                                          vlan);
-               }
-               if (mode != VPORT_MISS_MODE_ACCEPT_MULTI &&
-                   qlcnic_sriov_vf_check(adapter))
-                       qlcnic_vf_add_mc_list(netdev, vlan);
+       } else if ((netdev->flags & IFF_ALLMULTI) ||
+                  (netdev_mc_count(netdev) > ahw->max_mc_count)) {
+               mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+       } else if (!netdev_mc_empty(netdev) &&
+                  !qlcnic_sriov_vf_check(adapter)) {
+               netdev_for_each_mc_addr(ha, netdev)
+                       qlcnic_nic_add_mac(adapter, ha->addr, vlan);
        }
 
+       if (qlcnic_sriov_vf_check(adapter))
+               qlcnic_vf_add_mc_list(netdev, vlan);
+
        /* configure unicast MAC address, if there is not sufficient space
         * to store all the unicast addresses then enable promiscuous mode
         */
@@ -1161,7 +1166,8 @@ int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off,
        return -EIO;
 }
 
-int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off,
+                             int *err)
 {
        unsigned long flags;
        int rv;
@@ -1417,7 +1423,7 @@ int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
 
 int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
 {
-       int offset, board_type, magic;
+       int offset, board_type, magic, err = 0;
        struct pci_dev *pdev = adapter->pdev;
 
        offset = QLCNIC_FW_MAGIC_OFFSET;
@@ -1437,7 +1443,9 @@ int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
        adapter->ahw->board_type = board_type;
 
        if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) {
-               u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I);
+               u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I, &err);
+               if (err == -EIO)
+                       return err;
                if ((gpio & 0x8000) == 0)
                        board_type = QLCNIC_BRDTYPE_P3P_10G_TP;
        }
@@ -1477,10 +1485,13 @@ int
 qlcnic_wol_supported(struct qlcnic_adapter *adapter)
 {
        u32 wol_cfg;
+       int err = 0;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
        if (wol_cfg & (1UL << adapter->portnum)) {
-               wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+               wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
+               if (err == -EIO)
+                       return err;
                if (wol_cfg & (1 << adapter->portnum))
                        return 1;
        }
@@ -1541,6 +1552,7 @@ void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
 void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                          loff_t offset, size_t size)
 {
+       int err = 0;
        u32 data;
        u64 qmdata;
 
@@ -1548,7 +1560,7 @@ void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
                memcpy(buf, &qmdata, size);
        } else {
-               data = QLCRD32(adapter, offset);
+               data = QLCRD32(adapter, offset, &err);
                memcpy(buf, &data, size);
        }
 }
index 2c22504f57aac090b5cfecf9ec819f876b2ef6ed..4a71b28effcb041421d1332cf3dc810a3b9fe8ae 100644 (file)
@@ -154,7 +154,7 @@ struct qlcnic_hardware_context;
 struct qlcnic_adapter;
 
 int qlcnic_82xx_start_firmware(struct qlcnic_adapter *);
-int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong);
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *);
 int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
 int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int);
 int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
index d28336fc65abe5752f4a295ae54708edf9d3b0ae..974d62607e138c792fb44224cf5a06b5f0794130 100644 (file)
@@ -142,7 +142,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter)
                                         buffrag->length, PCI_DMA_TODEVICE);
                        buffrag->dma = 0ULL;
                }
-               for (j = 0; j < cmd_buf->frag_count; j++) {
+               for (j = 1; j < cmd_buf->frag_count; j++) {
                        buffrag++;
                        if (buffrag->dma) {
                                pci_unmap_page(adapter->pdev, buffrag->dma,
@@ -286,10 +286,11 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
 {
        long timeout = 0;
        long done = 0;
+       int err = 0;
 
        cond_resched();
        while (done == 0) {
-               done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS);
+               done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS, &err);
                done &= 2;
                if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) {
                        dev_err(&adapter->pdev->dev,
@@ -304,6 +305,8 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
 static int do_rom_fast_read(struct qlcnic_adapter *adapter,
                            u32 addr, u32 *valp)
 {
+       int err = 0;
+
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr);
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3);
@@ -317,7 +320,9 @@ static int do_rom_fast_read(struct qlcnic_adapter *adapter,
        udelay(10);
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
 
-       *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA);
+       *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA, &err);
+       if (err == -EIO)
+               return err;
        return 0;
 }
 
@@ -369,11 +374,11 @@ int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp)
 
 int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
 {
-       int addr, val;
+       int addr, err = 0;
        int i, n, init_delay;
        struct crb_addr_pair *buf;
        unsigned offset;
-       u32 off;
+       u32 off, val;
        struct pci_dev *pdev = adapter->pdev;
 
        QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, 0);
@@ -402,7 +407,9 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, QLCNIC_CRB_NIU + 0xb0000, 0x00);
 
        /* halt sre */
-       val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000);
+       val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000, &err);
+       if (err == -EIO)
+               return err;
        QLCWR32(adapter, QLCNIC_CRB_SRE + 0x1000, val & (~(0x1)));
 
        /* halt epg */
@@ -719,10 +726,12 @@ qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter)
 static int
 qlcnic_has_mn(struct qlcnic_adapter *adapter)
 {
-       u32 capability;
-       capability = 0;
+       u32 capability = 0;
+       int err = 0;
 
-       capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY);
+       capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY, &err);
+       if (err == -EIO)
+               return err;
        if (capability & QLCNIC_PEG_TUNE_MN_PRESENT)
                return 1;
 
index d3f8797efcc3d7a6012ea56ddb4feda210727f22..6946d354f44f76c1e6e990a092cc043a21cf7e09 100644 (file)
@@ -161,36 +161,68 @@ static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data)
        return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0;
 }
 
+static void qlcnic_delete_rx_list_mac(struct qlcnic_adapter *adapter,
+                                     struct qlcnic_filter *fil,
+                                     void *addr, u16 vlan_id)
+{
+       int ret;
+       u8 op;
+
+       op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+       ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op);
+       if (ret)
+               return;
+
+       op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
+       ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op);
+       if (!ret) {
+               hlist_del(&fil->fnode);
+               adapter->rx_fhash.fnum--;
+       }
+}
+
+static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head,
+                                                   void *addr, u16 vlan_id)
+{
+       struct qlcnic_filter *tmp_fil = NULL;
+       struct hlist_node *n;
+
+       hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
+               if (!memcmp(tmp_fil->faddr, addr, ETH_ALEN) &&
+                   tmp_fil->vlan_id == vlan_id)
+                       return tmp_fil;
+       }
+
+       return NULL;
+}
+
 void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
                          int loopback_pkt, u16 vlan_id)
 {
        struct ethhdr *phdr = (struct ethhdr *)(skb->data);
        struct qlcnic_filter *fil, *tmp_fil;
-       struct hlist_node *n;
        struct hlist_head *head;
        unsigned long time;
        u64 src_addr = 0;
-       u8 hindex, found = 0, op;
+       u8 hindex, op;
        int ret;
 
        memcpy(&src_addr, phdr->h_source, ETH_ALEN);
+       hindex = qlcnic_mac_hash(src_addr) &
+                (adapter->fhash.fbucket_size - 1);
 
        if (loopback_pkt) {
                if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax)
                        return;
 
-               hindex = qlcnic_mac_hash(src_addr) &
-                        (adapter->fhash.fbucket_size - 1);
                head = &(adapter->rx_fhash.fhead[hindex]);
 
-               hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
-                       if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
-                           tmp_fil->vlan_id == vlan_id) {
-                               time = tmp_fil->ftime;
-                               if (jiffies > (QLCNIC_READD_AGE * HZ + time))
-                                       tmp_fil->ftime = jiffies;
-                               return;
-                       }
+               tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
+               if (tmp_fil) {
+                       time = tmp_fil->ftime;
+                       if (time_after(jiffies, QLCNIC_READD_AGE * HZ + time))
+                               tmp_fil->ftime = jiffies;
+                       return;
                }
 
                fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
@@ -205,36 +237,37 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
                adapter->rx_fhash.fnum++;
                spin_unlock(&adapter->rx_mac_learn_lock);
        } else {
-               hindex = qlcnic_mac_hash(src_addr) &
-                        (adapter->fhash.fbucket_size - 1);
-               head = &(adapter->rx_fhash.fhead[hindex]);
-               spin_lock(&adapter->rx_mac_learn_lock);
-               hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
-                       if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
-                           tmp_fil->vlan_id == vlan_id) {
-                               found = 1;
-                               break;
-                       }
-               }
+               head = &adapter->fhash.fhead[hindex];
 
-               if (!found) {
-                       spin_unlock(&adapter->rx_mac_learn_lock);
-                       return;
-               }
+               spin_lock(&adapter->mac_learn_lock);
 
-               op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
-               ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr,
-                                               vlan_id, op);
-               if (!ret) {
+               tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
+               if (tmp_fil) {
                        op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
                        ret = qlcnic_sre_macaddr_change(adapter,
                                                        (u8 *)&src_addr,
                                                        vlan_id, op);
                        if (!ret) {
-                               hlist_del(&(tmp_fil->fnode));
-                               adapter->rx_fhash.fnum--;
+                               hlist_del(&tmp_fil->fnode);
+                               adapter->fhash.fnum--;
                        }
+
+                       spin_unlock(&adapter->mac_learn_lock);
+
+                       return;
                }
+
+               spin_unlock(&adapter->mac_learn_lock);
+
+               head = &adapter->rx_fhash.fhead[hindex];
+
+               spin_lock(&adapter->rx_mac_learn_lock);
+
+               tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
+               if (tmp_fil)
+                       qlcnic_delete_rx_list_mac(adapter, tmp_fil, &src_addr,
+                                                 vlan_id);
+
                spin_unlock(&adapter->rx_mac_learn_lock);
        }
 }
@@ -262,7 +295,7 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
 
        mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
        mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
-       memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
+       memcpy(mac_req->mac_addr, uaddr, ETH_ALEN);
 
        vlan_req = (struct qlcnic_vlan_req *)&req->words[1];
        vlan_req->vlan_id = cpu_to_le16(vlan_id);
index 4528f8ec333bb50d01c116958cb1a86c7392ef7c..ee013fcc33220f4d7bfdf8e60600accaefab77cd 100644 (file)
@@ -977,8 +977,8 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
 static int
 qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
 {
-       int err;
        struct qlcnic_info nic_info;
+       int err = 0;
 
        memset(&nic_info, 0, sizeof(struct qlcnic_info));
        err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func);
@@ -993,7 +993,9 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
 
        if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
                u32 temp;
-               temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+               temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2, &err);
+               if (err == -EIO)
+                       return err;
                adapter->ahw->extra_capability[0] = temp;
        }
        adapter->ahw->max_mac_filters = nic_info.max_mac_filters;
@@ -1383,6 +1385,8 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
        if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                if (qlcnic_82xx_check(adapter))
                        handler = qlcnic_tmp_intr;
+               else
+                       handler = qlcnic_83xx_tmp_intr;
                if (!QLCNIC_IS_MSI_FAMILY(adapter))
                        flags |= IRQF_SHARED;
 
@@ -1531,12 +1535,12 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
        if (netdev->features & NETIF_F_LRO)
                qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
 
+       set_bit(__QLCNIC_DEV_UP, &adapter->state);
        qlcnic_napi_enable(adapter);
 
        qlcnic_linkevent_request(adapter, 1);
 
        adapter->ahw->reset_context = 0;
-       set_bit(__QLCNIC_DEV_UP, &adapter->state);
        return 0;
 }
 
@@ -2139,7 +2143,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (qlcnic_83xx_check(adapter) && !qlcnic_use_msi_x &&
            !!qlcnic_use_msi)
                dev_warn(&pdev->dev,
-                        "83xx adapter do not support MSI interrupts\n");
+                        "Device does not support MSI interrupts\n");
 
        err = qlcnic_setup_intr(adapter, 0);
        if (err) {
@@ -3093,6 +3097,7 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
 {
        u32 state = 0, heartbeat;
        u32 peg_status;
+       int err = 0;
 
        if (qlcnic_check_temp(adapter))
                goto detach;
@@ -3139,11 +3144,11 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
                        "PEG_NET_4_PC: 0x%x\n",
                        peg_status,
                        QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, &err));
        if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
                dev_err(&adapter->pdev->dev,
                        "Firmware aborted with error code 0x00006700. "
index ab8a6744d402f43e794007db16ee218916051675..79e54efe07b921cc2d7e1986c7d45e16ee9e7ecb 100644 (file)
@@ -1084,7 +1084,7 @@ flash_temp:
        tmpl_hdr = ahw->fw_dump.tmpl_hdr;
        tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
 
-       if ((tmpl_hdr->version & 0xffffff) >= 0x20001)
+       if ((tmpl_hdr->version & 0xfffff) >= 0x20001)
                ahw->fw_dump.use_pex_dma = true;
        else
                ahw->fw_dump.use_pex_dma = false;
index 62380ce8990555a2b120fd768cae0f2192508a8e..5d40045b3ceaa47038593dfffc52c986f18cef21 100644 (file)
@@ -562,7 +562,7 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
        INIT_LIST_HEAD(&adapter->vf_mc_list);
        if (!qlcnic_use_msi_x && !!qlcnic_use_msi)
                dev_warn(&adapter->pdev->dev,
-                        "83xx adapter do not support MSI interrupts\n");
+                        "Device does not support MSI interrupts\n");
 
        err = qlcnic_setup_intr(adapter, 1);
        if (err) {
@@ -762,6 +762,7 @@ static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type)
                        memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
                        mbx->req.arg[0] = (type | (mbx->req.num << 16) |
                                           (3 << 29));
+                       mbx->rsp.arg[0] = (type & 0xffff) | mbx->rsp.num << 16;
                        return 0;
                }
        }
@@ -813,6 +814,7 @@ static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans,
                cmd->req.num = trans->req_pay_size / 4;
                cmd->rsp.num = trans->rsp_pay_size / 4;
                hdr = trans->rsp_hdr;
+               cmd->op_type = trans->req_hdr->op_type;
        }
 
        trans->trans_id = seq;
index ee0c1d307966d842d824c3ed64449690946b7d76..eb49cd65378cdcf5feec210a2812d3d09ef8f0cb 100644 (file)
@@ -635,12 +635,12 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
                                           struct qlcnic_cmd_args *cmd)
 {
        struct qlcnic_vf_info *vf = trans->vf;
-       struct qlcnic_adapter *adapter = vf->adapter;
-       int err;
+       struct qlcnic_vport *vp = vf->vp;
+       struct qlcnic_adapter *adapter;
        u16 func = vf->pci_func;
+       int err;
 
-       cmd->rsp.arg[0] = trans->req_hdr->cmd_op;
-       cmd->rsp.arg[0] |= (1 << 16);
+       adapter = vf->adapter;
 
        if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) {
                err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
@@ -650,6 +650,8 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
                                qlcnic_sriov_pf_config_vport(adapter, 0, func);
                }
        } else {
+               if (vp->vlan_mode == QLC_GUEST_VLAN_MODE)
+                       vp->vlan = 0;
                err = qlcnic_sriov_pf_config_vport(adapter, 0, func);
        }
 
@@ -1183,7 +1185,7 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,
        u8 cmd_op, mode = vp->vlan_mode;
 
        cmd_op = trans->req_hdr->cmd_op;
-       cmd->rsp.arg[0] = (cmd_op & 0xffff) | 14 << 16 | 1 << 25;
+       cmd->rsp.arg[0] |= 1 << 25;
 
        switch (mode) {
        case QLC_GUEST_VLAN_MODE:
@@ -1561,6 +1563,7 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
                                struct qlcnic_vf_info *vf)
 {
        struct net_device *dev = vf->adapter->netdev;
+       struct qlcnic_vport *vp = vf->vp;
 
        if (!test_and_clear_bit(QLC_BC_VF_STATE, &vf->state)) {
                clear_bit(QLC_BC_VF_FLR, &vf->state);
@@ -1573,6 +1576,9 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
                return;
        }
 
+       if (vp->vlan_mode == QLC_GUEST_VLAN_MODE)
+               vp->vlan = 0;
+
        qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);
        netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func);
 }
@@ -1621,13 +1627,15 @@ int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct qlcnic_sriov *sriov = adapter->ahw->sriov;
-       int i, num_vfs = sriov->num_vfs;
+       int i, num_vfs;
        struct qlcnic_vf_info *vf_info;
        u8 *curr_mac;
 
        if (!qlcnic_sriov_pf_check(adapter))
                return -EOPNOTSUPP;
 
+       num_vfs = sriov->num_vfs;
+
        if (!is_valid_ether_addr(mac) || vf >= num_vfs)
                return -EINVAL;
 
@@ -1741,6 +1749,7 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
 
        switch (vlan) {
        case 4095:
+               vp->vlan = 0;
                vp->vlan_mode = QLC_GUEST_VLAN_MODE;
                break;
        case 0:
@@ -1759,6 +1768,29 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
        return 0;
 }
 
+static inline __u32 qlcnic_sriov_get_vf_vlan(struct qlcnic_adapter *adapter,
+                                            struct qlcnic_vport *vp, int vf)
+{
+       __u32 vlan = 0;
+
+       switch (vp->vlan_mode) {
+       case QLC_PVID_MODE:
+               vlan = vp->vlan;
+               break;
+       case QLC_GUEST_VLAN_MODE:
+               vlan = MAX_VLAN_ID;
+               break;
+       case QLC_NO_VLAN_MODE:
+               vlan = 0;
+               break;
+       default:
+               netdev_info(adapter->netdev, "Invalid VLAN mode = %d for VF %d\n",
+                           vp->vlan_mode, vf);
+       }
+
+       return vlan;
+}
+
 int qlcnic_sriov_get_vf_config(struct net_device *netdev,
                               int vf, struct ifla_vf_info *ivi)
 {
@@ -1774,7 +1806,7 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev,
 
        vp = sriov->vf_info[vf].vp;
        memcpy(&ivi->mac, vp->mac, ETH_ALEN);
-       ivi->vlan = vp->vlan;
+       ivi->vlan = qlcnic_sriov_get_vf_vlan(adapter, vp, vf);
        ivi->qos = vp->qos;
        ivi->spoofchk = vp->spoofchk;
        if (vp->max_tx_bw == MAX_BW)
index e6acb9fa5767687d8565596adc11328f55e2a12b..6f35f8404d68adeffa84e9adbdbe4927176db74e 100644 (file)
@@ -478,7 +478,7 @@ rx_status_loop:
 
        while (1) {
                u32 status, len;
-               dma_addr_t mapping;
+               dma_addr_t mapping, new_mapping;
                struct sk_buff *skb, *new_skb;
                struct cp_desc *desc;
                const unsigned buflen = cp->rx_buf_sz;
@@ -520,6 +520,13 @@ rx_status_loop:
                        goto rx_next;
                }
 
+               new_mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
+                                        PCI_DMA_FROMDEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, new_mapping)) {
+                       dev->stats.rx_dropped++;
+                       goto rx_next;
+               }
+
                dma_unmap_single(&cp->pdev->dev, mapping,
                                 buflen, PCI_DMA_FROMDEVICE);
 
@@ -531,12 +538,11 @@ rx_status_loop:
 
                skb_put(skb, len);
 
-               mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
-                                        PCI_DMA_FROMDEVICE);
                cp->rx_skb[rx_tail] = new_skb;
 
                cp_rx_skb(cp, skb, desc);
                rx++;
+               mapping = new_mapping;
 
 rx_next:
                cp->rx_ring[rx_tail].opts2 = 0;
@@ -716,6 +722,22 @@ static inline u32 cp_tx_vlan_tag(struct sk_buff *skb)
                TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
 }
 
+static void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb,
+                                  int first, int entry_last)
+{
+       int frag, index;
+       struct cp_desc *txd;
+       skb_frag_t *this_frag;
+       for (frag = 0; frag+first < entry_last; frag++) {
+               index = first+frag;
+               cp->tx_skb[index] = NULL;
+               txd = &cp->tx_ring[index];
+               this_frag = &skb_shinfo(skb)->frags[frag];
+               dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
+                                skb_frag_size(this_frag), PCI_DMA_TODEVICE);
+       }
+}
+
 static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                                        struct net_device *dev)
 {
@@ -749,6 +771,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
 
                len = skb->len;
                mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, mapping))
+                       goto out_dma_error;
+
                txd->opts2 = opts2;
                txd->addr = cpu_to_le64(mapping);
                wmb();
@@ -786,6 +811,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                first_len = skb_headlen(skb);
                first_mapping = dma_map_single(&cp->pdev->dev, skb->data,
                                               first_len, PCI_DMA_TODEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, first_mapping))
+                       goto out_dma_error;
+
                cp->tx_skb[entry] = skb;
                entry = NEXT_TX(entry);
 
@@ -799,6 +827,11 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                        mapping = dma_map_single(&cp->pdev->dev,
                                                 skb_frag_address(this_frag),
                                                 len, PCI_DMA_TODEVICE);
+                       if (dma_mapping_error(&cp->pdev->dev, mapping)) {
+                               unwind_tx_frag_mapping(cp, skb, first_entry, entry);
+                               goto out_dma_error;
+                       }
+
                        eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 
                        ctrl = eor | len | DescOwn;
@@ -859,11 +892,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
        if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
                netif_stop_queue(dev);
 
+out_unlock:
        spin_unlock_irqrestore(&cp->lock, intr_flags);
 
        cpw8(TxPoll, NormalTxPoll);
 
        return NETDEV_TX_OK;
+out_dma_error:
+       kfree_skb(skb);
+       cp->dev->stats.tx_dropped++;
+       goto out_unlock;
 }
 
 /* Set or clear the multicast filter for this adaptor.
@@ -1054,6 +1092,10 @@ static int cp_refill_rx(struct cp_private *cp)
 
                mapping = dma_map_single(&cp->pdev->dev, skb->data,
                                         cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, mapping)) {
+                       kfree_skb(skb);
+                       goto err_out;
+               }
                cp->rx_skb[i] = skb;
 
                cp->rx_ring[i].opts2 = 0;
index 4106a743ca74c16e0dcf02b1d9b9bc10b76e79a9..b5eb4195fc9927a8b88493c7b1f783926928dc8c 100644 (file)
@@ -3689,7 +3689,7 @@ static void rtl_phy_work(struct rtl8169_private *tp)
        if (tp->link_ok(ioaddr))
                return;
 
-       netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
+       netif_dbg(tp, link, tp->dev, "PHY reset until link up\n");
 
        tp->phy_reset_enable(tp);
 
@@ -6468,6 +6468,8 @@ static int rtl8169_close(struct net_device *dev)
        rtl8169_down(dev);
        rtl_unlock_work(tp);
 
+       cancel_work_sync(&tp->wk.work);
+
        free_irq(pdev->irq, dev);
 
        dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
@@ -6793,8 +6795,6 @@ static void rtl_remove_one(struct pci_dev *pdev)
                rtl8168_driver_stop(tp);
        }
 
-       cancel_work_sync(&tp->wk.work);
-
        netif_napi_del(&tp->napi);
 
        unregister_netdev(dev);
index b74a60ab9ac79913111a4f79d4a5a8ca1c723862..2a469b27a5061641a07a8502ecf63736953070a2 100644 (file)
@@ -1209,7 +1209,9 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
        EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + 4 * ip->ihl + 4);
        ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl);
 
-       efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, 0, rxq_index);
+       efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT,
+                          efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0,
+                          rxq_index);
        rc = efx_filter_set_ipv4_full(&spec, ip->protocol,
                                      ip->daddr, ports[1], ip->saddr, ports[0]);
        if (rc)
index eb4aea3fe793a8372292023877eecae57c5b5acd..f5d7ad75e47903ce2156864c6dabd1444ae27baf 100644 (file)
@@ -1318,7 +1318,7 @@ static void sis900_timer(unsigned long data)
                if (duplex){
                        sis900_set_mode(sis_priv, speed, duplex);
                        sis630_set_eq(net_dev, sis_priv->chipset_rev);
-                       netif_start_queue(net_dev);
+                       netif_carrier_on(net_dev);
                }
 
                sis_priv->timer.expires = jiffies + HZ;
@@ -1336,10 +1336,8 @@ static void sis900_timer(unsigned long data)
                status = sis900_default_phy(net_dev);
                mii_phy = sis_priv->mii;
 
-               if (status & MII_STAT_LINK){
+               if (status & MII_STAT_LINK)
                        sis900_check_mode(net_dev, mii_phy);
-                       netif_carrier_on(net_dev);
-               }
        } else {
        /* Link ON -> OFF */
                 if (!(status & MII_STAT_LINK)){
@@ -1612,12 +1610,6 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
        unsigned int  index_cur_tx, index_dirty_tx;
        unsigned int  count_dirty_tx;
 
-       /* Don't transmit data before the complete of auto-negotiation */
-       if(!sis_priv->autong_complete){
-               netif_stop_queue(net_dev);
-               return NETDEV_TX_BUSY;
-       }
-
        spin_lock_irqsave(&sis_priv->lock, flags);
 
        /* Calculate the next Tx descriptor entry. */
index 05a1674e204f772f84eb3d4ff70633942ba7c256..22a7a43362113c60d251a0daa85b536bcebd3648 100644 (file)
@@ -1867,7 +1867,7 @@ static int cpsw_probe(struct platform_device *pdev)
 
        while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
                for (i = res->start; i <= res->end; i++) {
-                       if (request_irq(i, cpsw_interrupt, IRQF_DISABLED,
+                       if (request_irq(i, cpsw_interrupt, 0,
                                        dev_name(&pdev->dev), priv)) {
                                dev_err(priv->dev, "error attaching irq\n");
                                goto clean_ale_ret;
index 07b176bcf929706a7f3c3974e49becd346a2dc27..1a222bce4bd7bb4e84ce8a845a81c27440b4f863 100644 (file)
@@ -1568,8 +1568,7 @@ static int emac_dev_open(struct net_device *ndev)
        while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
                for (i = res->start; i <= res->end; i++) {
                        if (devm_request_irq(&priv->pdev->dev, i, emac_irq,
-                                            IRQF_DISABLED,
-                                            ndev->name, ndev))
+                                            0, ndev->name, ndev))
                                goto rollback;
                }
                k++;
index 18373b6ae37d78543cf925e2d86efab1578f3019..d0f9c2fd1d4fdaa06110d394411f48bb5f8874bb 100644 (file)
@@ -337,8 +337,11 @@ static int macvlan_open(struct net_device *dev)
        int err;
 
        if (vlan->port->passthru) {
-               if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
-                       dev_set_promiscuity(lowerdev, 1);
+               if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) {
+                       err = dev_set_promiscuity(lowerdev, 1);
+                       if (err < 0)
+                               goto out;
+               }
                goto hash_add;
        }
 
@@ -863,6 +866,18 @@ static int macvlan_changelink(struct net_device *dev,
                struct nlattr *tb[], struct nlattr *data[])
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
+       enum macvlan_mode mode;
+       bool set_mode = false;
+
+       /* Validate mode, but don't set yet: setting flags may fail. */
+       if (data && data[IFLA_MACVLAN_MODE]) {
+               set_mode = true;
+               mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+               /* Passthrough mode can't be set or cleared dynamically */
+               if ((mode == MACVLAN_MODE_PASSTHRU) !=
+                   (vlan->mode == MACVLAN_MODE_PASSTHRU))
+                       return -EINVAL;
+       }
 
        if (data && data[IFLA_MACVLAN_FLAGS]) {
                __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
@@ -879,8 +894,8 @@ static int macvlan_changelink(struct net_device *dev,
                }
                vlan->flags = flags;
        }
-       if (data && data[IFLA_MACVLAN_MODE])
-               vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+       if (set_mode)
+               vlan->mode = mode;
        return 0;
 }
 
index 61d3f4ebf52e5590f41b260aa7a354e2ac4b862a..7f25e49ae37f21167bebda2f8051dc4da6c6ba0c 100644 (file)
@@ -40,7 +40,7 @@ struct sun4i_mdio_data {
 static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
        struct sun4i_mdio_data *data = bus->priv;
-       unsigned long start_jiffies;
+       unsigned long timeout_jiffies;
        int value;
 
        /* issue the phy address and reg */
@@ -49,10 +49,9 @@ static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
 
        /* Wait read complete */
-       start_jiffies = jiffies;
+       timeout_jiffies = jiffies + MDIO_TIMEOUT;
        while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
-               if (time_after(start_jiffies,
-                              start_jiffies + MDIO_TIMEOUT))
+               if (time_is_before_jiffies(timeout_jiffies))
                        return -ETIMEDOUT;
                msleep(1);
        }
@@ -69,7 +68,7 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
                            u16 value)
 {
        struct sun4i_mdio_data *data = bus->priv;
-       unsigned long start_jiffies;
+       unsigned long timeout_jiffies;
 
        /* issue the phy address and reg */
        writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG);
@@ -77,10 +76,9 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
 
        /* Wait read complete */
-       start_jiffies = jiffies;
+       timeout_jiffies = jiffies + MDIO_TIMEOUT;
        while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
-               if (time_after(start_jiffies,
-                              start_jiffies + MDIO_TIMEOUT))
+               if (time_is_before_jiffies(timeout_jiffies))
                        return -ETIMEDOUT;
                msleep(1);
        }
index 1e3c302d94fe338dec36ba934fc90a79bfb00e0d..2bc87e3a8141d259502bcfbfccc9e0a5b649800b 100644 (file)
@@ -1029,10 +1029,10 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.supports_gmii = 1;
 
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                             NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                             NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                                NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                                NETIF_F_RXCSUM;
 
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
@@ -1173,7 +1173,6 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
        if (((skb->len + 8) % frame_size) == 0)
                tx_hdr2 |= 0x80008000;  /* Enable padding */
 
-       skb_linearize(skb);
        headroom = skb_headroom(skb);
        tailroom = skb_tailroom(skb);
 
@@ -1317,10 +1316,10 @@ static int ax88179_reset(struct usbnet *dev)
                          1, 1, tmp);
 
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                             NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                             NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                                NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                                NETIF_F_RXCSUM;
 
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
index ee13f9eb740c0bf18b793b308194675e9967a317..11c51f275366a15999ad7684330bb644de76b557 100644 (file)
@@ -344,17 +344,41 @@ static const int multicast_filter_limit = 32;
 static
 int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 {
-       return usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
+       int ret;
+       void *tmp;
+
+       tmp = kmalloc(size, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
                               RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-                              value, index, data, size, 500);
+                              value, index, tmp, size, 500);
+
+       memcpy(data, tmp, size);
+       kfree(tmp);
+
+       return ret;
 }
 
 static
 int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 {
-       return usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
+       int ret;
+       void *tmp;
+
+       tmp = kmalloc(size, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       memcpy(tmp, data, size);
+
+       ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
                               RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
-                              value, index, data, size, 500);
+                              value, index, tmp, size, 500);
+
+       kfree(tmp);
+       return ret;
 }
 
 static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
@@ -490,37 +514,31 @@ int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
 
 static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index)
 {
-       u32 data;
+       __le32 data;
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(data), &data);
-       else
-               usb_ocp_read(tp, index, sizeof(data), &data);
+       generic_ocp_read(tp, index, sizeof(data), &data, type);
 
        return __le32_to_cpu(data);
 }
 
 static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data)
 {
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
-       else
-               usb_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
+       __le32 tmp = __cpu_to_le32(data);
+
+       generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
 }
 
 static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
 {
        u32 data;
+       __le32 tmp;
        u8 shift = index & 2;
 
        index &= ~3;
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(data), &data);
-       else
-               usb_ocp_read(tp, index, sizeof(data), &data);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       data = __le32_to_cpu(data);
+       data = __le32_to_cpu(tmp);
        data >>= (shift * 8);
        data &= 0xffff;
 
@@ -529,7 +547,8 @@ static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
 
 static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
 {
-       u32 tmp, mask = 0xffff;
+       u32 mask = 0xffff;
+       __le32 tmp;
        u16 byen = BYTE_EN_WORD;
        u8 shift = index & 2;
 
@@ -542,34 +561,25 @@ static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
                index &= ~3;
        }
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(tmp), &tmp);
-       else
-               usb_ocp_read(tp, index, sizeof(tmp), &tmp);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       tmp = __le32_to_cpu(tmp) & ~mask;
-       tmp |= data;
-       tmp = __cpu_to_le32(tmp);
+       data |= __le32_to_cpu(tmp) & ~mask;
+       tmp = __cpu_to_le32(data);
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
-       else
-               usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
+       generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
 }
 
 static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
 {
        u32 data;
+       __le32 tmp;
        u8 shift = index & 3;
 
        index &= ~3;
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(data), &data);
-       else
-               usb_ocp_read(tp, index, sizeof(data), &data);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       data = __le32_to_cpu(data);
+       data = __le32_to_cpu(tmp);
        data >>= (shift * 8);
        data &= 0xff;
 
@@ -578,7 +588,8 @@ static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
 
 static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
 {
-       u32 tmp, mask = 0xff;
+       u32 mask = 0xff;
+       __le32 tmp;
        u16 byen = BYTE_EN_BYTE;
        u8 shift = index & 3;
 
@@ -591,19 +602,12 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
                index &= ~3;
        }
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(tmp), &tmp);
-       else
-               usb_ocp_read(tp, index, sizeof(tmp), &tmp);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       tmp = __le32_to_cpu(tmp) & ~mask;
-       tmp |= data;
-       tmp = __cpu_to_le32(tmp);
+       data |= __le32_to_cpu(tmp) & ~mask;
+       tmp = __cpu_to_le32(data);
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
-       else
-               usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
+       generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
 }
 
 static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
@@ -685,21 +689,14 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
 static inline void set_ethernet_addr(struct r8152 *tp)
 {
        struct net_device *dev = tp->netdev;
-       u8 *node_id;
-
-       node_id = kmalloc(sizeof(u8) * 8, GFP_KERNEL);
-       if (!node_id) {
-               netif_err(tp, probe, dev, "out of memory");
-               return;
-       }
+       u8 node_id[8] = {0};
 
-       if (pla_ocp_read(tp, PLA_IDR, sizeof(u8) * 8, node_id) < 0)
+       if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0)
                netif_notice(tp, probe, dev, "inet addr fail\n");
        else {
                memcpy(dev->dev_addr, node_id, dev->addr_len);
                memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        }
-       kfree(node_id);
 }
 
 static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
@@ -882,15 +879,10 @@ static void rtl8152_set_rx_mode(struct net_device *netdev)
 static void _rtl8152_set_rx_mode(struct net_device *netdev)
 {
        struct r8152 *tp = netdev_priv(netdev);
-       u32 tmp, *mc_filter;    /* Multicast hash filter */
+       u32 mc_filter[2];       /* Multicast hash filter */
+       __le32 tmp[2];
        u32 ocp_data;
 
-       mc_filter = kmalloc(sizeof(u32) * 2, GFP_KERNEL);
-       if (!mc_filter) {
-               netif_err(tp, link, netdev, "out of memory");
-               return;
-       }
-
        clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
        netif_stop_queue(netdev);
        ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@@ -918,14 +910,12 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
                }
        }
 
-       tmp = mc_filter[0];
-       mc_filter[0] = __cpu_to_le32(swab32(mc_filter[1]));
-       mc_filter[1] = __cpu_to_le32(swab32(tmp));
+       tmp[0] = __cpu_to_le32(swab32(mc_filter[1]));
+       tmp[1] = __cpu_to_le32(swab32(mc_filter[0]));
 
-       pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(u32) * 2, mc_filter);
+       pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp);
        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
        netif_wake_queue(netdev);
-       kfree(mc_filter);
 }
 
 static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
index 852392269718e1892119a3c42d45c635f768a77f..2df2f4fb42a7c381fb68275bfab10052b7a71363 100644 (file)
 
 static int pla_read_word(struct usb_device *udev, u16 index)
 {
-       int data, ret;
+       int ret;
        u8 shift = index & 2;
-       __le32 ocp_data;
+       __le32 *tmp;
+
+       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
 
        index &= ~3;
 
        ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
-                             500);
+                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
        if (ret < 0)
-               return ret;
+               goto out2;
 
-       data = __le32_to_cpu(ocp_data);
-       data >>= (shift * 8);
-       data &= 0xffff;
+       ret = __le32_to_cpu(*tmp);
+       ret >>= (shift * 8);
+       ret &= 0xffff;
 
-       return data;
+out2:
+       kfree(tmp);
+       return ret;
 }
 
 static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
 {
-       __le32 ocp_data;
+       __le32 *tmp;
        u32 mask = 0xffff;
        u16 byen = BYTE_EN_WORD;
        u8 shift = index & 2;
        int ret;
 
+       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
        data &= mask;
 
        if (shift) {
@@ -63,19 +72,20 @@ static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
 
        ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
-                             500);
+                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
        if (ret < 0)
-               return ret;
+               goto out3;
 
-       data |= __le32_to_cpu(ocp_data) & ~mask;
-       ocp_data = __cpu_to_le32(data);
+       data |= __le32_to_cpu(*tmp) & ~mask;
+       *tmp = __cpu_to_le32(data);
 
        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                              RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
-                             index, MCU_TYPE_PLA | byen, &ocp_data,
-                             sizeof(ocp_data), 500);
+                             index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
+                             500);
 
+out3:
+       kfree(tmp);
        return ret;
 }
 
@@ -116,11 +126,18 @@ out1:
 static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
 {
        struct usbnet *dev = netdev_priv(netdev);
+       int ret;
 
        if (phy_id != R815x_PHY_ID)
                return -EINVAL;
 
-       return ocp_reg_read(dev, BASE_MII + reg * 2);
+       if (usb_autopm_get_interface(dev->intf) < 0)
+               return -ENODEV;
+
+       ret = ocp_reg_read(dev, BASE_MII + reg * 2);
+
+       usb_autopm_put_interface(dev->intf);
+       return ret;
 }
 
 static
@@ -131,7 +148,12 @@ void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
        if (phy_id != R815x_PHY_ID)
                return;
 
+       if (usb_autopm_get_interface(dev->intf) < 0)
+               return;
+
        ocp_reg_write(dev, BASE_MII + reg * 2, val);
+
+       usb_autopm_put_interface(dev->intf);
 }
 
 static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -150,7 +172,7 @@ static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = R815x_PHY_ID;
        dev->mii.supports_gmii = 1;
 
-       return 0;
+       return status;
 }
 
 static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -169,7 +191,7 @@ static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = R815x_PHY_ID;
        dev->mii.supports_gmii = 0;
 
-       return 0;
+       return status;
 }
 
 static const struct driver_info r8152_info = {
index 75409748c77470da8cc5bcc7390e9f4c5a94ea6a..66ebbacf066f6692ba21d2fa07538535827074b9 100644 (file)
@@ -45,7 +45,6 @@
 #define EEPROM_MAC_OFFSET              (0x01)
 #define DEFAULT_TX_CSUM_ENABLE         (true)
 #define DEFAULT_RX_CSUM_ENABLE         (true)
-#define DEFAULT_TSO_ENABLE             (true)
 #define SMSC75XX_INTERNAL_PHY_ID       (1)
 #define SMSC75XX_TX_OVERHEAD           (8)
 #define MAX_RX_FIFO_SIZE               (20 * 1024)
@@ -1410,17 +1409,14 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
 
        INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);
 
-       if (DEFAULT_TX_CSUM_ENABLE) {
+       if (DEFAULT_TX_CSUM_ENABLE)
                dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-               if (DEFAULT_TSO_ENABLE)
-                       dev->net->features |= NETIF_F_SG |
-                               NETIF_F_TSO | NETIF_F_TSO6;
-       }
+
        if (DEFAULT_RX_CSUM_ENABLE)
                dev->net->features |= NETIF_F_RXCSUM;
 
        dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-               NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM;
+                               NETIF_F_RXCSUM;
 
        ret = smsc75xx_wait_ready(dev, 0);
        if (ret < 0) {
@@ -2200,8 +2196,6 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev,
 {
        u32 tx_cmd_a, tx_cmd_b;
 
-       skb_linearize(skb);
-
        if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) {
                struct sk_buff *skb2 =
                        skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags);
index da866523cf20097d57550c7357020e937782fd37..eee1f19ef1e9397469e343133490ec6972b4bbdc 100644 (file)
@@ -269,6 +269,7 @@ static void veth_setup(struct net_device *dev)
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
        dev->features |= VETH_FEATURES;
+       dev->vlan_features = dev->features;
        dev->destructor = veth_dev_free;
 
        dev->hw_features = VETH_FEATURES;
index a5ba8dd7e6bea33d060e9d5306b9eab6bb2095da..f4c6db419ddb3b56a9ecede0b62988c33e1d7c29 100644 (file)
@@ -136,7 +136,8 @@ struct vxlan_dev {
        u32               flags;        /* VXLAN_F_* below */
 
        struct work_struct sock_work;
-       struct work_struct igmp_work;
+       struct work_struct igmp_join;
+       struct work_struct igmp_leave;
 
        unsigned long     age_interval;
        struct timer_list age_timer;
@@ -736,7 +737,6 @@ static bool vxlan_snoop(struct net_device *dev,
        return false;
 }
 
-
 /* See if multicast group is already in use by other ID */
 static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip)
 {
@@ -770,12 +770,13 @@ static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs)
        queue_work(vxlan_wq, &vs->del_work);
 }
 
-/* Callback to update multicast group membership.
- * Scheduled when vxlan goes up/down.
+/* Callback to update multicast group membership when first VNI on
+ * multicast asddress is brought up
+ * Done as workqueue because ip_mc_join_group acquires RTNL.
  */
-static void vxlan_igmp_work(struct work_struct *work)
+static void vxlan_igmp_join(struct work_struct *work)
 {
-       struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_work);
+       struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join);
        struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
        struct vxlan_sock *vs = vxlan->vn_sock;
        struct sock *sk = vs->sock->sk;
@@ -785,10 +786,27 @@ static void vxlan_igmp_work(struct work_struct *work)
        };
 
        lock_sock(sk);
-       if (vxlan_group_used(vn, vxlan->default_dst.remote_ip))
-               ip_mc_join_group(sk, &mreq);
-       else
-               ip_mc_leave_group(sk, &mreq);
+       ip_mc_join_group(sk, &mreq);
+       release_sock(sk);
+
+       vxlan_sock_release(vn, vs);
+       dev_put(vxlan->dev);
+}
+
+/* Inverse of vxlan_igmp_join when last VNI is brought down */
+static void vxlan_igmp_leave(struct work_struct *work)
+{
+       struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave);
+       struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
+       struct vxlan_sock *vs = vxlan->vn_sock;
+       struct sock *sk = vs->sock->sk;
+       struct ip_mreqn mreq = {
+               .imr_multiaddr.s_addr   = vxlan->default_dst.remote_ip,
+               .imr_ifindex            = vxlan->default_dst.remote_ifindex,
+       };
+
+       lock_sock(sk);
+       ip_mc_leave_group(sk, &mreq);
        release_sock(sk);
 
        vxlan_sock_release(vn, vs);
@@ -1359,6 +1377,7 @@ static void vxlan_uninit(struct net_device *dev)
 /* Start ageing timer and join group when device is brought up */
 static int vxlan_open(struct net_device *dev)
 {
+       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_sock *vs = vxlan->vn_sock;
 
@@ -1366,10 +1385,11 @@ static int vxlan_open(struct net_device *dev)
        if (!vs)
                return -ENOTCONN;
 
-       if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
+       if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
+           ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
                vxlan_sock_hold(vs);
                dev_hold(dev);
-               queue_work(vxlan_wq, &vxlan->igmp_work);
+               queue_work(vxlan_wq, &vxlan->igmp_join);
        }
 
        if (vxlan->age_interval)
@@ -1400,13 +1420,15 @@ static void vxlan_flush(struct vxlan_dev *vxlan)
 /* Cleanup timer and forwarding table on shutdown */
 static int vxlan_stop(struct net_device *dev)
 {
+       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_sock *vs = vxlan->vn_sock;
 
-       if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
+       if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
+           ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
                vxlan_sock_hold(vs);
                dev_hold(dev);
-               queue_work(vxlan_wq, &vxlan->igmp_work);
+               queue_work(vxlan_wq, &vxlan->igmp_leave);
        }
 
        del_timer_sync(&vxlan->age_timer);
@@ -1471,7 +1493,8 @@ static void vxlan_setup(struct net_device *dev)
 
        INIT_LIST_HEAD(&vxlan->next);
        spin_lock_init(&vxlan->hash_lock);
-       INIT_WORK(&vxlan->igmp_work, vxlan_igmp_work);
+       INIT_WORK(&vxlan->igmp_join, vxlan_igmp_join);
+       INIT_WORK(&vxlan->igmp_leave, vxlan_igmp_leave);
        INIT_WORK(&vxlan->sock_work, vxlan_sock_work);
 
        init_timer_deferrable(&vxlan->age_timer);
@@ -1878,10 +1901,12 @@ static __net_exit void vxlan_exit_net(struct net *net)
 {
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        struct vxlan_dev *vxlan;
+       LIST_HEAD(list);
 
        rtnl_lock();
        list_for_each_entry(vxlan, &vn->vxlan_list, next)
-               dev_close(vxlan->dev);
+               unregister_netdevice_queue(vxlan->dev, &list);
+       unregister_netdevice_many(&list);
        rtnl_unlock();
 }
 
index cde58fe962543dff415d45f2be2ae06d0d7ceb91..82e8088ca9b4944e5cb13c3fb3c2b14c7af27efe 100644 (file)
@@ -1,6 +1,6 @@
 config ATH10K
         tristate "Atheros 802.11ac wireless cards support"
-        depends on MAC80211
+        depends on MAC80211 && HAS_DMA
        select ATH_COMMON
         ---help---
           This module adds support for wireless adapters based on
index 81b686c6a3764111e8c8e969a90d36d6ced054ea..40825d43322edb511862c90bd2587395745852e7 100644 (file)
@@ -325,7 +325,7 @@ ath5k_prepare_multicast(struct ieee80211_hw *hw,
        struct netdev_hw_addr *ha;
 
        mfilt[0] = 0;
-       mfilt[1] = 1;
+       mfilt[1] = 0;
 
        netdev_hw_addr_list_for_each(ha, mc_list) {
                /* calculate XOR of eight 6-bit values */
index d1acfe98918a2a50689c2760ed6455cf2c239b2a..1576d58291d457612ddeadf0933904bf6f552d3a 100644 (file)
@@ -610,7 +610,15 @@ static void ar5008_hw_override_ini(struct ath_hw *ah,
        REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 
        if (AR_SREV_9280_20_OR_LATER(ah)) {
-               val = REG_READ(ah, AR_PCU_MISC_MODE2);
+               /*
+                * For AR9280 and above, there is a new feature that allows
+                * Multicast search based on both MAC Address and Key ID.
+                * By default, this feature is enabled. But since the driver
+                * is not using this feature, we switch it off; otherwise
+                * multicast search based on MAC addr only will fail.
+                */
+               val = REG_READ(ah, AR_PCU_MISC_MODE2) &
+                       (~AR_ADHOC_MCAST_KEYID_ENABLE);
 
                if (!AR_SREV_9271(ah))
                        val &= ~AR_PCU_MISC_MODE2_HWWAR1;
index 9e582e14da74609361b689e5f5741d425fd14659..5205a3625e849f3f6d3d775bb7b4b8f866aebca4 100644 (file)
@@ -1082,7 +1082,7 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
        struct device *dev = &hif_dev->udev->dev;
        struct device *parent = dev->parent;
 
-       complete(&hif_dev->fw_done);
+       complete_all(&hif_dev->fw_done);
 
        if (parent)
                device_lock(parent);
@@ -1131,7 +1131,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
 
        release_firmware(fw);
        hif_dev->flags |= HIF_USB_READY;
-       complete(&hif_dev->fw_done);
+       complete_all(&hif_dev->fw_done);
 
        return;
 
@@ -1295,7 +1295,9 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
 
        usb_set_intfdata(interface, NULL);
 
-       if (!unplugged && (hif_dev->flags & HIF_USB_START))
+       /* If firmware was loaded we should drop it
+        * go back to first stage bootloader. */
+       if (!unplugged && (hif_dev->flags & HIF_USB_READY))
                ath9k_hif_usb_reboot(udev);
 
        kfree(hif_dev);
@@ -1316,7 +1318,10 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface,
        if (!(hif_dev->flags & HIF_USB_START))
                ath9k_htc_suspend(hif_dev->htc_handle);
 
-       ath9k_hif_usb_dealloc_urbs(hif_dev);
+       wait_for_completion(&hif_dev->fw_done);
+
+       if (hif_dev->flags & HIF_USB_READY)
+               ath9k_hif_usb_dealloc_urbs(hif_dev);
 
        return 0;
 }
index 71a183ffc77faf04f590b3d9454d1fb3c798ccaf..c3676bf1d6c45ab92d8a161d18ad5f3f0c586d18 100644 (file)
@@ -861,6 +861,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
        if (error != 0)
                goto err_rx;
 
+       ath9k_hw_disable(priv->ah);
 #ifdef CONFIG_MAC80211_LEDS
        /* must be initialized before ieee80211_register_hw */
        priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
index c59ae43b9b35aeba9356f499a83f73ae02e96a8b..9279927326203d02f421233b9456f074cb92e5ec 100644 (file)
@@ -146,6 +146,28 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
                               ARRAY_SIZE(bf->rates));
 }
 
+static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+                            struct sk_buff *skb)
+{
+       int q;
+
+       q = skb_get_queue_mapping(skb);
+       if (txq == sc->tx.uapsdq)
+               txq = sc->tx.txq_map[q];
+
+       if (txq != sc->tx.txq_map[q])
+               return;
+
+       if (WARN_ON(--txq->pending_frames < 0))
+               txq->pending_frames = 0;
+
+       if (txq->stopped &&
+           txq->pending_frames < sc->tx.txq_max_pending[q]) {
+               ieee80211_wake_queue(sc->hw, q);
+               txq->stopped = false;
+       }
+}
+
 static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
        struct ath_txq *txq = tid->ac->txq;
@@ -167,6 +189,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
                if (!bf) {
                        bf = ath_tx_setup_buffer(sc, txq, tid, skb);
                        if (!bf) {
+                               ath_txq_skb_done(sc, txq, skb);
                                ieee80211_free_txskb(sc->hw, skb);
                                continue;
                        }
@@ -811,6 +834,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
 
                if (!bf) {
                        __skb_unlink(skb, &tid->buf_q);
+                       ath_txq_skb_done(sc, txq, skb);
                        ieee80211_free_txskb(sc->hw, skb);
                        continue;
                }
@@ -1824,6 +1848,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq,
 
        bf = ath_tx_setup_buffer(sc, txq, tid, skb);
        if (!bf) {
+               ath_txq_skb_done(sc, txq, skb);
                ieee80211_free_txskb(sc->hw, skb);
                return;
        }
@@ -2090,6 +2115,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        bf = ath_tx_setup_buffer(sc, txq, tid, skb);
        if (!bf) {
+               ath_txq_skb_done(sc, txq, skb);
                if (txctl->paprd)
                        dev_kfree_skb_any(skb);
                else
@@ -2189,7 +2215,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
-       int q, padpos, padsize;
+       int padpos, padsize;
        unsigned long flags;
 
        ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
@@ -2225,21 +2251,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        __skb_queue_tail(&txq->complete_q, skb);
-
-       q = skb_get_queue_mapping(skb);
-       if (txq == sc->tx.uapsdq)
-               txq = sc->tx.txq_map[q];
-
-       if (txq == sc->tx.txq_map[q]) {
-               if (WARN_ON(--txq->pending_frames < 0))
-                       txq->pending_frames = 0;
-
-               if (txq->stopped &&
-                   txq->pending_frames < sc->tx.txq_max_pending[q]) {
-                       ieee80211_wake_queue(sc->hw, q);
-                       txq->stopped = false;
-               }
-       }
+       ath_txq_skb_done(sc, txq, skb);
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
index e8308ec309704958b1754c06dbeb7b3fef9f452b..ab636767fbde098ce41bd952aa7d950b6932cb28 100644 (file)
@@ -145,7 +145,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
                                   le16_to_cpu(hdr.type), hdr.flags);
                        if (len <= MAX_MBOXITEM_SIZE) {
                                int n = 0;
-                               unsigned char printbuf[16 * 3 + 2];
+                               char printbuf[16 * 3 + 2];
                                unsigned char databuf[MAX_MBOXITEM_SIZE];
                                void __iomem *src = wmi_buffer(wil, d.addr) +
                                        sizeof(struct wil6210_mbox_hdr);
@@ -416,7 +416,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
                seq_printf(s, "  SKB = %p\n", skb);
 
                if (skb) {
-                       unsigned char printbuf[16 * 3 + 2];
+                       char printbuf[16 * 3 + 2];
                        int i = 0;
                        int len = le16_to_cpu(d->dma.length);
                        void *p = skb->data;
index 8e8975562ec3b819ff20b32de938a3b012b6671b..80099016d21f4a04cb22b5e3b98ccd84608e658a 100644 (file)
@@ -242,7 +242,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
 {
        unsigned long flags;
 
-       if (!ifp)
+       if (!ifp || !ifp->ndev)
                return;
 
        brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
index f0d9f7f6c83d70fbd677175b43ebe70f306795eb..29b1f24c2d0f92c86a55dade5e0e61a943004608 100644 (file)
@@ -1744,13 +1744,14 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
        ulong flags;
        int fifo = BRCMF_FWS_FIFO_BCMC;
        bool multicast = is_multicast_ether_addr(eh->h_dest);
+       bool pae = eh->h_proto == htons(ETH_P_PAE);
 
        /* determine the priority */
        if (!skb->priority)
                skb->priority = cfg80211_classify8021d(skb);
 
        drvr->tx_multicast += !!multicast;
-       if (ntohs(eh->h_proto) == ETH_P_PAE)
+       if (pae)
                atomic_inc(&ifp->pend_8021x_cnt);
 
        if (!brcmf_fws_fc_active(fws)) {
@@ -1781,6 +1782,11 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
                brcmf_fws_schedule_deq(fws);
        } else {
                brcmf_err("drop skb: no hanger slot\n");
+               if (pae) {
+                       atomic_dec(&ifp->pend_8021x_cnt);
+                       if (waitqueue_active(&ifp->pend_8021x_wait))
+                               wake_up(&ifp->pend_8021x_wait);
+               }
                brcmu_pkt_buf_free_skb(skb);
        }
        brcmf_fws_unlock(drvr, flags);
index 277b37ae71267a194d6ebcc541b93cc786ef9078..7fa71f73cfe89c5bfb5f2fca8e1e83c4d7124045 100644 (file)
@@ -1093,8 +1093,11 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
                brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
                err = brcmf_fil_cmd_data_set(vif->ifp,
                                             BRCMF_C_DISASSOC, NULL, 0);
-               if (err)
+               if (err) {
                        brcmf_err("WLC_DISASSOC failed (%d)\n", err);
+                       cfg80211_disconnected(vif->wdev.netdev, 0,
+                                             NULL, 0, GFP_KERNEL);
+               }
                clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
        }
        clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
index 5862c373d7148851816a5b16bfeb9c1acaebb191..e824d4d4a18d7e1d385d9d95f8fea195766a3ae8 100644 (file)
@@ -1165,7 +1165,7 @@ void cw1200_rx_cb(struct cw1200_common *priv,
                if (cw1200_handle_action_rx(priv, skb))
                        return;
        } else if (ieee80211_is_beacon(frame->frame_control) &&
-                  !arg->status &&
+                  !arg->status && priv->vif &&
                   !memcmp(ieee80211_get_SA(frame), priv->vif->bss_conf.bssid,
                           ETH_ALEN)) {
                const u8 *tim_ie;
index 3952ddf2ddb2bb596ffca3d0ff951238774bdb98..1531a4fc09601bd101fde1e20a528d7631f8baf8 100644 (file)
@@ -758,7 +758,7 @@ int iwl_alive_start(struct iwl_priv *priv)
                                         BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
                if (ret)
                        return ret;
-       } else {
+       } else if (priv->lib->bt_params) {
                /*
                 * default is 2-wire BT coexexistence support
                 */
index ff8cc75c189d4d842abf8611fb8c5e7c7a63bf38..a70c7b9d9bad897345fb1e1e89d5c421e0d8a3da 100644 (file)
@@ -97,6 +97,8 @@
 
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS         (0x00000800)
 
+#define APMG_RTC_INT_STT_RFKILL                (0x10000000)
+
 /* Device system time */
 #define DEVICE_SYSTEM_TIME_REG 0xA0206C
 
index 7e5e5c2f9f87316f5319605b1d9c6814c2940dc0..83da884cf3032564df37a96be42c1601496fbc52 100644 (file)
@@ -134,7 +134,7 @@ struct wowlan_key_data {
        struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
        struct iwl_wowlan_tkip_params_cmd *tkip;
        bool error, use_rsc_tsc, use_tkip;
-       int gtk_key_idx;
+       int wep_key_idx;
 };
 
 static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
@@ -188,8 +188,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                        wkc.wep_key.key_offset = 0;
                } else {
                        /* others start at 1 */
-                       data->gtk_key_idx++;
-                       wkc.wep_key.key_offset = data->gtk_key_idx;
+                       data->wep_key_idx++;
+                       wkc.wep_key.key_offset = data->wep_key_idx;
                }
 
                ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC,
@@ -316,8 +316,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                mvm->ptk_ivlen = key->iv_len;
                mvm->ptk_icvlen = key->icv_len;
        } else {
-               data->gtk_key_idx++;
-               key->hw_key_idx = data->gtk_key_idx;
+               /*
+                * firmware only supports TSC/RSC for a single key,
+                * so if there are multiple keep overwriting them
+                * with new ones -- this relies on mac80211 doing
+                * list_add_tail().
+                */
+               key->hw_key_idx = 1;
                mvm->gtk_ivlen = key->iv_len;
                mvm->gtk_icvlen = key->icv_len;
        }
index e56ed2a848886ce6c9001ef9a69a12d54c5f102b..c24a744910acd447c0b7376670e5e97b038cb09c 100644 (file)
@@ -988,7 +988,11 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        char buf[100];
 
-       if (!dbgfs_dir)
+       /*
+        * Check if debugfs directory already exist before creating it.
+        * This may happen when, for example, resetting hw or suspend-resume
+        */
+       if (!dbgfs_dir || mvmvif->dbgfs_dir)
                return;
 
        mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
index b60d14151721da3cb141b9b74ac0e3aee2d43a92..365095a0c3b3101e3c87b76036dbd82b352b9deb 100644 (file)
@@ -69,7 +69,6 @@
 /* Scan Commands, Responses, Notifications */
 
 /* Masks for iwl_scan_channel.type flags */
-#define SCAN_CHANNEL_TYPE_PASSIVE      0
 #define SCAN_CHANNEL_TYPE_ACTIVE       BIT(0)
 #define SCAN_CHANNEL_NARROW_BAND       BIT(22)
 
index e08683b2053183f7e7ea9df370a37bdb4b70c2e4..f19baf0dea6b9c84dac1a86d393c8ddb68aa5f53 100644 (file)
@@ -257,7 +257,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        if (ret)
                return ret;
 
-       return ieee80211_register_hw(mvm->hw);
+       ret = ieee80211_register_hw(mvm->hw);
+       if (ret)
+               iwl_mvm_leds_exit(mvm);
+
+       return ret;
 }
 
 static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
@@ -385,6 +389,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
        ieee80211_wake_queues(mvm->hw);
 
        mvm->vif_count = 0;
+       mvm->rx_ba_sessions = 0;
 }
 
 static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
@@ -506,6 +511,27 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        if (ret)
                goto out_unlock;
 
+       /*
+        * TODO: remove this temporary code.
+        * Currently MVM FW supports power management only on single MAC.
+        * If new interface added, disable PM on existing interface.
+        * P2P device is a special case, since it is handled by FW similary to
+        * scan. If P2P deviced is added, PM remains enabled on existing
+        * interface.
+        * Note: the method below does not count the new interface being added
+        * at this moment.
+        */
+       if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
+               mvm->vif_count++;
+       if (mvm->vif_count > 1) {
+               IWL_DEBUG_MAC80211(mvm,
+                                  "Disable power on existing interfaces\n");
+               ieee80211_iterate_active_interfaces_atomic(
+                                           mvm->hw,
+                                           IEEE80211_IFACE_ITER_NORMAL,
+                                           iwl_mvm_pm_disable_iterator, mvm);
+       }
+
        /*
         * The AP binding flow can be done only after the beacon
         * template is configured (which happens only in the mac80211
@@ -529,27 +555,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
-       /*
-        * TODO: remove this temporary code.
-        * Currently MVM FW supports power management only on single MAC.
-        * If new interface added, disable PM on existing interface.
-        * P2P device is a special case, since it is handled by FW similary to
-        * scan. If P2P deviced is added, PM remains enabled on existing
-        * interface.
-        * Note: the method below does not count the new interface being added
-        * at this moment.
-        */
-       if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
-               mvm->vif_count++;
-       if (mvm->vif_count > 1) {
-               IWL_DEBUG_MAC80211(mvm,
-                                  "Disable power on existing interfaces\n");
-               ieee80211_iterate_active_interfaces_atomic(
-                                           mvm->hw,
-                                           IEEE80211_IFACE_ITER_NORMAL,
-                                           iwl_mvm_pm_disable_iterator, mvm);
-       }
-
        ret = iwl_mvm_mac_ctxt_add(mvm, vif);
        if (ret)
                goto out_release;
@@ -1006,6 +1011,21 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
        mutex_lock(&mvm->mutex);
        if (old_state == IEEE80211_STA_NOTEXIST &&
            new_state == IEEE80211_STA_NONE) {
+               /*
+                * Firmware bug - it'll crash if the beacon interval is less
+                * than 16. We can't avoid connecting at all, so refuse the
+                * station state change, this will cause mac80211 to abandon
+                * attempts to connect to this AP, and eventually wpa_s will
+                * blacklist the AP...
+                */
+               if (vif->type == NL80211_IFTYPE_STATION &&
+                   vif->bss_conf.beacon_int < 16) {
+                       IWL_ERR(mvm,
+                               "AP %pM beacon interval is %d, refusing due to firmware bug!\n",
+                               sta->addr, vif->bss_conf.beacon_int);
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
                ret = iwl_mvm_add_sta(mvm, vif, sta);
        } else if (old_state == IEEE80211_STA_NONE &&
                   new_state == IEEE80211_STA_AUTH) {
@@ -1038,6 +1058,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
        } else {
                ret = -EIO;
        }
+ out_unlock:
        mutex_unlock(&mvm->mutex);
 
        return ret;
index d40d7db185d6cdbb22ca2a2d1fefef0794970971..420e82d379d9826690d297de690c3e84a2307f87 100644 (file)
@@ -419,6 +419,7 @@ struct iwl_mvm {
        struct work_struct sta_drained_wk;
        unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
        atomic_t pending_frames[IWL_MVM_STATION_COUNT];
+       u8 rx_ba_sessions;
 
        /* configured by mac80211 */
        u32 rts_threshold;
index 2157b0f8ced5cc7c314a246d758a869128e57c59..acdff6b67e0460e669e5c25192af245df93ac4b5 100644 (file)
@@ -137,8 +137,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
 {
        int fw_idx, req_idx;
 
-       fw_idx = 0;
-       for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) {
+       for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx > 0;
+            req_idx--, fw_idx++) {
                cmd->direct_scan[fw_idx].id = WLAN_EID_SSID;
                cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len;
                memcpy(cmd->direct_scan[fw_idx].ssid,
@@ -153,7 +153,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
  * just to notify that this scan is active and not passive.
  * In order to notify the FW of the number of SSIDs we wish to scan (including
  * the zero-length one), we need to set the corresponding bits in chan->type,
- * one for each SSID, and set the active bit (first).
+ * one for each SSID, and set the active bit (first). The first SSID is already
+ * included in the probe template, so we need to set only req->n_ssids - 1 bits
+ * in addition to the first bit.
  */
 static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
 {
@@ -176,19 +178,12 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
        struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
                (cmd->data + le16_to_cpu(cmd->tx_cmd.len));
        int i;
-       __le32 chan_type_value;
-
-       if (req->n_ssids > 0)
-               chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1);
-       else
-               chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE;
 
        for (i = 0; i < cmd->channel_count; i++) {
                chan->channel = cpu_to_le16(req->channels[i]->hw_value);
+               chan->type = cpu_to_le32(BIT(req->n_ssids) - 1);
                if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       chan->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               else
-                       chan->type = chan_type_value;
+                       chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
                chan->active_dwell = cpu_to_le16(active_dwell);
                chan->passive_dwell = cpu_to_le16(passive_dwell);
                chan->iteration_count = cpu_to_le16(1);
index 62fe5209093bf7637cb024b2c81dfd301cfd4649..563f559b902da8560f7cbdd06726872d7849b34b 100644 (file)
@@ -608,6 +608,8 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
        return ret;
 }
 
+#define IWL_MAX_RX_BA_SESSIONS 16
+
 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                       int tid, u16 ssn, bool start)
 {
@@ -618,11 +620,20 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 
        lockdep_assert_held(&mvm->mutex);
 
+       if (start && mvm->rx_ba_sessions >= IWL_MAX_RX_BA_SESSIONS) {
+               IWL_WARN(mvm, "Not enough RX BA SESSIONS\n");
+               return -ENOSPC;
+       }
+
        cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
        cmd.sta_id = mvm_sta->sta_id;
        cmd.add_modify = STA_MODE_MODIFY;
-       cmd.add_immediate_ba_tid = (u8) tid;
-       cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+       if (start) {
+               cmd.add_immediate_ba_tid = (u8) tid;
+               cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+       } else {
+               cmd.remove_immediate_ba_tid = (u8) tid;
+       }
        cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID :
                                  STA_MODIFY_REMOVE_BA_TID;
 
@@ -648,6 +659,14 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                break;
        }
 
+       if (!ret) {
+               if (start)
+                       mvm->rx_ba_sessions++;
+               else if (mvm->rx_ba_sessions > 0)
+                       /* check that restart flow didn't zero the counter */
+                       mvm->rx_ba_sessions--;
+       }
+
        return ret;
 }
 
@@ -896,6 +915,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
        struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
        u16 txq_id;
+       enum iwl_mvm_agg_state old_state;
 
        /*
         * First set the agg state to OFF to avoid calling
@@ -905,13 +925,17 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        txq_id = tid_data->txq_id;
        IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
                            mvmsta->sta_id, tid, txq_id, tid_data->state);
+       old_state = tid_data->state;
        tid_data->state = IWL_AGG_OFF;
        spin_unlock_bh(&mvmsta->lock);
 
-       if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
-               IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+       if (old_state >= IWL_AGG_ON) {
+               if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
+                       IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+
+               iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+       }
 
-       iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
        mvm->queue_to_mac80211[tid_data->txq_id] =
                                IWL_INVALID_MAC80211_QUEUE;
 
index 81f3ea5b09a4b7f26d0f4bb7877e50dedea6cd38..ff13458efc27096343f17e5c408465d9dce1253a 100644 (file)
@@ -130,6 +130,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1326, iwl5150_abg_cfg)}, /* Half Mini Card */
 
        {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
index fd848cd1583ebeb3372792911849a0eec25d9667..f600e68a410a1abe454170bd65d29b5937df41a9 100644 (file)
@@ -888,6 +888,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 
                iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
                if (hw_rfkill) {
+                       /*
+                        * Clear the interrupt in APMG if the NIC is going down.
+                        * Note that when the NIC exits RFkill (else branch), we
+                        * can't access prph and the NIC will be reset in
+                        * start_hw anyway.
+                        */
+                       iwl_write_prph(trans, APMG_RTC_INT_STT_REG,
+                                      APMG_RTC_INT_STT_RFKILL);
                        set_bit(STATUS_RFKILL, &trans_pcie->status);
                        if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
                                               &trans_pcie->status))
index 826c15602c469a524b857c135f7b38cb4e5782a1..96cfcdd390794060ee6c72c3951984f33da5ff38 100644 (file)
@@ -670,6 +670,11 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
                return err;
        }
 
+       /* Reset the entire device */
+       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+       usleep_range(10, 15);
+
        iwl_pcie_apm_init(trans);
 
        /* From now on, the op_mode will be kept updated about RF kill state */
index ef5fa890a28628666398f39624f83e1bfe6aa1f5..89459db4c53b9f1468f832f4e3d0be0200b7ec22 100644 (file)
@@ -1716,9 +1716,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
        int ret;
 
-       if (priv->bss_mode != NL80211_IFTYPE_STATION) {
+       if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) {
                wiphy_err(wiphy,
-                         "%s: reject infra assoc request in non-STA mode\n",
+                         "%s: reject infra assoc request in non-STA role\n",
                          dev->name);
                return -EINVAL;
        }
index 988552dece75d49ab3af4628dec68bd6a9627030..5178c4630d89310e17a5db810977fa5aad8ca525 100644 (file)
@@ -415,7 +415,8 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
        u32 k = 0;
        struct mwifiex_adapter *adapter = priv->adapter;
 
-       if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+       if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+           priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
                switch (adapter->config_bands) {
                case BAND_B:
                        dev_dbg(adapter->dev, "info: infra band=%d "
index caaf4bd56b3062ea4c9a11028233c1517f69296c..2cf8b964e966c5dec94b37ca9a826799d73f4dee 100644 (file)
@@ -693,7 +693,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
                if (!ret) {
                        dev_notice(adapter->dev,
                                   "WLAN FW already running! Skip FW dnld\n");
-                       goto done;
+                       return 0;
                }
 
                poll_num = MAX_FIRMWARE_POLL_TRIES;
@@ -719,14 +719,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
 poll_fw:
        /* Check if the firmware is downloaded successfully or not */
        ret = adapter->if_ops.check_fw_status(adapter, poll_num);
-       if (ret) {
+       if (ret)
                dev_err(adapter->dev, "FW failed to be active in time\n");
-               return -1;
-       }
-done:
-       /* re-enable host interrupt for mwifiex after fw dnld is successful */
-       if (adapter->if_ops.enable_int)
-               adapter->if_ops.enable_int(adapter);
 
        return ret;
 }
index 1c8a771e8e8127e666265d10447b88f884a4c5fa..12e778159ec58f5be70ab8c3e9d515beab28b48a 100644 (file)
@@ -1291,8 +1291,10 @@ int mwifiex_associate(struct mwifiex_private *priv,
 {
        u8 current_bssid[ETH_ALEN];
 
-       /* Return error if the adapter or table entry is not marked as infra */
-       if ((priv->bss_mode != NL80211_IFTYPE_STATION) ||
+       /* Return error if the adapter is not STA role or table entry
+        * is not marked as infra.
+        */
+       if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) ||
            (bss_desc->bss_mode != NL80211_IFTYPE_STATION))
                return -1;
 
index e15ab72fb03ddc1ad6eab8e54aded37de3143253..1753431de361b807890ec8bcb177760f457faa07 100644 (file)
@@ -427,6 +427,10 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
                                "Cal data request_firmware() failed\n");
        }
 
+       /* enable host interrupt after fw dnld is successful */
+       if (adapter->if_ops.enable_int)
+               adapter->if_ops.enable_int(adapter);
+
        adapter->init_wait_q_woken = false;
        ret = mwifiex_init_fw(adapter);
        if (ret == -1) {
@@ -478,6 +482,8 @@ err_add_intf:
        mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
        rtnl_unlock();
 err_init_fw:
+       if (adapter->if_ops.disable_int)
+               adapter->if_ops.disable_int(adapter);
        pr_debug("info: %s: unregister device\n", __func__);
        adapter->if_ops.unregister_dev(adapter);
 done:
@@ -855,7 +861,7 @@ mwifiex_add_card(void *card, struct semaphore *sem,
        INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
 
        /* Register the device. Fill up the private data structure with relevant
-          information from the card and request for the required IRQ. */
+          information from the card. */
        if (adapter->if_ops.register_dev(adapter)) {
                pr_err("%s: failed to register mwifiex device\n", __func__);
                goto err_registerdev;
@@ -919,6 +925,11 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
        if (!adapter)
                goto exit_remove;
 
+       /* We can no longer handle interrupts once we start doing the teardown
+        * below. */
+       if (adapter->if_ops.disable_int)
+               adapter->if_ops.disable_int(adapter);
+
        adapter->surprise_removed = true;
 
        /* Stop data */
index 3da73d36acdf5e9a5ebe30ce75333704d98a00c0..253e0bd38e25e22ce911e6e49b4d99261afe596d 100644 (file)
@@ -601,6 +601,7 @@ struct mwifiex_if_ops {
        int (*register_dev) (struct mwifiex_adapter *);
        void (*unregister_dev) (struct mwifiex_adapter *);
        int (*enable_int) (struct mwifiex_adapter *);
+       void (*disable_int) (struct mwifiex_adapter *);
        int (*process_int_status) (struct mwifiex_adapter *);
        int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *,
                             struct mwifiex_tx_param *);
index 5ee5ed02eccd56645c94f8b4972962130f5b305b..09185c9632483b324d63953652ac6acc93a36752 100644 (file)
@@ -51,6 +51,7 @@ static struct mwifiex_if_ops sdio_ops;
 static struct semaphore add_remove_card_sem;
 
 static int mwifiex_sdio_resume(struct device *dev);
+static void mwifiex_sdio_interrupt(struct sdio_func *func);
 
 /*
  * SDIO probe.
@@ -296,6 +297,15 @@ static struct sdio_driver mwifiex_sdio = {
        }
 };
 
+/* Write data into SDIO card register. Caller claims SDIO device. */
+static int
+mwifiex_write_reg_locked(struct sdio_func *func, u32 reg, u8 data)
+{
+       int ret = -1;
+       sdio_writeb(func, data, reg, &ret);
+       return ret;
+}
+
 /*
  * This function writes data into SDIO card register.
  */
@@ -303,10 +313,10 @@ static int
 mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data)
 {
        struct sdio_mmc_card *card = adapter->card;
-       int ret = -1;
+       int ret;
 
        sdio_claim_host(card->func);
-       sdio_writeb(card->func, data, reg, &ret);
+       ret = mwifiex_write_reg_locked(card->func, reg, data);
        sdio_release_host(card->func);
 
        return ret;
@@ -685,23 +695,15 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
  * The host interrupt mask is read, the disable bit is reset and
  * written back to the card host interrupt mask register.
  */
-static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
+static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
 {
-       u8 host_int_mask, host_int_disable = HOST_INT_DISABLE;
-
-       /* Read back the host_int_mask register */
-       if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
-               return -1;
-
-       /* Update with the mask and write back to the register */
-       host_int_mask &= ~host_int_disable;
-
-       if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) {
-               dev_err(adapter->dev, "disable host interrupt failed\n");
-               return -1;
-       }
+       struct sdio_mmc_card *card = adapter->card;
+       struct sdio_func *func = card->func;
 
-       return 0;
+       sdio_claim_host(func);
+       mwifiex_write_reg_locked(func, HOST_INT_MASK_REG, 0);
+       sdio_release_irq(func);
+       sdio_release_host(func);
 }
 
 /*
@@ -713,14 +715,29 @@ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
 static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
 {
        struct sdio_mmc_card *card = adapter->card;
+       struct sdio_func *func = card->func;
+       int ret;
+
+       sdio_claim_host(func);
+
+       /* Request the SDIO IRQ */
+       ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
+       if (ret) {
+               dev_err(adapter->dev, "claim irq failed: ret=%d\n", ret);
+               goto out;
+       }
 
        /* Simply write the mask to the register */
-       if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG,
-                             card->reg->host_int_enable)) {
+       ret = mwifiex_write_reg_locked(func, HOST_INT_MASK_REG,
+                                      card->reg->host_int_enable);
+       if (ret) {
                dev_err(adapter->dev, "enable host interrupt failed\n");
-               return -1;
+               sdio_release_irq(func);
        }
-       return 0;
+
+out:
+       sdio_release_host(func);
+       return ret;
 }
 
 /*
@@ -997,9 +1014,6 @@ mwifiex_sdio_interrupt(struct sdio_func *func)
        }
        adapter = card->adapter;
 
-       if (adapter->surprise_removed)
-               return;
-
        if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
                adapter->ps_state = PS_STATE_AWAKE;
 
@@ -1625,8 +1639,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
        /* Allocate buffer and copy payload */
        blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
        buf_block_len = (pkt_len + blk_size - 1) / blk_size;
-       *(u16 *) &payload[0] = (u16) pkt_len;
-       *(u16 *) &payload[2] = type;
+       *(__le16 *)&payload[0] = cpu_to_le16((u16)pkt_len);
+       *(__le16 *)&payload[2] = cpu_to_le16(type);
 
        /*
         * This is SDIO specific header
@@ -1728,9 +1742,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
        struct sdio_mmc_card *card = adapter->card;
 
        if (adapter->card) {
-               /* Release the SDIO IRQ */
                sdio_claim_host(card->func);
-               sdio_release_irq(card->func);
                sdio_disable_func(card->func);
                sdio_release_host(card->func);
                sdio_set_drvdata(card->func, NULL);
@@ -1744,7 +1756,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
  */
 static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 {
-       int ret = 0;
+       int ret;
        struct sdio_mmc_card *card = adapter->card;
        struct sdio_func *func = card->func;
 
@@ -1753,22 +1765,14 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 
        sdio_claim_host(func);
 
-       /* Request the SDIO IRQ */
-       ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
-       if (ret) {
-               pr_err("claim irq failed: ret=%d\n", ret);
-               goto disable_func;
-       }
-
        /* Set block size */
        ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
+       sdio_release_host(func);
        if (ret) {
                pr_err("cannot set SDIO block size\n");
-               ret = -1;
-               goto release_irq;
+               return ret;
        }
 
-       sdio_release_host(func);
        sdio_set_drvdata(func, card);
 
        adapter->dev = &func->dev;
@@ -1776,15 +1780,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
        strcpy(adapter->fw_name, card->firmware);
 
        return 0;
-
-release_irq:
-       sdio_release_irq(func);
-disable_func:
-       sdio_disable_func(func);
-       sdio_release_host(func);
-       adapter->card = NULL;
-
-       return -1;
 }
 
 /*
@@ -1813,9 +1808,6 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
         */
        mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg);
 
-       /* Disable host interrupt mask register for SDIO */
-       mwifiex_sdio_disable_host_int(adapter);
-
        /* Get SDIO ioport */
        mwifiex_init_sdio_ioport(adapter);
 
@@ -1957,6 +1949,7 @@ static struct mwifiex_if_ops sdio_ops = {
        .register_dev = mwifiex_register_dev,
        .unregister_dev = mwifiex_unregister_dev,
        .enable_int = mwifiex_sdio_enable_host_int,
+       .disable_int = mwifiex_sdio_disable_host_int,
        .process_int_status = mwifiex_process_int_status,
        .host_to_card = mwifiex_sdio_host_to_card,
        .wakeup = mwifiex_pm_wakeup_card,
index 6d51dfdd8251a515c3f6a17e94029b5c10f6672a..532ae0ac4dfb3e40bb12592db32ec94e702a4c2b 100644 (file)
@@ -92,9 +92,6 @@
 /* Host Control Registers : Download host interrupt mask */
 #define DN_LD_HOST_INT_MASK            (0x2U)
 
-/* Disable Host interrupt mask */
-#define        HOST_INT_DISABLE                0xff
-
 /* Host Control Registers : Host interrupt status */
 #define HOST_INTSTATUS_REG             0x03
 /* Host Control Registers : Upload host interrupt status */
index 206c3e03807235425ee3c0ad12676cc7c187cad7..8af97abf71088589b61cbc847fdc494a616de7c7 100644 (file)
@@ -257,10 +257,10 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                        goto done;
        }
 
-       if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+       if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+           priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
                u8 config_bands;
 
-               /* Infra mode */
                ret = mwifiex_deauthenticate(priv, NULL);
                if (ret)
                        goto done;
index 9b915d3a44bee4c7d585ca79d8209415c40d7c01..3e60a31582f8b3b15f359a5325a8031de96f4427 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig RT2X00
        tristate "Ralink driver support"
-       depends on MAC80211
+       depends on MAC80211 && HAS_DMA
        ---help---
          This will enable the support for the Ralink drivers,
          developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
index 6c0a91ff963c6833bb7d325cac7954c7c10b41fc..aa95c6cf3545432bf93b0743af97900a91f55ec9 100644 (file)
@@ -936,13 +936,8 @@ void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index)
        spin_unlock_irqrestore(&queue->index_lock, irqflags);
 }
 
-void rt2x00queue_pause_queue(struct data_queue *queue)
+void rt2x00queue_pause_queue_nocheck(struct data_queue *queue)
 {
-       if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
-           !test_bit(QUEUE_STARTED, &queue->flags) ||
-           test_and_set_bit(QUEUE_PAUSED, &queue->flags))
-               return;
-
        switch (queue->qid) {
        case QID_AC_VO:
        case QID_AC_VI:
@@ -958,6 +953,15 @@ void rt2x00queue_pause_queue(struct data_queue *queue)
                break;
        }
 }
+void rt2x00queue_pause_queue(struct data_queue *queue)
+{
+       if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+           !test_bit(QUEUE_STARTED, &queue->flags) ||
+           test_and_set_bit(QUEUE_PAUSED, &queue->flags))
+               return;
+
+       rt2x00queue_pause_queue_nocheck(queue);
+}
 EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue);
 
 void rt2x00queue_unpause_queue(struct data_queue *queue)
@@ -1019,7 +1023,7 @@ void rt2x00queue_stop_queue(struct data_queue *queue)
                return;
        }
 
-       rt2x00queue_pause_queue(queue);
+       rt2x00queue_pause_queue_nocheck(queue);
 
        queue->rt2x00dev->ops->lib->stop_queue(queue);
 
index 7253de3d8c6671c78e732b001e7270731465d039..c2ffce7a907c90cf3fcc01400f50f2850d371533 100644 (file)
@@ -1,27 +1,20 @@
-config RTLWIFI
-       tristate "Realtek wireless card support"
-       depends on MAC80211
-       select FW_LOADER
-       ---help---
-         This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE
-         drivers.  This module does nothing by itself - the various front-end
-         drivers need to be enabled to support any desired devices.
-
-         If you choose to build as a module, it'll be called rtlwifi.
-
-config RTLWIFI_DEBUG
-       bool "Debugging output for rtlwifi driver family"
-       depends on RTLWIFI
+menuconfig RTL_CARDS
+       tristate "Realtek rtlwifi family of devices"
+       depends on MAC80211 && (PCI || USB)
        default y
        ---help---
-       To use the module option that sets the dynamic-debugging level for,
-       the front-end driver, this parameter must be "Y". For memory-limited
-       systems, choose "N". If in doubt, choose "Y".
+         This option will enable support for the Realtek mac80211-based
+         wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de,
+         rtl8723eu, and rtl8188eu share some common code.
+
+if RTL_CARDS
 
 config RTL8192CE
        tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
        select RTL8192C_COMMON
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe
        wireless network adapters.
@@ -30,7 +23,9 @@ config RTL8192CE
 
 config RTL8192SE
        tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe
        wireless network adapters.
@@ -39,7 +34,9 @@ config RTL8192SE
 
 config RTL8192DE
        tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe
        wireless network adapters.
@@ -48,7 +45,9 @@ config RTL8192DE
 
 config RTL8723AE
        tristate "Realtek RTL8723AE PCIe Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8723AE 802.11n PCIe
        wireless network adapters.
@@ -57,7 +56,9 @@ config RTL8723AE
 
 config RTL8188EE
        tristate "Realtek RTL8188EE Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8188EE 802.11n PCIe
        wireless network adapters.
@@ -66,7 +67,9 @@ config RTL8188EE
 
 config RTL8192CU
        tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
-       depends on RTLWIFI && USB
+       depends on USB
+       select RTLWIFI
+       select RTLWIFI_USB
        select RTL8192C_COMMON
        ---help---
        This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB
@@ -74,7 +77,28 @@ config RTL8192CU
 
        If you choose to build it as a module, it will be called rtl8192cu
 
+config RTLWIFI
+       tristate
+       select FW_LOADER
+
+config RTLWIFI_PCI
+       tristate
+
+config RTLWIFI_USB
+       tristate
+
+config RTLWIFI_DEBUG
+       bool "Debugging output for rtlwifi driver family"
+       depends on RTLWIFI
+       default y
+       ---help---
+       To use the module option that sets the dynamic-debugging level for,
+       the front-end driver, this parameter must be "Y". For memory-limited
+       systems, choose "N". If in doubt, choose "Y".
+
 config RTL8192C_COMMON
        tristate
        depends on RTL8192CE || RTL8192CU
-       default m
+       default y
+
+endif
index ff02b874f8d87dfd15ff0205a6036e65c0b9ad5c..d56f023a4b90dfadabf45670b2f5c8d0ca1fa46d 100644 (file)
@@ -12,13 +12,11 @@ rtlwifi-objs        :=              \
 
 rtl8192c_common-objs +=                \
 
-ifneq ($(CONFIG_PCI),)
-rtlwifi-objs   += pci.o
-endif
+obj-$(CONFIG_RTLWIFI_PCI)      += rtl_pci.o
+rtl_pci-objs   :=              pci.o
 
-ifneq ($(CONFIG_USB),)
-rtlwifi-objs   += usb.o
-endif
+obj-$(CONFIG_RTLWIFI_USB)      += rtl_usb.o
+rtl_usb-objs   :=              usb.o
 
 obj-$(CONFIG_RTL8192C_COMMON)  += rtl8192c/
 obj-$(CONFIG_RTL8192CE)                += rtl8192ce/
index 9d558ac77b0c78b36ad6f6a31a49cf5aa4aae765..7651f5acc14bcccdc179fc09450af258f9d30e23 100644 (file)
@@ -172,6 +172,7 @@ u8 rtl_tid_to_ac(u8 tid)
 {
        return tid_to_ac[tid];
 }
+EXPORT_SYMBOL_GPL(rtl_tid_to_ac);
 
 static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
                                  struct ieee80211_sta_ht_cap *ht_cap)
@@ -406,6 +407,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
        cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
        cancel_delayed_work(&rtlpriv->works.fwevt_wq);
 }
+EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work);
 
 void rtl_init_rfkill(struct ieee80211_hw *hw)
 {
@@ -439,6 +441,7 @@ void rtl_deinit_rfkill(struct ieee80211_hw *hw)
 {
        wiphy_rfkill_stop_polling(hw->wiphy);
 }
+EXPORT_SYMBOL_GPL(rtl_deinit_rfkill);
 
 int rtl_init_core(struct ieee80211_hw *hw)
 {
@@ -489,10 +492,12 @@ int rtl_init_core(struct ieee80211_hw *hw)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(rtl_init_core);
 
 void rtl_deinit_core(struct ieee80211_hw *hw)
 {
 }
+EXPORT_SYMBOL_GPL(rtl_deinit_core);
 
 void rtl_init_rx_config(struct ieee80211_hw *hw)
 {
@@ -501,6 +506,7 @@ void rtl_init_rx_config(struct ieee80211_hw *hw)
 
        rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
 }
+EXPORT_SYMBOL_GPL(rtl_init_rx_config);
 
 /*********************************************************
  *
@@ -879,6 +885,7 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        return true;
 }
+EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc);
 
 void rtl_get_tcb_desc(struct ieee80211_hw *hw,
                      struct ieee80211_tx_info *info,
@@ -1052,6 +1059,7 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 
        return true;
 }
+EXPORT_SYMBOL_GPL(rtl_action_proc);
 
 /*should call before software enc*/
 u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
@@ -1125,6 +1133,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 
        return false;
 }
+EXPORT_SYMBOL_GPL(rtl_is_special_data);
 
 /*********************************************************
  *
@@ -1300,6 +1309,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        rtlpriv->link_info.bcn_rx_inperiod++;
 }
+EXPORT_SYMBOL_GPL(rtl_beacon_statistic);
 
 void rtl_watchdog_wq_callback(void *data)
 {
@@ -1793,6 +1803,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
 
        mac->vendor = vendor;
 }
+EXPORT_SYMBOL_GPL(rtl_recognize_peer);
 
 /*********************************************************
  *
@@ -1849,6 +1860,7 @@ struct attribute_group rtl_attribute_group = {
        .name = "rtlsysfs",
        .attrs = rtl_sysfs_entries,
 };
+EXPORT_SYMBOL_GPL(rtl_attribute_group);
 
 MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
 MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
@@ -1856,7 +1868,8 @@ MODULE_AUTHOR("Larry Finger       <Larry.FInger@lwfinger.net>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
 
-struct rtl_global_var global_var = {};
+struct rtl_global_var rtl_global_var = {};
+EXPORT_SYMBOL_GPL(rtl_global_var);
 
 static int __init rtl_core_module_init(void)
 {
@@ -1864,8 +1877,8 @@ static int __init rtl_core_module_init(void)
                pr_err("Unable to register rtl_rc, use default RC !!\n");
 
        /* init some global vars */
-       INIT_LIST_HEAD(&global_var.glb_priv_list);
-       spin_lock_init(&global_var.glb_list_lock);
+       INIT_LIST_HEAD(&rtl_global_var.glb_priv_list);
+       spin_lock_init(&rtl_global_var.glb_list_lock);
 
        return 0;
 }
index 8576bc34b03289ef077db41f5700e3a2eea5bf21..0e5fe0902daf6eb180a1da431ce54477e49486cb 100644 (file)
@@ -147,7 +147,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
 u8 rtl_tid_to_ac(u8 tid);
 extern struct attribute_group rtl_attribute_group;
 void rtl_easy_concurrent_retrytimer_callback(unsigned long data);
-extern struct rtl_global_var global_var;
+extern struct rtl_global_var rtl_global_var;
 int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
                         bool isht, u8 desc_rate, bool first_ampdu);
 bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
index ee84844be0080c2e1bcef681f7e53a7f42f93125..733b7ce7f0e2a981f442cd9cdadd8f40a6426558 100644 (file)
@@ -1330,3 +1330,4 @@ const struct ieee80211_ops rtl_ops = {
        .rfkill_poll = rtl_op_rfkill_poll,
        .flush = rtl_op_flush,
 };
+EXPORT_SYMBOL_GPL(rtl_ops);
index 7d52d3d7769f0e357be0900ec0423dac70cb390c..76e2086e137e5f0356325887ecccc5c768d17f6c 100644 (file)
@@ -51,3 +51,4 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
 
        /*Init Debug flag enable condition */
 }
+EXPORT_SYMBOL_GPL(rtl_dbgp_flag_init);
index 9e3894178e7773b3d6aca8a4cca70fc518fd6a96..838a1ed3f1942b9f3d56a122c2840548b38103c9 100644 (file)
@@ -229,6 +229,7 @@ void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
 
        *pbuf = (u8) (value32 & 0xff);
 }
+EXPORT_SYMBOL_GPL(read_efuse_byte);
 
 void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 {
index c97e9d327331c8b25624327ec4d672c7289f4492..703f839af6ca0b4abefcfc754dc21eb3d13b2dac 100644 (file)
 #include "efuse.h"
 #include <linux/export.h>
 #include <linux/kmemleak.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCI basic driver for rtlwifi");
 
 static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
        PCI_VENDOR_ID_INTEL,
@@ -1008,19 +1015,6 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        return;
 }
 
-static void rtl_lps_change_work_callback(struct work_struct *work)
-{
-       struct rtl_works *rtlworks =
-           container_of(work, struct rtl_works, lps_change_work);
-       struct ieee80211_hw *hw = rtlworks->hw;
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-
-       if (rtlpriv->enter_ps)
-               rtl_lps_enter(hw);
-       else
-               rtl_lps_leave(hw);
-}
-
 static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
 {
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1899,7 +1893,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
        rtlpriv->rtlhal.interface = INTF_PCI;
        rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
        rtlpriv->intf_ops = &rtl_pci_ops;
-       rtlpriv->glb_var = &global_var;
+       rtlpriv->glb_var = &rtl_global_var;
 
        /*
         *init dbgp flags before all
index 884bceae38a91d2b9ce4e07cf70c5c040e844df4..298b615964e861acb23c9ccd85e7b154854e9cda 100644 (file)
@@ -269,6 +269,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw)
 
        spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
 }
+EXPORT_SYMBOL_GPL(rtl_ips_nic_on);
 
 /*for FW LPS*/
 
@@ -518,6 +519,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
                         "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed);
        }
 }
+EXPORT_SYMBOL_GPL(rtl_swlps_beacon);
 
 void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
 {
@@ -611,6 +613,19 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
                        MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
 }
 
+void rtl_lps_change_work_callback(struct work_struct *work)
+{
+       struct rtl_works *rtlworks =
+           container_of(work, struct rtl_works, lps_change_work);
+       struct ieee80211_hw *hw = rtlworks->hw;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->enter_ps)
+               rtl_lps_enter(hw);
+       else
+               rtl_lps_leave(hw);
+}
+EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback);
 
 void rtl_swlps_wq_callback(void *data)
 {
@@ -922,3 +937,4 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
        else
                rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
 }
+EXPORT_SYMBOL_GPL(rtl_p2p_info);
index 4d682b753f503df0f61b5e58b98e871f58c31029..88bd76ea88f7621dd92cb4ff495ee22e9dc53912 100644 (file)
@@ -49,5 +49,6 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
 void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
 void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
 void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
+void rtl_lps_change_work_callback(struct work_struct *work);
 
 #endif
index a3532e0778710ff5975a3c3fec4e21299e45e301..e56778cac9bfce39e56d5aa239e34f2fb1135ffb 100644 (file)
 #include "ps.h"
 #include "rtl8192c/fw_common.h"
 #include <linux/export.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("USB basic driver for rtlwifi");
 
 #define        REALTEK_USB_VENQT_READ                  0xC0
 #define        REALTEK_USB_VENQT_WRITE                 0x40
@@ -1070,6 +1077,8 @@ int rtl_usb_probe(struct usb_interface *intf,
        spin_lock_init(&rtlpriv->locks.usb_lock);
        INIT_WORK(&rtlpriv->works.fill_h2c_cmd,
                  rtl_fill_h2c_cmd_work_callback);
+       INIT_WORK(&rtlpriv->works.lps_change_work,
+                 rtl_lps_change_work_callback);
 
        rtlpriv->usb_data_index = 0;
        init_completion(&rtlpriv->firmware_loading_complete);
index a3c1c5aae6a9eaa5de0ecd0dd0335771ac8f7fab..1264923ade0f2c7973528080d3fa75167b6be0b4 100644 (file)
@@ -345,6 +345,7 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
        if (r && irq) {
                const char *name = NULL;
 
+               memset(r, 0, sizeof(*r));
                /*
                 * Get optional "interrupts-names" property to add a name
                 * to the resource.
@@ -482,8 +483,9 @@ void __init of_irq_init(const struct of_device_id *matches)
                }
 
                /* Get the next pending parent that might have children */
-               desc = list_first_entry(&intc_parent_list, typeof(*desc), list);
-               if (list_empty(&intc_parent_list) || !desc) {
+               desc = list_first_entry_or_null(&intc_parent_list,
+                                               typeof(*desc), list);
+               if (!desc) {
                        pr_err("of_irq_init: children remain, but no parents\n");
                        break;
                }
index e79e006eb9abc4eab4722aa483d2c6fb38a8c455..9ee04b4b68bf39569acd6dd360c62a6cb4e4b76e 100644 (file)
@@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
        return pcidev->irq;
 }
 
-static struct iosapic_info *first_isi = NULL;
+static struct iosapic_info *iosapic_list;
 
 #ifdef CONFIG_64BIT
-int iosapic_serial_irq(int num)
+int iosapic_serial_irq(struct parisc_device *dev)
 {
-       struct iosapic_info *isi = first_isi;
-       struct irt_entry *irte = NULL;  /* only used if PAT PDC */
+       struct iosapic_info *isi;
+       struct irt_entry *irte;
        struct vector_info *vi;
-       int isi_line;   /* line used by device */
+       int cnt;
+       int intin;
+
+       intin = (dev->mod_info >> 24) & 15;
 
        /* lookup IRT entry for isi/slot/pin set */
-       irte = &irt_cell[num];
+       for (cnt = 0; cnt < irt_num_entry; cnt++) {
+               irte = &irt_cell[cnt];
+               if (COMPARE_IRTE_ADDR(irte, dev->mod0) &&
+                   irte->dest_iosapic_intin == intin)
+                       break;
+       }
+       if (cnt >= irt_num_entry)
+               return 0; /* no irq found, force polling */
 
        DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n",
                irte,
@@ -834,11 +844,17 @@ int iosapic_serial_irq(int num)
                irte->src_seg_id,
                irte->dest_iosapic_intin,
                (u32) irte->dest_iosapic_addr);
-       isi_line = irte->dest_iosapic_intin;
+
+       /* search for iosapic */
+       for (isi = iosapic_list; isi; isi = isi->isi_next)
+               if (isi->isi_hpa == dev->mod0)
+                       break;
+       if (!isi)
+               return 0; /* no iosapic found, force polling */
 
        /* get vector info for this input line */
-       vi = isi->isi_vector + isi_line;
-       DBG_IRT("iosapic_serial_irq:  line %d vi 0x%p\n", isi_line, vi);
+       vi = isi->isi_vector + intin;
+       DBG_IRT("iosapic_serial_irq:  line %d vi 0x%p\n", iosapic_intin, vi);
 
        /* If this IRQ line has already been setup, skip it */
        if (vi->irte)
@@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa)
                vip->irqline = (unsigned char) cnt;
                vip->iosapic = isi;
        }
-       if (!first_isi)
-               first_isi = isi;
+       isi->isi_next = iosapic_list;
+       iosapic_list = isi;
        return isi;
 }
 
index 13a633b1612e1786b9cdcb7f2eebece8b0a70dde..7bf3926aecc0d765af64f166cbeb871ea66ac127 100644 (file)
@@ -86,10 +86,6 @@ struct mvebu_sw_pci_bridge {
        u16 secondary_status;
        u16 membase;
        u16 memlimit;
-       u16 prefmembase;
-       u16 prefmemlimit;
-       u32 prefbaseupper;
-       u32 preflimitupper;
        u16 iobaseupper;
        u16 iolimitupper;
        u8 cappointer;
@@ -419,15 +415,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
                break;
 
        case PCI_PREF_MEMORY_BASE:
-               *value = (bridge->prefmemlimit << 16 | bridge->prefmembase);
-               break;
-
-       case PCI_PREF_BASE_UPPER32:
-               *value = bridge->prefbaseupper;
-               break;
-
-       case PCI_PREF_LIMIT_UPPER32:
-               *value = bridge->preflimitupper;
+               *value = 0;
                break;
 
        case PCI_IO_BASE_UPPER16:
@@ -501,19 +489,6 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
                mvebu_pcie_handle_membase_change(port);
                break;
 
-       case PCI_PREF_MEMORY_BASE:
-               bridge->prefmembase = value & 0xffff;
-               bridge->prefmemlimit = value >> 16;
-               break;
-
-       case PCI_PREF_BASE_UPPER32:
-               bridge->prefbaseupper = value;
-               break;
-
-       case PCI_PREF_LIMIT_UPPER32:
-               bridge->preflimitupper = value;
-               break;
-
        case PCI_IO_BASE_UPPER16:
                bridge->iobaseupper = value & 0xffff;
                bridge->iolimitupper = value >> 16;
index bb7ebb22db01e39a66840ba4684f811e7d89e075..d85009de713d647b9e3a81024776b6bdaf312754 100644 (file)
@@ -3,16 +3,13 @@
 #
 
 menuconfig HOTPLUG_PCI
-       tristate "Support for PCI Hotplug"
+       bool "Support for PCI Hotplug"
        depends on PCI && SYSFS
        ---help---
          Say Y here if you have a motherboard with a PCI Hotplug controller.
          This allows you to add and remove PCI cards while the machine is
          powered up and running.
 
-         To compile this driver as a module, choose M here: the
-         module will be called pci_hotplug.
-
          When in doubt, say N.
 
 if HOTPLUG_PCI
index aac7a40e4a4ac9205441d9c6918a080531117571..0e0d0f7f63fdd83aa551549d38b174cdca8d034d 100644 (file)
@@ -92,7 +92,14 @@ int pciehp_unconfigure_device(struct slot *p_slot)
        if (ret)
                presence = 0;
 
-       list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
+       /*
+        * Stopping an SR-IOV PF device removes all the associated VFs,
+        * which will update the bus->devices list and confuse the
+        * iterator.  Therefore, iterate in reverse so we remove the VFs
+        * first, then the PF.  We do the same in pci_stop_bus_device().
+        */
+       list_for_each_entry_safe_reverse(dev, temp, &parent->devices,
+                                        bus_list) {
                pci_dev_get(dev);
                if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
                        pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl);
index b29e20b7862f168673b3ad980200dd3c80fff175..bb7af78e4eedd359a08db0fab40682a82abac5e1 100644 (file)
@@ -388,7 +388,6 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
        /* Remove the EADS bridge device itself */
        BUG_ON(!bus->self);
        pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
-       eeh_remove_bus_device(bus->self, true);
        pci_stop_and_remove_bus_device(bus->self);
 
        return 0;
index 569f82fc9e22bb826fbfca36ba74b891cc15b0d8..3b94cfcfa03bee1dd1a1d319f9d038a46b07b834 100644 (file)
@@ -14,15 +14,12 @@ config PCIEPORTBUS
 # Include service Kconfig here
 #
 config HOTPLUG_PCI_PCIE
-       tristate "PCI Express Hotplug driver"
+       bool "PCI Express Hotplug driver"
        depends on HOTPLUG_PCI && PCIEPORTBUS
        help
          Say Y here if you have a motherboard that supports PCI Express Native
          Hotplug
 
-         To compile this driver as a module, choose M here: the
-         module will be called pciehp.
-
          When in doubt, say N.
 
 source "drivers/pci/pcie/aer/Kconfig"
index d254e237953382bb99768c7cca79b65c3b9aded8..64a7de22d9afe0edb548b3b20f96d7c288e53273 100644 (file)
@@ -300,6 +300,47 @@ static void assign_requested_resources_sorted(struct list_head *head,
        }
 }
 
+static unsigned long pci_fail_res_type_mask(struct list_head *fail_head)
+{
+       struct pci_dev_resource *fail_res;
+       unsigned long mask = 0;
+
+       /* check failed type */
+       list_for_each_entry(fail_res, fail_head, list)
+               mask |= fail_res->flags;
+
+       /*
+        * one pref failed resource will set IORESOURCE_MEM,
+        * as we can allocate pref in non-pref range.
+        * Will release all assigned non-pref sibling resources
+        * according to that bit.
+        */
+       return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH);
+}
+
+static bool pci_need_to_release(unsigned long mask, struct resource *res)
+{
+       if (res->flags & IORESOURCE_IO)
+               return !!(mask & IORESOURCE_IO);
+
+       /* check pref at first */
+       if (res->flags & IORESOURCE_PREFETCH) {
+               if (mask & IORESOURCE_PREFETCH)
+                       return true;
+               /* count pref if its parent is non-pref */
+               else if ((mask & IORESOURCE_MEM) &&
+                        !(res->parent->flags & IORESOURCE_PREFETCH))
+                       return true;
+               else
+                       return false;
+       }
+
+       if (res->flags & IORESOURCE_MEM)
+               return !!(mask & IORESOURCE_MEM);
+
+       return false;   /* should not get here */
+}
+
 static void __assign_resources_sorted(struct list_head *head,
                                 struct list_head *realloc_head,
                                 struct list_head *fail_head)
@@ -312,11 +353,24 @@ static void __assign_resources_sorted(struct list_head *head,
         *  if could do that, could get out early.
         *  if could not do that, we still try to assign requested at first,
         *    then try to reassign add_size for some resources.
+        *
+        * Separate three resource type checking if we need to release
+        * assigned resource after requested + add_size try.
+        *      1. if there is io port assign fail, will release assigned
+        *         io port.
+        *      2. if there is pref mmio assign fail, release assigned
+        *         pref mmio.
+        *         if assigned pref mmio's parent is non-pref mmio and there
+        *         is non-pref mmio assign fail, will release that assigned
+        *         pref mmio.
+        *      3. if there is non-pref mmio assign fail or pref mmio
+        *         assigned fail, will release assigned non-pref mmio.
         */
        LIST_HEAD(save_head);
        LIST_HEAD(local_fail_head);
        struct pci_dev_resource *save_res;
-       struct pci_dev_resource *dev_res;
+       struct pci_dev_resource *dev_res, *tmp_res;
+       unsigned long fail_type;
 
        /* Check if optional add_size is there */
        if (!realloc_head || list_empty(realloc_head))
@@ -348,6 +402,19 @@ static void __assign_resources_sorted(struct list_head *head,
                return;
        }
 
+       /* check failed type */
+       fail_type = pci_fail_res_type_mask(&local_fail_head);
+       /* remove not need to be released assigned res from head list etc */
+       list_for_each_entry_safe(dev_res, tmp_res, head, list)
+               if (dev_res->res->parent &&
+                   !pci_need_to_release(fail_type, dev_res->res)) {
+                       /* remove it from realloc_head list */
+                       remove_from_list(realloc_head, dev_res->res);
+                       remove_from_list(&save_head, dev_res->res);
+                       list_del(&dev_res->list);
+                       kfree(dev_res);
+               }
+
        free_list(&local_fail_head);
        /* Release assigned resource */
        list_for_each_entry(dev_res, head, list)
index 5b272bfd261d6803fad6eaac61a3fa28dab4e767..2a00239661b3c27ec979802a3f040f92f2276060 100644 (file)
@@ -1193,6 +1193,7 @@ void pinctrl_unregister_map(struct pinctrl_map const *map)
        list_for_each_entry(maps_node, &pinctrl_maps, node) {
                if (maps_node->maps == map) {
                        list_del(&maps_node->node);
+                       kfree(maps_node);
                        mutex_unlock(&pinctrl_maps_mutex);
                        return;
                }
index 6866548fab31669d5141a7c8af21c10e0caa895d..7323cca440b5929ef7248d6d73662d200c01109b 100644 (file)
@@ -1483,6 +1483,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
        return ret;
 }
 
+#ifdef CONFIG_PM
 static int pinctrl_single_suspend(struct platform_device *pdev,
                                        pm_message_t state)
 {
@@ -1505,6 +1506,7 @@ static int pinctrl_single_resume(struct platform_device *pdev)
 
        return pinctrl_force_default(pcs->pctl);
 }
+#endif
 
 static int pcs_probe(struct platform_device *pdev)
 {
index 7956df58d751a3231db71b2c4f8c00f0cb231b7d..31f7d0e04aaaaa6f335342ee99b5df269e792beb 100644 (file)
@@ -3785,6 +3785,7 @@ static const struct regulator_desc sh73a0_vccq_mc0_desc = {
 
 static struct regulator_consumer_supply sh73a0_vccq_mc0_consumers[] = {
        REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vqmmc", "ee100000.sdhi"),
 };
 
 static const struct regulator_init_data sh73a0_vccq_mc0_init_data = {
index 1fa39a4441717e233c8844c0a7e72357356ece0d..867c9681763cab5ad42790dd98eb6137745c0d87 100644 (file)
@@ -496,7 +496,7 @@ static const unsigned sdmmc5_pins[] = { 24, 25, 26 };
 static const struct sirfsoc_muxmask usp0_muxmask[] = {
        {
                .group = 1,
-               .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22),
+               .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23),
        },
 };
 
@@ -507,8 +507,21 @@ static const struct sirfsoc_padmux usp0_padmux = {
        .funcval = 0,
 };
 
-static const unsigned usp0_pins[] = { 51, 52, 53, 54 };
+static const unsigned usp0_pins[] = { 51, 52, 53, 54, 55 };
 
+static const struct sirfsoc_muxmask usp0_uart_nostreamctrl_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(20) | BIT(21),
+       },
+};
+
+static const struct sirfsoc_padmux usp0_uart_nostreamctrl_padmux = {
+       .muxmask_counts = ARRAY_SIZE(usp0_uart_nostreamctrl_muxmask),
+       .muxmask = usp0_uart_nostreamctrl_muxmask,
+};
+
+static const unsigned usp0_uart_nostreamctrl_pins[] = { 52, 53 };
 static const struct sirfsoc_muxmask usp1_muxmask[] = {
        {
                .group = 0,
@@ -822,6 +835,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
        SIRFSOC_PIN_GROUP("uart2grp", uart2_pins),
        SIRFSOC_PIN_GROUP("uart2_nostreamctrlgrp", uart2_nostreamctrl_pins),
        SIRFSOC_PIN_GROUP("usp0grp", usp0_pins),
+       SIRFSOC_PIN_GROUP("usp0_uart_nostreamctrl_grp",
+                                       usp0_uart_nostreamctrl_pins),
        SIRFSOC_PIN_GROUP("usp1grp", usp1_pins),
        SIRFSOC_PIN_GROUP("i2c0grp", i2c0_pins),
        SIRFSOC_PIN_GROUP("i2c1grp", i2c1_pins),
@@ -862,6 +877,8 @@ static const char * const uart0grp[] = { "uart0grp" };
 static const char * const uart1grp[] = { "uart1grp" };
 static const char * const uart2grp[] = { "uart2grp" };
 static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" };
+static const char * const usp0_uart_nostreamctrl_grp[] = {
+                                       "usp0_uart_nostreamctrl_grp" };
 static const char * const usp0grp[] = { "usp0grp" };
 static const char * const usp1grp[] = { "usp1grp" };
 static const char * const i2c0grp[] = { "i2c0grp" };
@@ -904,6 +921,9 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
        SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux),
        SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux),
        SIRFSOC_PMX_FUNCTION("usp0", usp0grp, usp0_padmux),
+       SIRFSOC_PMX_FUNCTION("usp0_uart_nostreamctrl",
+                                               usp0_uart_nostreamctrl_grp,
+                                               usp0_uart_nostreamctrl_padmux),
        SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux),
        SIRFSOC_PMX_FUNCTION("i2c0", i2c0grp, i2c0_padmux),
        SIRFSOC_PMX_FUNCTION("i2c1", i2c1grp, i2c1_padmux),
index f4f30af2df68c682744cc125ede61da5f87eb4d1..2e8a20cac58848cdd0e2afa6201f3f82f4a88e84 100644 (file)
@@ -1715,11 +1715,13 @@ int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops)
                    (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops))
                        port->nscan = NULL;
 
-       list_for_each_entry(scan, &rio_scans, node)
+       list_for_each_entry(scan, &rio_scans, node) {
                if (scan->mport_id == mport_id) {
                        list_del(&scan->node);
                        kfree(scan);
+                       break;
                }
+       }
 
        mutex_unlock(&rio_mport_list_lock);
 
index 02faf3c4e0d51d13cd6fd7c55b2de4f09776f08f..c2e80d7ca5e26b618a19bfc5aac45e8497651082 100644 (file)
@@ -524,6 +524,8 @@ static int twl_rtc_probe(struct platform_device *pdev)
        if (ret < 0)
                goto out1;
 
+       device_init_wakeup(&pdev->dev, 1);
+
        rtc = rtc_device_register(pdev->name,
                                  &pdev->dev, &twl_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc)) {
@@ -542,7 +544,6 @@ static int twl_rtc_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, rtc);
-       device_init_wakeup(&pdev->dev, 1);
        return 0;
 
 out2:
index 17150a77898433c27e58b2a8ac9ccb81bd228ddb..451bf99582ff09948c04e6634ca2d381c0d6a45a 100644 (file)
@@ -2392,6 +2392,12 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
                rc = cqr->intrc;
        else
                rc = -EIO;
+
+       /* kick tasklets */
+       dasd_schedule_device_bh(device);
+       if (device->block)
+               dasd_schedule_block_bh(device->block);
+
        return rc;
 }
 
index 7b082157eb79668b5fa6bcda0b16d6df25cd6acb..99d2930b18c80e319d3c506244c80b6205bab17e 100644 (file)
@@ -185,7 +185,7 @@ static void sci_io_request_build_ssp_command_iu(struct isci_request *ireq)
        cmd_iu->_r_c = 0;
 
        sci_swab32_cpy(&cmd_iu->cdb, task->ssp_task.cmd->cmnd,
-                      task->ssp_task.cmd->cmd_len / sizeof(u32));
+                      (task->ssp_task.cmd->cmd_len+3) / sizeof(u32));
 }
 
 static void sci_task_request_build_ssp_task_iu(struct isci_request *ireq)
index 9bb020ac089cddf6b665e8a52f728c95621ece34..0d30ca849e8f71502c9ecddfa9aa539e4e59af0f 100644 (file)
@@ -491,6 +491,7 @@ int isci_task_abort_task(struct sas_task *task)
        struct isci_tmf           tmf;
        int                       ret = TMF_RESP_FUNC_FAILED;
        unsigned long             flags;
+       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
@@ -505,9 +506,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) {
                idev = isci_get_device(task->dev->lldd_dev);
-
+               target_done_already = test_bit(IREQ_COMPLETE_IN_TARGET,
+                                              &old_request->flags);
+       }
        spin_unlock(&task->task_state_lock);
        spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
@@ -561,7 +564,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 ||
            test_bit(IDEV_GONE, &idev->flags)) {
 
                spin_unlock_irqrestore(&ihost->scic_lock, flags);
index f14665a6293dbb702d9c7c4a98fc135fc6f489eb..6b1b4e91e53f655128edf0235589bd02081963fb 100644 (file)
@@ -1857,11 +1857,16 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
                goto out;
        }
 
-       /* error info record present */
-       if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
+       /*
+        * error info record present; slot->response is 32 bit aligned but may
+        * not be 64 bit aligned, so check for zero in two 32 bit reads
+        */
+       if (unlikely((rx_desc & RXQ_ERR)
+                    && (*((u32 *)slot->response)
+                        || *(((u32 *)slot->response) + 1)))) {
                mv_dprintk("port %d slot %d rx_desc %X has error info"
                        "%016llX.\n", slot->port->sas_port.id, slot_idx,
-                        rx_desc, (u64)(*(u64 *)slot->response));
+                        rx_desc, get_unaligned_le64(slot->response));
                tstat->stat = mvs_slot_err(mvi, task, slot_idx);
                tstat->resp = SAS_TASK_COMPLETE;
                goto out;
index 60e2fb7f2dca7e37512b128bea9b59fd1c9cd579..d6b19dc80bee522a934bb1bb64dd56c1ecad0c51 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/irq.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <asm/unaligned.h>
 #include <scsi/libsas.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_tcq.h>
index 42ef481db942a79685900c136e7140a199cd8dc4..ef0a5481b9dd46ce0efbad796fa9a6cf04744296 100644 (file)
@@ -419,6 +419,8 @@ qla2x00_start_scsi(srb_t *sp)
                            __constant_cpu_to_le16(CF_SIMPLE_TAG);
                        break;
                }
+       } else {
+               cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
        }
 
        /* Load SCSI command packet. */
@@ -1307,11 +1309,11 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
                    fcp_cmnd->task_attribute = TSK_ORDERED;
                    break;
                default:
-                   fcp_cmnd->task_attribute = 0;
+                   fcp_cmnd->task_attribute = TSK_SIMPLE;
                    break;
                }
        } else {
-               fcp_cmnd->task_attribute = 0;
+               fcp_cmnd->task_attribute = TSK_SIMPLE;
        }
 
        cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
@@ -1525,7 +1527,12 @@ qla24xx_start_scsi(srb_t *sp)
                case ORDERED_QUEUE_TAG:
                        cmd_pkt->task = TSK_ORDERED;
                        break;
+               default:
+                   cmd_pkt->task = TSK_SIMPLE;
+                   break;
                }
+       } else {
+               cmd_pkt->task = TSK_SIMPLE;
        }
 
        /* Load SCSI command packet. */
index 80f39b8b02239ad325143fb3e5e38c9753729ab4..86fcf2c313ad2ef9c5539149bb0006a06bd5c25b 100644 (file)
@@ -838,10 +838,17 @@ static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq)
 
 static void sd_unprep_fn(struct request_queue *q, struct request *rq)
 {
+       struct scsi_cmnd *SCpnt = rq->special;
+
        if (rq->cmd_flags & REQ_DISCARD) {
                free_page((unsigned long)rq->buffer);
                rq->buffer = NULL;
        }
+       if (SCpnt->cmnd != rq->cmd) {
+               mempool_free(SCpnt->cmnd, sd_cdb_pool);
+               SCpnt->cmnd = NULL;
+               SCpnt->cmd_len = 0;
+       }
 }
 
 /**
@@ -1720,21 +1727,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
        if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))
                sd_dif_complete(SCpnt, good_bytes);
 
-       if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type)
-           == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd) {
-
-               /* We have to print a failed command here as the
-                * extended CDB gets freed before scsi_io_completion()
-                * is called.
-                */
-               if (result)
-                       scsi_print_command(SCpnt);
-
-               mempool_free(SCpnt->cmnd, sd_cdb_pool);
-               SCpnt->cmnd = NULL;
-               SCpnt->cmd_len = 0;
-       }
-
        return good_bytes;
 }
 
index 080abf2faf972ab3b999ac58f923c03dbec7e9b8..a8c344422a77d5cce6c34fcadfd7d61781d660bc 100644 (file)
@@ -469,7 +469,7 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
                         unsigned long nr_segs, loff_t ppos)
 {
        struct logger_log *log = file_get_log(iocb->ki_filp);
-       size_t orig = log->w_off;
+       size_t orig;
        struct logger_entry header;
        struct timespec now;
        ssize_t ret = 0;
@@ -490,6 +490,8 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
 
        mutex_lock(&log->mutex);
 
+       orig = log->w_off;
+
        /*
         * Fix up any readers, pulling them forward to the first readable
         * entry after (what will be) the new write offset. We do this now
index b10f739b7e3e1fcbe16acaf7d66705b59e534441..fa8da9aada3079b6a18fc0189d4fdca36af753c6 100644 (file)
@@ -9,4 +9,4 @@ TODO:
 Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
 copy:
        Ian Abbott <abbotti@mev.co.uk>
-       Frank Mori Hess <fmhess@users.sourceforge.net>
+       H Hartley Sweeten <hsweeten@visionengravers.com>
index 8647518259f6dd5ab3379babc218d5ef6cf24831..f4a197b2d1fd951f8879b78cd96e6a2cce1f24d3 100644 (file)
@@ -1413,22 +1413,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 (cmd.chanlist_len > s->len_chanlist) {
                DPRINTK("channel/gain list too long %u > %d\n",
                        cmd.chanlist_len, s->len_chanlist);
-               ret = -EINVAL;
-               goto cleanup;
+               return -EINVAL;
        }
 
        /* make sure channel/gain list isn't too short */
        if (cmd.chanlist_len < 1) {
                DPRINTK("channel/gain list too short %u < 1\n",
                        cmd.chanlist_len);
-               ret = -EINVAL;
-               goto cleanup;
+               return -EINVAL;
        }
 
        async->cmd = cmd;
@@ -1438,8 +1435,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_chanlist,
@@ -1491,6 +1487,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;
@@ -1705,6 +1704,7 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
                           void *file)
 {
        struct comedi_subdevice *s;
+       int ret;
 
        if (arg >= dev->n_subdevices)
                return -EINVAL;
@@ -1721,7 +1721,11 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
        if (s->busy != file)
                return -EBUSY;
 
-       return do_cancel(dev, s);
+       ret = do_cancel(dev, s);
+       if (comedi_get_subdevice_runflags(s) & SRF_USER)
+               wake_up_interruptible(&s->async->wait_head);
+
+       return ret;
 }
 
 /*
@@ -2053,11 +2057,13 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
 
                if (!comedi_is_subdevice_running(s)) {
                        if (count == 0) {
+                               mutex_lock(&dev->mutex);
                                if (comedi_is_subdevice_in_error(s))
                                        retval = -EPIPE;
                                else
                                        retval = 0;
                                do_become_nonbusy(dev, s);
+                               mutex_unlock(&dev->mutex);
                        }
                        break;
                }
@@ -2156,11 +2162,13 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
 
                if (n == 0) {
                        if (!comedi_is_subdevice_running(s)) {
+                               mutex_lock(&dev->mutex);
                                do_become_nonbusy(dev, s);
                                if (comedi_is_subdevice_in_error(s))
                                        retval = -EPIPE;
                                else
                                        retval = 0;
+                               mutex_unlock(&dev->mutex);
                                break;
                        }
                        if (file->f_flags & O_NONBLOCK) {
@@ -2198,9 +2206,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_is_subdevice_idle(s) &&
-           async->buf_read_count - async->buf_write_count == 0) {
-               do_become_nonbusy(dev, s);
+       if (comedi_is_subdevice_idle(s)) {
+               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);
index 5590ebf1da15218c50561fcbd01b0ebc907ce693..817f837b240d656ccf4379bd3f68be4bbf49b867 100644 (file)
@@ -827,11 +827,11 @@ static void usb_alphatrack_disconnect(struct usb_interface *intf)
                mutex_unlock(&dev->mtx);
                usb_alphatrack_delete(dev);
        } else {
+               atomic_set(&dev->writes_pending, 0);
                dev->intf = NULL;
                mutex_unlock(&dev->mtx);
        }
 
-       atomic_set(&dev->writes_pending, 0);
        mutex_unlock(&disconnect_mutex);
 
        dev_info(&intf->dev, "Alphatrack Surface #%d now disconnected\n",
index b795353e8348a3fcab6d1a01d0472a7168c370a1..cc3692439a5c95fedc0f2c584a52b3d03c0bf391 100644 (file)
@@ -250,8 +250,8 @@ static void send_qos_list(struct nic *nic, struct list_head *head)
 
        list_for_each_entry_safe(entry, n, head, list) {
                list_del(&entry->list);
-               free_qos_entry(entry);
                gdm_wimax_send_tx(entry->skb, entry->dev);
+               free_qos_entry(entry);
        }
 }
 
index 22339059837ff34a15919ca319ede0e0bb1bbf9f..bd0f2fd01db4be91e4f16709c1d788ab1ec2336f 100644 (file)
@@ -33,7 +33,6 @@ config DRM_IMX_TVE
 config DRM_IMX_LDB
        tristate "Support for LVDS displays"
        depends on DRM_IMX
-       select OF_VIDEOMODE
        help
          Choose this to enable the internal LVDS Display Bridge (LDB)
          found on i.MX53 and i.MX6 processors.
index c191ae20356583a48aaba72526a64c92261c073b..41e88abe47af1f518ddf7f0ac955d8ca0812203e 100644 (file)
@@ -1120,8 +1120,11 @@ static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
           or DYN_EXTERNAL, then mem granularity information is present
           within the section name - only process if there are at least three
           tokens within the section name (just a minor optimization) */
-       if (count >= 3)
-               strict_strtol(sz_last_token, 10, (long *)&req);
+       if (count >= 3) {
+               status = kstrtos32(sz_last_token, 10, &req);
+               if (status)
+                       goto func_cont;
+       }
 
        if ((req == 0) || (req == 1)) {
                if (strcmp(sz_sec_last_token, "DYN_DARAM") == 0) {
index 82c7202fd5cc963668dc8e74caf7dfce11e8f66a..e77fb6ea40c905f3cb72571ef3ca424b44b37440 100644 (file)
@@ -527,8 +527,11 @@ static void zram_reset_device(struct zram *zram)
        size_t index;
        struct zram_meta *meta;
 
-       if (!zram->init_done)
+       down_write(&zram->init_lock);
+       if (!zram->init_done) {
+               up_write(&zram->init_lock);
                return;
+       }
 
        meta = zram->meta;
        zram->init_done = 0;
@@ -549,6 +552,7 @@ static void zram_reset_device(struct zram *zram)
 
        zram->disksize = 0;
        set_capacity(zram->disk, 0);
+       up_write(&zram->init_lock);
 }
 
 static void zram_init_device(struct zram *zram, struct zram_meta *meta)
index 5de56f671a9dd207faa954cf1868e7ef21284747..f36950e4134f55deb02e3a6eb172e9481828ea18 100644 (file)
@@ -54,6 +54,8 @@ MODULE_PARM_DESC(notify_delay_ms,
 * is some wrong values returned by cpuid for number of thresholds.
 */
 #define MAX_NUMBER_OF_TRIPS    2
+/* Limit number of package temp zones */
+#define MAX_PKG_TEMP_ZONE_IDS  256
 
 struct phy_dev_entry {
        struct list_head list;
@@ -394,12 +396,16 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
        char buffer[30];
        int thres_count;
        u32 eax, ebx, ecx, edx;
+       u8 *temp;
 
        cpuid(6, &eax, &ebx, &ecx, &edx);
        thres_count = ebx & 0x07;
        if (!thres_count)
                return -ENODEV;
 
+       if (topology_physical_package_id(cpu) > MAX_PKG_TEMP_ZONE_IDS)
+               return -ENODEV;
+
        thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS);
 
        err = get_tj_max(cpu, &tj_max);
@@ -417,13 +423,14 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
        spin_lock(&pkg_work_lock);
        if (topology_physical_package_id(cpu) > max_phy_id)
                max_phy_id = topology_physical_package_id(cpu);
-       pkg_work_scheduled = krealloc(pkg_work_scheduled,
-                               (max_phy_id+1) * sizeof(u8), GFP_ATOMIC);
-       if (!pkg_work_scheduled) {
+       temp = krealloc(pkg_work_scheduled,
+                       (max_phy_id+1) * sizeof(u8), GFP_ATOMIC);
+       if (!temp) {
                spin_unlock(&pkg_work_lock);
                err = -ENOMEM;
                goto err_ret_free;
        }
+       pkg_work_scheduled = temp;
        pkg_work_scheduled[topology_physical_package_id(cpu)] = 0;
        spin_unlock(&pkg_work_lock);
 
@@ -511,7 +518,7 @@ static int get_core_online(unsigned int cpu)
 
        /* Check if there is already an instance for this package */
        if (!phdev) {
-               if (!cpu_has(c, X86_FEATURE_DTHERM) &&
+               if (!cpu_has(c, X86_FEATURE_DTHERM) ||
                                        !cpu_has(c, X86_FEATURE_PTS))
                        return -ENODEV;
                if (pkg_temp_thermal_device_add(cpu))
@@ -562,7 +569,7 @@ static struct notifier_block pkg_temp_thermal_notifier __refdata = {
 };
 
 static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = {
-       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM },
+       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_PTS },
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids);
@@ -592,7 +599,6 @@ static int __init pkg_temp_thermal_init(void)
        return 0;
 
 err_ret:
-       get_online_cpus();
        for_each_online_cpu(i)
                put_core_offline(i);
        put_online_cpus();
index 721904f8efa92b8816665410822b355619679f47..946ddd2b3a541990277aabad488843a429e3e6f5 100644 (file)
@@ -193,7 +193,8 @@ static int __init parse_options(struct early_serial8250_device *device,
        if (options) {
                options++;
                device->baud = simple_strtoul(options, NULL, 0);
-               length = min(strcspn(options, " "), sizeof(device->options));
+               length = min(strcspn(options, " ") + 1,
+                            sizeof(device->options));
                strlcpy(device->options, options, length);
        } else {
                device->baud = probe_baud(port);
index bb91b4713ebdb8c7ba8849cba643d046c5bc9973..2e3ea1a70d7b90768f33f26a39f098eed7df2c12 100644 (file)
@@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev)
        int err;
 
 #ifdef CONFIG_64BIT
-       extern int iosapic_serial_irq(int cellnum);
        if (!dev->irq && (dev->id.sversion == 0xad))
-               dev->irq = iosapic_serial_irq(dev->mod_index-1);
+               dev->irq = iosapic_serial_irq(dev);
 #endif
 
        if (!dev->irq) {
index 5e3d68917ffed2529c3cd0181d40d7ae95f8ebcd..1456673bcca09b58cc4d1e7c27fd31569b8439bf 100644 (file)
@@ -277,7 +277,7 @@ config SERIAL_TEGRA
        select SERIAL_CORE
        help
          Support for the on-chip UARTs on the NVIDIA Tegra series SOCs
-         providing /dev/ttyHS0, 1, 2, 3 and 4 (note, some machines may not
+         providing /dev/ttyTHS0, 1, 2, 3 and 4 (note, some machines may not
          provide all of these ports, depending on how the serial port
          are enabled). This driver uses the APB DMA to achieve higher baudrate
          and better performance.
index cbf1d155b7b2a8c80ef782443edbf77c0e7f5595..22f280aa4f2c521b5829a6ea5e72b8c05f2265d9 100644 (file)
@@ -773,6 +773,6 @@ module_init(arc_serial_init);
 module_exit(arc_serial_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("plat-arcfpga/uart");
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("Vineet Gupta");
 MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver");
index 4f5f161896a139852e46f93f30239be979838bda..f85b8e6d0346fc472fbc835b0451a706ce46aab3 100644 (file)
@@ -678,11 +678,18 @@ static void mxs_auart_settermios(struct uart_port *u,
 
 static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
 {
-       u32 istatus, istat;
+       u32 istat;
        struct mxs_auart_port *s = context;
        u32 stat = readl(s->port.membase + AUART_STAT);
 
-       istatus = istat = readl(s->port.membase + AUART_INTR);
+       istat = readl(s->port.membase + AUART_INTR);
+
+       /* ack irq */
+       writel(istat & (AUART_INTR_RTIS
+               | AUART_INTR_TXIS
+               | AUART_INTR_RXIS
+               | AUART_INTR_CTSMIS),
+                       s->port.membase + AUART_INTR_CLR);
 
        if (istat & AUART_INTR_CTSMIS) {
                uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
@@ -702,12 +709,6 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
                istat &= ~AUART_INTR_TXIS;
        }
 
-       writel(istatus & (AUART_INTR_RTIS
-               | AUART_INTR_TXIS
-               | AUART_INTR_RXIS
-               | AUART_INTR_CTSMIS),
-                       s->port.membase + AUART_INTR_CLR);
-
        return IRQ_HANDLED;
 }
 
@@ -850,7 +851,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
        struct mxs_auart_port *s;
        struct uart_port *port;
        unsigned int old_ctrl0, old_ctrl2;
-       unsigned int to = 1000;
+       unsigned int to = 20000;
 
        if (co->index >= MXS_AUART_PORTS || co->index < 0)
                return;
@@ -871,18 +872,23 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
 
        uart_console_write(port, str, count, mxs_auart_console_putchar);
 
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore the TCR
-        */
+       /* Finally, wait for transmitter to become empty ... */
        while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
+               udelay(1);
                if (!to--)
                        break;
-               udelay(1);
        }
 
-       writel(old_ctrl0, port->membase + AUART_CTRL0);
-       writel(old_ctrl2, port->membase + AUART_CTRL2);
+       /*
+        * ... and restore the TCR if we waited long enough for the transmitter
+        * to be idle. This might keep the transmitter enabled although it is
+        * unused, but that is better than to disable it while it is still
+        * transmitting.
+        */
+       if (!(readl(port->membase + AUART_STAT) & AUART_STAT_BUSY)) {
+               writel(old_ctrl0, port->membase + AUART_CTRL0);
+               writel(old_ctrl2, port->membase + AUART_CTRL2);
+       }
 
        clk_disable(s->clk);
 }
index ff171384ea5256cabcf018c3a3dc839279f71392..dc6e96996ead4796eace1ba3bb4b61232f132302 100644 (file)
@@ -3478,7 +3478,7 @@ static int alloc_buf_list(SLMP_INFO *info)
        for ( i = 0; i < info->rx_buf_count; i++ ) {
                /* calculate and store physical address of this buffer entry */
                info->rx_buf_list_ex[i].phys_entry =
-                       info->buffer_list_phys + (i * sizeof(SCABUFSIZE));
+                       info->buffer_list_phys + (i * SCABUFSIZE);
 
                /* calculate and store physical address of */
                /* next entry in cirular list of entries */
index 121aeb9393e1172e75fe5972a7c4b8ab4640557f..f597e88a705d1fa8e65cf36ae98a61f84f20b9a3 100644 (file)
@@ -256,10 +256,9 @@ void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
 {
        struct tty_struct *tty = tty_port_tty_get(port);
 
-       if (tty && (!check_clocal || !C_CLOCAL(tty))) {
+       if (tty && (!check_clocal || !C_CLOCAL(tty)))
                tty_hangup(tty);
-               tty_kref_put(tty);
-       }
+       tty_kref_put(tty);
 }
 EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
 
index eb2aa2e5a842f48eae096d29e279572982e215b8..d1bd8ef1f9c1d48b7e0566220149deaf0de10da4 100644 (file)
@@ -12,7 +12,7 @@ if USB_CHIPIDEA
 
 config USB_CHIPIDEA_UDC
        bool "ChipIdea device controller"
-       depends on USB_GADGET=y || USB_CHIPIDEA=m
+       depends on USB_GADGET=y || (USB_CHIPIDEA=m && USB_GADGET=m)
        help
          Say Y here to enable device controller functionality of the
          ChipIdea driver.
@@ -20,7 +20,7 @@ config USB_CHIPIDEA_UDC
 config USB_CHIPIDEA_HOST
        bool "ChipIdea host controller"
        depends on USB=y
-       depends on USB_EHCI_HCD=y || USB_CHIPIDEA=m
+       depends on USB_EHCI_HCD=y || (USB_CHIPIDEA=m && USB_EHCI_HCD=m)
        select USB_EHCI_ROOT_HUB_TT
        help
          Say Y here to enable host controller functionality of the
index aefa0261220c048322a62059ddc35f9df047e7bb..1b23e354f9fb371f5851206b58944b0221109600 100644 (file)
@@ -50,7 +50,7 @@
 #define PORTSC_PTC            (0x0FUL << 16)
 /* PTS and PTW for non lpm version only */
 #define PORTSC_PTS(d)                                          \
-       ((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
+       (u32)((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
 #define PORTSC_PTW            BIT(28)
 #define PORTSC_STS            BIT(29)
 
@@ -59,7 +59,7 @@
 #define DEVLC_PSPD_HS         (0x02UL << 25)
 #define DEVLC_PTW             BIT(27)
 #define DEVLC_STS             BIT(28)
-#define DEVLC_PTS(d)          (((d) & 0x7) << 29)
+#define DEVLC_PTS(d)          (u32)(((d) & 0x7) << 29)
 
 /* Encoding for DEVLC_PTS and PORTSC_PTS */
 #define PTS_UTMI              0
index 4191db32f12c2ccf4901287c6ccb1a357c9b552a..4a8a1d68002c0fa1695078c6566c616bf764fa35 100644 (file)
@@ -668,6 +668,15 @@ resubmit:
 static inline int
 hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
 {
+       /* Need to clear both directions for control ep */
+       if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) ==
+                       USB_ENDPOINT_XFER_CONTROL) {
+               int status = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+                               HUB_CLEAR_TT_BUFFER, USB_RT_PORT,
+                               devinfo ^ 0x8000, tt, NULL, 0, 1000);
+               if (status)
+                       return status;
+       }
        return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
                               HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
                               tt, NULL, 0, 1000);
@@ -2848,6 +2857,15 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
                                USB_CTRL_SET_TIMEOUT);
 }
 
+/* Count of wakeup-enabled devices at or below udev */
+static unsigned wakeup_enabled_descendants(struct usb_device *udev)
+{
+       struct usb_hub *hub = usb_hub_to_struct_hub(udev);
+
+       return udev->do_remote_wakeup +
+                       (hub ? hub->wakeup_enabled_descendants : 0);
+}
+
 /*
  * usb_port_suspend - suspend a usb device's upstream port
  * @udev: device that's no longer in active use, not a root hub
@@ -2888,8 +2906,8 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
  * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
  * timer, no SRP, no requests through sysfs.
  *
- * If Runtime PM isn't enabled or used, non-SuperSpeed devices really get
- * suspended only when their bus goes into global suspend (i.e., the root
+ * If Runtime PM isn't enabled or used, non-SuperSpeed devices may not get
+ * suspended until their bus goes into global suspend (i.e., the root
  * hub is suspended).  Nevertheless, we change @udev->state to
  * USB_STATE_SUSPENDED as this is the device's "logical" state.  The actual
  * upstream port setting is stored in @udev->port_is_suspended.
@@ -2960,15 +2978,21 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
        /* see 7.1.7.6 */
        if (hub_is_superspeed(hub->hdev))
                status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
-       else if (PMSG_IS_AUTO(msg))
-               status = set_port_feature(hub->hdev, port1,
-                                               USB_PORT_FEAT_SUSPEND);
+
        /*
         * For system suspend, we do not need to enable the suspend feature
         * on individual USB-2 ports.  The devices will automatically go
         * into suspend a few ms after the root hub stops sending packets.
         * The USB 2.0 spec calls this "global suspend".
+        *
+        * However, many USB hubs have a bug: They don't relay wakeup requests
+        * from a downstream port if the port's suspend feature isn't on.
+        * Therefore we will turn on the suspend feature if udev or any of its
+        * descendants is enabled for remote wakeup.
         */
+       else if (PMSG_IS_AUTO(msg) || wakeup_enabled_descendants(udev) > 0)
+               status = set_port_feature(hub->hdev, port1,
+                               USB_PORT_FEAT_SUSPEND);
        else {
                really_suspend = false;
                status = 0;
@@ -3003,15 +3027,16 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
                if (!PMSG_IS_AUTO(msg))
                        status = 0;
        } else {
-               /* device has up to 10 msec to fully suspend */
                dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
                                (PMSG_IS_AUTO(msg) ? "auto-" : ""),
                                udev->do_remote_wakeup);
-               usb_set_device_state(udev, USB_STATE_SUSPENDED);
                if (really_suspend) {
                        udev->port_is_suspended = 1;
+
+                       /* device has up to 10 msec to fully suspend */
                        msleep(10);
                }
+               usb_set_device_state(udev, USB_STATE_SUSPENDED);
        }
 
        /*
@@ -3293,7 +3318,11 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
        unsigned                port1;
        int                     status;
 
-       /* Warn if children aren't already suspended */
+       /*
+        * Warn if children aren't already suspended.
+        * Also, add up the number of wakeup-enabled descendants.
+        */
+       hub->wakeup_enabled_descendants = 0;
        for (port1 = 1; port1 <= hdev->maxchild; port1++) {
                struct usb_device       *udev;
 
@@ -3303,6 +3332,9 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
                        if (PMSG_IS_AUTO(msg))
                                return -EBUSY;
                }
+               if (udev)
+                       hub->wakeup_enabled_descendants +=
+                                       wakeup_enabled_descendants(udev);
        }
 
        if (hdev->do_remote_wakeup && hub->quirk_check_port_auto_suspend) {
index 6508e02b3dac91718c31dda7e90b6984fed0c898..4e4790dea3439fc10a57b9fac30f73d77245fdf8 100644 (file)
@@ -59,6 +59,9 @@ struct usb_hub {
        struct usb_tt           tt;             /* Transaction Translator */
 
        unsigned                mA_per_port;    /* current for each child */
+#ifdef CONFIG_PM
+       unsigned                wakeup_enabled_descendants;
+#endif
 
        unsigned                limited_power:1;
        unsigned                quiescing:1;
index 757aa18027d05ca0eb198d97d92f1710e8e58def..2378958ea63e01426edbda87183674256a4334ff 100644 (file)
@@ -1,6 +1,6 @@
 config USB_DWC3
        tristate "DesignWare USB3 DRD Core Support"
-       depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
+       depends on (USB || USB_GADGET) && GENERIC_HARDIRQS && HAS_DMA
        select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
        help
          Say Y or M here if your system has a Dual Role SuperSpeed
index c35d49d39b7615f83e7e71a9f009643e33c8d760..358375e0b291098d8be40d65bdfbbff7f97f0826 100644 (file)
@@ -450,7 +450,7 @@ static int dwc3_probe(struct platform_device *pdev)
        }
 
        if (IS_ERR(dwc->usb3_phy)) {
-               ret = PTR_ERR(dwc->usb2_phy);
+               ret = PTR_ERR(dwc->usb3_phy);
 
                /*
                 * if -ENXIO is returned, it means PHY layer wasn't
index b69d322e3cab51c4bcdb784d8f0e3eeda66028e2..27dad993b00706ef5a14a257c40bd353ca6ee560 100644 (file)
@@ -759,8 +759,8 @@ struct dwc3 {
 
 struct dwc3_event_type {
        u32     is_devspec:1;
-       u32     type:6;
-       u32     reserved8_31:25;
+       u32     type:7;
+       u32     reserved8_31:24;
 } __packed;
 
 #define DWC3_DEPEVT_XFERCOMPLETE       0x01
index b5e5b35df49c8ff49ca5817ced0838e79dad9ccf..f77083fedc68d0d1bfc7afb579e6aae96edb1d63 100644 (file)
@@ -1584,6 +1584,7 @@ err1:
        __dwc3_gadget_ep_disable(dwc->eps[0]);
 
 err0:
+       dwc->gadget_driver = NULL;
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return ret;
index 62f6802f6e0fd98bec3aa03abe3d0fff4a1ee191..8e9368330b103a60cc7fb53be21991315c489fd8 100644 (file)
@@ -193,6 +193,7 @@ config USB_FUSB300
           Faraday usb device controller FUSB300 driver
 
 config USB_FOTG210_UDC
+       depends on HAS_DMA
        tristate "Faraday FOTG210 USB Peripheral Controller"
        help
           Faraday USB2.0 OTG controller which can be configured as
@@ -328,13 +329,14 @@ config USB_S3C_HSUDC
 
 config USB_MV_UDC
        tristate "Marvell USB2.0 Device Controller"
-       depends on GENERIC_HARDIRQS
+       depends on GENERIC_HARDIRQS && HAS_DMA
        help
          Marvell Socs (including PXA and MMP series) include a high speed
          USB2.0 OTG controller, which can be configured as high speed or
          full speed USB peripheral.
 
 config USB_MV_U3D
+       depends on HAS_DMA
        tristate "MARVELL PXA2128 USB 3.0 controller"
        help
          MARVELL PXA2128 Processor series include a super speed USB3.0 device
@@ -639,6 +641,7 @@ config USB_CONFIGFS_RNDIS
        depends on USB_CONFIGFS
        depends on NET
        select USB_U_ETHER
+       select USB_U_RNDIS
        select USB_F_RNDIS
        help
           Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
index 073b938f913546793d24443a89dc928982eecaaa..d9a6add0c8526e06778addb733ce3e53da78a291 100644 (file)
@@ -870,8 +870,8 @@ static void clk_on(struct at91_udc *udc)
        if (udc->clocked)
                return;
        udc->clocked = 1;
-       clk_enable(udc->iclk);
-       clk_enable(udc->fclk);
+       clk_prepare_enable(udc->iclk);
+       clk_prepare_enable(udc->fclk);
 }
 
 static void clk_off(struct at91_udc *udc)
@@ -880,8 +880,8 @@ static void clk_off(struct at91_udc *udc)
                return;
        udc->clocked = 0;
        udc->gadget.speed = USB_SPEED_UNKNOWN;
-       clk_disable(udc->fclk);
-       clk_disable(udc->iclk);
+       clk_disable_unprepare(udc->fclk);
+       clk_disable_unprepare(udc->iclk);
 }
 
 /*
@@ -1725,7 +1725,7 @@ static int at91udc_probe(struct platform_device *pdev)
        /* init software state */
        udc = &controller;
        udc->gadget.dev.parent = dev;
-       if (pdev->dev.of_node)
+       if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
                at91udc_of_init(udc, pdev->dev.of_node);
        else
                memcpy(&udc->board, dev->platform_data,
@@ -1782,12 +1782,14 @@ static int at91udc_probe(struct platform_device *pdev)
        }
 
        /* don't do anything until we have both gadget driver and VBUS */
-       clk_enable(udc->iclk);
+       retval = clk_prepare_enable(udc->iclk);
+       if (retval)
+               goto fail1;
        at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
        at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
        /* Clear all pending interrupts - UDP may be used by bootloader. */
        at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
-       clk_disable(udc->iclk);
+       clk_disable_unprepare(udc->iclk);
 
        /* request UDC and maybe VBUS irqs */
        udc->udp_irq = platform_get_irq(pdev, 0);
index f48712ffe261470487f7be0476ad7d89d8a808cf..c1c113ef950c86d9c4170cebaa47a91426cf74fa 100644 (file)
@@ -449,14 +449,20 @@ fail:
 
 static int __exit eth_unbind(struct usb_composite_dev *cdev)
 {
-       if (has_rndis())
+       if (has_rndis()) {
+               usb_put_function(f_rndis);
                usb_put_function_instance(fi_rndis);
-       if (use_eem)
+       }
+       if (use_eem) {
+               usb_put_function(f_eem);
                usb_put_function_instance(fi_eem);
-       else if (can_support_ecm(cdev->gadget))
+       } else if (can_support_ecm(cdev->gadget)) {
+               usb_put_function(f_ecm);
                usb_put_function_instance(fi_ecm);
-       else
+       } else {
+               usb_put_function(f_geth);
                usb_put_function_instance(fi_geth);
+       }
        return 0;
 }
 
index 5d3561ea1c1595ea30f07bc3ad35253647701d97..edab45da37417e16960b75033a46a8453475b77b 100644 (file)
@@ -959,8 +959,11 @@ static struct usb_function_instance *ecm_alloc_inst(void)
        mutex_init(&opts->lock);
        opts->func_inst.free_func_inst = ecm_free_inst;
        opts->net = gether_setup_default();
-       if (IS_ERR(opts->net))
-               return ERR_PTR(PTR_ERR(opts->net));
+       if (IS_ERR(opts->net)) {
+               struct net_device *net = opts->net;
+               kfree(opts);
+               return ERR_CAST(net);
+       }
 
        config_group_init_type_name(&opts->func_inst.group, "", &ecm_func_type);
 
index 90ee8022e8d80c29fbff9a1298d62c13ec869b42..d00392d879db3aa3e75d093d4e26041fa42bcb54 100644 (file)
@@ -593,8 +593,11 @@ static struct usb_function_instance *eem_alloc_inst(void)
        mutex_init(&opts->lock);
        opts->func_inst.free_func_inst = eem_free_inst;
        opts->net = gether_setup_default();
-       if (IS_ERR(opts->net))
-               return ERR_CAST(opts->net);
+       if (IS_ERR(opts->net)) {
+               struct net_device *net = opts->net;
+               kfree(opts);
+               return ERR_CAST(net);
+       }
 
        config_group_init_type_name(&opts->func_inst.group, "", &eem_func_type);
 
index 952177f7eb9b40e8045bfa85730239ab22efd97c..1c28fe13328a13935a3976ecc409cba113a81221 100644 (file)
@@ -1350,8 +1350,11 @@ static struct usb_function_instance *ncm_alloc_inst(void)
        mutex_init(&opts->lock);
        opts->func_inst.free_func_inst = ncm_free_inst;
        opts->net = gether_setup_default();
-       if (IS_ERR(opts->net))
-               return ERR_PTR(PTR_ERR(opts->net));
+       if (IS_ERR(opts->net)) {
+               struct net_device *net = opts->net;
+               kfree(opts);
+               return ERR_CAST(net);
+       }
 
        config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type);
 
index 7944fb0efe3b6a67471e7379a03a5d8ebc9b23fb..eb3aa817a662616810a4c9d9c6232c1e8f2a2e2f 100644 (file)
@@ -488,7 +488,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_ep *ep;
        int status, i;
 
-#ifndef USBF_PHONET_INCLUDED
        struct f_phonet_opts *phonet_opts;
 
        phonet_opts = container_of(f->fi, struct f_phonet_opts, func_inst);
@@ -507,7 +506,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
                        return status;
                phonet_opts->bound = true;
        }
-#endif
 
        /* Reserve interface IDs */
        status = usb_interface_id(c, f);
@@ -656,8 +654,11 @@ static struct usb_function_instance *phonet_alloc_inst(void)
 
        opts->func_inst.free_func_inst = phonet_free_inst;
        opts->net = gphonet_setup_default();
-       if (IS_ERR(opts->net))
-               return ERR_PTR(PTR_ERR(opts->net));
+       if (IS_ERR(opts->net)) {
+               struct net_device *net = opts->net;
+               kfree(opts);
+               return ERR_CAST(net);
+       }
 
        config_group_init_type_name(&opts->func_inst.group, "",
                        &phonet_func_type);
index 191df35ae69d04e31c6fc70ac7d76f2b4ff83be3..717ed7f956395412bf5d6da1d605921c71b82532 100644 (file)
@@ -963,8 +963,11 @@ static struct usb_function_instance *rndis_alloc_inst(void)
        mutex_init(&opts->lock);
        opts->func_inst.free_func_inst = rndis_free_inst;
        opts->net = gether_setup_default();
-       if (IS_ERR(opts->net))
-               return ERR_CAST(opts->net);
+       if (IS_ERR(opts->net)) {
+               struct net_device *net = opts->net;
+               kfree(opts);
+               return ERR_CAST(net);
+       }
 
        config_group_init_type_name(&opts->func_inst.group, "",
                                    &rndis_func_type);
index 5601e1d96c4fabd7f8a44bc80703080495fba56a..7c8674fa7e8094074aa794fe9407e2adeab7548a 100644 (file)
@@ -505,8 +505,11 @@ static struct usb_function_instance *geth_alloc_inst(void)
        mutex_init(&opts->lock);
        opts->func_inst.free_func_inst = geth_free_inst;
        opts->net = gether_setup_default();
-       if (IS_ERR(opts->net))
-               return ERR_CAST(opts->net);
+       if (IS_ERR(opts->net)) {
+               struct net_device *net = opts->net;
+               kfree(opts);
+               return ERR_CAST(net);
+       }
 
        config_group_init_type_name(&opts->func_inst.group, "",
                                    &gether_func_type);
index cce5535b1dc6744f86a2a3c88d35c756ef4335cd..10cd18ddd0d40207f2d33bd94e41dff040c842f2 100644 (file)
@@ -1074,7 +1074,7 @@ static struct usb_gadget_ops fotg210_gadget_ops = {
        .udc_stop               = fotg210_udc_stop,
 };
 
-static int __exit fotg210_udc_remove(struct platform_device *pdev)
+static int fotg210_udc_remove(struct platform_device *pdev)
 {
        struct fotg210_udc *fotg210 = dev_get_drvdata(&pdev->dev);
 
@@ -1088,7 +1088,7 @@ static int __exit fotg210_udc_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __init fotg210_udc_probe(struct platform_device *pdev)
+static int fotg210_udc_probe(struct platform_device *pdev)
 {
        struct resource *res, *ires;
        struct fotg210_udc *fotg210 = NULL;
index 032b96a51ce4e06a517f35070542067a002275e2..2a1ebefd8f9eb31318fc861fbc010214148db18d 100644 (file)
@@ -160,10 +160,8 @@ static __init int rndis_do_config(struct usb_configuration *c)
                return ret;
 
        f_acm_rndis = usb_get_function(fi_acm);
-       if (IS_ERR(f_acm_rndis)) {
-               ret = PTR_ERR(f_acm_rndis);
-               goto err_func_acm;
-       }
+       if (IS_ERR(f_acm_rndis))
+               return PTR_ERR(f_acm_rndis);
 
        ret = usb_add_function(c, f_acm_rndis);
        if (ret)
@@ -178,7 +176,6 @@ err_fsg:
        usb_remove_function(c, f_acm_rndis);
 err_conf:
        usb_put_function(f_acm_rndis);
-err_func_acm:
        return ret;
 }
 
@@ -226,7 +223,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
        /* implicit port_num is zero */
        f_acm_multi = usb_get_function(fi_acm);
        if (IS_ERR(f_acm_multi))
-               goto err_func_acm;
+               return PTR_ERR(f_acm_multi);
 
        ret = usb_add_function(c, f_acm_multi);
        if (ret)
@@ -241,7 +238,6 @@ err_fsg:
        usb_remove_function(c, f_acm_multi);
 err_conf:
        usb_put_function(f_acm_multi);
-err_func_acm:
        return ret;
 }
 
index 07fdb3eaf48a4fd1be386e346e6e9fccc53e78ce..ec6a2d2903988ffb7a23aa12b63b0f95fd4f601a 100644 (file)
@@ -1776,7 +1776,7 @@ static int mv_u3d_remove(struct platform_device *dev)
        kfree(u3d->eps);
 
        if (u3d->irq)
-               free_irq(u3d->irq, &dev->dev);
+               free_irq(u3d->irq, u3d);
 
        if (u3d->cap_regs)
                iounmap(u3d->cap_regs);
@@ -1974,7 +1974,7 @@ static int mv_u3d_probe(struct platform_device *dev)
        return 0;
 
 err_unregister:
-       free_irq(u3d->irq, &dev->dev);
+       free_irq(u3d->irq, u3d);
 err_request_irq:
 err_get_irq:
        kfree(u3d->status_req);
index ffd8fa5411015f823bc5701777e20cd928848f56..13e25f80fc201f347784ace2f35c7003850f381a 100644 (file)
@@ -50,6 +50,8 @@ static DEFINE_MUTEX(udc_lock);
 
 /* ------------------------------------------------------------------------- */
 
+#ifdef CONFIG_HAS_DMA
+
 int usb_gadget_map_request(struct usb_gadget *gadget,
                struct usb_request *req, int is_in)
 {
@@ -99,13 +101,15 @@ void usb_gadget_unmap_request(struct usb_gadget *gadget,
 }
 EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
 
+#endif /* CONFIG_HAS_DMA */
+
 /* ------------------------------------------------------------------------- */
 
 void usb_gadget_set_state(struct usb_gadget *gadget,
                enum usb_device_state state)
 {
        gadget->state = state;
-       sysfs_notify(&gadget->dev.kobj, NULL, "status");
+       sysfs_notify(&gadget->dev.kobj, NULL, "state");
 }
 EXPORT_SYMBOL_GPL(usb_gadget_set_state);
 
@@ -194,9 +198,11 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
        dev_set_name(&gadget->dev, "gadget");
        gadget->dev.parent = parent;
 
+#ifdef CONFIG_HAS_DMA
        dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
        gadget->dev.dma_parms = parent->dma_parms;
        gadget->dev.dma_mask = parent->dma_mask;
+#endif
 
        if (release)
                gadget->dev.release = release;
index 2b702772d04d3353cc570c340f04c9701fa11210..6dce37555c4f6303b5efa657af88096db2b2140e 100644 (file)
@@ -874,6 +874,7 @@ static int ehci_hub_control (
                                ehci->reset_done[wIndex] = jiffies
                                                + msecs_to_jiffies(20);
                                usb_hcd_start_port_resume(&hcd->self, wIndex);
+                               set_bit(wIndex, &ehci->resuming_ports);
                                /* check the port again */
                                mod_timer(&ehci_to_hcd(ehci)->rh_timer,
                                                ehci->reset_done[wIndex]);
index 4b8a2092432f8911b5d73053e34b135041fd0e4d..978c849f9c9a1ef9631d86fa80ccea93371f61ea 100644 (file)
@@ -13,6 +13,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 void sb800_prefetch(struct device *dev, int on);
 #else
+struct pci_dev;
 static inline void usb_amd_quirk_pll_disable(void) {}
 static inline void usb_amd_quirk_pll_enable(void) {}
 static inline void usb_amd_dev_put(void) {}
index cc24e39b97d5b8b2bdf7faada7f7767b4f8013c2..f00cb203faea569b2e87e79e8371455a7abd77b4 100644 (file)
@@ -93,7 +93,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        }
        if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
                        pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
-               xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
                xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
                xhci->limit_active_eps = 64;
                xhci->quirks |= XHCI_SW_BW_CHECKING;
index 1e57eafa69101aaee797b7890020c66865ef4c16..5b08cd85f8e7fe9646228da946166dfb188c10d2 100644 (file)
@@ -434,7 +434,7 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
 
        /* A ring has pending URBs if its TD list is not empty */
        if (!(ep->ep_state & EP_HAS_STREAMS)) {
-               if (!(list_empty(&ep->ring->td_list)))
+               if (ep->ring && !(list_empty(&ep->ring->td_list)))
                        xhci_ring_ep_doorbell(xhci, slot_id, ep_index, 0);
                return;
        }
index 2c49f00260ca2ad9cd0e79bb3078dbd25bb864d6..41eb4fc33453525422b95218b6d51b34aaa617b5 100644 (file)
@@ -329,7 +329,7 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
        return;
 }
 
-static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci)
 {
        int i;
 
@@ -1181,9 +1181,6 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
        }
 
        xhci = hcd_to_xhci(hcd);
-       if (xhci->xhc_state & XHCI_STATE_HALTED)
-               return -ENODEV;
-
        if (check_virt_dev) {
                if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
                        printk(KERN_DEBUG "xHCI %s called with unaddressed "
@@ -1199,6 +1196,9 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
                }
        }
 
+       if (xhci->xhc_state & XHCI_STATE_HALTED)
+               return -ENODEV;
+
        return 1;
 }
 
@@ -3898,7 +3898,7 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
  * Issue an Evaluate Context command to change the Maximum Exit Latency in the
  * slot context.  If that succeeds, store the new MEL in the xhci_virt_device.
  */
-static int xhci_change_max_exit_latency(struct xhci_hcd *xhci,
+static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
                        struct usb_device *udev, u16 max_exit_latency)
 {
        struct xhci_virt_device *virt_dev;
@@ -4892,6 +4892,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 
        get_quirks(dev, xhci);
 
+       /* In xhci controllers which follow xhci 1.0 spec gives a spurious
+        * success event after a short transfer. This quirk will ignore such
+        * spurious event.
+        */
+       if (xhci->hci_version > 0x96)
+               xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
+
        /* Make sure the HC is halted. */
        retval = xhci_halt(xhci);
        if (retval)
index c21386ec5d35d142b7d0d84abe2e3f3cb5be7125..de98906f786d08ebac625b3cc8213de5d79cf68e 100644 (file)
@@ -3247,6 +3247,7 @@ static const struct usb_device_id sisusb_table[] = {
        { USB_DEVICE(0x0711, 0x0903) },
        { USB_DEVICE(0x0711, 0x0918) },
        { USB_DEVICE(0x0711, 0x0920) },
+       { USB_DEVICE(0x0711, 0x0950) },
        { USB_DEVICE(0x182d, 0x021c) },
        { USB_DEVICE(0x182d, 0x0269) },
        { }
index 6708a3b78ad8b3d06130dabefe2c2e11e78fa106..f44e8b5e00c94b3b22ddf06b632041e0c462b060 100644 (file)
@@ -481,7 +481,7 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32);
 
 static int omap2430_probe(struct platform_device *pdev)
 {
-       struct resource                 musb_resources[2];
+       struct resource                 musb_resources[3];
        struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
        struct omap_musb_board_data     *data;
        struct platform_device          *musb;
@@ -581,6 +581,11 @@ static int omap2430_probe(struct platform_device *pdev)
        musb_resources[1].end = pdev->resource[1].end;
        musb_resources[1].flags = pdev->resource[1].flags;
 
+       musb_resources[2].name = pdev->resource[2].name;
+       musb_resources[2].start = pdev->resource[2].start;
+       musb_resources[2].end = pdev->resource[2].end;
+       musb_resources[2].flags = pdev->resource[2].flags;
+
        ret = platform_device_add_resources(musb, musb_resources,
                        ARRAY_SIZE(musb_resources));
        if (ret) {
index 2c06a8969a9f793153d6f6f0546be9d5eb1ff8a0..6f8a9ca96ae753f31b637d0f0c08c1d27a550699 100644 (file)
@@ -1156,7 +1156,7 @@ static u64 tusb_dmamask = DMA_BIT_MASK(32);
 
 static int tusb_probe(struct platform_device *pdev)
 {
-       struct resource musb_resources[2];
+       struct resource musb_resources[3];
        struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
        struct platform_device          *musb;
        struct tusb6010_glue            *glue;
@@ -1199,6 +1199,11 @@ static int tusb_probe(struct platform_device *pdev)
        musb_resources[1].end = pdev->resource[1].end;
        musb_resources[1].flags = pdev->resource[1].flags;
 
+       musb_resources[2].name = pdev->resource[2].name;
+       musb_resources[2].start = pdev->resource[2].start;
+       musb_resources[2].end = pdev->resource[2].end;
+       musb_resources[2].flags = pdev->resource[2].flags;
+
        ret = platform_device_add_resources(musb, musb_resources,
                        ARRAY_SIZE(musb_resources));
        if (ret) {
index efe6e1464f45b59fb831a9ca5c05361593b3b7a5..a2fb30bbb971c41f76fc8ad1eb358449f0117657 100644 (file)
@@ -71,9 +71,9 @@ static struct usb_dpll_params omap_usb3_dpll_params[NUM_SYS_CLKS] = {
        {1250, 5, 4, 20, 0},            /* 12 MHz */
        {3125, 20, 4, 20, 0},           /* 16.8 MHz */
        {1172, 8, 4, 20, 65537},        /* 19.2 MHz */
+       {1000, 7, 4, 10, 0},            /* 20 MHz */
        {1250, 12, 4, 20, 0},           /* 26 MHz */
        {3125, 47, 4, 20, 92843},       /* 38.4 MHz */
-       {1000, 7, 4, 10, 0},            /* 20 MHz */
 
 };
 
index 1011c16ade7e4b2de81db46d0ab8ddfc599b24bc..758b86d0fcb386af39561d2d25e8ad9983c97fbf 100644 (file)
@@ -388,7 +388,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev)
                clk = devm_clk_get(dev, "otg");
 
        if (IS_ERR(clk)) {
-               dev_err(dev, "Failed to get otg clock\n");
+               dev_err(dev, "Failed to get usbhost/otg clock\n");
                return PTR_ERR(clk);
        }
 
index ed4949faa70d14502a6669a3fb35b6fb814b35c6..805940c373532bd4d548b5cf4d868ce4d75024ad 100644 (file)
@@ -855,10 +855,6 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget,
        struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
        struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
 
-       if (!driver             ||
-           !driver->unbind)
-               return -EINVAL;
-
        usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD);
        gpriv->driver = NULL;
 
index 8c3a42ea910cd1d6ef7b503bf4a753f7f521e343..7eef9b33fde66c78405509adf6ca8b461f8045c7 100644 (file)
@@ -719,6 +719,13 @@ config USB_SERIAL_FLASHLOADER
          To compile this driver as a module, choose M here: the
          module will be called flashloader.
 
+config USB_SERIAL_SUUNTO
+       tristate "USB Suunto ANT+ driver"
+       help
+         Say Y here if you want to use the Suunto ANT+ USB device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called suunto.
 
 config USB_SERIAL_DEBUG
        tristate "USB Debugging Device"
index f7130114488f8b95a4ee1c8570c61417cfcdb97b..a14a870d993fe3bc1ea60001c9f1dcb6637c620a 100644 (file)
@@ -54,6 +54,7 @@ obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI)          += siemens_mpi.o
 obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS)                += sierra.o
 obj-$(CONFIG_USB_SERIAL_SPCP8X5)               += spcp8x5.o
 obj-$(CONFIG_USB_SERIAL_SSU100)                        += ssu100.o
+obj-$(CONFIG_USB_SERIAL_SUUNTO)                        += suunto.o
 obj-$(CONFIG_USB_SERIAL_SYMBOL)                        += symbolserial.o
 obj-$(CONFIG_USB_SERIAL_WWAN)                  += usb_wwan.o
 obj-$(CONFIG_USB_SERIAL_TI)                    += ti_usb_3410_5052.o
index d6ef2f8da37dca2f7206f26db7d6269bdf0d13e6..0eae4ba3760ed87f633b0d449a833f1e5109107d 100644 (file)
@@ -53,6 +53,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
        { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
        { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
+       { USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
        { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
        { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
        { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
@@ -118,6 +119,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
        { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
        { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
+       { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
+       { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
@@ -148,6 +151,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
        { 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(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
        { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
        { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */
index 7260ec66034715e7a065d0f5fe6441f49a37f6b4..b65e657c641da56a1545be79e22a13a9fdad653c 100644 (file)
@@ -735,9 +735,34 @@ 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(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
-       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
-       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_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) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29A_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29F_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S01_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29C_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_81B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_82B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5D_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K4Y_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5G_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S05_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_60_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_61_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_64_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_65_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92D_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_W5R_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_A5R_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_PW1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
        { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
index 6dd79253205dd7ec54278ddb078f08346cdbb4f8..1b8af461b522c65a111983226ba1e704f012ac8c 100644 (file)
 /*
  * RT Systems programming cables for various ham radios
  */
-#define RTSYSTEMS_VID                  0x2100  /* Vendor ID */
-#define RTSYSTEMS_SERIAL_VX7_PID       0x9e52  /* Serial converter for VX-7 Radios using FT232RL */
-#define RTSYSTEMS_CT29B_PID            0x9e54  /* CT29B Radio Cable */
-#define RTSYSTEMS_RTS01_PID            0x9e57  /* USB-RTS01 Radio Cable */
-
+#define RTSYSTEMS_VID          0x2100  /* Vendor ID */
+#define RTSYSTEMS_USB_S03_PID  0x9001  /* RTS-03 USB to Serial Adapter */
+#define RTSYSTEMS_USB_59_PID   0x9e50  /* USB-59 USB to 8 pin plug */
+#define RTSYSTEMS_USB_57A_PID  0x9e51  /* USB-57A USB to 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_57B_PID  0x9e52  /* USB-57B USB to extended 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_29A_PID  0x9e53  /* USB-29A USB to 3.5mm stereo plug */
+#define RTSYSTEMS_USB_29B_PID  0x9e54  /* USB-29B USB to 6 pin mini din */
+#define RTSYSTEMS_USB_29F_PID  0x9e55  /* USB-29F USB to 6 pin modular plug */
+#define RTSYSTEMS_USB_62B_PID  0x9e56  /* USB-62B USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_S01_PID  0x9e57  /* USB-RTS01 USB to 3.5 mm stereo plug*/
+#define RTSYSTEMS_USB_63_PID   0x9e58  /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_29C_PID  0x9e59  /* USB-29C USB to 4 pin modular plug*/
+#define RTSYSTEMS_USB_81B_PID  0x9e5A  /* USB-81 USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_82B_PID  0x9e5B  /* USB-82 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_K5D_PID  0x9e5C  /* USB-K5D USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_K4Y_PID  0x9e5D  /* USB-K4Y USB to 2.5/3.5 mm plugs*/
+#define RTSYSTEMS_USB_K5G_PID  0x9e5E  /* USB-K5G USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_S05_PID  0x9e5F  /* USB-RTS05 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_60_PID   0x9e60  /* USB-60 USB to 6 pin din*/
+#define RTSYSTEMS_USB_61_PID   0x9e61  /* USB-61 USB to 6 pin mini din*/
+#define RTSYSTEMS_USB_62_PID   0x9e62  /* USB-62 USB to 8 pin mini din*/
+#define RTSYSTEMS_USB_63B_PID  0x9e63  /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_64_PID   0x9e64  /* USB-64 USB to 9 pin male*/
+#define RTSYSTEMS_USB_65_PID   0x9e65  /* USB-65 USB to 9 pin female null modem*/
+#define RTSYSTEMS_USB_92_PID   0x9e66  /* USB-92 USB to 12 pin plug*/
+#define RTSYSTEMS_USB_92D_PID  0x9e67  /* USB-92D USB to 12 pin plug data*/
+#define RTSYSTEMS_USB_W5R_PID  0x9e68  /* USB-W5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_A5R_PID  0x9e69  /* USB-A5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_PW1_PID  0x9e6A  /* USB-PW1 USB to 8 pin modular plug*/
 
 /*
  * Physik Instrumente
index 0a818b238508e26ab4b1932a844b740ba25c5d3c..d953d674f22295a0aac144a7f9958c8dbb4df6a6 100644 (file)
 #define LED_ON_MS      500
 #define LED_OFF_MS     500
 
-static int device_type;
+enum mos7840_flag {
+       MOS7840_FLAG_CTRL_BUSY,
+       MOS7840_FLAG_LED_BUSY,
+};
 
 static const struct usb_device_id id_table[] = {
        {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
@@ -238,9 +241,12 @@ struct moschip_port {
 
        /* For device(s) with LED indicator */
        bool has_led;
-       bool led_flag;
        struct timer_list led_timer1;   /* Timer for LED on */
        struct timer_list led_timer2;   /* Timer for LED off */
+       struct urb *led_urb;
+       struct usb_ctrlrequest *led_dr;
+
+       unsigned long flags;
 };
 
 /*
@@ -460,10 +466,10 @@ static void mos7840_control_callback(struct urb *urb)
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
                dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
-               return;
+               goto out;
        default:
                dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
-               return;
+               goto out;
        }
 
        dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
@@ -476,6 +482,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,
@@ -486,6 +494,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 */
@@ -497,6 +508,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;
 }
 
@@ -523,7 +537,7 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
                                __u16 reg)
 {
        struct usb_device *dev = mcs->port->serial->dev;
-       struct usb_ctrlrequest *dr = mcs->dr;
+       struct usb_ctrlrequest *dr = mcs->led_dr;
 
        dr->bRequestType = MCS_WR_RTYPE;
        dr->bRequest = MCS_WRREQ;
@@ -531,10 +545,10 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
        dr->wIndex = cpu_to_le16(reg);
        dr->wLength = cpu_to_le16(0);
 
-       usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
+       usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0),
                (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
 
-       usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+       usb_submit_urb(mcs->led_urb, GFP_ATOMIC);
 }
 
 static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
@@ -560,7 +574,19 @@ static void mos7840_led_flag_off(unsigned long arg)
 {
        struct moschip_port *mcs = (struct moschip_port *) arg;
 
-       mcs->led_flag = false;
+       clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags);
+}
+
+static void mos7840_led_activity(struct usb_serial_port *port)
+{
+       struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
+
+       if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags))
+               return;
+
+       mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER);
+       mod_timer(&mos7840_port->led_timer1,
+                               jiffies + msecs_to_jiffies(LED_ON_MS));
 }
 
 /*****************************************************************************
@@ -758,14 +784,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
                return;
        }
 
-       /* Turn on LED */
-       if (mos7840_port->has_led && !mos7840_port->led_flag) {
-               mos7840_port->led_flag = true;
-               mos7840_set_led_async(mos7840_port, 0x0301,
-                                       MODEM_CONTROL_REGISTER);
-               mod_timer(&mos7840_port->led_timer1,
-                               jiffies + msecs_to_jiffies(LED_ON_MS));
-       }
+       if (mos7840_port->has_led)
+               mos7840_led_activity(port);
 
        mos7840_port->read_urb_busy = true;
        retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
@@ -816,18 +836,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
 /************************************************************************/
 /*       D R I V E R  T T Y  I N T E R F A C E  F U N C T I O N S       */
 /************************************************************************/
-#ifdef MCSSerialProbe
-static int mos7840_serial_probe(struct usb_serial *serial,
-                               const struct usb_device_id *id)
-{
-
-       /*need to implement the mode_reg reading and updating\
-          structures usb_serial_ device_type\
-          (i.e num_ports, num_bulkin,bulkout etc) */
-       /* Also we can update the changes  attach */
-       return 1;
-}
-#endif
 
 /*****************************************************************************
  * mos7840_open
@@ -905,20 +913,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) {
                dev_dbg(&port->dev, "Reading Spreg failed\n");
-               return -1;
+               goto err;
        }
        Data |= 0x80;
        status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
        if (status < 0) {
                dev_dbg(&port->dev, "writing Spreg failed\n");
-               return -1;
+               goto err;
        }
 
        Data &= ~0x80;
        status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
        if (status < 0) {
                dev_dbg(&port->dev, "writing Spreg failed\n");
-               return -1;
+               goto err;
        }
        /* End of block to be checked */
 
@@ -927,7 +935,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
                                                                        &Data);
        if (status < 0) {
                dev_dbg(&port->dev, "Reading Controlreg failed\n");
-               return -1;
+               goto err;
        }
        Data |= 0x08;           /* Driver done bit */
        Data |= 0x20;           /* rx_disable */
@@ -935,7 +943,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
                                mos7840_port->ControlRegOffset, Data);
        if (status < 0) {
                dev_dbg(&port->dev, "writing Controlreg failed\n");
-               return -1;
+               goto err;
        }
        /* do register settings here */
        /* Set all regs to the device default values. */
@@ -946,21 +954,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) {
                dev_dbg(&port->dev, "disabling interrupts failed\n");
-               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) {
                dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER  failed\n");
-               return -1;
+               goto err;
        }
 
        Data = 0xcf;
        status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
        if (status < 0) {
                dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER  failed\n");
-               return -1;
+               goto err;
        }
 
        Data = 0x03;
@@ -1103,6 +1111,15 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
        /* mos7840_change_port_settings(mos7840_port,old_termios); */
 
        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;
 }
 
 /*****************************************************************************
@@ -1445,13 +1462,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
        data1 = urb->transfer_buffer;
        dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress);
 
-       /* Turn on LED */
-       if (mos7840_port->has_led && !mos7840_port->led_flag) {
-               mos7840_port->led_flag = true;
-               mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
-               mod_timer(&mos7840_port->led_timer1,
-                               jiffies + msecs_to_jiffies(LED_ON_MS));
-       }
+       if (mos7840_port->has_led)
+               mos7840_led_activity(port);
 
        /* send it down the pipe */
        status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -2178,38 +2190,48 @@ static int mos7810_check(struct usb_serial *serial)
        return 0;
 }
 
-static int mos7840_calc_num_ports(struct usb_serial *serial)
+static int mos7840_probe(struct usb_serial *serial,
+                               const struct usb_device_id *id)
 {
-       __u16 data = 0x00;
+       u16 product = serial->dev->descriptor.idProduct;
        u8 *buf;
-       int mos7840_num_ports;
+       int device_type;
+
+       if (product == MOSCHIP_DEVICE_ID_7810 ||
+               product == MOSCHIP_DEVICE_ID_7820) {
+               device_type = product;
+               goto out;
+       }
 
        buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
-       if (buf) {
-               usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+       if (!buf)
+               return -ENOMEM;
+
+       usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                        MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
                        VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
-               data = *buf;
-               kfree(buf);
-       }
 
-       if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
-               serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
-               device_type = serial->dev->descriptor.idProduct;
-       } else {
-               /* For a MCS7840 device GPIO0 must be set to 1 */
-               if ((data & 0x01) == 1)
-                       device_type = MOSCHIP_DEVICE_ID_7840;
-               else if (mos7810_check(serial))
-                       device_type = MOSCHIP_DEVICE_ID_7810;
-               else
-                       device_type = MOSCHIP_DEVICE_ID_7820;
-       }
+       /* For a MCS7840 device GPIO0 must be set to 1 */
+       if (buf[0] & 0x01)
+               device_type = MOSCHIP_DEVICE_ID_7840;
+       else if (mos7810_check(serial))
+               device_type = MOSCHIP_DEVICE_ID_7810;
+       else
+               device_type = MOSCHIP_DEVICE_ID_7820;
+
+       kfree(buf);
+out:
+       usb_set_serial_data(serial, (void *)(unsigned long)device_type);
+
+       return 0;
+}
+
+static int mos7840_calc_num_ports(struct usb_serial *serial)
+{
+       int device_type = (unsigned long)usb_get_serial_data(serial);
+       int mos7840_num_ports;
 
        mos7840_num_ports = (device_type >> 4) & 0x000F;
-       serial->num_bulk_in = mos7840_num_ports;
-       serial->num_bulk_out = mos7840_num_ports;
-       serial->num_ports = mos7840_num_ports;
 
        return mos7840_num_ports;
 }
@@ -2217,6 +2239,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
 static int mos7840_port_probe(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
+       int device_type = (unsigned long)usb_get_serial_data(serial);
        struct moschip_port *mos7840_port;
        int status;
        int pnum;
@@ -2392,6 +2415,14 @@ static int mos7840_port_probe(struct usb_serial_port *port)
        if (device_type == MOSCHIP_DEVICE_ID_7810) {
                mos7840_port->has_led = true;
 
+               mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL);
+               mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr),
+                                                               GFP_KERNEL);
+               if (!mos7840_port->led_urb || !mos7840_port->led_dr) {
+                       status = -ENOMEM;
+                       goto error;
+               }
+
                init_timer(&mos7840_port->led_timer1);
                mos7840_port->led_timer1.function = mos7840_led_off;
                mos7840_port->led_timer1.expires =
@@ -2404,8 +2435,6 @@ static int mos7840_port_probe(struct usb_serial_port *port)
                        jiffies + msecs_to_jiffies(LED_OFF_MS);
                mos7840_port->led_timer2.data = (unsigned long)mos7840_port;
 
-               mos7840_port->led_flag = false;
-
                /* Turn off LED */
                mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
        }
@@ -2427,6 +2456,8 @@ out:
        }
        return 0;
 error:
+       kfree(mos7840_port->led_dr);
+       usb_free_urb(mos7840_port->led_urb);
        kfree(mos7840_port->dr);
        kfree(mos7840_port->ctrl_buf);
        usb_free_urb(mos7840_port->control_urb);
@@ -2447,6 +2478,10 @@ static int mos7840_port_remove(struct usb_serial_port *port)
 
                del_timer_sync(&mos7840_port->led_timer1);
                del_timer_sync(&mos7840_port->led_timer2);
+
+               usb_kill_urb(mos7840_port->led_urb);
+               usb_free_urb(mos7840_port->led_urb);
+               kfree(mos7840_port->led_dr);
        }
        usb_kill_urb(mos7840_port->control_urb);
        usb_free_urb(mos7840_port->control_urb);
@@ -2473,9 +2508,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
        .throttle = mos7840_throttle,
        .unthrottle = mos7840_unthrottle,
        .calc_num_ports = mos7840_calc_num_ports,
-#ifdef MCSSerialProbe
-       .probe = mos7840_serial_probe,
-#endif
+       .probe = mos7840_probe,
        .ioctl = mos7840_ioctl,
        .set_termios = mos7840_set_termios,
        .break_ctl = mos7840_break,
index 5dd857de05b04f5ecf4cefe7a370e6013db67118..1cf6f125f5f078624b41bd1256686d35f28ee4b7 100644 (file)
@@ -341,17 +341,12 @@ static void option_instat_callback(struct urb *urb);
 #define OLIVETTI_VENDOR_ID                     0x0b3c
 #define OLIVETTI_PRODUCT_OLICARD100            0xc000
 #define OLIVETTI_PRODUCT_OLICARD145            0xc003
+#define OLIVETTI_PRODUCT_OLICARD200            0xc005
 
 /* Celot products */
 #define CELOT_VENDOR_ID                                0x211f
 #define CELOT_PRODUCT_CT680M                   0x6801
 
-/* ONDA Communication vendor id */
-#define ONDA_VENDOR_ID       0x1ee8
-
-/* ONDA MT825UP HSDPA 14.2 modem */
-#define ONDA_MT825UP         0x000b
-
 /* Samsung products */
 #define SAMSUNG_VENDOR_ID                       0x04e8
 #define SAMSUNG_PRODUCT_GT_B3730                0x6889
@@ -444,7 +439,8 @@ static void option_instat_callback(struct urb *urb);
 
 /* Hyundai Petatel Inc. products */
 #define PETATEL_VENDOR_ID                      0x1ff4
-#define PETATEL_PRODUCT_NP10T                  0x600e
+#define PETATEL_PRODUCT_NP10T_600A             0x600a
+#define PETATEL_PRODUCT_NP10T_600E             0x600e
 
 /* TP-LINK Incorporated products */
 #define TPLINK_VENDOR_ID                       0x2357
@@ -782,6 +778,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) },
        { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
        { 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) },
@@ -817,7 +814,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff),
+               .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
@@ -1256,8 +1254,8 @@ static const struct usb_device_id option_ids[] = {
 
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
+       { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200) },
        { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
-       { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP 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) },
        { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM610) },
@@ -1329,9 +1327,12 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) },
        { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) },
        { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
-       { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) },
+       { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600A) },
+       { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) },
        { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+       { USB_DEVICE(TPLINK_VENDOR_ID, 0x9000),                                 /* TP-Link MA260 */
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) },
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) },    /* D-Link DWM-156 (variant) */
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) },    /* D-Link DWM-156 (variant) */
@@ -1339,6 +1340,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) },
        { 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 */
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/suunto.c b/drivers/usb/serial/suunto.c
new file mode 100644 (file)
index 0000000..2248e7a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Suunto ANT+ USB Driver
+ *
+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ * Copyright (C) 2013 Linux Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation only.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+static const struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x0fcf, 0x1008) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_serial_driver suunto_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         KBUILD_MODNAME,
+       },
+       .id_table =             id_table,
+       .num_ports =            1,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+       &suunto_device,
+       NULL,
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+MODULE_LICENSE("GPL");
index 7182bb774b7958f70f50efb823b084c5ea9284d5..375b5a400b6fb8a63b0aaa83272299a15aef6e83 100644 (file)
@@ -371,7 +371,7 @@ static int ti_startup(struct usb_serial *serial)
        usb_set_serial_data(serial, tdev);
 
        /* determine device type */
-       if (usb_match_id(serial->interface, ti_id_table_3410))
+       if (serial->type == &ti_1port_device)
                tdev->td_is_3410 = 1;
        dev_dbg(&dev->dev, "%s - device type is %s\n", __func__,
                tdev->td_is_3410 ? "3410" : "5052");
index 1799335288bd5e60522a60def1c311f07df62286..c015f2c16729c5b4030fc829fae9a3cfb90acde6 100644 (file)
@@ -665,6 +665,13 @@ UNUSUAL_DEV(  0x054c, 0x016a, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_FIX_INQUIRY ),
 
+/* Submitted by Ren Bigcren <bigcren.ren@sonymobile.com> */
+UNUSUAL_DEV(  0x054c, 0x02a5, 0x0100, 0x0100,
+               "Sony Corp.",
+               "MicroVault Flash Drive",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_READ_CAPACITY_16 ),
+
 /* floppy reports multiple luns */
 UNUSUAL_DEV(  0x055d, 0x2020, 0x0000, 0x0210,
                "SAMSUNG",
index c5179e269df64ade2de20a384b6732a6922c9bcf..cef6002acbd49aa078568fe2fe9ea4511230e861 100644 (file)
@@ -137,8 +137,27 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
         */
        pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
 
-       if (vdev->reset_works)
-               __pci_reset_function(pdev);
+       /*
+        * Careful, device_lock may already be held.  This is the case if
+        * a driver unbind is blocked.  Try to get the locks ourselves to
+        * prevent a deadlock.
+        */
+       if (vdev->reset_works) {
+               bool reset_done = false;
+
+               if (pci_cfg_access_trylock(pdev)) {
+                       if (device_trylock(&pdev->dev)) {
+                               __pci_reset_function_locked(pdev);
+                               reset_done = true;
+                               device_unlock(&pdev->dev);
+                       }
+                       pci_cfg_access_unlock(pdev);
+               }
+
+               if (!reset_done)
+                       pr_warn("%s: Unable to acquire locks for reset of %s\n",
+                               __func__, dev_name(&pdev->dev));
+       }
 
        pci_restore_state(pdev);
 }
index c488da5db7c7f1b0bda8e3b7559971ebfba0c442..842f4507883e1b1d10c99d343e35e450abf56db0 100644 (file)
@@ -494,27 +494,6 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
        return 0;
 }
 
-static int vfio_group_nb_del_dev(struct vfio_group *group, struct device *dev)
-{
-       struct vfio_device *device;
-
-       /*
-        * Expect to fall out here.  If a device was in use, it would
-        * have been bound to a vfio sub-driver, which would have blocked
-        * in .remove at vfio_del_group_dev.  Sanity check that we no
-        * longer track the device, so it's safe to remove.
-        */
-       device = vfio_group_get_device(group, dev);
-       if (likely(!device))
-               return 0;
-
-       WARN("Device %s removed from live group %d!\n", dev_name(dev),
-            iommu_group_id(group->iommu_group));
-
-       vfio_device_put(device);
-       return 0;
-}
-
 static int vfio_group_nb_verify(struct vfio_group *group, struct device *dev)
 {
        /* We don't care what happens when the group isn't in use */
@@ -531,13 +510,11 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
        struct device *dev = data;
 
        /*
-        * Need to go through a group_lock lookup to get a reference or
-        * we risk racing a group being removed.  Leave a WARN_ON for
-        * debuging, but if the group no longer exists, a spurious notify
-        * is harmless.
+        * Need to go through a group_lock lookup to get a reference or we
+        * risk racing a group being removed.  Ignore spurious notifies.
         */
        group = vfio_group_try_get(group);
-       if (WARN_ON(!group))
+       if (!group)
                return NOTIFY_OK;
 
        switch (action) {
@@ -545,7 +522,13 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
                vfio_group_nb_add_dev(group, dev);
                break;
        case IOMMU_GROUP_NOTIFY_DEL_DEVICE:
-               vfio_group_nb_del_dev(group, dev);
+               /*
+                * Nothing to do here.  If the device is in use, then the
+                * vfio sub-driver should block the remove callback until
+                * it is unused.  If the device is unused or attached to a
+                * stub driver, then it should be released and we don't
+                * care that it will be going away.
+                */
                break;
        case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
                pr_debug("%s: Device %s, group %d binding to driver\n",
index 027be91db139c43eaadd5e12727c2b18c1a65bcc..969a85960e9f6bf09a5bb9a6b1ea828d9f5ae9fb 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
-#include <linux/rcupdate.h>
 #include <linux/file.h>
 #include <linux/slab.h>
 
@@ -346,12 +345,11 @@ static void handle_tx(struct vhost_net *net)
        struct vhost_net_ubuf_ref *uninitialized_var(ubufs);
        bool zcopy, zcopy_used;
 
-       /* TODO: check that we are running from vhost_worker? */
-       sock = rcu_dereference_check(vq->private_data, 1);
+       mutex_lock(&vq->mutex);
+       sock = vq->private_data;
        if (!sock)
-               return;
+               goto out;
 
-       mutex_lock(&vq->mutex);
        vhost_disable_notify(&net->dev, vq);
 
        hdr_size = nvq->vhost_hlen;
@@ -461,7 +459,7 @@ static void handle_tx(struct vhost_net *net)
                        break;
                }
        }
-
+out:
        mutex_unlock(&vq->mutex);
 }
 
@@ -570,14 +568,14 @@ static void handle_rx(struct vhost_net *net)
        s16 headcount;
        size_t vhost_hlen, sock_hlen;
        size_t vhost_len, sock_len;
-       /* TODO: check that we are running from vhost_worker? */
-       struct socket *sock = rcu_dereference_check(vq->private_data, 1);
-
-       if (!sock)
-               return;
+       struct socket *sock;
 
        mutex_lock(&vq->mutex);
+       sock = vq->private_data;
+       if (!sock)
+               goto out;
        vhost_disable_notify(&net->dev, vq);
+
        vhost_hlen = nvq->vhost_hlen;
        sock_hlen = nvq->sock_hlen;
 
@@ -652,7 +650,7 @@ static void handle_rx(struct vhost_net *net)
                        break;
                }
        }
-
+out:
        mutex_unlock(&vq->mutex);
 }
 
@@ -750,8 +748,7 @@ static int vhost_net_enable_vq(struct vhost_net *n,
        struct vhost_poll *poll = n->poll + (nvq - n->vqs);
        struct socket *sock;
 
-       sock = rcu_dereference_protected(vq->private_data,
-                                        lockdep_is_held(&vq->mutex));
+       sock = vq->private_data;
        if (!sock)
                return 0;
 
@@ -764,10 +761,9 @@ static struct socket *vhost_net_stop_vq(struct vhost_net *n,
        struct socket *sock;
 
        mutex_lock(&vq->mutex);
-       sock = rcu_dereference_protected(vq->private_data,
-                                        lockdep_is_held(&vq->mutex));
+       sock = vq->private_data;
        vhost_net_disable_vq(n, vq);
-       rcu_assign_pointer(vq->private_data, NULL);
+       vq->private_data = NULL;
        mutex_unlock(&vq->mutex);
        return sock;
 }
@@ -923,8 +919,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
        }
 
        /* start polling new socket */
-       oldsock = rcu_dereference_protected(vq->private_data,
-                                           lockdep_is_held(&vq->mutex));
+       oldsock = vq->private_data;
        if (sock != oldsock) {
                ubufs = vhost_net_ubuf_alloc(vq,
                                             sock && vhost_sock_zcopy(sock));
@@ -934,7 +929,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
                }
 
                vhost_net_disable_vq(n, vq);
-               rcu_assign_pointer(vq->private_data, sock);
+               vq->private_data = sock;
                r = vhost_init_used(vq);
                if (r)
                        goto err_used;
@@ -968,7 +963,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
        return 0;
 
 err_used:
-       rcu_assign_pointer(vq->private_data, oldsock);
+       vq->private_data = oldsock;
        vhost_net_enable_vq(n, vq);
        if (ubufs)
                vhost_net_ubuf_put_wait_and_free(ubufs);
index 06adf31a92484a6f32f01ab71c2dd76c6553c920..0c27c7df1b093e6ad64292a5211387a3103543e2 100644 (file)
@@ -902,19 +902,15 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
        int head, ret;
        u8 target;
 
+       mutex_lock(&vq->mutex);
        /*
         * We can handle the vq only after the endpoint is setup by calling the
         * VHOST_SCSI_SET_ENDPOINT ioctl.
-        *
-        * TODO: Check that we are running from vhost_worker which acts
-        * as read-side critical section for vhost kind of RCU.
-        * See the comments in struct vhost_virtqueue in drivers/vhost/vhost.h
         */
-       vs_tpg = rcu_dereference_check(vq->private_data, 1);
+       vs_tpg = vq->private_data;
        if (!vs_tpg)
-               return;
+               goto out;
 
-       mutex_lock(&vq->mutex);
        vhost_disable_notify(&vs->dev, vq);
 
        for (;;) {
@@ -1064,6 +1060,7 @@ err_free:
        vhost_scsi_free_cmd(cmd);
 err_cmd:
        vhost_scsi_send_bad_target(vs, vq, head, out);
+out:
        mutex_unlock(&vq->mutex);
 }
 
@@ -1232,9 +1229,8 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs,
                       sizeof(vs->vs_vhost_wwpn));
                for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
                        vq = &vs->vqs[i].vq;
-                       /* Flushing the vhost_work acts as synchronize_rcu */
                        mutex_lock(&vq->mutex);
-                       rcu_assign_pointer(vq->private_data, vs_tpg);
+                       vq->private_data = vs_tpg;
                        vhost_init_used(vq);
                        mutex_unlock(&vq->mutex);
                }
@@ -1313,9 +1309,8 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
        if (match) {
                for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
                        vq = &vs->vqs[i].vq;
-                       /* Flushing the vhost_work acts as synchronize_rcu */
                        mutex_lock(&vq->mutex);
-                       rcu_assign_pointer(vq->private_data, NULL);
+                       vq->private_data = NULL;
                        mutex_unlock(&vq->mutex);
                }
        }
index a73ea217f24dc79a0f92a95cca39c416e828a6b9..339eae85859a58afbd6ea563b4b9fae3f667100c 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
-#include <linux/rcupdate.h>
 #include <linux/file.h>
 #include <linux/slab.h>
 
@@ -200,9 +199,8 @@ static long vhost_test_run(struct vhost_test *n, int test)
                priv = test ? n : NULL;
 
                /* start polling new socket */
-               oldpriv = rcu_dereference_protected(vq->private_data,
-                                                   lockdep_is_held(&vq->mutex));
-               rcu_assign_pointer(vq->private_data, priv);
+               oldpriv = vq->private_data;
+               vq->private_data = priv;
 
                r = vhost_init_used(&n->vqs[index]);
 
index 42298cd23c73842e6a4ec7f8434428b56e700098..4465ed5f316d6e9b36e1f43c05df1c980aa908ae 100644 (file)
@@ -103,14 +103,8 @@ struct vhost_virtqueue {
        struct iovec iov[UIO_MAXIOV];
        struct iovec *indirect;
        struct vring_used_elem *heads;
-       /* We use a kind of RCU to access private pointer.
-        * All readers access it from worker, which makes it possible to
-        * flush the vhost_work instead of synchronize_rcu. Therefore readers do
-        * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
-        * vhost_work execution acts instead of rcu_read_lock() and the end of
-        * vhost_work execution acts instead of rcu_read_unlock().
-        * Writers use virtqueue mutex. */
-       void __rcu *private_data;
+       /* Protected by virtqueue mutex. */
+       void *private_data;
        /* Log write descriptors */
        void __user *log_base;
        struct vhost_log *log;
index a89c15de9f45c885f3dc7fe76bad22bde184013d..9b0f12c5c2842f783501821d7c6bb4a9527f936f 100644 (file)
@@ -435,8 +435,8 @@ static int correct_chipset(struct atyfb_par *par)
        const char *name;
        int i;
 
-       for (i = ARRAY_SIZE(aty_chips); i > 0; i--)
-               if (par->pci_id == aty_chips[i - 1].pci_id)
+       for (i = (int)ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
+               if (par->pci_id == aty_chips[i].pci_id)
                        break;
 
        if (i < 0)
index 5ca11b066b7e51b31e346759fed356e98bfe0d12..886e797f75f9e7b0c6571f2f8ba0ec0b561f0d83 100644 (file)
@@ -101,33 +101,37 @@ static const struct backlight_ops max8925_backlight_ops = {
        .get_brightness = max8925_backlight_get_brightness,
 };
 
-#ifdef CONFIG_OF
-static int max8925_backlight_dt_init(struct platform_device *pdev,
-                             struct max8925_backlight_pdata *pdata)
+static void max8925_backlight_dt_init(struct platform_device *pdev)
 {
        struct device_node *nproot = pdev->dev.parent->of_node, *np;
-       int dual_string;
+       struct max8925_backlight_pdata *pdata;
+       u32 val;
+
+       if (!nproot || !IS_ENABLED(CONFIG_OF))
+               return;
+
+       pdata = devm_kzalloc(&pdev->dev,
+                            sizeof(struct max8925_backlight_pdata),
+                            GFP_KERNEL);
+       if (!pdata)
+               return;
 
-       if (!nproot)
-               return -ENODEV;
        np = of_find_node_by_name(nproot, "backlight");
        if (!np) {
                dev_err(&pdev->dev, "failed to find backlight node\n");
-               return -ENODEV;
+               return;
        }
 
-       of_property_read_u32(np, "maxim,max8925-dual-string", &dual_string);
-       pdata->dual_string = dual_string;
-       return 0;
+       if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
+               pdata->dual_string = val;
+
+       pdev->dev.platform_data = pdata;
 }
-#else
-#define max8925_backlight_dt_init(x, y)        (-1)
-#endif
 
 static int max8925_backlight_probe(struct platform_device *pdev)
 {
        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
-       struct max8925_backlight_pdata *pdata = pdev->dev.platform_data;
+       struct max8925_backlight_pdata *pdata;
        struct max8925_backlight_data *data;
        struct backlight_device *bl;
        struct backlight_properties props;
@@ -170,13 +174,10 @@ static int max8925_backlight_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, bl);
 
        value = 0;
-       if (pdev->dev.parent->of_node && !pdata) {
-               pdata = devm_kzalloc(&pdev->dev,
-                                    sizeof(struct max8925_backlight_pdata),
-                                    GFP_KERNEL);
-               max8925_backlight_dt_init(pdev, pdata);
-       }
+       if (!pdev->dev.platform_data)
+               max8925_backlight_dt_init(pdev);
 
+       pdata = pdev->dev.platform_data;
        if (pdata) {
                if (pdata->lxw_scl)
                        value |= (1 << 7);
index 8c527e5b293cbe5bf91718f5c1f68b0ffbcc4c44..796e5112ceeeb1f139bf947197e96ea2af42ee60 100644 (file)
@@ -587,8 +587,7 @@ static int nuc900fb_probe(struct platform_device *pdev)
        fbinfo->flags                   = FBINFO_FLAG_DEFAULT;
        fbinfo->pseudo_palette          = &fbi->pseudo_pal;
 
-       ret = request_irq(irq, nuc900fb_irqhandler, 0,
-                         pdev->name, fbinfo);
+       ret = request_irq(irq, nuc900fb_irqhandler, 0, pdev->name, fbi);
        if (ret) {
                dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
                        irq, ret);
index b2a8912f6435ac504e4b09361c12dbe8b7d01bc6..a9ac3ce2d0e9de56aaab9f836b0037fe62651596 100644 (file)
@@ -713,7 +713,7 @@ static int sgivwfb_mmap(struct fb_info *info,
        r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size);
 
        printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
-              offset, vma->vm_start);
+               sgivwfb_mem_phys + (vma->vm_pgoff << PAGE_SHIFT), vma->vm_start);
 
        return r;
 }
index a8c6c43a4658565c8b21fa38a3baaf1c5bd82e36..1265b25f9f99993efd8d094716acb65563d8570f 100644 (file)
@@ -567,7 +567,7 @@ static int sh7760fb_remove(struct platform_device *dev)
        fb_dealloc_cmap(&info->cmap);
        sh7760fb_free_mem(info);
        if (par->irq >= 0)
-               free_irq(par->irq, par);
+               free_irq(par->irq, &par->vsync);
        iounmap(par->base);
        release_mem_region(par->ioarea->start, resource_size(par->ioarea));
        framebuffer_release(info);
index 830ded45fd4758a9a3d9ba6c6640653ac9b32490..2827333703d96d151b86952470c590a5d2820636 100644 (file)
@@ -1265,7 +1265,6 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image
 
 static void vga16fb_destroy(struct fb_info *info)
 {
-       struct platform_device *dev = container_of(info->device, struct platform_device, dev);
        iounmap(info->screen_base);
        fb_dealloc_cmap(&info->cmap);
        /* XXX unshare VGA regions */
index f3d4a69e1e4e9058c4c4cc605705f1d62d923a48..6629b29a820221eedfe774a1cd4c62163bd29bb1 100644 (file)
@@ -341,8 +341,8 @@ static int xilinxfb_assign(struct platform_device *pdev,
 
        if (drvdata->flags & BUS_ACCESS_FLAG) {
                /* Put a banner in the log (for DEBUG) */
-               dev_dbg(dev, "regs: phys=%x, virt=%p\n", drvdata->regs_phys,
-                                       drvdata->regs);
+               dev_dbg(dev, "regs: phys=%pa, virt=%p\n",
+                       &drvdata->regs_phys, drvdata->regs);
        }
        /* Put a banner in the log (for DEBUG) */
        dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n",
index 9e02d60a364b00d271efb0b4d4eda046a25fbf08..23eae5cb69c21e16d2f71ce2c29e1b307ba3c05c 100644 (file)
@@ -145,7 +145,7 @@ config SWIOTLB_XEN
 
 config XEN_TMEM
        tristate
-       depends on !ARM
+       depends on !ARM && !ARM64
        default m if (CLEANCACHE || FRONTSWAP)
        help
          Shim to interface in-kernel Transcendent Memory hooks
index eabd0ee1c2bc2f298d0938515e204b42430e9852..14fe79d8634abfe2307d53e65e151f403c86bcad 100644 (file)
@@ -1,9 +1,8 @@
-ifneq ($(CONFIG_ARM),y)
-obj-y  += manage.o
+ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
 obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 endif
 obj-$(CONFIG_X86)                      += fallback.o
-obj-y  += grant-table.o features.o events.o balloon.o
+obj-y  += grant-table.o features.o events.o balloon.o manage.o
 obj-y  += xenbus/
 
 nostackp := $(call cc-option, -fno-stack-protector)
index 8feecf01d55c95c9241080cf36823f197b3b2d5c..b6165e047f48083c5a254dc66a6f4bc3e6e9ddb9 100644 (file)
@@ -379,18 +379,12 @@ static long evtchn_ioctl(struct file *file,
                if (unbind.port >= NR_EVENT_CHANNELS)
                        break;
 
-               spin_lock_irq(&port_user_lock);
-
                rc = -ENOTCONN;
-               if (get_port_user(unbind.port) != u) {
-                       spin_unlock_irq(&port_user_lock);
+               if (get_port_user(unbind.port) != u)
                        break;
-               }
 
                disable_irq(irq_from_evtchn(unbind.port));
 
-               spin_unlock_irq(&port_user_lock);
-
                evtchn_unbind_from_user(u, unbind.port);
 
                rc = 0;
@@ -490,26 +484,15 @@ static int evtchn_release(struct inode *inode, struct file *filp)
        int i;
        struct per_user_data *u = filp->private_data;
 
-       spin_lock_irq(&port_user_lock);
-
-       free_page((unsigned long)u->ring);
-
        for (i = 0; i < NR_EVENT_CHANNELS; i++) {
                if (get_port_user(i) != u)
                        continue;
 
                disable_irq(irq_from_evtchn(i));
-       }
-
-       spin_unlock_irq(&port_user_lock);
-
-       for (i = 0; i < NR_EVENT_CHANNELS; i++) {
-               if (get_port_user(i) != u)
-                       continue;
-
                evtchn_unbind_from_user(get_port_user(i), i);
        }
 
+       free_page((unsigned long)u->ring);
        kfree(u->name);
        kfree(u);
 
index 6ed8a9df4472edc36b91b70ca3a0f463f237108d..34b20bfa4e8c3cf813194a45c4545e01c1d88eb1 100644 (file)
@@ -115,7 +115,6 @@ static int xenbus_frontend_dev_resume(struct device *dev)
                        return -EFAULT;
                }
 
-               INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
                queue_work(xenbus_frontend_wq, &xdev->work);
 
                return 0;
@@ -124,6 +123,16 @@ static int xenbus_frontend_dev_resume(struct device *dev)
        return xenbus_dev_resume(dev);
 }
 
+static int xenbus_frontend_dev_probe(struct device *dev)
+{
+       if (xen_store_domain_type == XS_LOCAL) {
+               struct xenbus_device *xdev = to_xenbus_device(dev);
+               INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
+       }
+
+       return xenbus_dev_probe(dev);
+}
+
 static const struct dev_pm_ops xenbus_pm_ops = {
        .suspend        = xenbus_dev_suspend,
        .resume         = xenbus_frontend_dev_resume,
@@ -142,7 +151,7 @@ static struct xen_bus_type xenbus_frontend = {
                .name           = "xen",
                .match          = xenbus_match,
                .uevent         = xenbus_uevent_frontend,
-               .probe          = xenbus_dev_probe,
+               .probe          = xenbus_frontend_dev_probe,
                .remove         = xenbus_dev_remove,
                .shutdown       = xenbus_dev_shutdown,
                .dev_attrs      = xenbus_dev_attrs,
@@ -474,7 +483,11 @@ static int __init xenbus_probe_frontend_init(void)
 
        register_xenstore_notifier(&xenstore_notifier);
 
-       xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+       if (xen_store_domain_type == XS_LOCAL) {
+               xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+               if (!xenbus_frontend_wq)
+                       pr_warn("create xenbus frontend workqueue failed, S3 resume is likely to fail\n");
+       }
 
        return 0;
 }
index 4888cb3fdef76037b7af5f9db898bdcb82ce48c2..c7c83ff0f752ce6a86d6e42a420e34ed996ae8ca 100644 (file)
@@ -533,8 +533,7 @@ EXPORT_SYMBOL_GPL(debugfs_remove);
  */
 void debugfs_remove_recursive(struct dentry *dentry)
 {
-       struct dentry *child;
-       struct dentry *parent;
+       struct dentry *child, *next, *parent;
 
        if (IS_ERR_OR_NULL(dentry))
                return;
@@ -544,61 +543,37 @@ void debugfs_remove_recursive(struct dentry *dentry)
                return;
 
        parent = dentry;
+ down:
        mutex_lock(&parent->d_inode->i_mutex);
+       list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) {
+               if (!debugfs_positive(child))
+                       continue;
 
-       while (1) {
-               /*
-                * When all dentries under "parent" has been removed,
-                * walk up the tree until we reach our starting point.
-                */
-               if (list_empty(&parent->d_subdirs)) {
-                       mutex_unlock(&parent->d_inode->i_mutex);
-                       if (parent == dentry)
-                               break;
-                       parent = parent->d_parent;
-                       mutex_lock(&parent->d_inode->i_mutex);
-               }
-               child = list_entry(parent->d_subdirs.next, struct dentry,
-                               d_u.d_child);
- next_sibling:
-
-               /*
-                * If "child" isn't empty, walk down the tree and
-                * remove all its descendants first.
-                */
+               /* perhaps simple_empty(child) makes more sense */
                if (!list_empty(&child->d_subdirs)) {
                        mutex_unlock(&parent->d_inode->i_mutex);
                        parent = child;
-                       mutex_lock(&parent->d_inode->i_mutex);
-                       continue;
+                       goto down;
                }
-               __debugfs_remove(child, parent);
-               if (parent->d_subdirs.next == &child->d_u.d_child) {
-                       /*
-                        * Try the next sibling.
-                        */
-                       if (child->d_u.d_child.next != &parent->d_subdirs) {
-                               child = list_entry(child->d_u.d_child.next,
-                                                  struct dentry,
-                                                  d_u.d_child);
-                               goto next_sibling;
-                       }
-
-                       /*
-                        * Avoid infinite loop if we fail to remove
-                        * one dentry.
-                        */
-                       mutex_unlock(&parent->d_inode->i_mutex);
-                       break;
-               }
-               simple_release_fs(&debugfs_mount, &debugfs_mount_count);
+ up:
+               if (!__debugfs_remove(child, parent))
+                       simple_release_fs(&debugfs_mount, &debugfs_mount_count);
        }
 
-       parent = dentry->d_parent;
+       mutex_unlock(&parent->d_inode->i_mutex);
+       child = parent;
+       parent = parent->d_parent;
        mutex_lock(&parent->d_inode->i_mutex);
-       __debugfs_remove(dentry, parent);
+
+       if (child != dentry) {
+               next = list_entry(child->d_u.d_child.next, struct dentry,
+                                       d_u.d_child);
+               goto up;
+       }
+
+       if (!__debugfs_remove(child, parent))
+               simple_release_fs(&debugfs_mount, &debugfs_mount_count);
        mutex_unlock(&parent->d_inode->i_mutex);
-       simple_release_fs(&debugfs_mount, &debugfs_mount_count);
 }
 EXPORT_SYMBOL_GPL(debugfs_remove_recursive);
 
index 6599222536eb20e9deb22884bdc305efcf2cf1ae..65343c3741ff86876418deb9d18e3f72f5872898 100644 (file)
@@ -730,14 +730,14 @@ static int __init fcntl_init(void)
         * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
         * is defined as O_NONBLOCK on some platforms and not on others.
         */
-       BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
+       BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
                O_RDONLY        | O_WRONLY      | O_RDWR        |
                O_CREAT         | O_EXCL        | O_NOCTTY      |
                O_TRUNC         | O_APPEND      | /* O_NONBLOCK | */
                __O_SYNC        | O_DSYNC       | FASYNC        |
                O_DIRECT        | O_LARGEFILE   | O_DIRECTORY   |
                O_NOFOLLOW      | O_NOATIME     | O_CLOEXEC     |
-               __FMODE_EXEC    | O_PATH
+               __FMODE_EXEC    | O_PATH        | __O_TMPFILE
                ));
 
        fasync_cache = kmem_cache_create("fasync_cache",
index 0eda52738ec4d0fc6cac460fab9d4baddde4ff4b..72a5d5b04494ded2468bc4a2f5f30e30c9ca12f7 100644 (file)
@@ -1223,30 +1223,46 @@ static int fuse_direntplus_link(struct file *file,
                if (name.name[1] == '.' && name.len == 2)
                        return 0;
        }
+
+       if (invalid_nodeid(o->nodeid))
+               return -EIO;
+       if (!fuse_valid_type(o->attr.mode))
+               return -EIO;
+
        fc = get_fuse_conn(dir);
 
        name.hash = full_name_hash(name.name, name.len);
        dentry = d_lookup(parent, &name);
-       if (dentry && dentry->d_inode) {
+       if (dentry) {
                inode = dentry->d_inode;
-               if (get_node_id(inode) == o->nodeid) {
+               if (!inode) {
+                       d_drop(dentry);
+               } else if (get_node_id(inode) != o->nodeid ||
+                          ((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
+                       err = d_invalidate(dentry);
+                       if (err)
+                               goto out;
+               } else if (is_bad_inode(inode)) {
+                       err = -EIO;
+                       goto out;
+               } else {
                        struct fuse_inode *fi;
                        fi = get_fuse_inode(inode);
                        spin_lock(&fc->lock);
                        fi->nlookup++;
                        spin_unlock(&fc->lock);
 
+                       fuse_change_attributes(inode, &o->attr,
+                                              entry_attr_timeout(o),
+                                              attr_version);
+
                        /*
                         * The other branch to 'found' comes via fuse_iget()
                         * which bumps nlookup inside
                         */
                        goto found;
                }
-               err = d_invalidate(dentry);
-               if (err)
-                       goto out;
                dput(dentry);
-               dentry = NULL;
        }
 
        dentry = d_alloc(parent, &name);
@@ -1259,25 +1275,30 @@ static int fuse_direntplus_link(struct file *file,
        if (!inode)
                goto out;
 
-       alias = d_materialise_unique(dentry, inode);
-       err = PTR_ERR(alias);
-       if (IS_ERR(alias))
-               goto out;
+       if (S_ISDIR(inode->i_mode)) {
+               mutex_lock(&fc->inst_mutex);
+               alias = fuse_d_add_directory(dentry, inode);
+               mutex_unlock(&fc->inst_mutex);
+               err = PTR_ERR(alias);
+               if (IS_ERR(alias)) {
+                       iput(inode);
+                       goto out;
+               }
+       } else {
+               alias = d_splice_alias(inode, dentry);
+       }
+
        if (alias) {
                dput(dentry);
                dentry = alias;
        }
 
 found:
-       fuse_change_attributes(inode, &o->attr, entry_attr_timeout(o),
-                              attr_version);
-
        fuse_change_entry_timeout(dentry, o);
 
        err = 0;
 out:
-       if (dentry)
-               dput(dentry);
+       dput(dentry);
        return err;
 }
 
index 8b61d103a8a7a15b0c5e8eab070e92f940a64b88..89a612e392ebb28e9a00bfa1c2c8562d8a3fb7c6 100644 (file)
@@ -3671,15 +3671,11 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
        if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
                return -EINVAL;
        /*
-        * To use null names we require CAP_DAC_READ_SEARCH
-        * This ensures that not everyone will be able to create
-        * handlink using the passed filedescriptor.
+        * Using empty names is equivalent to using AT_SYMLINK_FOLLOW
+        * on /proc/self/fd/<fd>.
         */
-       if (flags & AT_EMPTY_PATH) {
-               if (!capable(CAP_DAC_READ_SEARCH))
-                       return -ENOENT;
+       if (flags & AT_EMPTY_PATH)
                how = LOOKUP_EMPTY;
-       }
 
        if (flags & AT_SYMLINK_FOLLOW)
                how |= LOOKUP_FOLLOW;
index c74d6168db99b917ad202c874a9f161f29e920e5..3850b018815f2d07e4740fdd3ff8200523b9fe92 100644 (file)
@@ -1118,11 +1118,11 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                                len, ((char *)p - (char *)q) + 4);
                BUG();
        }
-       len = (char *)p - (char *)q - (bmval_len << 2);
        *q++ = htonl(bmval0);
        *q++ = htonl(bmval1);
        if (bmval_len == 3)
                *q++ = htonl(bmval2);
+       len = (char *)p - (char *)(q + 1);
        *q = htonl(len);
 
 /* out: */
index 8ff6a0019b0b9cc6016da02c3210ae6840a20dfa..c827acb0e943bdab08fd077e56228b170a6a9549 100644 (file)
@@ -830,9 +830,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
                        flags = O_WRONLY|O_LARGEFILE;
        }
        *filp = dentry_open(&path, 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)
index 998b17eda09d807b2b1d2ccc0b94cdc2a45974a1..9f6b96a09615bcc243b81ebc5cf3c9139c2deec3 100644 (file)
@@ -2965,6 +2965,11 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle,
                        to = map_end & (PAGE_CACHE_SIZE - 1);
 
                page = find_or_create_page(mapping, page_index, GFP_NOFS);
+               if (!page) {
+                       ret = -ENOMEM;
+                       mlog_errno(ret);
+                       break;
+               }
 
                /*
                 * In case PAGE_CACHE_SIZE <= CLUSTER_SIZE, This page
index d53e29895082306747de0998c730159b73d08528..7931f76acc2beede0298747df1d505b30cd225b4 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -823,7 +823,7 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
        int lookup_flags = 0;
        int acc_mode;
 
-       if (flags & O_CREAT)
+       if (flags & (O_CREAT | __O_TMPFILE))
                op->mode = (mode & S_IALLUGO) | S_IFREG;
        else
                op->mode = 0;
index 33532f79b4f714923ec951fa5fb75d1758fbfda3..a958444a75fc310627d56de6a37e28a15a99273a 100644 (file)
 /*
  * LOCKING:
  *
- * We rely on new Alexander Viro's super-block locking.
+ * These guys are evicted from procfs as the very first step in ->kill_sb().
  *
  */
 
-static int show_version(struct seq_file *m, struct super_block *sb)
+static int show_version(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        char *format;
 
        if (REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_6)) {
@@ -66,8 +67,9 @@ static int show_version(struct seq_file *m, struct super_block *sb)
 #define DJP( x ) le32_to_cpu( jp -> x )
 #define JF( x ) ( r -> s_journal -> x )
 
-static int show_super(struct seq_file *m, struct super_block *sb)
+static int show_super(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *r = REISERFS_SB(sb);
 
        seq_printf(m, "state: \t%s\n"
@@ -128,8 +130,9 @@ static int show_super(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_per_level(struct seq_file *m, struct super_block *sb)
+static int show_per_level(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *r = REISERFS_SB(sb);
        int level;
 
@@ -186,8 +189,9 @@ static int show_per_level(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_bitmap(struct seq_file *m, struct super_block *sb)
+static int show_bitmap(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *r = REISERFS_SB(sb);
 
        seq_printf(m, "free_block: %lu\n"
@@ -218,8 +222,9 @@ static int show_bitmap(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_on_disk_super(struct seq_file *m, struct super_block *sb)
+static int show_on_disk_super(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *sb_info = REISERFS_SB(sb);
        struct reiserfs_super_block *rs = sb_info->s_rs;
        int hash_code = DFL(s_hash_function_code);
@@ -261,8 +266,9 @@ static int show_on_disk_super(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_oidmap(struct seq_file *m, struct super_block *sb)
+static int show_oidmap(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *sb_info = REISERFS_SB(sb);
        struct reiserfs_super_block *rs = sb_info->s_rs;
        unsigned int mapsize = le16_to_cpu(rs->s_v1.s_oid_cursize);
@@ -291,8 +297,9 @@ static int show_oidmap(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_journal(struct seq_file *m, struct super_block *sb)
+static int show_journal(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *r = REISERFS_SB(sb);
        struct reiserfs_super_block *rs = r->s_rs;
        struct journal_params *jp = &rs->s_v1.s_journal;
@@ -383,92 +390,24 @@ static int show_journal(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-/* iterator */
-static int test_sb(struct super_block *sb, void *data)
-{
-       return data == sb;
-}
-
-static int set_sb(struct super_block *sb, void *data)
-{
-       return -ENOENT;
-}
-
-struct reiserfs_seq_private {
-       struct super_block *sb;
-       int (*show) (struct seq_file *, struct super_block *);
-};
-
-static void *r_start(struct seq_file *m, loff_t * pos)
-{
-       struct reiserfs_seq_private *priv = m->private;
-       loff_t l = *pos;
-
-       if (l)
-               return NULL;
-
-       if (IS_ERR(sget(&reiserfs_fs_type, test_sb, set_sb, 0, priv->sb)))
-               return NULL;
-
-       up_write(&priv->sb->s_umount);
-       return priv->sb;
-}
-
-static void *r_next(struct seq_file *m, void *v, loff_t * pos)
-{
-       ++*pos;
-       if (v)
-               deactivate_super(v);
-       return NULL;
-}
-
-static void r_stop(struct seq_file *m, void *v)
-{
-       if (v)
-               deactivate_super(v);
-}
-
-static int r_show(struct seq_file *m, void *v)
-{
-       struct reiserfs_seq_private *priv = m->private;
-       return priv->show(m, v);
-}
-
-static const struct seq_operations r_ops = {
-       .start = r_start,
-       .next = r_next,
-       .stop = r_stop,
-       .show = r_show,
-};
-
 static int r_open(struct inode *inode, struct file *file)
 {
-       struct reiserfs_seq_private *priv;
-       int ret = seq_open_private(file, &r_ops,
-                                  sizeof(struct reiserfs_seq_private));
-
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-               priv = m->private;
-               priv->sb = proc_get_parent_data(inode);
-               priv->show = PDE_DATA(inode);
-       }
-       return ret;
+       return single_open(file, PDE_DATA(inode), 
+                               proc_get_parent_data(inode));
 }
 
 static const struct file_operations r_file_operations = {
        .open = r_open,
        .read = seq_read,
        .llseek = seq_lseek,
-       .release = seq_release_private,
-       .owner = THIS_MODULE,
+       .release = single_release,
 };
 
 static struct proc_dir_entry *proc_info_root = NULL;
 static const char proc_info_root_name[] = "fs/reiserfs";
 
 static void add_file(struct super_block *sb, char *name,
-                    int (*func) (struct seq_file *, struct super_block *))
+                    int (*func) (struct seq_file *, void *))
 {
        proc_create_data(name, 0, REISERFS_SB(sb)->procdir,
                         &r_file_operations, func);
index f8a23c3078f87d5eda59c30d55cea7ecc94b9273..e2e202a07b317cff5c84d8b51e3b66efafd689ea 100644 (file)
@@ -499,6 +499,7 @@ int remove_save_link(struct inode *inode, int truncate)
 static void reiserfs_kill_sb(struct super_block *s)
 {
        if (REISERFS_SB(s)) {
+               reiserfs_proc_info_done(s);
                /*
                 * Force any pending inode evictions to occur now. Any
                 * inodes to be removed that have extended attributes
@@ -554,8 +555,6 @@ static void reiserfs_put_super(struct super_block *s)
                                 REISERFS_SB(s)->reserved_blocks);
        }
 
-       reiserfs_proc_info_done(s);
-
        reiserfs_write_unlock(s);
        mutex_destroy(&REISERFS_SB(s)->lock);
        kfree(s->s_fs_info);
index 07d735a80a0f777c342c4323ba9393556afe182b..e5869b50dc41acd1788123e0cd49ea2670101e3f 100644 (file)
@@ -39,6 +39,9 @@ typedef struct xfs_timestamp {
  * There is a very similar struct icdinode in xfs_inode which matches the
  * layout of the first 96 bytes of this structure, but is kept in native
  * format instead of big endian.
+ *
+ * Note: di_flushiter is only used by v1/2 inodes - it's effectively a zeroed
+ * padding field for v3 inodes.
  */
 typedef struct xfs_dinode {
        __be16          di_magic;       /* inode magic # = XFS_DINODE_MAGIC */
index b78481f99d9d6a683f0d18815432fce69d8d2838..bb262c25c8de463276e9282d64b299c975eceb7b 100644 (file)
@@ -896,7 +896,6 @@ xfs_dinode_to_disk(
        to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
        to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
        memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
-       to->di_flushiter = cpu_to_be16(from->di_flushiter);
        to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec);
        to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec);
        to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec);
@@ -924,6 +923,9 @@ xfs_dinode_to_disk(
                to->di_lsn = cpu_to_be64(from->di_lsn);
                memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
                uuid_copy(&to->di_uuid, &from->di_uuid);
+               to->di_flushiter = 0;
+       } else {
+               to->di_flushiter = cpu_to_be16(from->di_flushiter);
        }
 }
 
@@ -1029,10 +1031,14 @@ xfs_dinode_calc_crc(
 /*
  * Read the disk inode attributes into the in-core inode structure.
  *
- * If we are initialising a new inode and we are not utilising the
- * XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new inode core
- * with a random generation number. If we are keeping inodes around, we need to
- * read the inode cluster to get the existing generation number off disk.
+ * For version 5 superblocks, if we are initialising a new inode and we are not
+ * utilising the XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new
+ * inode core with a random generation number. If we are keeping inodes around,
+ * we need to read the inode cluster to get the existing generation number off
+ * disk. Further, if we are using version 4 superblocks (i.e. v1/v2 inode
+ * format) then log recovery is dependent on the di_flushiter field being
+ * initialised from the current on-disk value and hence we must also read the
+ * inode off disk.
  */
 int
 xfs_iread(
@@ -1054,6 +1060,7 @@ xfs_iread(
 
        /* shortcut IO on inode allocation if possible */
        if ((iget_flags & XFS_IGET_CREATE) &&
+           xfs_sb_version_hascrc(&mp->m_sb) &&
            !(mp->m_flags & XFS_MOUNT_IKEEP)) {
                /* initialise the on-disk inode core */
                memset(&ip->i_d, 0, sizeof(ip->i_d));
@@ -2882,12 +2889,18 @@ xfs_iflush_int(
                        __func__, ip->i_ino, ip->i_d.di_forkoff, ip);
                goto corrupt_out;
        }
+
        /*
-        * bump the flush iteration count, used to detect flushes which
-        * postdate a log record during recovery. This is redundant as we now
-        * log every change and hence this can't happen. Still, it doesn't hurt.
+        * Inode item log recovery for v1/v2 inodes are dependent on the
+        * di_flushiter count for correct sequencing. We bump the flush
+        * iteration count so we can detect flushes which postdate a log record
+        * during recovery. This is redundant as we now log every change and
+        * hence this can't happen but we need to still do it to ensure
+        * backwards compatibility with old kernels that predate logging all
+        * inode changes.
         */
-       ip->i_d.di_flushiter++;
+       if (ip->i_d.di_version < 3)
+               ip->i_d.di_flushiter++;
 
        /*
         * Copy the dirty parts of the inode into the on-disk
index 6fcc910a50b9d7e3fbd3c15851aa0ee0cfc1b6af..7681b19aa5dc565a9807005ff3f1d6428a22f016 100644 (file)
@@ -2592,8 +2592,16 @@ xlog_recover_inode_pass2(
                goto error;
        }
 
-       /* Skip replay when the on disk inode is newer than the log one */
-       if (dicp->di_flushiter < be16_to_cpu(dip->di_flushiter)) {
+       /*
+        * di_flushiter is only valid for v1/2 inodes. All changes for v3 inodes
+        * are transactional and if ordering is necessary we can determine that
+        * more accurately by the LSN field in the V3 inode core. Don't trust
+        * the inode versions we might be changing them here - use the
+        * superblock flag to determine whether we need to look at di_flushiter
+        * to skip replay when the on disk inode is newer than the log one
+        */
+       if (!xfs_sb_version_hascrc(&mp->m_sb) &&
+           dicp->di_flushiter < be16_to_cpu(dip->di_flushiter)) {
                /*
                 * Deal with the wrap case, DI_MAX_FLUSH is less
                 * than smaller numbers
@@ -2608,6 +2616,7 @@ xlog_recover_inode_pass2(
                        goto error;
                }
        }
+
        /* Take the opportunity to reset the flush iteration count */
        dicp->di_flushiter = 0;
 
index b26dc4fb7ba8283f22b0d8f646a58a06fd00d510..61109f2609fc3ee446ec43e242875b28ae719344 100644 (file)
@@ -17,21 +17,12 @@ struct acpi_device;
 #define ACPI_VIDEO_DISPLAY_LEGACY_TV      0x0200
 
 #if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
-extern int __acpi_video_register(bool backlight_quirks);
-static inline int acpi_video_register(void)
-{
-       return __acpi_video_register(false);
-}
-static inline int acpi_video_register_with_quirks(void)
-{
-       return __acpi_video_register(true);
-}
+extern int acpi_video_register(void);
 extern void acpi_video_unregister(void);
 extern int acpi_video_get_edid(struct acpi_device *device, int type,
                               int device_id, void **edid);
 #else
 static inline int acpi_video_register(void) { return 0; }
-static inline int acpi_video_register_with_quirks(void) { return 0; }
 static inline void acpi_video_unregister(void) { return; }
 static inline int acpi_video_get_edid(struct acpi_device *device, int type,
                                      int device_id, void **edid)
index f5e1168c76473d3c1180cbcac654eac67ee2373f..d639049a613dfdb264650f8ee938836e6ed28e10 100644 (file)
@@ -84,12 +84,12 @@ static inline int drm_fixp2int(int64_t a)
        return ((s64)a) >> DRM_FIXED_POINT;
 }
 
-static inline s64 drm_fixp_msbset(int64_t a)
+static inline unsigned drm_fixp_msbset(int64_t a)
 {
        unsigned shift, sign = (a >> 63) & 1;
 
        for (shift = 62; shift > 0; --shift)
-               if ((a >> shift) != sign)
+               if (((a >> shift) & 1) != sign)
                        return shift;
 
        return 0;
@@ -100,9 +100,9 @@ static inline s64 drm_fixp_mul(s64 a, s64 b)
        unsigned shift = drm_fixp_msbset(a) + drm_fixp_msbset(b);
        s64 result;
 
-       if (shift > 63) {
-               shift = shift - 63;
-               a >>= shift >> 1;
+       if (shift > 61) {
+               shift = shift - 61;
+               a >>= (shift >> 1) + (shift & 1);
                b >>= shift >> 1;
        } else
                shift = 0;
@@ -120,7 +120,7 @@ static inline s64 drm_fixp_mul(s64 a, s64 b)
 
 static inline s64 drm_fixp_div(s64 a, s64 b)
 {
-       unsigned shift = 63 - drm_fixp_msbset(a);
+       unsigned shift = 62 - drm_fixp_msbset(a);
        s64 result;
 
        a <<= shift;
@@ -154,7 +154,7 @@ static inline s64 drm_fixp_exp(s64 x)
        }
 
        if (x < 0)
-               sum = drm_fixp_div(1, sum);
+               sum = drm_fixp_div(DRM_FIXED_ONE, sum);
 
        return sum;
 }
index 15e997fa78f24d9822defea3d2eb097b088580e7..4aa2b48cd15183e457a3eb96288dca81039cef37 100644 (file)
 #define VF610_CLK_GPU_SEL              145
 #define VF610_CLK_GPU_EN               146
 #define VF610_CLK_GPU2D                        147
-#define VF610_CLK_END                  148
+#define VF610_CLK_ENET0                        148
+#define VF610_CLK_ENET1                        149
+#define VF610_CLK_END                  150
 
 #endif /* __DT_BINDINGS_CLOCK_VF610_H */
index 469e0325e6f4b409fb07168da7b9adb1ddce5915..2fbc804e1a45cea943c9241309601f941abd5d14 100644 (file)
@@ -5,7 +5,7 @@
 #ifndef _DT_BINDINGS_PINCTRL_AM33XX_H
 #define _DT_BINDINGS_PINCTRL_AM33XX_H
 
-#include <include/dt-bindings/pinctrl/omap.h>
+#include <dt-bindings/pinctrl/omap.h>
 
 /* am33xx specific mux bit defines */
 #undef PULL_ENA
index 6ad72f92469c556368742f7c2d3301acfcfd5a0c..353ba256f3681e4f6ddd8b18b9feba61b1d98cec 100644 (file)
@@ -191,7 +191,6 @@ extern bool wmi_has_guid(const char *guid);
 #define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO                 0x0200
 #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR         0x0400
 #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO          0x0800
-#define ACPI_VIDEO_SKIP_BACKLIGHT                      0x1000
 
 #if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
 
index 297462b9f41acb7c95607daa36516b017e37be53..e9ac882868c0353f8f6bb7f2baba2a73c8602c41 100644 (file)
@@ -542,8 +542,7 @@ int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
 bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor);
 
 int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen);
-int task_cgroup_path_from_hierarchy(struct task_struct *task, int hierarchy_id,
-                                   char *buf, size_t buflen);
+int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen);
 
 int cgroup_task_count(const struct cgroup *cgrp);
 
index 6e7ec64b69ab4b7aa5ee7aacef569f633f0de296..b613ffd402d1bdd38747e45e26260b28a4355768 100644 (file)
@@ -1,86 +1,55 @@
-/* Add subsystem definitions of the form SUBSYS(<name>) in this
- * file. Surround each one by a line of comment markers so that
- * patches don't collide
+/*
+ * List of cgroup subsystems.
+ *
+ * DO NOT ADD ANY SUBSYSTEM WITHOUT EXPLICIT ACKS FROM CGROUP MAINTAINERS.
  */
-
-/* */
-
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_CPUSETS)
 SUBSYS(cpuset)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_CGROUP_DEBUG)
 SUBSYS(debug)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_CGROUP_SCHED)
 SUBSYS(cpu_cgroup)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_CGROUP_CPUACCT)
 SUBSYS(cpuacct)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_MEMCG)
 SUBSYS(mem_cgroup)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_CGROUP_DEVICE)
 SUBSYS(devices)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_CGROUP_FREEZER)
 SUBSYS(freezer)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_NET_CLS_CGROUP)
 SUBSYS(net_cls)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_BLK_CGROUP)
 SUBSYS(blkio)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_CGROUP_PERF)
 SUBSYS(perf)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_NETPRIO_CGROUP)
 SUBSYS(net_prio)
 #endif
 
-/* */
-
 #if IS_SUBSYS_ENABLED(CONFIG_CGROUP_HUGETLB)
 SUBSYS(hugetlb)
 #endif
-
-/* */
-
-#ifdef CONFIG_CGROUP_BCACHE
-SUBSYS(bcache)
-#endif
-
-/* */
+/*
+ * DO NOT ADD ANY SUBSYSTEM WITHOUT EXPLICIT ACKS FROM CGROUP MAINTAINERS.
+ */
index b3cb71f0d3b0d19b8c08e70348dee1bb5e5ba6ad..a9c96d865ee7144b577afc3752c0a1a94cd95e11 100644 (file)
@@ -3,10 +3,6 @@
 
 #include <linux/types.h>
 
-#define CRC_T10DIF_DIGEST_SIZE 2
-#define CRC_T10DIF_BLOCK_SIZE 1
-
-__u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer, size_t len);
 __u16 crc_t10dif(unsigned char const *, size_t);
 
 #endif
index 1b4d4ee1168ffb3b8ac90c42aaad073753573b1f..de7d74ab3de6df5237c5b117fa2dced482779842 100644 (file)
@@ -177,7 +177,11 @@ enum drbd_ret_code {
        ERR_NEED_APV_100        = 163,
        ERR_NEED_ALLOW_TWO_PRI  = 164,
        ERR_MD_UNCLEAN          = 165,
-
+       ERR_MD_LAYOUT_CONNECTED = 166,
+       ERR_MD_LAYOUT_TOO_BIG   = 167,
+       ERR_MD_LAYOUT_TOO_SMALL = 168,
+       ERR_MD_LAYOUT_NO_FIT    = 169,
+       ERR_IMPLICIT_SHRINK     = 170,
        /* insert new ones above this line */
        AFTER_LAST_ERR_CODE
 };
index d0d8fac8a6e4ffa77141b038f898537f31ed28f0..e8c44572b8cba2d244d87c528d3e683173d5fd1e 100644 (file)
@@ -181,6 +181,8 @@ GENL_struct(DRBD_NLA_RESIZE_PARMS, 7, resize_parms,
        __u64_field(1, DRBD_GENLA_F_MANDATORY,  resize_size)
        __flg_field(2, DRBD_GENLA_F_MANDATORY,  resize_force)
        __flg_field(3, DRBD_GENLA_F_MANDATORY,  no_resync)
+       __u32_field_def(4, 0 /* OPTIONAL */, al_stripes, DRBD_AL_STRIPES_DEF)
+       __u32_field_def(5, 0 /* OPTIONAL */, al_stripe_size, DRBD_AL_STRIPE_SIZE_DEF)
 )
 
 GENL_struct(DRBD_NLA_STATE_INFO, 8, state_info,
index 1fedf2b17cc801805581a185638fe97184be27b3..17e50bb00521362f0840eae9e79da52e2b34d139 100644 (file)
 #define DRBD_ALWAYS_ASBP_DEF   0
 #define DRBD_USE_RLE_DEF       1
 
+#define DRBD_AL_STRIPES_MIN     1
+#define DRBD_AL_STRIPES_MAX     1024
+#define DRBD_AL_STRIPES_DEF     1
+#define DRBD_AL_STRIPES_SCALE   '1'
+
+#define DRBD_AL_STRIPE_SIZE_MIN   4
+#define DRBD_AL_STRIPE_SIZE_MAX   16777216
+#define DRBD_AL_STRIPE_SIZE_DEF   32
+#define DRBD_AL_STRIPE_SIZE_SCALE 'k' /* kilobytes */
 #endif
index 0b763276f6199a255d304b572e0c414c90252056..5c6d7fbaf89e00dbed2d9cc418318980f7de3d2b 100644 (file)
@@ -622,7 +622,7 @@ struct edac_raw_error_desc {
  */
 struct mem_ctl_info {
        struct device                   dev;
-       struct bus_type                 bus;
+       struct bus_type                 *bus;
 
        struct list_head link;  /* for global list of mem_ctl_info structs */
 
@@ -742,4 +742,9 @@ struct mem_ctl_info {
 #endif
 };
 
+/*
+ * Maximum number of memory controllers in the coherent fabric.
+ */
+#define EDAC_MAX_MCS   16
+
 #endif
index 3b0e820375ab90c2e0f9a05ffaa94f7a36f76abd..5d7782e42b8f22f81df12652348ff9a21aebc7e4 100644 (file)
@@ -436,6 +436,7 @@ struct fw_iso_context {
        int type;
        int channel;
        int speed;
+       bool drop_overflow_headers;
        size_t header_size;
        union {
                fw_iso_callback_t sc;
index 4372658c73ae5eddd3dd6570d4dfac8c5d8825c8..120d57a1c3a5dcb452a75d4fd21a6d338b128a0d 100644 (file)
@@ -78,6 +78,11 @@ struct trace_iterator {
        /* trace_seq for __print_flags() and __print_symbolic() etc. */
        struct trace_seq        tmp_seq;
 
+       cpumask_var_t           started;
+
+       /* it's true when current open file is snapshot */
+       bool                    snapshot;
+
        /* The below is zeroed out in pipe_read */
        struct trace_seq        seq;
        struct trace_entry      *ent;
@@ -90,10 +95,7 @@ struct trace_iterator {
        loff_t                  pos;
        long                    idx;
 
-       cpumask_var_t           started;
-
-       /* it's true when current open file is snapshot */
-       bool                    snapshot;
+       /* All new field here will be zeroed out in pipe_read */
 };
 
 enum trace_iter_flags {
@@ -332,7 +334,7 @@ extern int trace_define_field(struct ftrace_event_call *call, const char *type,
                              const char *name, int offset, int size,
                              int is_signed, int filter_type);
 extern int trace_add_event_call(struct ftrace_event_call *call);
-extern void trace_remove_event_call(struct ftrace_event_call *call);
+extern int trace_remove_event_call(struct ftrace_event_call *call);
 
 #define is_signed_type(type)   (((type)(-1)) < (type)1)
 
index 3bef14c6586bc9d7d875e6579352a62e53e13c6a..482ad2d84a32dae333c74cccb2d1394b247d5ae8 100644 (file)
@@ -629,7 +629,7 @@ extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode);
 static inline void tracing_start(void) { }
 static inline void tracing_stop(void) { }
 static inline void ftrace_off_permanent(void) { }
-static inline void trace_dump_stack(void) { }
+static inline void trace_dump_stack(int skip) { }
 
 static inline void tracing_on(void) { }
 static inline void tracing_off(void) { }
index dab34a1deb2c156ecdb8a67328d6cfbb6b0d5c8d..b6bdcd66c07d2e758ba677f9c9c1796ada542bc8 100644 (file)
 #define IMX6Q_GPR1_EXC_MON_MASK                        BIT(22)
 #define IMX6Q_GPR1_EXC_MON_OKAY                        0x0
 #define IMX6Q_GPR1_EXC_MON_SLVE                        BIT(22)
-#define IMX6Q_GPR1_MIPI_IPU2_SEL_MASK          BIT(21)
-#define IMX6Q_GPR1_MIPI_IPU2_SEL_GASKET                0x0
-#define IMX6Q_GPR1_MIPI_IPU2_SEL_IOMUX         BIT(21)
-#define IMX6Q_GPR1_MIPI_IPU1_MUX_MASK          BIT(20)
-#define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET                0x0
-#define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX         BIT(20)
-#define IMX6Q_GPR1_MIPI_IPU2_MUX_MASK          BIT(19)
+#define IMX6Q_GPR1_ENET_CLK_SEL_MASK           BIT(21)
+#define IMX6Q_GPR1_ENET_CLK_SEL_PAD            0
+#define IMX6Q_GPR1_ENET_CLK_SEL_ANATOP         BIT(21)
+#define IMX6Q_GPR1_MIPI_IPU2_MUX_MASK          BIT(20)
 #define IMX6Q_GPR1_MIPI_IPU2_MUX_GASKET                0x0
-#define IMX6Q_GPR1_MIPI_IPU2_MUX_IOMUX         BIT(19)
+#define IMX6Q_GPR1_MIPI_IPU2_MUX_IOMUX         BIT(20)
+#define IMX6Q_GPR1_MIPI_IPU1_MUX_MASK          BIT(19)
+#define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET                0x0
+#define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX         BIT(19)
 #define IMX6Q_GPR1_PCIE_TEST_PD                        BIT(18)
 #define IMX6Q_GPR1_IPU_VPU_MUX_MASK            BIT(17)
 #define IMX6Q_GPR1_IPU_VPU_MUX_IPU1            0x0
 #define IMX6Q_GPR13_CAN2_STOP_REQ              BIT(29)
 #define IMX6Q_GPR13_CAN1_STOP_REQ              BIT(28)
 #define IMX6Q_GPR13_ENET_STOP_REQ              BIT(27)
-#define IMX6Q_GPR13_SATA_PHY_8_MASK            (0x7 << 24)
-#define IMX6Q_GPR13_SATA_PHY_8_0_5_DB          (0x0 << 24)
-#define IMX6Q_GPR13_SATA_PHY_8_1_0_DB          (0x1 << 24)
-#define IMX6Q_GPR13_SATA_PHY_8_1_5_DB          (0x2 << 24)
-#define IMX6Q_GPR13_SATA_PHY_8_2_0_DB          (0x3 << 24)
-#define IMX6Q_GPR13_SATA_PHY_8_2_5_DB          (0x4 << 24)
-#define IMX6Q_GPR13_SATA_PHY_8_3_0_DB          (0x5 << 24)
-#define IMX6Q_GPR13_SATA_PHY_8_3_5_DB          (0x6 << 24)
-#define IMX6Q_GPR13_SATA_PHY_8_4_0_DB          (0x7 << 24)
-#define IMX6Q_GPR13_SATA_PHY_7_MASK            (0x1f << 19)
-#define IMX6Q_GPR13_SATA_PHY_7_SATA1I          (0x10 << 19)
-#define IMX6Q_GPR13_SATA_PHY_7_SATA1M          (0x10 << 19)
-#define IMX6Q_GPR13_SATA_PHY_7_SATA1X          (0x1a << 19)
-#define IMX6Q_GPR13_SATA_PHY_7_SATA2I          (0x12 << 19)
-#define IMX6Q_GPR13_SATA_PHY_7_SATA2M          (0x12 << 19)
-#define IMX6Q_GPR13_SATA_PHY_7_SATA2X          (0x1a << 19)
-#define IMX6Q_GPR13_SATA_PHY_6_MASK            (0x7 << 16)
-#define IMX6Q_GPR13_SATA_SPEED_MASK            BIT(15)
-#define IMX6Q_GPR13_SATA_SPEED_1P5G            0x0
-#define IMX6Q_GPR13_SATA_SPEED_3P0G            BIT(15)
-#define IMX6Q_GPR13_SATA_PHY_5                 BIT(14)
-#define IMX6Q_GPR13_SATA_PHY_4_MASK            (0x7 << 11)
-#define IMX6Q_GPR13_SATA_PHY_4_16_16           (0x0 << 11)
-#define IMX6Q_GPR13_SATA_PHY_4_14_16           (0x1 << 11)
-#define IMX6Q_GPR13_SATA_PHY_4_12_16           (0x2 << 11)
-#define IMX6Q_GPR13_SATA_PHY_4_10_16           (0x3 << 11)
-#define IMX6Q_GPR13_SATA_PHY_4_9_16            (0x4 << 11)
-#define IMX6Q_GPR13_SATA_PHY_4_8_16            (0x5 << 11)
-#define IMX6Q_GPR13_SATA_PHY_3_MASK            (0xf << 7)
-#define IMX6Q_GPR13_SATA_PHY_3_OFF             0x7
-#define IMX6Q_GPR13_SATA_PHY_2_MASK            (0x1f << 2)
-#define IMX6Q_GPR13_SATA_PHY_2_OFF             0x2
-#define IMX6Q_GPR13_SATA_PHY_1_MASK            (0x3 << 0)
-#define IMX6Q_GPR13_SATA_PHY_1_FAST            (0x0 << 0)
-#define IMX6Q_GPR13_SATA_PHY_1_MED             (0x1 << 0)
-#define IMX6Q_GPR13_SATA_PHY_1_SLOW            (0x2 << 0)
-
+#define IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK                (0x7 << 24)
+#define IMX6Q_GPR13_SATA_RX_EQ_VAL_0_5_DB      (0x0 << 24)
+#define IMX6Q_GPR13_SATA_RX_EQ_VAL_1_0_DB      (0x1 << 24)
+#define IMX6Q_GPR13_SATA_RX_EQ_VAL_1_5_DB      (0x2 << 24)
+#define IMX6Q_GPR13_SATA_RX_EQ_VAL_2_0_DB      (0x3 << 24)
+#define IMX6Q_GPR13_SATA_RX_EQ_VAL_2_5_DB      (0x4 << 24)
+#define IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB      (0x5 << 24)
+#define IMX6Q_GPR13_SATA_RX_EQ_VAL_3_5_DB      (0x6 << 24)
+#define IMX6Q_GPR13_SATA_RX_EQ_VAL_4_0_DB      (0x7 << 24)
+#define IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK       (0x1f << 19)
+#define IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA1I     (0x10 << 19)
+#define IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA1M     (0x10 << 19)
+#define IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA1X     (0x1a << 19)
+#define IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2I     (0x12 << 19)
+#define IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M     (0x12 << 19)
+#define IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2X     (0x1a << 19)
+#define IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK     (0x7 << 16)
+#define IMX6Q_GPR13_SATA_RX_DPLL_MODE_1P_1F    (0x0 << 16)
+#define IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_2F    (0x1 << 16)
+#define IMX6Q_GPR13_SATA_RX_DPLL_MODE_1P_4F    (0x2 << 16)
+#define IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F    (0x3 << 16)
+#define IMX6Q_GPR13_SATA_SPD_MODE_MASK         BIT(15)
+#define IMX6Q_GPR13_SATA_SPD_MODE_1P5G         0x0
+#define IMX6Q_GPR13_SATA_SPD_MODE_3P0G         BIT(15)
+#define IMX6Q_GPR13_SATA_MPLL_SS_EN            BIT(14)
+#define IMX6Q_GPR13_SATA_TX_ATTEN_MASK         (0x7 << 11)
+#define IMX6Q_GPR13_SATA_TX_ATTEN_16_16                (0x0 << 11)
+#define IMX6Q_GPR13_SATA_TX_ATTEN_14_16                (0x1 << 11)
+#define IMX6Q_GPR13_SATA_TX_ATTEN_12_16                (0x2 << 11)
+#define IMX6Q_GPR13_SATA_TX_ATTEN_10_16                (0x3 << 11)
+#define IMX6Q_GPR13_SATA_TX_ATTEN_9_16         (0x4 << 11)
+#define IMX6Q_GPR13_SATA_TX_ATTEN_8_16         (0x5 << 11)
+#define IMX6Q_GPR13_SATA_TX_BOOST_MASK         (0xf << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_0_00_DB      (0x0 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_0_37_DB      (0x1 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_0_74_DB      (0x2 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB      (0x3 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB      (0x4 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB      (0x5 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB      (0x6 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB      (0x7 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB      (0x8 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB      (0x9 << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB      (0xa << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB      (0xb << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB      (0xc << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB      (0xd << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB      (0xe << 7)
+#define IMX6Q_GPR13_SATA_TX_BOOST_5_75_DB      (0xf << 7)
+#define IMX6Q_GPR13_SATA_TX_LVL_MASK           (0x1f << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_0_937_V                (0x00 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_0_947_V                (0x01 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_0_957_V                (0x02 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_0_966_V                (0x03 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_0_976_V                (0x04 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_0_986_V                (0x05 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_0_996_V                (0x06 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_005_V                (0x07 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_015_V                (0x08 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_025_V                (0x09 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_035_V                (0x0a << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_045_V                (0x0b << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_054_V                (0x0c << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_064_V                (0x0d << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_074_V                (0x0e << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_084_V                (0x0f << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_094_V                (0x10 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_104_V                (0x11 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_113_V                (0x12 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_123_V                (0x13 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_133_V                (0x14 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_143_V                (0x15 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_152_V                (0x16 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_162_V                (0x17 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_172_V                (0x18 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_182_V                (0x19 << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_191_V                (0x1a << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_201_V                (0x1b << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_211_V                (0x1c << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_221_V                (0x1d << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_230_V                (0x1e << 2)
+#define IMX6Q_GPR13_SATA_TX_LVL_1_240_V                (0x1f << 2)
+#define IMX6Q_GPR13_SATA_MPLL_CLK_EN           BIT(1)
+#define IMX6Q_GPR13_SATA_TX_EDGE_RATE          BIT(0)
 #endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */
index 8de8d8f22384b9abcd83ce0f76898c7afdf7ded9..737685e9e852e91fd93ccf142500c33773f42e71 100644 (file)
@@ -690,6 +690,26 @@ struct mlx5_query_cq_mbox_out {
        __be64                  pas[0];
 };
 
+struct mlx5_enable_hca_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_enable_hca_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_disable_hca_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_disable_hca_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
 struct mlx5_eq_context {
        u8                      status;
        u8                      ec_oi;
index f22e4419839b372b9cf6b6535b27cacf721ba9fc..2aa258b0ced1449b8281f6728d6f243d0c72d15f 100644 (file)
@@ -101,6 +101,8 @@ enum {
        MLX5_CMD_OP_QUERY_ADAPTER               = 0x101,
        MLX5_CMD_OP_INIT_HCA                    = 0x102,
        MLX5_CMD_OP_TEARDOWN_HCA                = 0x103,
+       MLX5_CMD_OP_ENABLE_HCA                  = 0x104,
+       MLX5_CMD_OP_DISABLE_HCA                 = 0x105,
        MLX5_CMD_OP_QUERY_PAGES                 = 0x107,
        MLX5_CMD_OP_MANAGE_PAGES                = 0x108,
        MLX5_CMD_OP_SET_HCA_CAP                 = 0x109,
@@ -690,7 +692,7 @@ int mlx5_pagealloc_start(struct mlx5_core_dev *dev);
 void mlx5_pagealloc_stop(struct mlx5_core_dev *dev);
 void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
                                 s16 npages);
-int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev);
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot);
 int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev);
 void mlx5_register_debugfs(void);
 void mlx5_unregister_debugfs(void);
index b62d4af6c667c27bbbd3620fde9813c9d6b529b8..45e921401b067b68c9912f82af1c19a1a8c6d048 100644 (file)
@@ -361,7 +361,8 @@ struct ssb_device_id {
        __u16   vendor;
        __u16   coreid;
        __u8    revision;
-};
+       __u8    __pad;
+} __attribute__((packed, aligned(2)));
 #define SSB_DEVICE(_vendor, _coreid, _revision)  \
        { .vendor = _vendor, .coreid = _coreid, .revision = _revision, }
 #define SSB_DEVTABLE_END  \
@@ -377,7 +378,7 @@ struct bcma_device_id {
        __u16   id;
        __u8    rev;
        __u8    class;
-};
+} __attribute__((packed,aligned(2)));
 #define BCMA_CORE(_manuf, _id, _rev, _class)  \
        { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, }
 #define BCMA_CORETABLE_END  \
index 0741a1e919a542c53e50003560d01ed06322e658..9a4156845e9348cb4fe4b803a64041d1db5de377 100644 (file)
@@ -973,7 +973,7 @@ struct net_device_ops {
                                                     gfp_t gfp);
        void                    (*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        int                     (*ndo_busy_poll)(struct napi_struct *dev);
 #endif
        int                     (*ndo_set_vf_mac)(struct net_device *dev,
index 9eb515bb799d071bdad4c342fa61b00e32072588..1706b3597ce00c10776d8c8fbf8e0c6067afcb6a 100644 (file)
@@ -12,7 +12,7 @@ struct pxamci_platform_data {
        unsigned long detect_delay_ms;          /* delay in millisecond before detecting cards after interrupt */
        int (*init)(struct device *, irq_handler_t , void *);
        int (*get_ro)(struct device *);
-       void (*setpower)(struct device *, unsigned int);
+       int (*setpower)(struct device *, unsigned int);
        void (*exit)(struct device *, void *);
        int gpio_card_detect;                   /* gpio detecting card insertion */
        int gpio_card_ro;                       /* gpio detecting read only toggle */
index 50d04b92cedaf900532f72d1acef35d04d7ecb69..d722490da030c5906d991b7c76f8dc178edadee8 100644 (file)
@@ -1628,6 +1628,7 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut,
 #define PF_MEMPOLICY   0x10000000      /* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER        0x20000000      /* Thread belongs to the rt mutex tester */
 #define PF_FREEZER_SKIP        0x40000000      /* Freezer should not count it as freezable */
+#define PF_SUSPEND_TASK 0x80000000      /* this thread called freeze_processes and should not be frozen */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
index 382cf710ca9aa11b001d874efa516e229f5b8254..5b1c9848124cb8c366f95a0dbfaa6d54d64d1927 100644 (file)
@@ -124,6 +124,10 @@ void shdma_chan_remove(struct shdma_chan *schan);
 int shdma_init(struct device *dev, struct shdma_dev *sdev,
                    int chan_num);
 void shdma_cleanup(struct shdma_dev *sdev);
+#if IS_ENABLED(CONFIG_SH_DMAE_BASE)
 bool shdma_chan_filter(struct dma_chan *chan, void *arg);
+#else
+#define shdma_chan_filter NULL
+#endif
 
 #endif
index 5afefa01a13c892e1fe9eb7ce6fc3f047e5880ba..3b71a4e8364200d85afe94b120e09e74edf35d32 100644 (file)
@@ -501,7 +501,7 @@ struct sk_buff {
        /* 7/9 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
-#if defined CONFIG_NET_DMA || defined CONFIG_NET_LL_RX_POLL
+#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
        union {
                unsigned int    napi_id;
                dma_cookie_t    dma_cookie;
index 9180f4b85e6deedd827fa071add91940c3ac48e5..62bd8b72873c0bed1702d41a2a8982831d01564b 100644 (file)
@@ -174,10 +174,4 @@ static inline void tick_nohz_task_switch(struct task_struct *tsk) { }
 #endif
 
 
-# ifdef CONFIG_CPU_IDLE_GOV_MENU
-extern void menu_hrtimer_cancel(void);
-# else
-static inline void menu_hrtimer_cancel(void) {}
-# endif /* CONFIG_CPU_IDLE_GOV_MENU */
-
 #endif
index a232b7ece1f63c687a2f50da506c9e70ec33555e..0eec2689b9556bee0c3aae530a3035ccbbe29d2a 100644 (file)
@@ -367,17 +367,6 @@ struct usb_bus {
 
 /* ----------------------------------------------------------------------- */
 
-/* This is arbitrary.
- * From USB 2.0 spec Table 11-13, offset 7, a hub can
- * have up to 255 ports. The most yet reported is 10.
- *
- * Current Wireless USB host hardware (Intel i1480 for example) allows
- * up to 22 devices to connect. Upcoming hardware might raise that
- * limit. Because the arrays need to add a bit for hub status data, we
- * do 31, so plus one evens out to four bytes.
- */
-#define USB_MAXCHILDREN                (31)
-
 struct usb_tt;
 
 enum usb_device_removable {
index 76be077340ea5c7c4d96f1299bea48b9aa40a98d..7dc17e2456de141ef3241a73af02fbec9b9c1ee5 100644 (file)
@@ -12,7 +12,7 @@ struct vmpressure {
        unsigned long scanned;
        unsigned long reclaimed;
        /* The lock is used to keep the scanned/reclaimed above in sync. */
-       struct mutex sr_lock;
+       struct spinlock sr_lock;
 
        /* The list of vmpressure_event structs. */
        struct list_head events;
@@ -30,6 +30,7 @@ extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
 extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio);
 
 extern void vmpressure_init(struct vmpressure *vmpr);
+extern void vmpressure_cleanup(struct vmpressure *vmpr);
 extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg);
 extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr);
 extern struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css);
index a14339c2985ff0f24e259861fa39dcf335f601b5..f18b91966d3de718528ae3d44887e937514718fc 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/netdevice.h>
 #include <net/ip.h>
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 
 struct napi_struct;
 extern unsigned int sysctl_net_busy_read __read_mostly;
@@ -146,7 +146,7 @@ static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb)
        sk->sk_napi_id = skb->napi_id;
 }
 
-#else /* CONFIG_NET_LL_RX_POLL */
+#else /* CONFIG_NET_RX_BUSY_POLL */
 static inline unsigned long net_busy_loop_on(void)
 {
        return 0;
@@ -181,5 +181,10 @@ static inline bool busy_loop_timeout(unsigned long end_time)
        return true;
 }
 
-#endif /* CONFIG_NET_LL_RX_POLL */
+static inline bool sk_busy_loop(struct sock *sk, int nonblock)
+{
+       return false;
+}
+
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 #endif /* _LINUX_NET_BUSY_POLL_H */
index 2a601e7da1bfc8b97490075531975dcdfebc8370..48ec25a7fcb60a09a2c323c70221a31853a82261 100644 (file)
@@ -300,7 +300,7 @@ extern void                 inet6_rt_notify(int event, struct rt6_info *rt,
                                                struct nl_info *info);
 
 extern void                    fib6_run_gc(unsigned long expires,
-                                           struct net *net);
+                                           struct net *net, bool force);
 
 extern void                    fib6_gc_cleanup(void);
 
index 949d77528f2f9cd87839029b424bded13cb52136..6fea32340ae8a5c697a18b7909c9b44d86cddeaf 100644 (file)
@@ -119,7 +119,7 @@ extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
  * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may
  * also need a pad of 2.
  */
-static int ndisc_addr_option_pad(unsigned short type)
+static inline int ndisc_addr_option_pad(unsigned short type)
 {
        switch (type) {
        case ARPHRD_INFINIBAND: return 2;
index 0af851c3b038186357b8576ec4025bb5193ee1fd..b64b7bce4b94302a8edb923bc54bc1e4b2c8b997 100644 (file)
@@ -59,7 +59,7 @@ struct nfc_hci_ops {
                              struct nfc_target *target);
        int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
                              struct sk_buff *skb);
-       int (*fw_upload)(struct nfc_hci_dev *hdev, const char *firmware_name);
+       int (*fw_download)(struct nfc_hci_dev *hdev, const char *firmware_name);
        int (*discover_se)(struct nfc_hci_dev *dev);
        int (*enable_se)(struct nfc_hci_dev *dev, u32 se_idx);
        int (*disable_se)(struct nfc_hci_dev *dev, u32 se_idx);
index 0e353f1658bb46e638b287ee2bbfdbd33b37a584..5f286b726bb691b3f62e3b6800870ea940a3d65f 100644 (file)
@@ -68,7 +68,7 @@ struct nfc_ops {
                             void *cb_context);
        int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
        int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
-       int (*fw_upload)(struct nfc_dev *dev, const char *firmware_name);
+       int (*fw_download)(struct nfc_dev *dev, const char *firmware_name);
 
        /* Secure Element API */
        int (*discover_se)(struct nfc_dev *dev);
@@ -127,7 +127,7 @@ struct nfc_dev {
        int targets_generation;
        struct device dev;
        bool dev_up;
-       bool fw_upload_in_progress;
+       bool fw_download_in_progress;
        u8 rf_mode;
        bool polling;
        struct nfc_target *active_target;
index 95a5a2c6925ab0745b563f7f04663721465460e7..31d5cfbb51ec9f52b57c0c339b9b5e92804701cb 100644 (file)
@@ -327,7 +327,7 @@ struct sock {
 #ifdef CONFIG_RPS
        __u32                   sk_rxhash;
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int            sk_napi_id;
        unsigned int            sk_ll_usec;
 #endif
index 3cc5a0b278c30c2045152d358254d11f109c6a0d..5ebda976ea93bd52c6ca80194d723e49e94c1558 100644 (file)
@@ -9,9 +9,7 @@
 struct search;
 
 DECLARE_EVENT_CLASS(bcache_request,
-
        TP_PROTO(struct search *s, struct bio *bio),
-
        TP_ARGS(s, bio),
 
        TP_STRUCT__entry(
@@ -22,7 +20,6 @@ DECLARE_EVENT_CLASS(bcache_request,
                __field(dev_t,          orig_sector             )
                __field(unsigned int,   nr_sector               )
                __array(char,           rwbs,   6               )
-               __array(char,           comm,   TASK_COMM_LEN   )
        ),
 
        TP_fast_assign(
@@ -33,36 +30,66 @@ DECLARE_EVENT_CLASS(bcache_request,
                __entry->orig_sector    = bio->bi_sector - 16;
                __entry->nr_sector      = bio->bi_size >> 9;
                blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
-               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
 
-       TP_printk("%d,%d %s %llu + %u [%s] (from %d,%d @ %llu)",
+       TP_printk("%d,%d %s %llu + %u (from %d,%d @ %llu)",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
-                 __entry->rwbs,
-                 (unsigned long long)__entry->sector,
-                 __entry->nr_sector, __entry->comm,
-                 __entry->orig_major, __entry->orig_minor,
+                 __entry->rwbs, (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->orig_major, __entry->orig_minor,
                  (unsigned long long)__entry->orig_sector)
 );
 
-DEFINE_EVENT(bcache_request, bcache_request_start,
+DECLARE_EVENT_CLASS(bkey,
+       TP_PROTO(struct bkey *k),
+       TP_ARGS(k),
 
-       TP_PROTO(struct search *s, struct bio *bio),
+       TP_STRUCT__entry(
+               __field(u32,    size                            )
+               __field(u32,    inode                           )
+               __field(u64,    offset                          )
+               __field(bool,   dirty                           )
+       ),
 
-       TP_ARGS(s, bio)
+       TP_fast_assign(
+               __entry->inode  = KEY_INODE(k);
+               __entry->offset = KEY_OFFSET(k);
+               __entry->size   = KEY_SIZE(k);
+               __entry->dirty  = KEY_DIRTY(k);
+       ),
+
+       TP_printk("%u:%llu len %u dirty %u", __entry->inode,
+                 __entry->offset, __entry->size, __entry->dirty)
 );
 
-DEFINE_EVENT(bcache_request, bcache_request_end,
+DECLARE_EVENT_CLASS(btree_node,
+       TP_PROTO(struct btree *b),
+       TP_ARGS(b),
+
+       TP_STRUCT__entry(
+               __field(size_t,         bucket                  )
+       ),
 
+       TP_fast_assign(
+               __entry->bucket = PTR_BUCKET_NR(b->c, &b->key, 0);
+       ),
+
+       TP_printk("bucket %zu", __entry->bucket)
+);
+
+/* request.c */
+
+DEFINE_EVENT(bcache_request, bcache_request_start,
        TP_PROTO(struct search *s, struct bio *bio),
+       TP_ARGS(s, bio)
+);
 
+DEFINE_EVENT(bcache_request, bcache_request_end,
+       TP_PROTO(struct search *s, struct bio *bio),
        TP_ARGS(s, bio)
 );
 
 DECLARE_EVENT_CLASS(bcache_bio,
-
        TP_PROTO(struct bio *bio),
-
        TP_ARGS(bio),
 
        TP_STRUCT__entry(
@@ -70,7 +97,6 @@ DECLARE_EVENT_CLASS(bcache_bio,
                __field(sector_t,       sector                  )
                __field(unsigned int,   nr_sector               )
                __array(char,           rwbs,   6               )
-               __array(char,           comm,   TASK_COMM_LEN   )
        ),
 
        TP_fast_assign(
@@ -78,191 +104,328 @@ DECLARE_EVENT_CLASS(bcache_bio,
                __entry->sector         = bio->bi_sector;
                __entry->nr_sector      = bio->bi_size >> 9;
                blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
-               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
 
-       TP_printk("%d,%d  %s %llu + %u [%s]",
-                 MAJOR(__entry->dev), MINOR(__entry->dev),
-                 __entry->rwbs,
-                 (unsigned long long)__entry->sector,
-                 __entry->nr_sector, __entry->comm)
+       TP_printk("%d,%d  %s %llu + %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector, __entry->nr_sector)
 );
 
-
-DEFINE_EVENT(bcache_bio, bcache_passthrough,
-
+DEFINE_EVENT(bcache_bio, bcache_bypass_sequential,
        TP_PROTO(struct bio *bio),
+       TP_ARGS(bio)
+);
 
+DEFINE_EVENT(bcache_bio, bcache_bypass_congested,
+       TP_PROTO(struct bio *bio),
        TP_ARGS(bio)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_cache_hit,
+TRACE_EVENT(bcache_read,
+       TP_PROTO(struct bio *bio, bool hit, bool bypass),
+       TP_ARGS(bio, hit, bypass),
 
-       TP_PROTO(struct bio *bio),
+       TP_STRUCT__entry(
+               __field(dev_t,          dev                     )
+               __field(sector_t,       sector                  )
+               __field(unsigned int,   nr_sector               )
+               __array(char,           rwbs,   6               )
+               __field(bool,           cache_hit               )
+               __field(bool,           bypass                  )
+       ),
 
-       TP_ARGS(bio)
+       TP_fast_assign(
+               __entry->dev            = bio->bi_bdev->bd_dev;
+               __entry->sector         = bio->bi_sector;
+               __entry->nr_sector      = bio->bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               __entry->cache_hit = hit;
+               __entry->bypass = bypass;
+       ),
+
+       TP_printk("%d,%d  %s %llu + %u hit %u bypass %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->rwbs, (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->cache_hit, __entry->bypass)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_cache_miss,
+TRACE_EVENT(bcache_write,
+       TP_PROTO(struct bio *bio, bool writeback, bool bypass),
+       TP_ARGS(bio, writeback, bypass),
 
-       TP_PROTO(struct bio *bio),
+       TP_STRUCT__entry(
+               __field(dev_t,          dev                     )
+               __field(sector_t,       sector                  )
+               __field(unsigned int,   nr_sector               )
+               __array(char,           rwbs,   6               )
+               __field(bool,           writeback               )
+               __field(bool,           bypass                  )
+       ),
 
-       TP_ARGS(bio)
+       TP_fast_assign(
+               __entry->dev            = bio->bi_bdev->bd_dev;
+               __entry->sector         = bio->bi_sector;
+               __entry->nr_sector      = bio->bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               __entry->writeback = writeback;
+               __entry->bypass = bypass;
+       ),
+
+       TP_printk("%d,%d  %s %llu + %u hit %u bypass %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->rwbs, (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->writeback, __entry->bypass)
 );
 
 DEFINE_EVENT(bcache_bio, bcache_read_retry,
-
        TP_PROTO(struct bio *bio),
-
        TP_ARGS(bio)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_writethrough,
+DEFINE_EVENT(bkey, bcache_cache_insert,
+       TP_PROTO(struct bkey *k),
+       TP_ARGS(k)
+);
 
-       TP_PROTO(struct bio *bio),
+/* Journal */
 
-       TP_ARGS(bio)
-);
+DECLARE_EVENT_CLASS(cache_set,
+       TP_PROTO(struct cache_set *c),
+       TP_ARGS(c),
 
-DEFINE_EVENT(bcache_bio, bcache_writeback,
+       TP_STRUCT__entry(
+               __array(char,           uuid,   16 )
+       ),
 
-       TP_PROTO(struct bio *bio),
+       TP_fast_assign(
+               memcpy(__entry->uuid, c->sb.set_uuid, 16);
+       ),
 
-       TP_ARGS(bio)
+       TP_printk("%pU", __entry->uuid)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_write_skip,
-
-       TP_PROTO(struct bio *bio),
+DEFINE_EVENT(bkey, bcache_journal_replay_key,
+       TP_PROTO(struct bkey *k),
+       TP_ARGS(k)
+);
 
-       TP_ARGS(bio)
+DEFINE_EVENT(cache_set, bcache_journal_full,
+       TP_PROTO(struct cache_set *c),
+       TP_ARGS(c)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_btree_read,
+DEFINE_EVENT(cache_set, bcache_journal_entry_full,
+       TP_PROTO(struct cache_set *c),
+       TP_ARGS(c)
+);
 
+DEFINE_EVENT(bcache_bio, bcache_journal_write,
        TP_PROTO(struct bio *bio),
-
        TP_ARGS(bio)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_btree_write,
+/* Btree */
 
-       TP_PROTO(struct bio *bio),
+DEFINE_EVENT(cache_set, bcache_btree_cache_cannibalize,
+       TP_PROTO(struct cache_set *c),
+       TP_ARGS(c)
+);
 
-       TP_ARGS(bio)
+DEFINE_EVENT(btree_node, bcache_btree_read,
+       TP_PROTO(struct btree *b),
+       TP_ARGS(b)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_write_dirty,
+TRACE_EVENT(bcache_btree_write,
+       TP_PROTO(struct btree *b),
+       TP_ARGS(b),
 
-       TP_PROTO(struct bio *bio),
+       TP_STRUCT__entry(
+               __field(size_t,         bucket                  )
+               __field(unsigned,       block                   )
+               __field(unsigned,       keys                    )
+       ),
 
-       TP_ARGS(bio)
+       TP_fast_assign(
+               __entry->bucket = PTR_BUCKET_NR(b->c, &b->key, 0);
+               __entry->block  = b->written;
+               __entry->keys   = b->sets[b->nsets].data->keys;
+       ),
+
+       TP_printk("bucket %zu", __entry->bucket)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_read_dirty,
+DEFINE_EVENT(btree_node, bcache_btree_node_alloc,
+       TP_PROTO(struct btree *b),
+       TP_ARGS(b)
+);
 
-       TP_PROTO(struct bio *bio),
+DEFINE_EVENT(btree_node, bcache_btree_node_alloc_fail,
+       TP_PROTO(struct btree *b),
+       TP_ARGS(b)
+);
 
-       TP_ARGS(bio)
+DEFINE_EVENT(btree_node, bcache_btree_node_free,
+       TP_PROTO(struct btree *b),
+       TP_ARGS(b)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_write_moving,
+TRACE_EVENT(bcache_btree_gc_coalesce,
+       TP_PROTO(unsigned nodes),
+       TP_ARGS(nodes),
 
-       TP_PROTO(struct bio *bio),
+       TP_STRUCT__entry(
+               __field(unsigned,       nodes                   )
+       ),
 
-       TP_ARGS(bio)
+       TP_fast_assign(
+               __entry->nodes  = nodes;
+       ),
+
+       TP_printk("coalesced %u nodes", __entry->nodes)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_read_moving,
+DEFINE_EVENT(cache_set, bcache_gc_start,
+       TP_PROTO(struct cache_set *c),
+       TP_ARGS(c)
+);
 
-       TP_PROTO(struct bio *bio),
+DEFINE_EVENT(cache_set, bcache_gc_end,
+       TP_PROTO(struct cache_set *c),
+       TP_ARGS(c)
+);
 
-       TP_ARGS(bio)
+DEFINE_EVENT(bkey, bcache_gc_copy,
+       TP_PROTO(struct bkey *k),
+       TP_ARGS(k)
 );
 
-DEFINE_EVENT(bcache_bio, bcache_journal_write,
+DEFINE_EVENT(bkey, bcache_gc_copy_collision,
+       TP_PROTO(struct bkey *k),
+       TP_ARGS(k)
+);
 
-       TP_PROTO(struct bio *bio),
+TRACE_EVENT(bcache_btree_insert_key,
+       TP_PROTO(struct btree *b, struct bkey *k, unsigned op, unsigned status),
+       TP_ARGS(b, k, op, status),
 
-       TP_ARGS(bio)
-);
+       TP_STRUCT__entry(
+               __field(u64,    btree_node                      )
+               __field(u32,    btree_level                     )
+               __field(u32,    inode                           )
+               __field(u64,    offset                          )
+               __field(u32,    size                            )
+               __field(u8,     dirty                           )
+               __field(u8,     op                              )
+               __field(u8,     status                          )
+       ),
 
-DECLARE_EVENT_CLASS(bcache_cache_bio,
+       TP_fast_assign(
+               __entry->btree_node = PTR_BUCKET_NR(b->c, &b->key, 0);
+               __entry->btree_level = b->level;
+               __entry->inode  = KEY_INODE(k);
+               __entry->offset = KEY_OFFSET(k);
+               __entry->size   = KEY_SIZE(k);
+               __entry->dirty  = KEY_DIRTY(k);
+               __entry->op = op;
+               __entry->status = status;
+       ),
 
-       TP_PROTO(struct bio *bio,
-                sector_t orig_sector,
-                struct block_device* orig_bdev),
+       TP_printk("%u for %u at %llu(%u): %u:%llu len %u dirty %u",
+                 __entry->status, __entry->op,
+                 __entry->btree_node, __entry->btree_level,
+                 __entry->inode, __entry->offset,
+                 __entry->size, __entry->dirty)
+);
 
-       TP_ARGS(bio, orig_sector, orig_bdev),
+DECLARE_EVENT_CLASS(btree_split,
+       TP_PROTO(struct btree *b, unsigned keys),
+       TP_ARGS(b, keys),
 
        TP_STRUCT__entry(
-               __field(dev_t,          dev                     )
-               __field(dev_t,          orig_dev                )
-               __field(sector_t,       sector                  )
-               __field(sector_t,       orig_sector             )
-               __field(unsigned int,   nr_sector               )
-               __array(char,           rwbs,   6               )
-               __array(char,           comm,   TASK_COMM_LEN   )
+               __field(size_t,         bucket                  )
+               __field(unsigned,       keys                    )
        ),
 
        TP_fast_assign(
-               __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->orig_dev       = orig_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
-               __entry->orig_sector    = orig_sector;
-               __entry->nr_sector      = bio->bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
-               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+               __entry->bucket = PTR_BUCKET_NR(b->c, &b->key, 0);
+               __entry->keys   = keys;
        ),
 
-       TP_printk("%d,%d  %s %llu + %u [%s] (from %d,%d %llu)",
-                 MAJOR(__entry->dev), MINOR(__entry->dev),
-                 __entry->rwbs,
-                 (unsigned long long)__entry->sector,
-                 __entry->nr_sector, __entry->comm,
-                 MAJOR(__entry->orig_dev), MINOR(__entry->orig_dev),
-                 (unsigned long long)__entry->orig_sector)
+       TP_printk("bucket %zu keys %u", __entry->bucket, __entry->keys)
 );
 
-DEFINE_EVENT(bcache_cache_bio, bcache_cache_insert,
-
-       TP_PROTO(struct bio *bio,
-                sector_t orig_sector,
-                struct block_device *orig_bdev),
+DEFINE_EVENT(btree_split, bcache_btree_node_split,
+       TP_PROTO(struct btree *b, unsigned keys),
+       TP_ARGS(b, keys)
+);
 
-       TP_ARGS(bio, orig_sector, orig_bdev)
+DEFINE_EVENT(btree_split, bcache_btree_node_compact,
+       TP_PROTO(struct btree *b, unsigned keys),
+       TP_ARGS(b, keys)
 );
 
-DECLARE_EVENT_CLASS(bcache_gc,
+DEFINE_EVENT(btree_node, bcache_btree_set_root,
+       TP_PROTO(struct btree *b),
+       TP_ARGS(b)
+);
 
-       TP_PROTO(uint8_t *uuid),
+/* Allocator */
 
-       TP_ARGS(uuid),
+TRACE_EVENT(bcache_alloc_invalidate,
+       TP_PROTO(struct cache *ca),
+       TP_ARGS(ca),
 
        TP_STRUCT__entry(
-               __field(uint8_t *,      uuid)
+               __field(unsigned,       free                    )
+               __field(unsigned,       free_inc                )
+               __field(unsigned,       free_inc_size           )
+               __field(unsigned,       unused                  )
        ),
 
        TP_fast_assign(
-               __entry->uuid           = uuid;
+               __entry->free           = fifo_used(&ca->free);
+               __entry->free_inc       = fifo_used(&ca->free_inc);
+               __entry->free_inc_size  = ca->free_inc.size;
+               __entry->unused         = fifo_used(&ca->unused);
        ),
 
-       TP_printk("%pU", __entry->uuid)
+       TP_printk("free %u free_inc %u/%u unused %u", __entry->free,
+                 __entry->free_inc, __entry->free_inc_size, __entry->unused)
 );
 
+TRACE_EVENT(bcache_alloc_fail,
+       TP_PROTO(struct cache *ca),
+       TP_ARGS(ca),
 
-DEFINE_EVENT(bcache_gc, bcache_gc_start,
+       TP_STRUCT__entry(
+               __field(unsigned,       free                    )
+               __field(unsigned,       free_inc                )
+               __field(unsigned,       unused                  )
+               __field(unsigned,       blocked                 )
+       ),
 
-            TP_PROTO(uint8_t *uuid),
+       TP_fast_assign(
+               __entry->free           = fifo_used(&ca->free);
+               __entry->free_inc       = fifo_used(&ca->free_inc);
+               __entry->unused         = fifo_used(&ca->unused);
+               __entry->blocked        = atomic_read(&ca->set->prio_blocked);
+       ),
 
-            TP_ARGS(uuid)
+       TP_printk("free %u free_inc %u unused %u blocked %u", __entry->free,
+                 __entry->free_inc, __entry->unused, __entry->blocked)
 );
 
-DEFINE_EVENT(bcache_gc, bcache_gc_end,
+/* Background writeback */
 
-            TP_PROTO(uint8_t *uuid),
+DEFINE_EVENT(bkey, bcache_writeback,
+       TP_PROTO(struct bkey *k),
+       TP_ARGS(k)
+);
 
-            TP_ARGS(uuid)
+DEFINE_EVENT(bkey, bcache_writeback_collision,
+       TP_PROTO(struct bkey *k),
+       TP_ARGS(k)
 );
 
 #endif /* _TRACE_BCACHE_H */
index d615f78cc6b6945d3fa73609056aa1f0bc577870..41a6643e21361cd3993a12e5135bf3e32db79163 100644 (file)
@@ -670,10 +670,6 @@ perf_trace_##call(void *__data, proto)                                     \
                             sizeof(u64));                              \
        __entry_size -= sizeof(u32);                                    \
                                                                        \
-       if (WARN_ONCE(__entry_size > PERF_MAX_TRACE_SIZE,               \
-                     "profile buffer not large enough"))               \
-               return;                                                 \
-                                                                       \
        entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare(     \
                __entry_size, event_call->event.type, &__regs, &rctx);  \
        if (!entry)                                                     \
index d500369534972c2dede7208ba69d7815e389f299..1db453e4b550ebc84b10ca27f32dd4fdc2ecffd7 100644 (file)
@@ -215,8 +215,8 @@ struct fw_cdev_event_request2 {
  * with the %FW_CDEV_ISO_INTERRUPT bit set, when explicitly requested with
  * %FW_CDEV_IOC_FLUSH_ISO, or when there have been so many completed packets
  * without the interrupt bit set that the kernel's internal buffer for @header
- * is about to overflow.  (In the last case, kernels with ABI version < 5 drop
- * header data up to the next interrupt packet.)
+ * is about to overflow.  (In the last case, ABI versions < 5 drop header data
+ * up to the next interrupt packet.)
  *
  * Isochronous transmit events (context type %FW_CDEV_ISO_CONTEXT_TRANSMIT):
  *
index caed0f324d5ffc6fd88a59dda72f51636af0707a..8137dd8d2adffd1c91d4caf76dfa08b47501408a 100644 (file)
@@ -69,8 +69,8 @@
  *     starting a poll from a device which has a secure element enabled means
  *     we want to do SE based card emulation.
  * @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element.
- * @NFC_CMD_FW_UPLOAD: Request to Load/flash firmware, or event to inform that
- *     some firmware was loaded
+ * @NFC_CMD_FW_DOWNLOAD: Request to Load/flash firmware, or event to inform
+ *     that some firmware was loaded
  */
 enum nfc_commands {
        NFC_CMD_UNSPEC,
@@ -94,7 +94,7 @@ enum nfc_commands {
        NFC_CMD_DISABLE_SE,
        NFC_CMD_LLC_SDREQ,
        NFC_EVENT_LLC_SDRES,
-       NFC_CMD_FW_UPLOAD,
+       NFC_CMD_FW_DOWNLOAD,
        NFC_EVENT_SE_ADDED,
        NFC_EVENT_SE_REMOVED,
 /* private: internal use only */
index 7692dc69ccf7aeeb16ebc682b57d519c56642ba1..331499d597fa86cd941d99d5ad8ab9ec2120cb86 100644 (file)
 
 #include <linux/types.h>       /* __u8 etc */
 
+/* This is arbitrary.
+ * From USB 2.0 spec Table 11-13, offset 7, a hub can
+ * have up to 255 ports. The most yet reported is 10.
+ *
+ * Current Wireless USB host hardware (Intel i1480 for example) allows
+ * up to 22 devices to connect. Upcoming hardware might raise that
+ * limit. Because the arrays need to add a bit for hub status data, we
+ * use 31, so plus one evens out to four bytes.
+ */
+#define USB_MAXCHILDREN                31
+
 /*
  * Hub request types
  */
index ffd4652de91ca390fff537f18f524300bf470246..65e12099ef89d9f3b5706858d956d8aabe427348 100644 (file)
@@ -102,6 +102,30 @@ typedef uint64_t blkif_sector_t;
  */
 #define BLKIF_OP_DISCARD           5
 
+/*
+ * Recognized if "feature-max-indirect-segments" in present in the backend
+ * xenbus info. The "feature-max-indirect-segments" node contains the maximum
+ * number of segments allowed by the backend per request. If the node is
+ * present, the frontend might use blkif_request_indirect structs in order to
+ * issue requests with more than BLKIF_MAX_SEGMENTS_PER_REQUEST (11). The
+ * maximum number of indirect segments is fixed by the backend, but the
+ * frontend can issue requests with any number of indirect segments as long as
+ * it's less than the number provided by the backend. The indirect_grefs field
+ * in blkif_request_indirect should be filled by the frontend with the
+ * grant references of the pages that are holding the indirect segments.
+ * This pages are filled with an array of blkif_request_segment_aligned
+ * that hold the information about the segments. The number of indirect
+ * pages to use is determined by the maximum number of segments
+ * a indirect request contains. Every indirect page can contain a maximum
+ * of 512 segments (PAGE_SIZE/sizeof(blkif_request_segment_aligned)),
+ * so to calculate the number of indirect pages to use we have to do
+ * ceil(indirect_segments/512).
+ *
+ * If a backend does not recognize BLKIF_OP_INDIRECT, it should *not*
+ * create the "feature-max-indirect-segments" node!
+ */
+#define BLKIF_OP_INDIRECT          6
+
 /*
  * Maximum scatter/gather segments per request.
  * This is carefully chosen so that sizeof(struct blkif_ring) <= PAGE_SIZE.
@@ -109,6 +133,16 @@ typedef uint64_t blkif_sector_t;
  */
 #define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
 
+#define BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST 8
+
+struct blkif_request_segment_aligned {
+       grant_ref_t gref;        /* reference to I/O buffer frame        */
+       /* @first_sect: first sector in frame to transfer (inclusive).   */
+       /* @last_sect: last sector in frame to transfer (inclusive).     */
+       uint8_t     first_sect, last_sect;
+       uint16_t    _pad; /* padding to make it 8 bytes, so it's cache-aligned */
+} __attribute__((__packed__));
+
 struct blkif_request_rw {
        uint8_t        nr_segments;  /* number of segments                   */
        blkif_vdev_t   handle;       /* only for read/write requests         */
@@ -147,12 +181,31 @@ struct blkif_request_other {
        uint64_t     id;           /* private guest value, echoed in resp  */
 } __attribute__((__packed__));
 
+struct blkif_request_indirect {
+       uint8_t        indirect_op;
+       uint16_t       nr_segments;
+#ifdef CONFIG_X86_64
+       uint32_t       _pad1;        /* offsetof(blkif_...,u.indirect.id) == 8 */
+#endif
+       uint64_t       id;
+       blkif_sector_t sector_number;
+       blkif_vdev_t   handle;
+       uint16_t       _pad2;
+       grant_ref_t    indirect_grefs[BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST];
+#ifdef CONFIG_X86_64
+       uint32_t      _pad3;         /* make it 64 byte aligned */
+#else
+       uint64_t      _pad3;         /* make it 64 byte aligned */
+#endif
+} __attribute__((__packed__));
+
 struct blkif_request {
        uint8_t        operation;    /* BLKIF_OP_???                         */
        union {
                struct blkif_request_rw rw;
                struct blkif_request_discard discard;
                struct blkif_request_other other;
+               struct blkif_request_indirect indirect;
        } u;
 } __attribute__((__packed__));
 
index 75271b9a8f61bedcec5a18465b5a9ca8e84a38c7..7d28aff605c7eb600c4c3bfe93b8b5f1edbaebfe 100644 (file)
@@ -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;                                \
index 470839d1a30ed72f68789df711bfa78bdc60e5f4..35ef1185e359457323d5513b578185ad16435bc2 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel.
 #
 
-obj-y     = fork.o exec_domain.o panic.o printk.o \
+obj-y     = fork.o exec_domain.o panic.o \
            cpu.o exit.o itimer.o time.o softirq.o resource.o \
            sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
            signal.o sys.o kmod.o workqueue.o pid.o task_work.o \
@@ -24,6 +24,7 @@ endif
 
 obj-y += sched/
 obj-y += power/
+obj-y += printk/
 obj-y += cpu/
 
 obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o
index 0e0b20b8c5db172e8dc07fe4de10358c19939d60..781845a013ab23c8f99f2c2153c70c9fd679c45d 100644 (file)
@@ -1845,36 +1845,43 @@ out:
 EXPORT_SYMBOL_GPL(cgroup_path);
 
 /**
- * task_cgroup_path_from_hierarchy - cgroup path of a task on a hierarchy
+ * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy
  * @task: target task
- * @hierarchy_id: the hierarchy to look up @task's cgroup from
  * @buf: the buffer to write the path into
  * @buflen: the length of the buffer
  *
- * Determine @task's cgroup on the hierarchy specified by @hierarchy_id and
- * copy its path into @buf.  This function grabs cgroup_mutex and shouldn't
- * be used inside locks used by cgroup controller callbacks.
+ * Determine @task's cgroup on the first (the one with the lowest non-zero
+ * hierarchy_id) cgroup hierarchy and copy its path into @buf.  This
+ * function grabs cgroup_mutex and shouldn't be used inside locks used by
+ * cgroup controller callbacks.
+ *
+ * Returns 0 on success, fails with -%ENAMETOOLONG if @buflen is too short.
  */
-int task_cgroup_path_from_hierarchy(struct task_struct *task, int hierarchy_id,
-                                   char *buf, size_t buflen)
+int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
 {
        struct cgroupfs_root *root;
-       struct cgroup *cgrp = NULL;
-       int ret = -ENOENT;
+       struct cgroup *cgrp;
+       int hierarchy_id = 1, ret = 0;
+
+       if (buflen < 2)
+               return -ENAMETOOLONG;
 
        mutex_lock(&cgroup_mutex);
 
-       root = idr_find(&cgroup_hierarchy_idr, hierarchy_id);
+       root = idr_get_next(&cgroup_hierarchy_idr, &hierarchy_id);
+
        if (root) {
                cgrp = task_cgroup_from_root(task, root);
                ret = cgroup_path(cgrp, buf, buflen);
+       } else {
+               /* if no hierarchy exists, everyone is in "/" */
+               memcpy(buf, "/", 2);
        }
 
        mutex_unlock(&cgroup_mutex);
-
        return ret;
 }
-EXPORT_SYMBOL_GPL(task_cgroup_path_from_hierarchy);
+EXPORT_SYMBOL_GPL(task_cgroup_path);
 
 /*
  * Control Group taskset
@@ -4328,8 +4335,10 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                }
 
                err = percpu_ref_init(&css->refcnt, css_release);
-               if (err)
+               if (err) {
+                       ss->css_free(cgrp);
                        goto err_free_all;
+               }
 
                init_cgroup_css(css, ss, cgrp);
 
index 8b2afc1c9df0c698eccd86664d25c33ed647fea7..b462fa197517b6176701fa860cdb966bc44a69ba 100644 (file)
@@ -33,7 +33,7 @@ static DEFINE_SPINLOCK(freezer_lock);
  */
 bool freezing_slow_path(struct task_struct *p)
 {
-       if (p->flags & PF_NOFREEZE)
+       if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK))
                return false;
 
        if (pm_nosig_freezing || cgroup_freezing(p))
index fc0df84864495f8c44261961cb6909e66d24a21e..06ec8869dbf1629f2c7cabc63f2edc96426ea87d 100644 (file)
@@ -109,6 +109,8 @@ static int try_to_freeze_tasks(bool user_only)
 
 /**
  * freeze_processes - Signal user space processes to enter the refrigerator.
+ * The current thread will not be frozen.  The same process that calls
+ * freeze_processes must later call thaw_processes.
  *
  * On success, returns 0.  On failure, -errno and system is fully thawed.
  */
@@ -120,6 +122,9 @@ int freeze_processes(void)
        if (error)
                return error;
 
+       /* Make sure this task doesn't get frozen */
+       current->flags |= PF_SUSPEND_TASK;
+
        if (!pm_freezing)
                atomic_inc(&system_freezing_cnt);
 
@@ -168,6 +173,7 @@ int freeze_kernel_threads(void)
 void thaw_processes(void)
 {
        struct task_struct *g, *p;
+       struct task_struct *curr = current;
 
        if (pm_freezing)
                atomic_dec(&system_freezing_cnt);
@@ -182,10 +188,15 @@ void thaw_processes(void)
 
        read_lock(&tasklist_lock);
        do_each_thread(g, p) {
+               /* No other threads should have PF_SUSPEND_TASK set */
+               WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK));
                __thaw_task(p);
        } while_each_thread(g, p);
        read_unlock(&tasklist_lock);
 
+       WARN_ON(!(curr->flags & PF_SUSPEND_TASK));
+       curr->flags &= ~PF_SUSPEND_TASK;
+
        usermodehelper_enable();
 
        schedule();
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
new file mode 100644 (file)
index 0000000..85405bd
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y  = printk.o
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE)     += braille.o
diff --git a/kernel/printk/braille.c b/kernel/printk/braille.c
new file mode 100644 (file)
index 0000000..276762f
--- /dev/null
@@ -0,0 +1,49 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/string.h>
+
+#include "console_cmdline.h"
+#include "braille.h"
+
+char *_braille_console_setup(char **str, char **brl_options)
+{
+       if (!memcmp(*str, "brl,", 4)) {
+               *brl_options = "";
+               *str += 4;
+       } else if (!memcmp(str, "brl=", 4)) {
+               *brl_options = *str + 4;
+               *str = strchr(*brl_options, ',');
+               if (!*str)
+                       pr_err("need port name after brl=\n");
+               else
+                       *((*str)++) = 0;
+       } else
+               return NULL;
+
+       return *str;
+}
+
+int
+_braille_register_console(struct console *console, struct console_cmdline *c)
+{
+       int rtn = 0;
+
+       if (c->brl_options) {
+               console->flags |= CON_BRL;
+               rtn = braille_register_console(console, c->index, c->options,
+                                              c->brl_options);
+       }
+
+       return rtn;
+}
+
+int
+_braille_unregister_console(struct console *console)
+{
+       if (console->flags & CON_BRL)
+               return braille_unregister_console(console);
+
+       return 0;
+}
diff --git a/kernel/printk/braille.h b/kernel/printk/braille.h
new file mode 100644 (file)
index 0000000..769d771
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _PRINTK_BRAILLE_H
+#define _PRINTK_BRAILLE_H
+
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+
+static inline void
+braille_set_options(struct console_cmdline *c, char *brl_options)
+{
+       c->brl_options = brl_options;
+}
+
+char *
+_braille_console_setup(char **str, char **brl_options);
+
+int
+_braille_register_console(struct console *console, struct console_cmdline *c);
+
+int
+_braille_unregister_console(struct console *console);
+
+#else
+
+static inline void
+braille_set_options(struct console_cmdline *c, char *brl_options)
+{
+}
+
+static inline char *
+_braille_console_setup(char **str, char **brl_options)
+{
+       return NULL;
+}
+
+static inline int
+_braille_register_console(struct console *console, struct console_cmdline *c)
+{
+       return 0;
+}
+
+static inline int
+_braille_unregister_console(struct console *console)
+{
+       return 0;
+}
+
+#endif
+
+#endif
diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
new file mode 100644 (file)
index 0000000..cbd69d8
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _CONSOLE_CMDLINE_H
+#define _CONSOLE_CMDLINE_H
+
+struct console_cmdline
+{
+       char    name[8];                        /* Name of the driver       */
+       int     index;                          /* Minor dev. to use        */
+       char    *options;                       /* Options for the driver   */
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+       char    *brl_options;                   /* Options for braille driver */
+#endif
+};
+
+#endif
similarity index 95%
rename from kernel/printk.c
rename to kernel/printk/printk.c
index 69b0890ed7e54aa0679d1154056a7d26454fb7bd..5b5a7080e2a5f2822dfd93190c05302be74b1784 100644 (file)
@@ -51,6 +51,9 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/printk.h>
 
+#include "console_cmdline.h"
+#include "braille.h"
+
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
 
@@ -105,19 +108,11 @@ static struct console *exclusive_console;
 /*
  *     Array of consoles built from command line options (console=)
  */
-struct console_cmdline
-{
-       char    name[8];                        /* Name of the driver       */
-       int     index;                          /* Minor dev. to use        */
-       char    *options;                       /* Options for the driver   */
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       char    *brl_options;                   /* Options for braille driver */
-#endif
-};
 
 #define MAX_CMDLINECONSOLES 8
 
 static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
+
 static int selected_console = -1;
 static int preferred_console = -1;
 int console_set_on_cmdline;
@@ -178,7 +173,7 @@ static int console_may_schedule;
  *         67                           "g"
  *   0032     00 00 00                  padding to next message header
  *
- * The 'struct log' buffer header must never be directly exported to
+ * The 'struct printk_log' buffer header must never be directly exported to
  * userspace, it is a kernel-private implementation detail that might
  * need to be changed in the future, when the requirements change.
  *
@@ -200,7 +195,7 @@ enum log_flags {
        LOG_CONT        = 8,    /* text is a fragment of a continuation line */
 };
 
-struct log {
+struct printk_log {
        u64 ts_nsec;            /* timestamp in nanoseconds */
        u16 len;                /* length of entire record */
        u16 text_len;           /* length of text buffer */
@@ -248,7 +243,7 @@ static u32 clear_idx;
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
 #define LOG_ALIGN 4
 #else
-#define LOG_ALIGN __alignof__(struct log)
+#define LOG_ALIGN __alignof__(struct printk_log)
 #endif
 #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
 static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
@@ -259,35 +254,35 @@ static u32 log_buf_len = __LOG_BUF_LEN;
 static volatile unsigned int logbuf_cpu = UINT_MAX;
 
 /* human readable text of the record */
-static char *log_text(const struct log *msg)
+static char *log_text(const struct printk_log *msg)
 {
-       return (char *)msg + sizeof(struct log);
+       return (char *)msg + sizeof(struct printk_log);
 }
 
 /* optional key/value pair dictionary attached to the record */
-static char *log_dict(const struct log *msg)
+static char *log_dict(const struct printk_log *msg)
 {
-       return (char *)msg + sizeof(struct log) + msg->text_len;
+       return (char *)msg + sizeof(struct printk_log) + msg->text_len;
 }
 
 /* get record by index; idx must point to valid msg */
-static struct log *log_from_idx(u32 idx)
+static struct printk_log *log_from_idx(u32 idx)
 {
-       struct log *msg = (struct log *)(log_buf + idx);
+       struct printk_log *msg = (struct printk_log *)(log_buf + idx);
 
        /*
         * A length == 0 record is the end of buffer marker. Wrap around and
         * read the message at the start of the buffer.
         */
        if (!msg->len)
-               return (struct log *)log_buf;
+               return (struct printk_log *)log_buf;
        return msg;
 }
 
 /* get next record; idx must point to valid msg */
 static u32 log_next(u32 idx)
 {
-       struct log *msg = (struct log *)(log_buf + idx);
+       struct printk_log *msg = (struct printk_log *)(log_buf + idx);
 
        /* length == 0 indicates the end of the buffer; wrap */
        /*
@@ -296,7 +291,7 @@ static u32 log_next(u32 idx)
         * return the one after that.
         */
        if (!msg->len) {
-               msg = (struct log *)log_buf;
+               msg = (struct printk_log *)log_buf;
                return msg->len;
        }
        return idx + msg->len;
@@ -308,11 +303,11 @@ static void log_store(int facility, int level,
                      const char *dict, u16 dict_len,
                      const char *text, u16 text_len)
 {
-       struct log *msg;
+       struct printk_log *msg;
        u32 size, pad_len;
 
        /* number of '\0' padding bytes to next message */
-       size = sizeof(struct log) + text_len + dict_len;
+       size = sizeof(struct printk_log) + text_len + dict_len;
        pad_len = (-size) & (LOG_ALIGN - 1);
        size += pad_len;
 
@@ -324,7 +319,7 @@ static void log_store(int facility, int level,
                else
                        free = log_first_idx - log_next_idx;
 
-               if (free > size + sizeof(struct log))
+               if (free > size + sizeof(struct printk_log))
                        break;
 
                /* drop old messages until we have enough contiuous space */
@@ -332,18 +327,18 @@ static void log_store(int facility, int level,
                log_first_seq++;
        }
 
-       if (log_next_idx + size + sizeof(struct log) >= log_buf_len) {
+       if (log_next_idx + size + sizeof(struct printk_log) >= log_buf_len) {
                /*
                 * This message + an additional empty header does not fit
                 * at the end of the buffer. Add an empty header with len == 0
                 * to signify a wrap around.
                 */
-               memset(log_buf + log_next_idx, 0, sizeof(struct log));
+               memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));
                log_next_idx = 0;
        }
 
        /* fill message */
-       msg = (struct log *)(log_buf + log_next_idx);
+       msg = (struct printk_log *)(log_buf + log_next_idx);
        memcpy(log_text(msg), text, text_len);
        msg->text_len = text_len;
        memcpy(log_dict(msg), dict, dict_len);
@@ -356,7 +351,7 @@ static void log_store(int facility, int level,
        else
                msg->ts_nsec = local_clock();
        memset(log_dict(msg) + dict_len, 0, pad_len);
-       msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
+       msg->len = sizeof(struct printk_log) + text_len + dict_len + pad_len;
 
        /* insert message */
        log_next_idx += msg->len;
@@ -479,7 +474,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
 {
        struct devkmsg_user *user = file->private_data;
-       struct log *msg;
+       struct printk_log *msg;
        u64 ts_usec;
        size_t i;
        char cont = '-';
@@ -724,14 +719,14 @@ void log_buf_kexec_setup(void)
        VMCOREINFO_SYMBOL(log_first_idx);
        VMCOREINFO_SYMBOL(log_next_idx);
        /*
-        * Export struct log size and field offsets. User space tools can
+        * Export struct printk_log size and field offsets. User space tools can
         * parse it and detect any changes to structure down the line.
         */
-       VMCOREINFO_STRUCT_SIZE(log);
-       VMCOREINFO_OFFSET(log, ts_nsec);
-       VMCOREINFO_OFFSET(log, len);
-       VMCOREINFO_OFFSET(log, text_len);
-       VMCOREINFO_OFFSET(log, dict_len);
+       VMCOREINFO_STRUCT_SIZE(printk_log);
+       VMCOREINFO_OFFSET(printk_log, ts_nsec);
+       VMCOREINFO_OFFSET(printk_log, len);
+       VMCOREINFO_OFFSET(printk_log, text_len);
+       VMCOREINFO_OFFSET(printk_log, dict_len);
 }
 #endif
 
@@ -884,7 +879,7 @@ static size_t print_time(u64 ts, char *buf)
                       (unsigned long)ts, rem_nsec / 1000);
 }
 
-static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
+static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf)
 {
        size_t len = 0;
        unsigned int prefix = (msg->facility << 3) | msg->level;
@@ -907,7 +902,7 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
        return len;
 }
 
-static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size)
 {
        const char *text = log_text(msg);
@@ -969,7 +964,7 @@ static size_t msg_print_text(const struct log *msg, enum log_flags prev,
 static int syslog_print(char __user *buf, int size)
 {
        char *text;
-       struct log *msg;
+       struct printk_log *msg;
        int len = 0;
 
        text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
@@ -1060,7 +1055,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                idx = clear_idx;
                prev = 0;
                while (seq < log_next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
 
                        len += msg_print_text(msg, prev, true, NULL, 0);
                        prev = msg->flags;
@@ -1073,7 +1068,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                idx = clear_idx;
                prev = 0;
                while (len > size && seq < log_next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
 
                        len -= msg_print_text(msg, prev, true, NULL, 0);
                        prev = msg->flags;
@@ -1087,7 +1082,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                len = 0;
                prev = 0;
                while (len >= 0 && seq < next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
                        int textlen;
 
                        textlen = msg_print_text(msg, prev, true, text,
@@ -1233,7 +1228,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
 
                        error = 0;
                        while (seq < log_next_seq) {
-                               struct log *msg = log_from_idx(idx);
+                               struct printk_log *msg = log_from_idx(idx);
 
                                error += msg_print_text(msg, prev, true, NULL, 0);
                                idx = log_next(idx);
@@ -1719,10 +1714,10 @@ static struct cont {
        u8 level;
        bool flushed:1;
 } cont;
-static struct log *log_from_idx(u32 idx) { return NULL; }
+static struct printk_log *log_from_idx(u32 idx) { return NULL; }
 static u32 log_next(u32 idx) { return 0; }
 static void call_console_drivers(int level, const char *text, size_t len) {}
-static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size) { return 0; }
 static size_t cont_print_text(char *text, size_t size) { return 0; }
 
@@ -1761,23 +1756,23 @@ static int __add_preferred_console(char *name, int idx, char *options,
         *      See if this tty is not yet registered, and
         *      if we have a slot free.
         */
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
-               if (strcmp(console_cmdline[i].name, name) == 0 &&
-                         console_cmdline[i].index == idx) {
-                               if (!brl_options)
-                                       selected_console = i;
-                               return 0;
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++) {
+               if (strcmp(c->name, name) == 0 && c->index == idx) {
+                       if (!brl_options)
+                               selected_console = i;
+                       return 0;
                }
+       }
        if (i == MAX_CMDLINECONSOLES)
                return -E2BIG;
        if (!brl_options)
                selected_console = i;
-       c = &console_cmdline[i];
        strlcpy(c->name, name, sizeof(c->name));
        c->options = options;
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       c->brl_options = brl_options;
-#endif
+       braille_set_options(c, brl_options);
+
        c->index = idx;
        return 0;
 }
@@ -1790,20 +1785,8 @@ static int __init console_setup(char *str)
        char *s, *options, *brl_options = NULL;
        int idx;
 
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       if (!memcmp(str, "brl,", 4)) {
-               brl_options = "";
-               str += 4;
-       } else if (!memcmp(str, "brl=", 4)) {
-               brl_options = str + 4;
-               str = strchr(brl_options, ',');
-               if (!str) {
-                       printk(KERN_ERR "need port name after brl=\n");
-                       return 1;
-               }
-               *(str++) = 0;
-       }
-#endif
+       if (_braille_console_setup(&str, &brl_options))
+               return 1;
 
        /*
         * Decode str into name, index, options.
@@ -1858,15 +1841,15 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha
        struct console_cmdline *c;
        int i;
 
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
-               if (strcmp(console_cmdline[i].name, name) == 0 &&
-                         console_cmdline[i].index == idx) {
-                               c = &console_cmdline[i];
-                               strlcpy(c->name, name_new, sizeof(c->name));
-                               c->name[sizeof(c->name) - 1] = 0;
-                               c->options = options;
-                               c->index = idx_new;
-                               return i;
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++)
+               if (strcmp(c->name, name) == 0 && c->index == idx) {
+                       strlcpy(c->name, name_new, sizeof(c->name));
+                       c->name[sizeof(c->name) - 1] = 0;
+                       c->options = options;
+                       c->index = idx_new;
+                       return i;
                }
        /* not found */
        return -1;
@@ -2046,7 +2029,7 @@ void console_unlock(void)
        console_cont_flush(text, sizeof(text));
 again:
        for (;;) {
-               struct log *msg;
+               struct printk_log *msg;
                size_t len;
                int level;
 
@@ -2241,6 +2224,7 @@ void register_console(struct console *newcon)
        int i;
        unsigned long flags;
        struct console *bcon = NULL;
+       struct console_cmdline *c;
 
        /*
         * before we register a new CON_BOOT console, make sure we don't
@@ -2288,30 +2272,25 @@ void register_console(struct console *newcon)
         *      See if this console matches one we selected on
         *      the command line.
         */
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
-                       i++) {
-               if (strcmp(console_cmdline[i].name, newcon->name) != 0)
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++) {
+               if (strcmp(c->name, newcon->name) != 0)
                        continue;
                if (newcon->index >= 0 &&
-                   newcon->index != console_cmdline[i].index)
+                   newcon->index != c->index)
                        continue;
                if (newcon->index < 0)
-                       newcon->index = console_cmdline[i].index;
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-               if (console_cmdline[i].brl_options) {
-                       newcon->flags |= CON_BRL;
-                       braille_register_console(newcon,
-                                       console_cmdline[i].index,
-                                       console_cmdline[i].options,
-                                       console_cmdline[i].brl_options);
+                       newcon->index = c->index;
+
+               if (_braille_register_console(newcon, c))
                        return;
-               }
-#endif
+
                if (newcon->setup &&
                    newcon->setup(newcon, console_cmdline[i].options) != 0)
                        break;
                newcon->flags |= CON_ENABLED;
-               newcon->index = console_cmdline[i].index;
+               newcon->index = c->index;
                if (i == selected_console) {
                        newcon->flags |= CON_CONSDEV;
                        preferred_console = selected_console;
@@ -2394,13 +2373,13 @@ EXPORT_SYMBOL(register_console);
 int unregister_console(struct console *console)
 {
         struct console *a, *b;
-       int res = 1;
+       int res;
 
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       if (console->flags & CON_BRL)
-               return braille_unregister_console(console);
-#endif
+       res = _braille_unregister_console(console);
+       if (res)
+               return res;
 
+       res = 1;
        console_lock();
        if (console_drivers == console) {
                console_drivers=console->next;
@@ -2666,7 +2645,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
 bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
                               char *line, size_t size, size_t *len)
 {
-       struct log *msg;
+       struct printk_log *msg;
        size_t l = 0;
        bool ret = false;
 
@@ -2778,7 +2757,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        idx = dumper->cur_idx;
        prev = 0;
        while (seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l += msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
@@ -2791,7 +2770,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        idx = dumper->cur_idx;
        prev = 0;
        while (l > size && seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l -= msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
@@ -2806,7 +2785,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        l = 0;
        prev = 0;
        while (seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l += msg_print_text(msg, prev, syslog, buf + l, size - l);
                idx = log_next(idx);
index 4041f5747e73bf70f8d8dbb412f8e7b7067a8017..a146ee327f6ac15029b64424f0abd07e8d316f67 100644 (file)
@@ -469,7 +469,6 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
        /* Architecture-specific hardware disable .. */
        ptrace_disable(child);
        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-       flush_ptrace_hw_breakpoint(child);
 
        write_lock_irq(&tasklist_lock);
        /*
index bb456f44b7b1cdbfc6b4e6be3b04cd6f22da6b4d..9565645e320218f394f36eb0edbaa95236bbfcd1 100644 (file)
@@ -851,7 +851,7 @@ void task_numa_fault(int node, int pages, bool migrated)
 {
        struct task_struct *p = current;
 
-       if (!sched_feat_numa(NUMA))
+       if (!numabalancing_enabled)
                return;
 
        /* FIXME: Allocate task-specific structure for placement policy here */
@@ -5786,7 +5786,7 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
                entity_tick(cfs_rq, se, queued);
        }
 
-       if (sched_feat_numa(NUMA))
+       if (numabalancing_enabled)
                task_tick_numa(rq, curr);
 
        update_rq_runnable_avg(rq, 1);
index ac09d98490aabc0729eb1a4691e8d2b1ec10a34c..07f6fc468e1732734e7fcf5f73982a93670e4194 100644 (file)
@@ -2346,7 +2346,11 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
                                            int write, void *data)
 {
        if (write) {
-               *valp = msecs_to_jiffies(*negp ? -*lvalp : *lvalp);
+               unsigned long jif = msecs_to_jiffies(*negp ? -*lvalp : *lvalp);
+
+               if (jif > INT_MAX)
+                       return 1;
+               *valp = (int)jif;
        } else {
                int val = *valp;
                unsigned long lval;
index e80183f4a6c4f3d6abea4b6d7720e381381259e0..e77edc97e036b4e8216ae8b54fe0e6cafaa2fe71 100644 (file)
@@ -827,13 +827,10 @@ void tick_nohz_irq_exit(void)
 {
        struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
 
-       if (ts->inidle) {
-               /* Cancel the timer because CPU already waken up from the C-states*/
-               menu_hrtimer_cancel();
+       if (ts->inidle)
                __tick_nohz_idle_enter(ts);
-       } else {
+       else
                tick_nohz_full_stop_tick(ts);
-       }
 }
 
 /**
@@ -931,8 +928,6 @@ void tick_nohz_idle_exit(void)
 
        ts->inidle = 0;
 
-       /* Cancel the timer because CPU already waken up from the C-states*/
-       menu_hrtimer_cancel();
        if (ts->idle_active || ts->tick_stopped)
                now = ktime_get();
 
index 67708f46baaefbd6bca64a34a213c2cc7fda5074..a6d098c6df3f47f960004019fb48468ecea64410 100644 (file)
@@ -1441,12 +1441,22 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
  * the hashes are freed with call_rcu_sched().
  */
 static int
-ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
+ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
 {
        struct ftrace_hash *filter_hash;
        struct ftrace_hash *notrace_hash;
        int ret;
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+       /*
+        * There's a small race when adding ops that the ftrace handler
+        * that wants regs, may be called without them. We can not
+        * allow that handler to be called if regs is NULL.
+        */
+       if (regs == NULL && (ops->flags & FTRACE_OPS_FL_SAVE_REGS))
+               return 0;
+#endif
+
        filter_hash = rcu_dereference_raw_notrace(ops->filter_hash);
        notrace_hash = rcu_dereference_raw_notrace(ops->notrace_hash);
 
@@ -2159,12 +2169,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);
+}
+
+/*
+ * 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;
 
-       hash = ops->filter_hash;
-       return ftrace_hash_empty(hash);
+       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)
@@ -2173,6 +2228,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;
 
        /*
@@ -2186,9 +2242,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;
+                       }
                }
        }
 
@@ -2198,12 +2257,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
@@ -2223,7 +2286,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);
@@ -3374,6 +3437,12 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
        return add_hash_entry(hash, ip);
 }
 
+static void ftrace_ops_update_code(struct ftrace_ops *ops)
+{
+       if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
+               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+}
+
 static int
 ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
                unsigned long ip, int remove, int reset, int enable)
@@ -3416,9 +3485,8 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
 
        mutex_lock(&ftrace_lock);
        ret = ftrace_hash_move(ops, enable, orig_hash, hash);
-       if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED
-           && ftrace_enabled)
-               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+       if (!ret)
+               ftrace_ops_update_code(ops);
 
        mutex_unlock(&ftrace_lock);
 
@@ -3645,9 +3713,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
                mutex_lock(&ftrace_lock);
                ret = ftrace_hash_move(iter->ops, filter_hash,
                                       orig_hash, iter->hash);
-               if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED)
-                   && ftrace_enabled)
-                       ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+               if (!ret)
+                       ftrace_ops_update_code(iter->ops);
 
                mutex_unlock(&ftrace_lock);
        }
@@ -4218,7 +4285,7 @@ static inline void ftrace_startup_enable(int command) { }
 # define ftrace_shutdown_sysctl()      do { } while (0)
 
 static inline int
-ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
+ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
 {
        return 1;
 }
@@ -4241,7 +4308,7 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip,
        do_for_each_ftrace_op(op, ftrace_control_list) {
                if (!(op->flags & FTRACE_OPS_FL_STUB) &&
                    !ftrace_function_local_disabled(op) &&
-                   ftrace_ops_test(op, ip))
+                   ftrace_ops_test(op, ip, regs))
                        op->func(ip, parent_ip, op, regs);
        } while_for_each_ftrace_op(op);
        trace_recursion_clear(TRACE_CONTROL_BIT);
@@ -4274,7 +4341,7 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
         */
        preempt_disable_notrace();
        do_for_each_ftrace_op(op, ftrace_ops_list) {
-               if (ftrace_ops_test(op, ip))
+               if (ftrace_ops_test(op, ip, regs))
                        op->func(ip, parent_ip, op, regs);
        } while_for_each_ftrace_op(op);
        preempt_enable_notrace();
index e444ff88f0a425a00a4921291b46678b6a7efe21..cc2f66f68dc579c7e93967e4306821df29d7adce 100644 (file)
@@ -36,11 +36,11 @@ int ring_buffer_print_entry_header(struct trace_seq *s)
 {
        int ret;
 
-       ret = trace_seq_printf(s, "# compressed entry header\n");
-       ret = trace_seq_printf(s, "\ttype_len    :    5 bits\n");
-       ret = trace_seq_printf(s, "\ttime_delta  :   27 bits\n");
-       ret = trace_seq_printf(s, "\tarray       :   32 bits\n");
-       ret = trace_seq_printf(s, "\n");
+       ret = trace_seq_puts(s, "# compressed entry header\n");
+       ret = trace_seq_puts(s, "\ttype_len    :    5 bits\n");
+       ret = trace_seq_puts(s, "\ttime_delta  :   27 bits\n");
+       ret = trace_seq_puts(s, "\tarray       :   32 bits\n");
+       ret = trace_seq_putc(s, '\n');
        ret = trace_seq_printf(s, "\tpadding     : type == %d\n",
                               RINGBUF_TYPE_PADDING);
        ret = trace_seq_printf(s, "\ttime_extend : type == %d\n",
@@ -1066,7 +1066,7 @@ static int rb_check_list(struct ring_buffer_per_cpu *cpu_buffer,
 }
 
 /**
- * check_pages - integrity check of buffer pages
+ * rb_check_pages - integrity check of buffer pages
  * @cpu_buffer: CPU buffer with pages to test
  *
  * As a safety measure we check to make sure the data pages have not
@@ -1258,7 +1258,7 @@ static int rb_cpu_notify(struct notifier_block *self,
 #endif
 
 /**
- * ring_buffer_alloc - allocate a new ring_buffer
+ * __ring_buffer_alloc - allocate a new ring_buffer
  * @size: the size in bytes per cpu that is needed.
  * @flags: attributes to set for the ring buffer.
  *
@@ -1607,6 +1607,7 @@ static void update_pages_handler(struct work_struct *work)
  * ring_buffer_resize - resize the ring buffer
  * @buffer: the buffer to resize.
  * @size: the new size.
+ * @cpu_id: the cpu buffer to resize
  *
  * Minimum size is 2 * BUF_PAGE_SIZE.
  *
@@ -3956,11 +3957,11 @@ EXPORT_SYMBOL_GPL(ring_buffer_consume);
  * expected.
  *
  * After a sequence of ring_buffer_read_prepare calls, the user is
- * expected to make at least one call to ring_buffer_prepare_sync.
+ * expected to make at least one call to ring_buffer_read_prepare_sync.
  * Afterwards, ring_buffer_read_start is invoked to get things going
  * for real.
  *
- * This overall must be paired with ring_buffer_finish.
+ * This overall must be paired with ring_buffer_read_finish.
  */
 struct ring_buffer_iter *
 ring_buffer_read_prepare(struct ring_buffer *buffer, int cpu)
@@ -4009,7 +4010,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_read_prepare_sync);
  * an intervening ring_buffer_read_prepare_sync must have been
  * performed.
  *
- * Must be paired with ring_buffer_finish.
+ * Must be paired with ring_buffer_read_finish.
  */
 void
 ring_buffer_read_start(struct ring_buffer_iter *iter)
@@ -4031,7 +4032,7 @@ ring_buffer_read_start(struct ring_buffer_iter *iter)
 EXPORT_SYMBOL_GPL(ring_buffer_read_start);
 
 /**
- * ring_buffer_finish - finish reading the iterator of the buffer
+ * ring_buffer_read_finish - finish reading the iterator of the buffer
  * @iter: The iterator retrieved by ring_buffer_start
  *
  * This re-enables the recording to the buffer, and frees the
@@ -4346,6 +4347,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu);
 /**
  * ring_buffer_alloc_read_page - allocate a page to read from buffer
  * @buffer: the buffer to allocate for.
+ * @cpu: the cpu buffer to allocate.
  *
  * This function is used in conjunction with ring_buffer_read_page.
  * When reading a full page from the ring buffer, these functions
@@ -4403,7 +4405,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
  * to swap with a page in the ring buffer.
  *
  * for example:
- *     rpage = ring_buffer_alloc_read_page(buffer);
+ *     rpage = ring_buffer_alloc_read_page(buffer, cpu);
  *     if (!rpage)
  *             return error;
  *     ret = ring_buffer_read_page(buffer, &rpage, len, cpu, 0);
index 0cd500bffd9b0a26fc9d5f7107f51e8037e1d4bd..496f94d57698294966d2c0c9bd10de34854b34a5 100644 (file)
@@ -243,20 +243,25 @@ int filter_current_check_discard(struct ring_buffer *buffer,
 }
 EXPORT_SYMBOL_GPL(filter_current_check_discard);
 
-cycle_t ftrace_now(int cpu)
+cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu)
 {
        u64 ts;
 
        /* Early boot up does not have a buffer yet */
-       if (!global_trace.trace_buffer.buffer)
+       if (!buf->buffer)
                return trace_clock_local();
 
-       ts = ring_buffer_time_stamp(global_trace.trace_buffer.buffer, cpu);
-       ring_buffer_normalize_time_stamp(global_trace.trace_buffer.buffer, cpu, &ts);
+       ts = ring_buffer_time_stamp(buf->buffer, cpu);
+       ring_buffer_normalize_time_stamp(buf->buffer, cpu, &ts);
 
        return ts;
 }
 
+cycle_t ftrace_now(int cpu)
+{
+       return buffer_ftrace_now(&global_trace.trace_buffer, cpu);
+}
+
 /**
  * tracing_is_enabled - Show if global_trace has been disabled
  *
@@ -1211,7 +1216,7 @@ void tracing_reset_online_cpus(struct trace_buffer *buf)
        /* Make sure all commits have finished */
        synchronize_sched();
 
-       buf->time_start = ftrace_now(buf->cpu);
+       buf->time_start = buffer_ftrace_now(buf, buf->cpu);
 
        for_each_online_cpu(cpu)
                ring_buffer_reset_cpu(buffer, cpu);
@@ -1219,23 +1224,17 @@ void tracing_reset_online_cpus(struct trace_buffer *buf)
        ring_buffer_record_enable(buffer);
 }
 
-void tracing_reset_current(int cpu)
-{
-       tracing_reset(&global_trace.trace_buffer, cpu);
-}
-
+/* Must have trace_types_lock held */
 void tracing_reset_all_online_cpus(void)
 {
        struct trace_array *tr;
 
-       mutex_lock(&trace_types_lock);
        list_for_each_entry(tr, &ftrace_trace_arrays, list) {
                tracing_reset_online_cpus(&tr->trace_buffer);
 #ifdef CONFIG_TRACER_MAX_TRACE
                tracing_reset_online_cpus(&tr->max_buffer);
 #endif
        }
-       mutex_unlock(&trace_types_lock);
 }
 
 #define SAVED_CMDLINES 128
@@ -2843,6 +2842,17 @@ static int s_show(struct seq_file *m, void *v)
        return 0;
 }
 
+/*
+ * Should be used after trace_array_get(), trace_types_lock
+ * ensures that i_cdev was already initialized.
+ */
+static inline int tracing_get_cpu(struct inode *inode)
+{
+       if (inode->i_cdev) /* See trace_create_cpu_file() */
+               return (long)inode->i_cdev - 1;
+       return RING_BUFFER_ALL_CPUS;
+}
+
 static const struct seq_operations tracer_seq_ops = {
        .start          = s_start,
        .next           = s_next,
@@ -2851,9 +2861,9 @@ static const struct seq_operations tracer_seq_ops = {
 };
 
 static struct trace_iterator *
-__tracing_open(struct trace_array *tr, struct trace_cpu *tc,
-              struct inode *inode, struct file *file, bool snapshot)
+__tracing_open(struct inode *inode, struct file *file, bool snapshot)
 {
+       struct trace_array *tr = inode->i_private;
        struct trace_iterator *iter;
        int cpu;
 
@@ -2894,8 +2904,8 @@ __tracing_open(struct trace_array *tr, struct trace_cpu *tc,
                iter->trace_buffer = &tr->trace_buffer;
        iter->snapshot = snapshot;
        iter->pos = -1;
+       iter->cpu_file = tracing_get_cpu(inode);
        mutex_init(&iter->mutex);
-       iter->cpu_file = tc->cpu;
 
        /* Notify the tracer early; before we stop tracing. */
        if (iter->trace && iter->trace->open)
@@ -2971,45 +2981,22 @@ static int tracing_open_generic_tr(struct inode *inode, struct file *filp)
        filp->private_data = inode->i_private;
 
        return 0;
-       
-}
-
-static int tracing_open_generic_tc(struct inode *inode, struct file *filp)
-{
-       struct trace_cpu *tc = inode->i_private;
-       struct trace_array *tr = tc->tr;
-
-       if (tracing_disabled)
-               return -ENODEV;
-
-       if (trace_array_get(tr) < 0)
-               return -ENODEV;
-
-       filp->private_data = inode->i_private;
-
-       return 0;
-       
 }
 
 static int tracing_release(struct inode *inode, struct file *file)
 {
+       struct trace_array *tr = inode->i_private;
        struct seq_file *m = file->private_data;
        struct trace_iterator *iter;
-       struct trace_array *tr;
        int cpu;
 
-       /* Writes do not use seq_file, need to grab tr from inode */
        if (!(file->f_mode & FMODE_READ)) {
-               struct trace_cpu *tc = inode->i_private;
-
-               trace_array_put(tc->tr);
+               trace_array_put(tr);
                return 0;
        }
 
+       /* Writes do not use seq_file */
        iter = m->private;
-       tr = iter->tr;
-       trace_array_put(tr);
-
        mutex_lock(&trace_types_lock);
 
        for_each_tracing_cpu(cpu) {
@@ -3023,6 +3010,9 @@ static int tracing_release(struct inode *inode, struct file *file)
        if (!iter->snapshot)
                /* reenable tracing if it was previously enabled */
                tracing_start_tr(tr);
+
+       __trace_array_put(tr);
+
        mutex_unlock(&trace_types_lock);
 
        mutex_destroy(&iter->mutex);
@@ -3042,15 +3032,6 @@ static int tracing_release_generic_tr(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int tracing_release_generic_tc(struct inode *inode, struct file *file)
-{
-       struct trace_cpu *tc = inode->i_private;
-       struct trace_array *tr = tc->tr;
-
-       trace_array_put(tr);
-       return 0;
-}
-
 static int tracing_single_release_tr(struct inode *inode, struct file *file)
 {
        struct trace_array *tr = inode->i_private;
@@ -3062,8 +3043,7 @@ static int tracing_single_release_tr(struct inode *inode, struct file *file)
 
 static int tracing_open(struct inode *inode, struct file *file)
 {
-       struct trace_cpu *tc = inode->i_private;
-       struct trace_array *tr = tc->tr;
+       struct trace_array *tr = inode->i_private;
        struct trace_iterator *iter;
        int ret = 0;
 
@@ -3071,16 +3051,17 @@ static int tracing_open(struct inode *inode, struct file *file)
                return -ENODEV;
 
        /* If this file was open for write, then erase contents */
-       if ((file->f_mode & FMODE_WRITE) &&
-           (file->f_flags & O_TRUNC)) {
-               if (tc->cpu == RING_BUFFER_ALL_CPUS)
+       if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
+               int cpu = tracing_get_cpu(inode);
+
+               if (cpu == RING_BUFFER_ALL_CPUS)
                        tracing_reset_online_cpus(&tr->trace_buffer);
                else
-                       tracing_reset(&tr->trace_buffer, tc->cpu);
+                       tracing_reset(&tr->trace_buffer, cpu);
        }
 
        if (file->f_mode & FMODE_READ) {
-               iter = __tracing_open(tr, tc, inode, file, false);
+               iter = __tracing_open(inode, file, false);
                if (IS_ERR(iter))
                        ret = PTR_ERR(iter);
                else if (trace_flags & TRACE_ITER_LATENCY_FMT)
@@ -3447,6 +3428,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
 static int tracing_trace_options_open(struct inode *inode, struct file *file)
 {
        struct trace_array *tr = inode->i_private;
+       int ret;
 
        if (tracing_disabled)
                return -ENODEV;
@@ -3454,7 +3436,11 @@ static int tracing_trace_options_open(struct inode *inode, struct file *file)
        if (trace_array_get(tr) < 0)
                return -ENODEV;
 
-       return single_open(file, tracing_trace_options_show, inode->i_private);
+       ret = single_open(file, tracing_trace_options_show, inode->i_private);
+       if (ret < 0)
+               trace_array_put(tr);
+
+       return ret;
 }
 
 static const struct file_operations tracing_iter_fops = {
@@ -3537,14 +3523,14 @@ static const char readme_msg[] =
        "\n  snapshot\t\t- Like 'trace' but shows the content of the static snapshot buffer\n"
        "\t\t\t  Read the contents for more information\n"
 #endif
-#ifdef CONFIG_STACKTRACE
+#ifdef CONFIG_STACK_TRACER
        "  stack_trace\t\t- Shows the max stack trace when active\n"
        "  stack_max_size\t- Shows current max stack size that was traced\n"
        "\t\t\t  Write into this file to reset the max size (trigger a new trace)\n"
 #ifdef CONFIG_DYNAMIC_FTRACE
        "  stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace traces\n"
 #endif
-#endif /* CONFIG_STACKTRACE */
+#endif /* CONFIG_STACK_TRACER */
 ;
 
 static ssize_t
@@ -3941,8 +3927,7 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf,
 
 static int tracing_open_pipe(struct inode *inode, struct file *filp)
 {
-       struct trace_cpu *tc = inode->i_private;
-       struct trace_array *tr = tc->tr;
+       struct trace_array *tr = inode->i_private;
        struct trace_iterator *iter;
        int ret = 0;
 
@@ -3958,6 +3943,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
        iter = kzalloc(sizeof(*iter), GFP_KERNEL);
        if (!iter) {
                ret = -ENOMEM;
+               __trace_array_put(tr);
                goto out;
        }
 
@@ -3987,9 +3973,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
        if (trace_clocks[tr->clock_id].in_ns)
                iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
 
-       iter->cpu_file = tc->cpu;
-       iter->tr = tc->tr;
-       iter->trace_buffer = &tc->tr->trace_buffer;
+       iter->tr = tr;
+       iter->trace_buffer = &tr->trace_buffer;
+       iter->cpu_file = tracing_get_cpu(inode);
        mutex_init(&iter->mutex);
        filp->private_data = iter;
 
@@ -4012,8 +3998,7 @@ fail:
 static int tracing_release_pipe(struct inode *inode, struct file *file)
 {
        struct trace_iterator *iter = file->private_data;
-       struct trace_cpu *tc = inode->i_private;
-       struct trace_array *tr = tc->tr;
+       struct trace_array *tr = inode->i_private;
 
        mutex_lock(&trace_types_lock);
 
@@ -4166,6 +4151,7 @@ waitagain:
        memset(&iter->seq, 0,
               sizeof(struct trace_iterator) -
               offsetof(struct trace_iterator, seq));
+       cpumask_clear(iter->started);
        iter->pos = -1;
 
        trace_event_read_lock();
@@ -4366,15 +4352,16 @@ static ssize_t
 tracing_entries_read(struct file *filp, char __user *ubuf,
                     size_t cnt, loff_t *ppos)
 {
-       struct trace_cpu *tc = filp->private_data;
-       struct trace_array *tr = tc->tr;
+       struct inode *inode = file_inode(filp);
+       struct trace_array *tr = inode->i_private;
+       int cpu = tracing_get_cpu(inode);
        char buf[64];
        int r = 0;
        ssize_t ret;
 
        mutex_lock(&trace_types_lock);
 
-       if (tc->cpu == RING_BUFFER_ALL_CPUS) {
+       if (cpu == RING_BUFFER_ALL_CPUS) {
                int cpu, buf_size_same;
                unsigned long size;
 
@@ -4401,7 +4388,7 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
                } else
                        r = sprintf(buf, "X\n");
        } else
-               r = sprintf(buf, "%lu\n", per_cpu_ptr(tr->trace_buffer.data, tc->cpu)->entries >> 10);
+               r = sprintf(buf, "%lu\n", per_cpu_ptr(tr->trace_buffer.data, cpu)->entries >> 10);
 
        mutex_unlock(&trace_types_lock);
 
@@ -4413,7 +4400,8 @@ static ssize_t
 tracing_entries_write(struct file *filp, const char __user *ubuf,
                      size_t cnt, loff_t *ppos)
 {
-       struct trace_cpu *tc = filp->private_data;
+       struct inode *inode = file_inode(filp);
+       struct trace_array *tr = inode->i_private;
        unsigned long val;
        int ret;
 
@@ -4427,8 +4415,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
 
        /* value is in KB */
        val <<= 10;
-
-       ret = tracing_resize_ring_buffer(tc->tr, val, tc->cpu);
+       ret = tracing_resize_ring_buffer(tr, val, tracing_get_cpu(inode));
        if (ret < 0)
                return ret;
 
@@ -4482,7 +4469,7 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
 
        /* disable tracing ? */
        if (trace_flags & TRACE_ITER_STOP_ON_FREE)
-               tracing_off();
+               tracer_tracing_off(tr);
        /* resize the ring buffer to 0 */
        tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
 
@@ -4647,12 +4634,12 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
         * New clock may not be consistent with the previous clock.
         * Reset the buffer so that it doesn't have incomparable timestamps.
         */
-       tracing_reset_online_cpus(&global_trace.trace_buffer);
+       tracing_reset_online_cpus(&tr->trace_buffer);
 
 #ifdef CONFIG_TRACER_MAX_TRACE
        if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer)
                ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func);
-       tracing_reset_online_cpus(&global_trace.max_buffer);
+       tracing_reset_online_cpus(&tr->max_buffer);
 #endif
 
        mutex_unlock(&trace_types_lock);
@@ -4689,8 +4676,7 @@ struct ftrace_buffer_info {
 #ifdef CONFIG_TRACER_SNAPSHOT
 static int tracing_snapshot_open(struct inode *inode, struct file *file)
 {
-       struct trace_cpu *tc = inode->i_private;
-       struct trace_array *tr = tc->tr;
+       struct trace_array *tr = inode->i_private;
        struct trace_iterator *iter;
        struct seq_file *m;
        int ret = 0;
@@ -4699,26 +4685,29 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
                return -ENODEV;
 
        if (file->f_mode & FMODE_READ) {
-               iter = __tracing_open(tr, tc, inode, file, true);
+               iter = __tracing_open(inode, file, true);
                if (IS_ERR(iter))
                        ret = PTR_ERR(iter);
        } else {
                /* Writes still need the seq_file to hold the private data */
+               ret = -ENOMEM;
                m = kzalloc(sizeof(*m), GFP_KERNEL);
                if (!m)
-                       return -ENOMEM;
+                       goto out;
                iter = kzalloc(sizeof(*iter), GFP_KERNEL);
                if (!iter) {
                        kfree(m);
-                       return -ENOMEM;
+                       goto out;
                }
+               ret = 0;
+
                iter->tr = tr;
-               iter->trace_buffer = &tc->tr->max_buffer;
-               iter->cpu_file = tc->cpu;
+               iter->trace_buffer = &tr->max_buffer;
+               iter->cpu_file = tracing_get_cpu(inode);
                m->private = iter;
                file->private_data = m;
        }
-
+out:
        if (ret < 0)
                trace_array_put(tr);
 
@@ -4873,11 +4862,11 @@ static const struct file_operations tracing_pipe_fops = {
 };
 
 static const struct file_operations tracing_entries_fops = {
-       .open           = tracing_open_generic_tc,
+       .open           = tracing_open_generic_tr,
        .read           = tracing_entries_read,
        .write          = tracing_entries_write,
        .llseek         = generic_file_llseek,
-       .release        = tracing_release_generic_tc,
+       .release        = tracing_release_generic_tr,
 };
 
 static const struct file_operations tracing_total_entries_fops = {
@@ -4929,8 +4918,7 @@ static const struct file_operations snapshot_raw_fops = {
 
 static int tracing_buffers_open(struct inode *inode, struct file *filp)
 {
-       struct trace_cpu *tc = inode->i_private;
-       struct trace_array *tr = tc->tr;
+       struct trace_array *tr = inode->i_private;
        struct ftrace_buffer_info *info;
        int ret;
 
@@ -4948,10 +4936,8 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)
 
        mutex_lock(&trace_types_lock);
 
-       tr->ref++;
-
        info->iter.tr           = tr;
-       info->iter.cpu_file     = tc->cpu;
+       info->iter.cpu_file     = tracing_get_cpu(inode);
        info->iter.trace        = tr->current_trace;
        info->iter.trace_buffer = &tr->trace_buffer;
        info->spare             = NULL;
@@ -5268,14 +5254,14 @@ static ssize_t
 tracing_stats_read(struct file *filp, char __user *ubuf,
                   size_t count, loff_t *ppos)
 {
-       struct trace_cpu *tc = filp->private_data;
-       struct trace_array *tr = tc->tr;
+       struct inode *inode = file_inode(filp);
+       struct trace_array *tr = inode->i_private;
        struct trace_buffer *trace_buf = &tr->trace_buffer;
+       int cpu = tracing_get_cpu(inode);
        struct trace_seq *s;
        unsigned long cnt;
        unsigned long long t;
        unsigned long usec_rem;
-       int cpu = tc->cpu;
 
        s = kmalloc(sizeof(*s), GFP_KERNEL);
        if (!s)
@@ -5328,9 +5314,10 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
 }
 
 static const struct file_operations tracing_stats_fops = {
-       .open           = tracing_open_generic,
+       .open           = tracing_open_generic_tr,
        .read           = tracing_stats_read,
        .llseek         = generic_file_llseek,
+       .release        = tracing_release_generic_tr,
 };
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -5519,10 +5506,20 @@ static struct dentry *tracing_dentry_percpu(struct trace_array *tr, int cpu)
        return tr->percpu_dir;
 }
 
+static struct dentry *
+trace_create_cpu_file(const char *name, umode_t mode, struct dentry *parent,
+                     void *data, long cpu, const struct file_operations *fops)
+{
+       struct dentry *ret = trace_create_file(name, mode, parent, data, fops);
+
+       if (ret) /* See tracing_get_cpu() */
+               ret->d_inode->i_cdev = (void *)(cpu + 1);
+       return ret;
+}
+
 static void
 tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
 {
-       struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
        struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
        struct dentry *d_cpu;
        char cpu_dir[30]; /* 30 characters should be more than enough */
@@ -5538,28 +5535,28 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
        }
 
        /* per cpu trace_pipe */
-       trace_create_file("trace_pipe", 0444, d_cpu,
-                       (void *)&data->trace_cpu, &tracing_pipe_fops);
+       trace_create_cpu_file("trace_pipe", 0444, d_cpu,
+                               tr, cpu, &tracing_pipe_fops);
 
        /* per cpu trace */
-       trace_create_file("trace", 0644, d_cpu,
-                       (void *)&data->trace_cpu, &tracing_fops);
+       trace_create_cpu_file("trace", 0644, d_cpu,
+                               tr, cpu, &tracing_fops);
 
-       trace_create_file("trace_pipe_raw", 0444, d_cpu,
-                       (void *)&data->trace_cpu, &tracing_buffers_fops);
+       trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu,
+                               tr, cpu, &tracing_buffers_fops);
 
-       trace_create_file("stats", 0444, d_cpu,
-                       (void *)&data->trace_cpu, &tracing_stats_fops);
+       trace_create_cpu_file("stats", 0444, d_cpu,
+                               tr, cpu, &tracing_stats_fops);
 
-       trace_create_file("buffer_size_kb", 0444, d_cpu,
-                       (void *)&data->trace_cpu, &tracing_entries_fops);
+       trace_create_cpu_file("buffer_size_kb", 0444, d_cpu,
+                               tr, cpu, &tracing_entries_fops);
 
 #ifdef CONFIG_TRACER_SNAPSHOT
-       trace_create_file("snapshot", 0644, d_cpu,
-                         (void *)&data->trace_cpu, &snapshot_fops);
+       trace_create_cpu_file("snapshot", 0644, d_cpu,
+                               tr, cpu, &snapshot_fops);
 
-       trace_create_file("snapshot_raw", 0444, d_cpu,
-                       (void *)&data->trace_cpu, &snapshot_raw_fops);
+       trace_create_cpu_file("snapshot_raw", 0444, d_cpu,
+                               tr, cpu, &snapshot_raw_fops);
 #endif
 }
 
@@ -5868,17 +5865,6 @@ struct dentry *trace_instance_dir;
 static void
 init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer);
 
-static void init_trace_buffers(struct trace_array *tr, struct trace_buffer *buf)
-{
-       int cpu;
-
-       for_each_tracing_cpu(cpu) {
-               memset(per_cpu_ptr(buf->data, cpu), 0, sizeof(struct trace_array_cpu));
-               per_cpu_ptr(buf->data, cpu)->trace_cpu.cpu = cpu;
-               per_cpu_ptr(buf->data, cpu)->trace_cpu.tr = tr;
-       }
-}
-
 static int
 allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size)
 {
@@ -5896,8 +5882,6 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size
                return -ENOMEM;
        }
 
-       init_trace_buffers(tr, buf);
-
        /* Allocate the first page for all buffers */
        set_buffer_entries(&tr->trace_buffer,
                           ring_buffer_size(tr->trace_buffer.buffer, 0));
@@ -5964,17 +5948,15 @@ static int new_instance_create(const char *name)
        if (allocate_trace_buffers(tr, trace_buf_size) < 0)
                goto out_free_tr;
 
-       /* Holder for file callbacks */
-       tr->trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
-       tr->trace_cpu.tr = tr;
-
        tr->dir = debugfs_create_dir(name, trace_instance_dir);
        if (!tr->dir)
                goto out_free_tr;
 
        ret = event_trace_add_tracer(tr->dir, tr);
-       if (ret)
+       if (ret) {
+               debugfs_remove_recursive(tr->dir);
                goto out_free_tr;
+       }
 
        init_tracer_debugfs(tr, tr->dir);
 
@@ -6120,13 +6102,13 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
                          tr, &tracing_iter_fops);
 
        trace_create_file("trace", 0644, d_tracer,
-                       (void *)&tr->trace_cpu, &tracing_fops);
+                         tr, &tracing_fops);
 
        trace_create_file("trace_pipe", 0444, d_tracer,
-                       (void *)&tr->trace_cpu, &tracing_pipe_fops);
+                         tr, &tracing_pipe_fops);
 
        trace_create_file("buffer_size_kb", 0644, d_tracer,
-                       (void *)&tr->trace_cpu, &tracing_entries_fops);
+                         tr, &tracing_entries_fops);
 
        trace_create_file("buffer_total_size_kb", 0444, d_tracer,
                          tr, &tracing_total_entries_fops);
@@ -6141,11 +6123,11 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
                          &trace_clock_fops);
 
        trace_create_file("tracing_on", 0644, d_tracer,
-                           tr, &rb_simple_fops);
+                         tr, &rb_simple_fops);
 
 #ifdef CONFIG_TRACER_SNAPSHOT
        trace_create_file("snapshot", 0644, d_tracer,
-                         (void *)&tr->trace_cpu, &snapshot_fops);
+                         tr, &snapshot_fops);
 #endif
 
        for_each_tracing_cpu(cpu)
@@ -6439,10 +6421,6 @@ __init static int tracer_alloc_buffers(void)
 
        global_trace.flags = TRACE_ARRAY_FL_GLOBAL;
 
-       /* Holder for file callbacks */
-       global_trace.trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
-       global_trace.trace_cpu.tr = &global_trace;
-
        INIT_LIST_HEAD(&global_trace.systems);
        INIT_LIST_HEAD(&global_trace.events);
        list_add(&global_trace.list, &ftrace_trace_arrays);
index 4a4f6e1828b633aa8a2ba8a7dc6db70ac87db6a3..afaae41b0a0269012ae394dc5df877cd5cf86045 100644 (file)
@@ -130,19 +130,12 @@ enum trace_flag_type {
 
 struct trace_array;
 
-struct trace_cpu {
-       struct trace_array      *tr;
-       struct dentry           *dir;
-       int                     cpu;
-};
-
 /*
  * The CPU trace array - it consists of thousands of trace entries
  * plus some other descriptor data: (for example which task started
  * the trace, etc.)
  */
 struct trace_array_cpu {
-       struct trace_cpu        trace_cpu;
        atomic_t                disabled;
        void                    *buffer_page;   /* ring buffer spare */
 
@@ -196,7 +189,6 @@ struct trace_array {
        bool                    allocated_snapshot;
 #endif
        int                     buffer_disabled;
-       struct trace_cpu        trace_cpu;      /* place holder */
 #ifdef CONFIG_FTRACE_SYSCALLS
        int                     sys_refcount_enter;
        int                     sys_refcount_exit;
@@ -214,7 +206,6 @@ struct trace_array {
        struct dentry           *event_dir;
        struct list_head        systems;
        struct list_head        events;
-       struct task_struct      *waiter;
        int                     ref;
 };
 
@@ -680,6 +671,15 @@ extern int trace_selftest_startup_sched_switch(struct tracer *trace,
                                               struct trace_array *tr);
 extern int trace_selftest_startup_branch(struct tracer *trace,
                                         struct trace_array *tr);
+/*
+ * Tracer data references selftest functions that only occur
+ * on boot up. These can be __init functions. Thus, when selftests
+ * are enabled, then the tracers need to reference __init functions.
+ */
+#define __tracer_data          __refdata
+#else
+/* Tracers are seldom changed. Optimize when selftests are disabled. */
+#define __tracer_data          __read_mostly
 #endif /* CONFIG_FTRACE_STARTUP_TEST */
 
 extern void *head_page(struct trace_array_cpu *data);
index 84b1e045faba836583fb371d285f49e79bfa6bd0..80c36bcf66e8e8d089776ff14b780f3f85efa418 100644 (file)
@@ -236,6 +236,10 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
 
        BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long));
 
+       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
+                       "perf buffer not large enough"))
+               return NULL;
+
        pc = preempt_count();
 
        *rctxp = perf_swevent_get_recursion_context();
@@ -266,6 +270,10 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip,
        struct pt_regs regs;
        int rctx;
 
+       head = this_cpu_ptr(event_function.perf_events);
+       if (hlist_empty(head))
+               return;
+
 #define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \
                    sizeof(u64)) - sizeof(u32))
 
@@ -279,8 +287,6 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip,
 
        entry->ip = ip;
        entry->parent_ip = parent_ip;
-
-       head = this_cpu_ptr(event_function.perf_events);
        perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0,
                              1, &regs, head, NULL);
 
index 7d854290bf817ef8c6b116b031830dc060ae5dc7..29a7ebcfb42621d05cb9a74a7bcf291515b38461 100644 (file)
@@ -409,33 +409,42 @@ static void put_system(struct ftrace_subsystem_dir *dir)
        mutex_unlock(&event_mutex);
 }
 
-/*
- * Open and update trace_array ref count.
- * Must have the current trace_array passed to it.
- */
-static int tracing_open_generic_file(struct inode *inode, struct file *filp)
+static void remove_subsystem(struct ftrace_subsystem_dir *dir)
 {
-       struct ftrace_event_file *file = inode->i_private;
-       struct trace_array *tr = file->tr;
-       int ret;
+       if (!dir)
+               return;
 
-       if (trace_array_get(tr) < 0)
-               return -ENODEV;
+       if (!--dir->nr_events) {
+               debugfs_remove_recursive(dir->entry);
+               list_del(&dir->list);
+               __put_system_dir(dir);
+       }
+}
 
-       ret = tracing_open_generic(inode, filp);
-       if (ret < 0)
-               trace_array_put(tr);
-       return ret;
+static void *event_file_data(struct file *filp)
+{
+       return ACCESS_ONCE(file_inode(filp)->i_private);
 }
 
-static int tracing_release_generic_file(struct inode *inode, struct file *filp)
+static void remove_event_file_dir(struct ftrace_event_file *file)
 {
-       struct ftrace_event_file *file = inode->i_private;
-       struct trace_array *tr = file->tr;
+       struct dentry *dir = file->dir;
+       struct dentry *child;
 
-       trace_array_put(tr);
+       if (dir) {
+               spin_lock(&dir->d_lock);        /* probably unneeded */
+               list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
+                       if (child->d_inode)     /* probably unneeded */
+                               child->d_inode->i_private = NULL;
+               }
+               spin_unlock(&dir->d_lock);
 
-       return 0;
+               debugfs_remove_recursive(dir);
+       }
+
+       list_del(&file->list);
+       remove_subsystem(file->system);
+       kmem_cache_free(file_cachep, file);
 }
 
 /*
@@ -679,15 +688,25 @@ static ssize_t
 event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
                  loff_t *ppos)
 {
-       struct ftrace_event_file *file = filp->private_data;
+       struct ftrace_event_file *file;
+       unsigned long flags;
        char buf[4] = "0";
 
-       if (file->flags & FTRACE_EVENT_FL_ENABLED &&
-           !(file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
+       mutex_lock(&event_mutex);
+       file = event_file_data(filp);
+       if (likely(file))
+               flags = file->flags;
+       mutex_unlock(&event_mutex);
+
+       if (!file)
+               return -ENODEV;
+
+       if (flags & FTRACE_EVENT_FL_ENABLED &&
+           !(flags & FTRACE_EVENT_FL_SOFT_DISABLED))
                strcpy(buf, "1");
 
-       if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED ||
-           file->flags & FTRACE_EVENT_FL_SOFT_MODE)
+       if (flags & FTRACE_EVENT_FL_SOFT_DISABLED ||
+           flags & FTRACE_EVENT_FL_SOFT_MODE)
                strcat(buf, "*");
 
        strcat(buf, "\n");
@@ -699,13 +718,10 @@ static ssize_t
 event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
                   loff_t *ppos)
 {
-       struct ftrace_event_file *file = filp->private_data;
+       struct ftrace_event_file *file;
        unsigned long val;
        int ret;
 
-       if (!file)
-               return -EINVAL;
-
        ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
        if (ret)
                return ret;
@@ -717,8 +733,11 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
        switch (val) {
        case 0:
        case 1:
+               ret = -ENODEV;
                mutex_lock(&event_mutex);
-               ret = ftrace_event_enable_disable(file, val);
+               file = event_file_data(filp);
+               if (likely(file))
+                       ret = ftrace_event_enable_disable(file, val);
                mutex_unlock(&event_mutex);
                break;
 
@@ -825,65 +844,39 @@ enum {
 
 static void *f_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct ftrace_event_call *call = m->private;
-       struct ftrace_event_field *field;
+       struct ftrace_event_call *call = event_file_data(m->private);
        struct list_head *common_head = &ftrace_common_fields;
        struct list_head *head = trace_get_fields(call);
+       struct list_head *node = v;
 
        (*pos)++;
 
        switch ((unsigned long)v) {
        case FORMAT_HEADER:
-               if (unlikely(list_empty(common_head)))
-                       return NULL;
-
-               field = list_entry(common_head->prev,
-                                  struct ftrace_event_field, link);
-               return field;
+               node = common_head;
+               break;
 
        case FORMAT_FIELD_SEPERATOR:
-               if (unlikely(list_empty(head)))
-                       return NULL;
-
-               field = list_entry(head->prev, struct ftrace_event_field, link);
-               return field;
+               node = head;
+               break;
 
        case FORMAT_PRINTFMT:
                /* all done */
                return NULL;
        }
 
-       field = v;
-       if (field->link.prev == common_head)
+       node = node->prev;
+       if (node == common_head)
                return (void *)FORMAT_FIELD_SEPERATOR;
-       else if (field->link.prev == head)
+       else if (node == head)
                return (void *)FORMAT_PRINTFMT;
-
-       field = list_entry(field->link.prev, struct ftrace_event_field, link);
-
-       return field;
-}
-
-static void *f_start(struct seq_file *m, loff_t *pos)
-{
-       loff_t l = 0;
-       void *p;
-
-       /* Start by showing the header */
-       if (!*pos)
-               return (void *)FORMAT_HEADER;
-
-       p = (void *)FORMAT_HEADER;
-       do {
-               p = f_next(m, p, &l);
-       } while (p && l < *pos);
-
-       return p;
+       else
+               return node;
 }
 
 static int f_show(struct seq_file *m, void *v)
 {
-       struct ftrace_event_call *call = m->private;
+       struct ftrace_event_call *call = event_file_data(m->private);
        struct ftrace_event_field *field;
        const char *array_descriptor;
 
@@ -904,8 +897,7 @@ static int f_show(struct seq_file *m, void *v)
                return 0;
        }
 
-       field = v;
-
+       field = list_entry(v, struct ftrace_event_field, link);
        /*
         * Smartly shows the array type(except dynamic array).
         * Normal:
@@ -932,8 +924,25 @@ static int f_show(struct seq_file *m, void *v)
        return 0;
 }
 
+static void *f_start(struct seq_file *m, loff_t *pos)
+{
+       void *p = (void *)FORMAT_HEADER;
+       loff_t l = 0;
+
+       /* ->stop() is called even if ->start() fails */
+       mutex_lock(&event_mutex);
+       if (!event_file_data(m->private))
+               return ERR_PTR(-ENODEV);
+
+       while (l < *pos && p)
+               p = f_next(m, p, &l);
+
+       return p;
+}
+
 static void f_stop(struct seq_file *m, void *p)
 {
+       mutex_unlock(&event_mutex);
 }
 
 static const struct seq_operations trace_format_seq_ops = {
@@ -945,7 +954,6 @@ static const struct seq_operations trace_format_seq_ops = {
 
 static int trace_format_open(struct inode *inode, struct file *file)
 {
-       struct ftrace_event_call *call = inode->i_private;
        struct seq_file *m;
        int ret;
 
@@ -954,7 +962,7 @@ static int trace_format_open(struct inode *inode, struct file *file)
                return ret;
 
        m = file->private_data;
-       m->private = call;
+       m->private = file;
 
        return 0;
 }
@@ -962,45 +970,47 @@ static int trace_format_open(struct inode *inode, struct file *file)
 static ssize_t
 event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
 {
-       struct ftrace_event_call *call = filp->private_data;
-       struct trace_seq *s;
-       int r;
+       int id = (long)event_file_data(filp);
+       char buf[32];
+       int len;
 
        if (*ppos)
                return 0;
 
-       s = kmalloc(sizeof(*s), GFP_KERNEL);
-       if (!s)
-               return -ENOMEM;
+       if (unlikely(!id))
+               return -ENODEV;
 
-       trace_seq_init(s);
-       trace_seq_printf(s, "%d\n", call->event.type);
+       len = sprintf(buf, "%d\n", id);
 
-       r = simple_read_from_buffer(ubuf, cnt, ppos,
-                                   s->buffer, s->len);
-       kfree(s);
-       return r;
+       return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
 }
 
 static ssize_t
 event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
                  loff_t *ppos)
 {
-       struct ftrace_event_call *call = filp->private_data;
+       struct ftrace_event_call *call;
        struct trace_seq *s;
-       int r;
+       int r = -ENODEV;
 
        if (*ppos)
                return 0;
 
        s = kmalloc(sizeof(*s), GFP_KERNEL);
+
        if (!s)
                return -ENOMEM;
 
        trace_seq_init(s);
 
-       print_event_filter(call, s);
-       r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
+       mutex_lock(&event_mutex);
+       call = event_file_data(filp);
+       if (call)
+               print_event_filter(call, s);
+       mutex_unlock(&event_mutex);
+
+       if (call)
+               r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
 
        kfree(s);
 
@@ -1011,9 +1021,9 @@ static ssize_t
 event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
                   loff_t *ppos)
 {
-       struct ftrace_event_call *call = filp->private_data;
+       struct ftrace_event_call *call;
        char *buf;
-       int err;
+       int err = -ENODEV;
 
        if (cnt >= PAGE_SIZE)
                return -EINVAL;
@@ -1028,7 +1038,12 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
        }
        buf[cnt] = '\0';
 
-       err = apply_event_filter(call, buf);
+       mutex_lock(&event_mutex);
+       call = event_file_data(filp);
+       if (call)
+               err = apply_event_filter(call, buf);
+       mutex_unlock(&event_mutex);
+
        free_page((unsigned long) buf);
        if (err < 0)
                return err;
@@ -1218,6 +1233,7 @@ show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
 
 static int ftrace_event_avail_open(struct inode *inode, struct file *file);
 static int ftrace_event_set_open(struct inode *inode, struct file *file);
+static int ftrace_event_release(struct inode *inode, struct file *file);
 
 static const struct seq_operations show_event_seq_ops = {
        .start = t_start,
@@ -1245,14 +1261,13 @@ static const struct file_operations ftrace_set_event_fops = {
        .read = seq_read,
        .write = ftrace_event_write,
        .llseek = seq_lseek,
-       .release = seq_release,
+       .release = ftrace_event_release,
 };
 
 static const struct file_operations ftrace_enable_fops = {
-       .open = tracing_open_generic_file,
+       .open = tracing_open_generic,
        .read = event_enable_read,
        .write = event_enable_write,
-       .release = tracing_release_generic_file,
        .llseek = default_llseek,
 };
 
@@ -1264,7 +1279,6 @@ static const struct file_operations ftrace_event_format_fops = {
 };
 
 static const struct file_operations ftrace_event_id_fops = {
-       .open = tracing_open_generic,
        .read = event_id_read,
        .llseek = default_llseek,
 };
@@ -1323,6 +1337,15 @@ ftrace_event_open(struct inode *inode, struct file *file,
        return ret;
 }
 
+static int ftrace_event_release(struct inode *inode, struct file *file)
+{
+       struct trace_array *tr = inode->i_private;
+
+       trace_array_put(tr);
+
+       return seq_release(inode, file);
+}
+
 static int
 ftrace_event_avail_open(struct inode *inode, struct file *file)
 {
@@ -1336,12 +1359,19 @@ ftrace_event_set_open(struct inode *inode, struct file *file)
 {
        const struct seq_operations *seq_ops = &show_set_event_seq_ops;
        struct trace_array *tr = inode->i_private;
+       int ret;
+
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
 
        if ((file->f_mode & FMODE_WRITE) &&
            (file->f_flags & O_TRUNC))
                ftrace_clear_events(tr);
 
-       return ftrace_event_open(inode, file, seq_ops);
+       ret = ftrace_event_open(inode, file, seq_ops);
+       if (ret < 0)
+               trace_array_put(tr);
+       return ret;
 }
 
 static struct event_subsystem *
@@ -1496,8 +1526,8 @@ event_create_dir(struct dentry *parent,
 
 #ifdef CONFIG_PERF_EVENTS
        if (call->event.type && call->class->reg)
-               trace_create_file("id", 0444, file->dir, call,
-                                 id);
+               trace_create_file("id", 0444, file->dir,
+                                 (void *)(long)call->event.type, id);
 #endif
 
        /*
@@ -1522,33 +1552,16 @@ event_create_dir(struct dentry *parent,
        return 0;
 }
 
-static void remove_subsystem(struct ftrace_subsystem_dir *dir)
-{
-       if (!dir)
-               return;
-
-       if (!--dir->nr_events) {
-               debugfs_remove_recursive(dir->entry);
-               list_del(&dir->list);
-               __put_system_dir(dir);
-       }
-}
-
 static void remove_event_from_tracers(struct ftrace_event_call *call)
 {
        struct ftrace_event_file *file;
        struct trace_array *tr;
 
        do_for_each_event_file_safe(tr, file) {
-
                if (file->event_call != call)
                        continue;
 
-               list_del(&file->list);
-               debugfs_remove_recursive(file->dir);
-               remove_subsystem(file->system);
-               kmem_cache_free(file_cachep, file);
-
+               remove_event_file_dir(file);
                /*
                 * The do_for_each_event_file_safe() is
                 * a double loop. After finding the call for this
@@ -1700,16 +1713,53 @@ static void __trace_remove_event_call(struct ftrace_event_call *call)
        destroy_preds(call);
 }
 
+static int probe_remove_event_call(struct ftrace_event_call *call)
+{
+       struct trace_array *tr;
+       struct ftrace_event_file *file;
+
+#ifdef CONFIG_PERF_EVENTS
+       if (call->perf_refcount)
+               return -EBUSY;
+#endif
+       do_for_each_event_file(tr, file) {
+               if (file->event_call != call)
+                       continue;
+               /*
+                * We can't rely on ftrace_event_enable_disable(enable => 0)
+                * we are going to do, FTRACE_EVENT_FL_SOFT_MODE can suppress
+                * TRACE_REG_UNREGISTER.
+                */
+               if (file->flags & FTRACE_EVENT_FL_ENABLED)
+                       return -EBUSY;
+               /*
+                * The do_for_each_event_file_safe() is
+                * a double loop. After finding the call for this
+                * trace_array, we use break to jump to the next
+                * trace_array.
+                */
+               break;
+       } while_for_each_event_file();
+
+       __trace_remove_event_call(call);
+
+       return 0;
+}
+
 /* Remove an event_call */
-void trace_remove_event_call(struct ftrace_event_call *call)
+int trace_remove_event_call(struct ftrace_event_call *call)
 {
+       int ret;
+
        mutex_lock(&trace_types_lock);
        mutex_lock(&event_mutex);
        down_write(&trace_event_sem);
-       __trace_remove_event_call(call);
+       ret = probe_remove_event_call(call);
        up_write(&trace_event_sem);
        mutex_unlock(&event_mutex);
        mutex_unlock(&trace_types_lock);
+
+       return ret;
 }
 
 #define for_each_event(event, start, end)                      \
@@ -2278,12 +2328,8 @@ __trace_remove_event_dirs(struct trace_array *tr)
 {
        struct ftrace_event_file *file, *next;
 
-       list_for_each_entry_safe(file, next, &tr->events, list) {
-               list_del(&file->list);
-               debugfs_remove_recursive(file->dir);
-               remove_subsystem(file->system);
-               kmem_cache_free(file_cachep, file);
-       }
+       list_for_each_entry_safe(file, next, &tr->events, list)
+               remove_event_file_dir(file);
 }
 
 static void
index 0d883dc057d68fe92bc36f0510298cff725256bb..97daa8cf958df8e73c9fa8090f89cbaf4e63893e 100644 (file)
@@ -637,17 +637,15 @@ static void append_filter_err(struct filter_parse_state *ps,
        free_page((unsigned long) buf);
 }
 
+/* caller must hold event_mutex */
 void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
 {
-       struct event_filter *filter;
+       struct event_filter *filter = call->filter;
 
-       mutex_lock(&event_mutex);
-       filter = call->filter;
        if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
-               trace_seq_printf(s, "none\n");
-       mutex_unlock(&event_mutex);
+               trace_seq_puts(s, "none\n");
 }
 
 void print_subsystem_event_filter(struct event_subsystem *system,
@@ -660,7 +658,7 @@ void print_subsystem_event_filter(struct event_subsystem *system,
        if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
-               trace_seq_printf(s, DEFAULT_SYS_FILTER_MESSAGE "\n");
+               trace_seq_puts(s, DEFAULT_SYS_FILTER_MESSAGE "\n");
        mutex_unlock(&event_mutex);
 }
 
@@ -1841,23 +1839,22 @@ static int create_system_filter(struct event_subsystem *system,
        return err;
 }
 
+/* caller must hold event_mutex */
 int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
 {
        struct event_filter *filter;
-       int err = 0;
-
-       mutex_lock(&event_mutex);
+       int err;
 
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_disable(call);
                filter = call->filter;
                if (!filter)
-                       goto out_unlock;
+                       return 0;
                RCU_INIT_POINTER(call->filter, NULL);
                /* Make sure the filter is not being used */
                synchronize_sched();
                __free_filter(filter);
-               goto out_unlock;
+               return 0;
        }
 
        err = create_filter(call, filter_string, true, &filter);
@@ -1884,8 +1881,6 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
                        __free_filter(tmp);
                }
        }
-out_unlock:
-       mutex_unlock(&event_mutex);
 
        return err;
 }
index b863f93b30f35caae4239629ea56d05b58b38639..38fe1483c50817cc4b1b6a33807985cda37d9b6a 100644 (file)
@@ -199,7 +199,7 @@ static int func_set_flag(u32 old_flags, u32 bit, int set)
        return 0;
 }
 
-static struct tracer function_trace __read_mostly =
+static struct tracer function_trace __tracer_data =
 {
        .name           = "function",
        .init           = function_trace_init,
index 8388bc99f2eee165efacbef7ddde4f7f21d49ea3..b5c09242683d8cd1c989d2706702d4d42e182d73 100644 (file)
@@ -446,7 +446,7 @@ print_graph_proc(struct trace_seq *s, pid_t pid)
 
        /* First spaces to align center */
        for (i = 0; i < spaces / 2; i++) {
-               ret = trace_seq_printf(s, " ");
+               ret = trace_seq_putc(s, ' ');
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
        }
@@ -457,7 +457,7 @@ print_graph_proc(struct trace_seq *s, pid_t pid)
 
        /* Last spaces to align center */
        for (i = 0; i < spaces - (spaces / 2); i++) {
-               ret = trace_seq_printf(s, " ");
+               ret = trace_seq_putc(s, ' ');
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
        }
@@ -503,7 +503,7 @@ verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
  ------------------------------------------
 
  */
-       ret = trace_seq_printf(s,
+       ret = trace_seq_puts(s,
                " ------------------------------------------\n");
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
@@ -516,7 +516,7 @@ verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
        if (ret == TRACE_TYPE_PARTIAL_LINE)
                return TRACE_TYPE_PARTIAL_LINE;
 
-       ret = trace_seq_printf(s, " => ");
+       ret = trace_seq_puts(s, " => ");
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
 
@@ -524,7 +524,7 @@ verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
        if (ret == TRACE_TYPE_PARTIAL_LINE)
                return TRACE_TYPE_PARTIAL_LINE;
 
-       ret = trace_seq_printf(s,
+       ret = trace_seq_puts(s,
                "\n ------------------------------------------\n\n");
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
@@ -645,7 +645,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
                        ret = print_graph_proc(s, pid);
                        if (ret == TRACE_TYPE_PARTIAL_LINE)
                                return TRACE_TYPE_PARTIAL_LINE;
-                       ret = trace_seq_printf(s, " | ");
+                       ret = trace_seq_puts(s, " | ");
                        if (!ret)
                                return TRACE_TYPE_PARTIAL_LINE;
                }
@@ -657,9 +657,9 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
                return ret;
 
        if (type == TRACE_GRAPH_ENT)
-               ret = trace_seq_printf(s, "==========>");
+               ret = trace_seq_puts(s, "==========>");
        else
-               ret = trace_seq_printf(s, "<==========");
+               ret = trace_seq_puts(s, "<==========");
 
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
@@ -668,7 +668,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
        if (ret != TRACE_TYPE_HANDLED)
                return ret;
 
-       ret = trace_seq_printf(s, "\n");
+       ret = trace_seq_putc(s, '\n');
 
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
@@ -705,13 +705,13 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
                len += strlen(nsecs_str);
        }
 
-       ret = trace_seq_printf(s, " us ");
+       ret = trace_seq_puts(s, " us ");
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
 
        /* Print remaining spaces to fit the row's width */
        for (i = len; i < 7; i++) {
-               ret = trace_seq_printf(s, " ");
+               ret = trace_seq_putc(s, ' ');
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
        }
@@ -731,13 +731,13 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s,
        /* No real adata, just filling the column with spaces */
        switch (duration) {
        case DURATION_FILL_FULL:
-               ret = trace_seq_printf(s, "              |  ");
+               ret = trace_seq_puts(s, "              |  ");
                return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
        case DURATION_FILL_START:
-               ret = trace_seq_printf(s, "  ");
+               ret = trace_seq_puts(s, "  ");
                return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
        case DURATION_FILL_END:
-               ret = trace_seq_printf(s, " |");
+               ret = trace_seq_puts(s, " |");
                return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
        }
 
@@ -745,10 +745,10 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s,
        if (flags & TRACE_GRAPH_PRINT_OVERHEAD) {
                /* Duration exceeded 100 msecs */
                if (duration > 100000ULL)
-                       ret = trace_seq_printf(s, "! ");
+                       ret = trace_seq_puts(s, "! ");
                /* Duration exceeded 10 msecs */
                else if (duration > 10000ULL)
-                       ret = trace_seq_printf(s, "+ ");
+                       ret = trace_seq_puts(s, "+ ");
        }
 
        /*
@@ -757,7 +757,7 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s,
         * to fill out the space.
         */
        if (ret == -1)
-               ret = trace_seq_printf(s, "  ");
+               ret = trace_seq_puts(s, "  ");
 
        /* Catching here any failure happenned above */
        if (!ret)
@@ -767,7 +767,7 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s,
        if (ret != TRACE_TYPE_HANDLED)
                return ret;
 
-       ret = trace_seq_printf(s, "|  ");
+       ret = trace_seq_puts(s, "|  ");
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
 
@@ -817,7 +817,7 @@ print_graph_entry_leaf(struct trace_iterator *iter,
 
        /* Function */
        for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
-               ret = trace_seq_printf(s, " ");
+               ret = trace_seq_putc(s, ' ');
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
        }
@@ -858,7 +858,7 @@ print_graph_entry_nested(struct trace_iterator *iter,
 
        /* Function */
        for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
-               ret = trace_seq_printf(s, " ");
+               ret = trace_seq_putc(s, ' ');
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
        }
@@ -917,7 +917,7 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
                if (ret == TRACE_TYPE_PARTIAL_LINE)
                        return TRACE_TYPE_PARTIAL_LINE;
 
-               ret = trace_seq_printf(s, " | ");
+               ret = trace_seq_puts(s, " | ");
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
        }
@@ -1117,7 +1117,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
 
        /* Closing brace */
        for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
-               ret = trace_seq_printf(s, " ");
+               ret = trace_seq_putc(s, ' ');
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
        }
@@ -1129,7 +1129,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
         * belongs to, write out the function name.
         */
        if (func_match) {
-               ret = trace_seq_printf(s, "}\n");
+               ret = trace_seq_puts(s, "}\n");
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
        } else {
@@ -1179,13 +1179,13 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
        /* Indentation */
        if (depth > 0)
                for (i = 0; i < (depth + 1) * TRACE_GRAPH_INDENT; i++) {
-                       ret = trace_seq_printf(s, " ");
+                       ret = trace_seq_putc(s, ' ');
                        if (!ret)
                                return TRACE_TYPE_PARTIAL_LINE;
                }
 
        /* The comment */
-       ret = trace_seq_printf(s, "/* ");
+       ret = trace_seq_puts(s, "/* ");
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
 
@@ -1216,7 +1216,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
                s->len--;
        }
 
-       ret = trace_seq_printf(s, " */\n");
+       ret = trace_seq_puts(s, " */\n");
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
 
@@ -1448,7 +1448,7 @@ static struct trace_event graph_trace_ret_event = {
        .funcs          = &graph_functions
 };
 
-static struct tracer graph_trace __read_mostly = {
+static struct tracer graph_trace __tracer_data = {
        .name           = "function_graph",
        .open           = graph_trace_open,
        .pipe_open      = graph_trace_open,
index 7ed6976493c87ec2d31637a60a285bc39b4925b8..243f6834d02675c9c1101e1eabe18e56eb7d3244 100644 (file)
@@ -95,7 +95,7 @@ static __kprobes bool trace_probe_is_on_module(struct trace_probe *tp)
 }
 
 static int register_probe_event(struct trace_probe *tp);
-static void unregister_probe_event(struct trace_probe *tp);
+static int unregister_probe_event(struct trace_probe *tp);
 
 static DEFINE_MUTEX(probe_lock);
 static LIST_HEAD(probe_list);
@@ -243,11 +243,11 @@ find_event_file_link(struct trace_probe *tp, struct ftrace_event_file *file)
 static int
 disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
 {
+       struct event_file_link *link = NULL;
+       int wait = 0;
        int ret = 0;
 
        if (file) {
-               struct event_file_link *link;
-
                link = find_event_file_link(tp, file);
                if (!link) {
                        ret = -EINVAL;
@@ -255,10 +255,7 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
                }
 
                list_del_rcu(&link->list);
-               /* synchronize with kprobe_trace_func/kretprobe_trace_func */
-               synchronize_sched();
-               kfree(link);
-
+               wait = 1;
                if (!list_empty(&tp->files))
                        goto out;
 
@@ -271,8 +268,22 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
                        disable_kretprobe(&tp->rp);
                else
                        disable_kprobe(&tp->rp.kp);
+               wait = 1;
        }
  out:
+       if (wait) {
+               /*
+                * Synchronize with kprobe_trace_func/kretprobe_trace_func
+                * to ensure disabled (all running handlers are finished).
+                * This is not only for kfree(), but also the caller,
+                * trace_remove_event_call() supposes it for releasing
+                * event_call related objects, which will be accessed in
+                * the kprobe_trace_func/kretprobe_trace_func.
+                */
+               synchronize_sched();
+               kfree(link);    /* Ignored if link == NULL */
+       }
+
        return ret;
 }
 
@@ -340,9 +351,12 @@ static int unregister_trace_probe(struct trace_probe *tp)
        if (trace_probe_is_enabled(tp))
                return -EBUSY;
 
+       /* Will fail if probe is being used by ftrace or perf */
+       if (unregister_probe_event(tp))
+               return -EBUSY;
+
        __unregister_trace_probe(tp);
        list_del(&tp->list);
-       unregister_probe_event(tp);
 
        return 0;
 }
@@ -621,7 +635,9 @@ static int release_all_trace_probes(void)
        /* TODO: Use batch unregistration */
        while (!list_empty(&probe_list)) {
                tp = list_entry(probe_list.next, struct trace_probe, list);
-               unregister_trace_probe(tp);
+               ret = unregister_trace_probe(tp);
+               if (ret)
+                       goto end;
                free_trace_probe(tp);
        }
 
@@ -1087,9 +1103,6 @@ kprobe_perf_func(struct trace_probe *tp, struct pt_regs *regs)
        __size = sizeof(*entry) + tp->size + dsize;
        size = ALIGN(__size + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
-       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
-                    "profile buffer not large enough"))
-               return;
 
        entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
        if (!entry)
@@ -1120,9 +1133,6 @@ kretprobe_perf_func(struct trace_probe *tp, struct kretprobe_instance *ri,
        __size = sizeof(*entry) + tp->size + dsize;
        size = ALIGN(__size + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
-       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
-                    "profile buffer not large enough"))
-               return;
 
        entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
        if (!entry)
@@ -1242,11 +1252,15 @@ static int register_probe_event(struct trace_probe *tp)
        return ret;
 }
 
-static void unregister_probe_event(struct trace_probe *tp)
+static int unregister_probe_event(struct trace_probe *tp)
 {
+       int ret;
+
        /* tp->event is unregistered in trace_remove_event_call() */
-       trace_remove_event_call(&tp->call);
-       kfree(tp->call.print_fmt);
+       ret = trace_remove_event_call(&tp->call);
+       if (!ret)
+               kfree(tp->call.print_fmt);
+       return ret;
 }
 
 /* Make a debugfs interface for controlling probe points */
index a5e8f4878bfa3015ebb3372c8d09c2aa641b5bc1..b3dcfb2f0fef4e1bc9e9815021adc3e8dfe7d32a 100644 (file)
@@ -90,7 +90,7 @@ static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
        if (drv)
                ret += trace_seq_printf(s, " %s\n", drv->name);
        else
-               ret += trace_seq_printf(s, " \n");
+               ret += trace_seq_puts(s, " \n");
        return ret;
 }
 
@@ -107,7 +107,7 @@ static void mmio_pipe_open(struct trace_iterator *iter)
        struct header_iter *hiter;
        struct trace_seq *s = &iter->seq;
 
-       trace_seq_printf(s, "VERSION 20070824\n");
+       trace_seq_puts(s, "VERSION 20070824\n");
 
        hiter = kzalloc(sizeof(*hiter), GFP_KERNEL);
        if (!hiter)
@@ -209,7 +209,7 @@ static enum print_line_t mmio_print_rw(struct trace_iterator *iter)
                        (rw->value >> 0) & 0xff, rw->pc, 0);
                break;
        default:
-               ret = trace_seq_printf(s, "rw what?\n");
+               ret = trace_seq_puts(s, "rw what?\n");
                break;
        }
        if (ret)
@@ -245,7 +245,7 @@ static enum print_line_t mmio_print_map(struct trace_iterator *iter)
                        secs, usec_rem, m->map_id, 0UL, 0);
                break;
        default:
-               ret = trace_seq_printf(s, "map what?\n");
+               ret = trace_seq_puts(s, "map what?\n");
                break;
        }
        if (ret)
index bb922d9ee51ba7b51171db284f6cd20576b012b2..34e7cbac0c9c17f8de2a0c8c137552deb9498b60 100644 (file)
@@ -78,7 +78,7 @@ enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)
 
        trace_assign_type(field, entry);
 
-       ret = trace_seq_printf(s, "%s", field->buf);
+       ret = trace_seq_puts(s, field->buf);
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
 
@@ -558,14 +558,14 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
                        if (ret)
                                ret = trace_seq_puts(s, "??");
                        if (ret)
-                               ret = trace_seq_puts(s, "\n");
+                               ret = trace_seq_putc(s, '\n');
                        continue;
                }
                if (!ret)
                        break;
                if (ret)
                        ret = seq_print_user_ip(s, mm, ip, sym_flags);
-               ret = trace_seq_puts(s, "\n");
+               ret = trace_seq_putc(s, '\n');
        }
 
        if (mm)
@@ -579,7 +579,7 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
        int ret;
 
        if (!ip)
-               return trace_seq_printf(s, "0");
+               return trace_seq_putc(s, '0');
 
        if (sym_flags & TRACE_ITER_SYM_OFFSET)
                ret = seq_print_sym_offset(s, "%s", ip);
@@ -964,14 +964,14 @@ static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags,
                goto partial;
 
        if ((flags & TRACE_ITER_PRINT_PARENT) && field->parent_ip) {
-               if (!trace_seq_printf(s, " <-"))
+               if (!trace_seq_puts(s, " <-"))
                        goto partial;
                if (!seq_print_ip_sym(s,
                                      field->parent_ip,
                                      flags))
                        goto partial;
        }
-       if (!trace_seq_printf(s, "\n"))
+       if (!trace_seq_putc(s, '\n'))
                goto partial;
 
        return TRACE_TYPE_HANDLED;
@@ -1210,7 +1210,7 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,
 
                if (!seq_print_ip_sym(s, *p, flags))
                        goto partial;
-               if (!trace_seq_puts(s, "\n"))
+               if (!trace_seq_putc(s, '\n'))
                        goto partial;
        }
 
index 322e16461072575e6d8439208891b5730bd41438..8fd03657bc7d1f684279c46681519e16a1812f87 100644 (file)
@@ -175,7 +175,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags,
        entry = syscall_nr_to_meta(syscall);
 
        if (!entry) {
-               trace_seq_printf(s, "\n");
+               trace_seq_putc(s, '\n');
                return TRACE_TYPE_HANDLED;
        }
 
@@ -566,15 +566,15 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
        if (!sys_data)
                return;
 
+       head = this_cpu_ptr(sys_data->enter_event->perf_events);
+       if (hlist_empty(head))
+               return;
+
        /* get the size after alignment with the u32 buffer size field */
        size = sizeof(unsigned long) * sys_data->nb_args + sizeof(*rec);
        size = ALIGN(size + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
 
-       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
-                     "perf buffer not large enough"))
-               return;
-
        rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size,
                                sys_data->enter_event->event.type, regs, &rctx);
        if (!rec)
@@ -583,8 +583,6 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
        rec->nr = syscall_nr;
        syscall_get_arguments(current, regs, 0, sys_data->nb_args,
                               (unsigned long *)&rec->args);
-
-       head = this_cpu_ptr(sys_data->enter_event->perf_events);
        perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
 }
 
@@ -642,18 +640,14 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
        if (!sys_data)
                return;
 
+       head = this_cpu_ptr(sys_data->exit_event->perf_events);
+       if (hlist_empty(head))
+               return;
+
        /* We can probably do that at build time */
        size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
 
-       /*
-        * Impossible, but be paranoid with the future
-        * How to put this check outside runtime?
-        */
-       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
-               "exit event has grown above perf buffer size"))
-               return;
-
        rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size,
                                sys_data->exit_event->event.type, regs, &rctx);
        if (!rec)
@@ -661,8 +655,6 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
 
        rec->nr = syscall_nr;
        rec->ret = syscall_get_return_value(current, regs);
-
-       head = this_cpu_ptr(sys_data->exit_event->perf_events);
        perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
 }
 
index d5d0cd368a5635737f749324b61d1037c361c968..272261b5f94ff84e3291be05aaa3b1a8c1ca00ca 100644 (file)
@@ -70,7 +70,7 @@ struct trace_uprobe {
        (sizeof(struct probe_arg) * (n)))
 
 static int register_uprobe_event(struct trace_uprobe *tu);
-static void unregister_uprobe_event(struct trace_uprobe *tu);
+static int unregister_uprobe_event(struct trace_uprobe *tu);
 
 static DEFINE_MUTEX(uprobe_lock);
 static LIST_HEAD(uprobe_list);
@@ -164,11 +164,17 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou
 }
 
 /* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */
-static void unregister_trace_uprobe(struct trace_uprobe *tu)
+static int unregister_trace_uprobe(struct trace_uprobe *tu)
 {
+       int ret;
+
+       ret = unregister_uprobe_event(tu);
+       if (ret)
+               return ret;
+
        list_del(&tu->list);
-       unregister_uprobe_event(tu);
        free_trace_uprobe(tu);
+       return 0;
 }
 
 /* Register a trace_uprobe and probe_event */
@@ -181,9 +187,12 @@ static int register_trace_uprobe(struct trace_uprobe *tu)
 
        /* register as an event */
        old_tp = find_probe_event(tu->call.name, tu->call.class->system);
-       if (old_tp)
+       if (old_tp) {
                /* delete old event */
-               unregister_trace_uprobe(old_tp);
+               ret = unregister_trace_uprobe(old_tp);
+               if (ret)
+                       goto end;
+       }
 
        ret = register_uprobe_event(tu);
        if (ret) {
@@ -256,6 +265,8 @@ static int create_trace_uprobe(int argc, char **argv)
                group = UPROBE_EVENT_SYSTEM;
 
        if (is_delete) {
+               int ret;
+
                if (!event) {
                        pr_info("Delete command needs an event name.\n");
                        return -EINVAL;
@@ -269,9 +280,9 @@ static int create_trace_uprobe(int argc, char **argv)
                        return -ENOENT;
                }
                /* delete an event */
-               unregister_trace_uprobe(tu);
+               ret = unregister_trace_uprobe(tu);
                mutex_unlock(&uprobe_lock);
-               return 0;
+               return ret;
        }
 
        if (argc < 2) {
@@ -408,16 +419,20 @@ fail_address_parse:
        return ret;
 }
 
-static void cleanup_all_probes(void)
+static int cleanup_all_probes(void)
 {
        struct trace_uprobe *tu;
+       int ret = 0;
 
        mutex_lock(&uprobe_lock);
        while (!list_empty(&uprobe_list)) {
                tu = list_entry(uprobe_list.next, struct trace_uprobe, list);
-               unregister_trace_uprobe(tu);
+               ret = unregister_trace_uprobe(tu);
+               if (ret)
+                       break;
        }
        mutex_unlock(&uprobe_lock);
+       return ret;
 }
 
 /* Probes listing interfaces */
@@ -462,8 +477,13 @@ static const struct seq_operations probes_seq_op = {
 
 static int probes_open(struct inode *inode, struct file *file)
 {
-       if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC))
-               cleanup_all_probes();
+       int ret;
+
+       if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
+               ret = cleanup_all_probes();
+               if (ret)
+                       return ret;
+       }
 
        return seq_open(file, &probes_seq_op);
 }
@@ -818,8 +838,6 @@ static void uprobe_perf_print(struct trace_uprobe *tu,
 
        size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
        size = ALIGN(size + tu->size + sizeof(u32), sizeof(u64)) - sizeof(u32);
-       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
-               return;
 
        preempt_disable();
        head = this_cpu_ptr(call->perf_events);
@@ -970,12 +988,17 @@ static int register_uprobe_event(struct trace_uprobe *tu)
        return ret;
 }
 
-static void unregister_uprobe_event(struct trace_uprobe *tu)
+static int unregister_uprobe_event(struct trace_uprobe *tu)
 {
+       int ret;
+
        /* tu->event is unregistered in trace_remove_event_call() */
-       trace_remove_event_call(&tu->call);
+       ret = trace_remove_event_call(&tu->call);
+       if (ret)
+               return ret;
        kfree(tu->call.print_fmt);
        tu->call.print_fmt = NULL;
+       return 0;
 }
 
 /* Make a trace interface for controling probe points */
index d8c30db06c5b75456098fe2f1a26785e9a9110ee..6e50a44610eedc4b5ebeece393b9c9331b0b5abb 100644 (file)
@@ -105,16 +105,21 @@ int create_user_ns(struct cred *new)
 int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
 {
        struct cred *cred;
+       int err = -ENOMEM;
 
        if (!(unshare_flags & CLONE_NEWUSER))
                return 0;
 
        cred = prepare_creds();
-       if (!cred)
-               return -ENOMEM;
+       if (cred) {
+               err = create_user_ns(cred);
+               if (err)
+                       put_cred(cred);
+               else
+                       *new_cred = cred;
+       }
 
-       *new_cred = cred;
-       return create_user_ns(cred);
+       return err;
 }
 
 void free_user_ns(struct user_namespace *ns)
index ce0daa320a261f1aebfc5e16d7d7b3e7caf71c37..dec68bd4e9d8e996404faa065b67354f1defa8eb 100644 (file)
@@ -333,7 +333,8 @@ int __wait_on_atomic_t(wait_queue_head_t *wq, struct wait_bit_queue *q,
                prepare_to_wait(wq, &q->wait, mode);
                val = q->key.flags;
                if (atomic_read(val) == 0)
-                       ret = (*action)(val);
+                       break;
+               ret = (*action)(val);
        } while (!ret && atomic_read(val) != 0);
        finish_wait(wq, &q->wait);
        return ret;
index 0b72e816b8d0126f0a3e72c1f3a2496fc3545030..7f5d4be220345b0899d38ced692f2458b9278ce7 100644 (file)
@@ -2817,6 +2817,19 @@ already_gone:
        return false;
 }
 
+static bool __flush_work(struct work_struct *work)
+{
+       struct wq_barrier barr;
+
+       if (start_flush_work(work, &barr)) {
+               wait_for_completion(&barr.done);
+               destroy_work_on_stack(&barr.work);
+               return true;
+       } else {
+               return false;
+       }
+}
+
 /**
  * flush_work - wait for a work to finish executing the last queueing instance
  * @work: the work to flush
@@ -2830,18 +2843,10 @@ already_gone:
  */
 bool flush_work(struct work_struct *work)
 {
-       struct wq_barrier barr;
-
        lock_map_acquire(&work->lockdep_map);
        lock_map_release(&work->lockdep_map);
 
-       if (start_flush_work(work, &barr)) {
-               wait_for_completion(&barr.done);
-               destroy_work_on_stack(&barr.work);
-               return true;
-       } else {
-               return false;
-       }
+       return __flush_work(work);
 }
 EXPORT_SYMBOL_GPL(flush_work);
 
@@ -3411,6 +3416,12 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to,
 {
        to->nice = from->nice;
        cpumask_copy(to->cpumask, from->cpumask);
+       /*
+        * Unlike hash and equality test, this function doesn't ignore
+        * ->no_numa as it is used for both pool and wq attrs.  Instead,
+        * get_unbound_pool() explicitly clears ->no_numa after copying.
+        */
+       to->no_numa = from->no_numa;
 }
 
 /* hash value of the content of @attr */
@@ -3578,6 +3589,12 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs)
        lockdep_set_subclass(&pool->lock, 1);   /* see put_pwq() */
        copy_workqueue_attrs(pool->attrs, attrs);
 
+       /*
+        * no_numa isn't a worker_pool attribute, always clear it.  See
+        * 'struct workqueue_attrs' comments for detail.
+        */
+       pool->attrs->no_numa = false;
+
        /* if cpumask is contained inside a NUMA node, we belong to that node */
        if (wq_numa_enabled) {
                for_each_node(node) {
@@ -4756,7 +4773,14 @@ long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
 
        INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
        schedule_work_on(cpu, &wfc.work);
-       flush_work(&wfc.work);
+
+       /*
+        * The work item is on-stack and can't lead to deadlock through
+        * flushing.  Use __flush_work() to avoid spurious lockdep warnings
+        * when work_on_cpu()s are nested.
+        */
+       __flush_work(&wfc.work);
+
        return wfc.ret;
 }
 EXPORT_SYMBOL_GPL(work_on_cpu);
index 35da51359d404180c8214c007195e97ca89563dd..71d9f81f6eed17e7623ce9d0b55934acac54358c 100644 (file)
@@ -66,8 +66,6 @@ config CRC16
 
 config CRC_T10DIF
        tristate "CRC calculation for the T10 Data Integrity Field"
-       select CRYPTO
-       select CRYPTO_CRCT10DIF
        help
          This option is only needed if a module that's not in the
          kernel tree needs to calculate CRC checks for use with the
index fe3428c07b47fb605f53dc1f4d9a48f32fce54c1..fbbd66ed86cde5ed7724ed8f17986cdf1a37edaa 100644 (file)
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/crc-t10dif.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <crypto/hash.h>
 
-static struct crypto_shash *crct10dif_tfm;
+/* Table generated using the following polynomium:
+ * x^16 + x^15 + x^11 + x^9 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
+ * gt: 0x8bb7
+ */
+static const __u16 t10_dif_crc_table[256] = {
+       0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
+       0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
+       0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
+       0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
+       0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
+       0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
+       0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
+       0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
+       0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
+       0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
+       0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
+       0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
+       0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
+       0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
+       0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
+       0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
+       0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
+       0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
+       0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
+       0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
+       0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
+       0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
+       0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
+       0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
+       0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
+       0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
+       0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
+       0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
+       0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
+       0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
+       0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
+       0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
+};
 
 __u16 crc_t10dif(const unsigned char *buffer, size_t len)
 {
-       struct {
-               struct shash_desc shash;
-               char ctx[2];
-       } desc;
-       int err;
-
-       desc.shash.tfm = crct10dif_tfm;
-       desc.shash.flags = 0;
-       *(__u16 *)desc.ctx = 0;
+       __u16 crc = 0;
+       unsigned int i;
 
-       err = crypto_shash_update(&desc.shash, buffer, len);
-       BUG_ON(err);
+       for (i = 0 ; i < len ; i++)
+               crc = (crc << 8) ^ t10_dif_crc_table[((crc >> 8) ^ buffer[i]) & 0xff];
 
-       return *(__u16 *)desc.ctx;
+       return crc;
 }
 EXPORT_SYMBOL(crc_t10dif);
 
-static int __init crc_t10dif_mod_init(void)
-{
-       crct10dif_tfm = crypto_alloc_shash("crct10dif", 0, 0);
-       return PTR_RET(crct10dif_tfm);
-}
-
-static void __exit crc_t10dif_mod_fini(void)
-{
-       crypto_free_shash(crct10dif_tfm);
-}
-
-module_init(crc_t10dif_mod_init);
-module_exit(crc_t10dif_mod_fini);
-
 MODULE_DESCRIPTION("T10 DIF CRC calculation");
 MODULE_LICENSE("GPL");
index d411355f238e2088247f0cbf51631c77ae78b10e..aac511417ad19af5d9e3472747a983be5ed3ee4b 100644 (file)
@@ -151,15 +151,12 @@ do { \
 #endif /* __a29k__ */
 
 #if defined(__alpha) && W_TYPE_SIZE == 64
-#define umul_ppmm(ph, pl, m0, m1) \
-do { \
-               UDItype __m0 = (m0), __m1 = (m1); \
-               __asm__ ("umulh %r1,%2,%0" \
-               : "=r" ((UDItype) ph) \
-               : "%rJ" (__m0), \
-                       "rI" (__m1)); \
-               (pl) = __m0 * __m1; \
-       } while (0)
+#define umul_ppmm(ph, pl, m0, m1)                      \
+do {                                                   \
+       UDItype __m0 = (m0), __m1 = (m1);               \
+       (ph) = __builtin_alpha_umulh(__m0, __m1);       \
+       (pl) = __m0 * __m1;                             \
+} while (0)
 #define UMUL_TIME 46
 #ifndef LONGLONG_STANDALONE
 #define udiv_qrnnd(q, r, n1, n0, d) \
@@ -167,7 +164,7 @@ do { UDItype __r; \
        (q) = __udiv_qrnnd(&__r, (n1), (n0), (d)); \
        (r) = __r; \
 } while (0)
-extern UDItype __udiv_qrnnd();
+extern UDItype __udiv_qrnnd(UDItype *, UDItype, UDItype, UDItype);
 #define UDIV_TIME 220
 #endif /* LONGLONG_STANDALONE */
 #endif /* __alpha */
index 243e710c6039a287f93ec9f303639c7316dbdf0e..a92012a71702e7156baba919e636bcfcce8971f2 100644 (file)
@@ -1620,7 +1620,9 @@ static void __split_huge_page_refcount(struct page *page,
                                     ((1L << PG_referenced) |
                                      (1L << PG_swapbacked) |
                                      (1L << PG_mlocked) |
-                                     (1L << PG_uptodate)));
+                                     (1L << PG_uptodate) |
+                                     (1L << PG_active) |
+                                     (1L << PG_unevictable)));
                page_tail->flags |= (1L << PG_dirty);
 
                /* clear PageTail before overwriting first_page */
index 00a7a664b9c16b92769f98fec8117e7c712e6ab1..c290a1cf38624adf8372d67ccf60d9ec01ff1357 100644 (file)
@@ -6335,6 +6335,7 @@ static void mem_cgroup_css_offline(struct cgroup *cont)
        mem_cgroup_invalidate_reclaim_iterators(memcg);
        mem_cgroup_reparent_charges(memcg);
        mem_cgroup_destroy_all_caches(memcg);
+       vmpressure_cleanup(&memcg->vmpressure);
 }
 
 static void mem_cgroup_css_free(struct cgroup *cont)
index 74310017296ee02317b79a2c28b25ef303fc7720..4baf12e534d19031d28ddc5eba5335f72de54099 100644 (file)
@@ -732,7 +732,10 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
                if (prev) {
                        vma = prev;
                        next = vma->vm_next;
-                       continue;
+                       if (mpol_equal(vma_policy(vma), new_pol))
+                               continue;
+                       /* vma_merge() joined vma && vma->next, case 8 */
+                       goto replace;
                }
                if (vma->vm_start != vmstart) {
                        err = split_vma(vma->vm_mm, vma, vmstart, 1);
@@ -744,6 +747,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
                        if (err)
                                goto out;
                }
+ replace:
                err = vma_replace_policy(vma, new_pol);
                if (err)
                        goto out;
index fbad7b091090d12ba0b101815fdc8699b092ee0d..1edbaa3136c3c464cf648e569f2f98499f00642c 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -865,7 +865,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
                if (next->anon_vma)
                        anon_vma_merge(vma, next);
                mm->map_count--;
-               vma_set_policy(vma, vma_policy(next));
+               mpol_put(vma_policy(next));
                kmem_cache_free(vm_area_cachep, next);
                /*
                 * In mprotect's case 6 (see comments on vma_merge),
index a87990cf9f94019c70d7263d247c1c94945aee5b..8335dbd3fc358ed1fe9d6521785ecee1dc031313 100644 (file)
@@ -1798,7 +1798,8 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
                }
        }
 
-       offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE);
+       if (offset >= 0)
+               offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE);
        mutex_unlock(&inode->i_mutex);
        return offset;
 }
index 2b02d666bf63aee43e60e17fab4544e31730383c..e3ba1f2cf60cc0caa5dd7ed059dbe583b477e073 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1968,9 +1968,6 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
        int pages;
        int pobjects;
 
-       if (!s->cpu_partial)
-               return;
-
        do {
                pages = 0;
                pobjects = 0;
index 4a1d0d2c52fa4ab4ca66ff4a2025e093521556c9..62b78a6e224f2f10682e9fa11f28b8d01da1c324 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -512,12 +512,7 @@ EXPORT_SYMBOL(__lru_cache_add);
  */
 void lru_cache_add(struct page *page)
 {
-       if (PageActive(page)) {
-               VM_BUG_ON(PageUnevictable(page));
-       } else if (PageUnevictable(page)) {
-               VM_BUG_ON(PageActive(page));
-       }
-
+       VM_BUG_ON(PageActive(page) && PageUnevictable(page));
        VM_BUG_ON(PageLRU(page));
        __lru_cache_add(page);
 }
@@ -539,6 +534,7 @@ void add_page_to_unevictable_list(struct page *page)
 
        spin_lock_irq(&zone->lru_lock);
        lruvec = mem_cgroup_page_lruvec(page, zone);
+       ClearPageActive(page);
        SetPageUnevictable(page);
        SetPageLRU(page);
        add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE);
@@ -774,8 +770,6 @@ EXPORT_SYMBOL(__pagevec_release);
 void lru_add_page_tail(struct page *page, struct page *page_tail,
                       struct lruvec *lruvec, struct list_head *list)
 {
-       int uninitialized_var(active);
-       enum lru_list lru;
        const int file = 0;
 
        VM_BUG_ON(!PageHead(page));
@@ -787,20 +781,6 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
        if (!list)
                SetPageLRU(page_tail);
 
-       if (page_evictable(page_tail)) {
-               if (PageActive(page)) {
-                       SetPageActive(page_tail);
-                       active = 1;
-                       lru = LRU_ACTIVE_ANON;
-               } else {
-                       active = 0;
-                       lru = LRU_INACTIVE_ANON;
-               }
-       } else {
-               SetPageUnevictable(page_tail);
-               lru = LRU_UNEVICTABLE;
-       }
-
        if (likely(PageLRU(page)))
                list_add_tail(&page_tail->lru, &page->lru);
        else if (list) {
@@ -816,13 +796,13 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
                 * Use the standard add function to put page_tail on the list,
                 * but then correct its position so they all end up in order.
                 */
-               add_page_to_lru_list(page_tail, lruvec, lru);
+               add_page_to_lru_list(page_tail, lruvec, page_lru(page_tail));
                list_head = page_tail->lru.prev;
                list_move_tail(&page_tail->lru, list_head);
        }
 
        if (!PageUnevictable(page))
-               update_page_reclaim_stat(lruvec, file, active);
+               update_page_reclaim_stat(lruvec, file, PageActive(page_tail));
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
@@ -833,7 +813,6 @@ static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec,
        int active = PageActive(page);
        enum lru_list lru = page_lru(page);
 
-       VM_BUG_ON(PageUnevictable(page));
        VM_BUG_ON(PageLRU(page));
 
        SetPageLRU(page);
index 736a6011c2c88606cc7908fe429b14823be18625..0c1e37d829fa026a9fc61ef93b569087939867c5 100644 (file)
@@ -180,12 +180,12 @@ static void vmpressure_work_fn(struct work_struct *work)
        if (!vmpr->scanned)
                return;
 
-       mutex_lock(&vmpr->sr_lock);
+       spin_lock(&vmpr->sr_lock);
        scanned = vmpr->scanned;
        reclaimed = vmpr->reclaimed;
        vmpr->scanned = 0;
        vmpr->reclaimed = 0;
-       mutex_unlock(&vmpr->sr_lock);
+       spin_unlock(&vmpr->sr_lock);
 
        do {
                if (vmpressure_event(vmpr, scanned, reclaimed))
@@ -240,13 +240,13 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
        if (!scanned)
                return;
 
-       mutex_lock(&vmpr->sr_lock);
+       spin_lock(&vmpr->sr_lock);
        vmpr->scanned += scanned;
        vmpr->reclaimed += reclaimed;
        scanned = vmpr->scanned;
-       mutex_unlock(&vmpr->sr_lock);
+       spin_unlock(&vmpr->sr_lock);
 
-       if (scanned < vmpressure_win || work_pending(&vmpr->work))
+       if (scanned < vmpressure_win)
                return;
        schedule_work(&vmpr->work);
 }
@@ -367,8 +367,24 @@ void vmpressure_unregister_event(struct cgroup *cg, struct cftype *cft,
  */
 void vmpressure_init(struct vmpressure *vmpr)
 {
-       mutex_init(&vmpr->sr_lock);
+       spin_lock_init(&vmpr->sr_lock);
        mutex_init(&vmpr->events_lock);
        INIT_LIST_HEAD(&vmpr->events);
        INIT_WORK(&vmpr->work, vmpressure_work_fn);
 }
+
+/**
+ * vmpressure_cleanup() - shuts down vmpressure control structure
+ * @vmpr:      Structure to be cleaned up
+ *
+ * This function should be called before the structure in which it is
+ * embedded is cleaned up.
+ */
+void vmpressure_cleanup(struct vmpressure *vmpr)
+{
+       /*
+        * Make sure there is no pending work before eventfd infrastructure
+        * goes away.
+        */
+       flush_work(&vmpr->work);
+}
index 9bb4710e35898b61c6824253501107898db76f36..ad1e781284fdd48492e7bac46c245fae5d578f95 100644 (file)
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -257,7 +257,7 @@ int zbud_alloc(struct zbud_pool *pool, int size, gfp_t gfp,
 
        if (size <= 0 || gfp & __GFP_HIGHMEM)
                return -EINVAL;
-       if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED)
+       if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
                return -ENOSPC;
        chunks = size_to_chunks(size);
        spin_lock(&pool->lock);
index 37702491abe98eedd91738408851c56d3a8ea3a5..2b406608a1a4a42606e6ca3eb583f5f1b136176a 100644 (file)
@@ -244,7 +244,7 @@ config NETPRIO_CGROUP
          Cgroup subsystem for use in assigning processes to network priorities on
          a per-interface basis
 
-config NET_LL_RX_POLL
+config NET_RX_BUSY_POLL
        boolean
        default y
 
index e3a349977595f2aff6bd27f49e2ee9ee00164470..cc27297da5a9f9094e3079ef43e207dbd9848b68 100644 (file)
@@ -513,7 +513,10 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt)
 
        hci_setup_event_mask(req);
 
-       if (hdev->hci_ver > BLUETOOTH_VER_1_1)
+       /* AVM Berlin (31), aka "BlueFRITZ!", doesn't support the read
+        * local supported commands HCI command.
+        */
+       if (hdev->manufacturer != 31 && hdev->hci_ver > BLUETOOTH_VER_1_1)
                hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
 
        if (lmp_ssp_capable(hdev)) {
@@ -2165,10 +2168,6 @@ int hci_register_dev(struct hci_dev *hdev)
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       write_lock(&hci_dev_list_lock);
-       list_add(&hdev->list, &hci_dev_list);
-       write_unlock(&hci_dev_list_lock);
-
        hdev->workqueue = alloc_workqueue("%s", WQ_HIGHPRI | WQ_UNBOUND |
                                          WQ_MEM_RECLAIM, 1, hdev->name);
        if (!hdev->workqueue) {
@@ -2203,6 +2202,10 @@ int hci_register_dev(struct hci_dev *hdev)
        if (hdev->dev_type != HCI_AMP)
                set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
 
+       write_lock(&hci_dev_list_lock);
+       list_add(&hdev->list, &hci_dev_list);
+       write_unlock(&hci_dev_list_lock);
+
        hci_notify(hdev, HCI_DEV_REG);
        hci_dev_hold(hdev);
 
@@ -2215,9 +2218,6 @@ err_wqueue:
        destroy_workqueue(hdev->req_workqueue);
 err:
        ida_simple_remove(&hci_index_ida, hdev->id);
-       write_lock(&hci_dev_list_lock);
-       list_del(&hdev->list);
-       write_unlock(&hci_dev_list_lock);
 
        return error;
 }
@@ -3399,8 +3399,16 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
         */
        if (hdev->sent_cmd) {
                req_complete = bt_cb(hdev->sent_cmd)->req.complete;
-               if (req_complete)
+
+               if (req_complete) {
+                       /* We must set the complete callback to NULL to
+                        * avoid calling the callback more than once if
+                        * this function gets called again.
+                        */
+                       bt_cb(hdev->sent_cmd)->req.complete = NULL;
+
                        goto call_complete;
+               }
        }
 
        /* Remove all pending commands belonging to this request */
index 2ef66781fedb3a9211448fa3db73eedab2c7d8a2..69363bd37f64ae016441df793e0f66ea3487bbb8 100644 (file)
@@ -70,7 +70,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
                }
 
                mdst = br_mdb_get(br, skb, vid);
-               if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
+               if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
+                   br_multicast_querier_exists(br))
                        br_multicast_deliver(mdst, skb);
                else
                        br_flood_deliver(br, skb, false);
index 1b8b8b824cd766b05665e1d89f0e1394abdfbe2f..8c561c0aa636e49615b13e267c98e4e5bdce1a23 100644 (file)
@@ -101,7 +101,8 @@ int br_handle_frame_finish(struct sk_buff *skb)
                unicast = false;
        } else if (is_multicast_ether_addr(dest)) {
                mdst = br_mdb_get(br, skb, vid);
-               if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
+               if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
+                   br_multicast_querier_exists(br)) {
                        if ((mdst && mdst->mglist) ||
                            br_multicast_is_router(br))
                                skb2 = skb;
index 69af490cce4437bdc107f8b5b1216780b4c126af..61c5e819380e52d6347cde7186251467e921c1a0 100644 (file)
@@ -619,6 +619,9 @@ rehash:
        mp->br = br;
        mp->addr = *group;
 
+       setup_timer(&mp->timer, br_multicast_group_expired,
+                   (unsigned long)mp);
+
        hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]);
        mdb->size++;
 
@@ -1011,6 +1014,16 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 }
 #endif
 
+static void br_multicast_update_querier_timer(struct net_bridge *br,
+                                             unsigned long max_delay)
+{
+       if (!timer_pending(&br->multicast_querier_timer))
+               br->multicast_querier_delay_time = jiffies + max_delay;
+
+       mod_timer(&br->multicast_querier_timer,
+                 jiffies + br->multicast_querier_interval);
+}
+
 /*
  * Add port to router_list
  *  list is maintained ordered by pointer value
@@ -1061,11 +1074,11 @@ timer:
 
 static void br_multicast_query_received(struct net_bridge *br,
                                        struct net_bridge_port *port,
-                                       int saddr)
+                                       int saddr,
+                                       unsigned long max_delay)
 {
        if (saddr)
-               mod_timer(&br->multicast_querier_timer,
-                         jiffies + br->multicast_querier_interval);
+               br_multicast_update_querier_timer(br, max_delay);
        else if (timer_pending(&br->multicast_querier_timer))
                return;
 
@@ -1093,8 +1106,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
-       br_multicast_query_received(br, port, !!iph->saddr);
-
        group = ih->group;
 
        if (skb->len == sizeof(*ih)) {
@@ -1118,6 +1129,8 @@ static int br_ip4_multicast_query(struct net_bridge *br,
                            IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
        }
 
+       br_multicast_query_received(br, port, !!iph->saddr, max_delay);
+
        if (!group)
                goto out;
 
@@ -1126,7 +1139,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
        mod_timer(&mp->timer, now + br->multicast_membership_interval);
        mp->timer_armed = true;
 
@@ -1174,8 +1186,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
-       br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
-
        if (skb->len == sizeof(*mld)) {
                if (!pskb_may_pull(skb, sizeof(*mld))) {
                        err = -EINVAL;
@@ -1196,6 +1206,9 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
        }
 
+       br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr),
+                                   max_delay);
+
        if (!group)
                goto out;
 
@@ -1204,7 +1217,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
        mod_timer(&mp->timer, now + br->multicast_membership_interval);
        mp->timer_armed = true;
 
@@ -1642,6 +1654,8 @@ void br_multicast_init(struct net_bridge *br)
        br->multicast_querier_interval = 255 * HZ;
        br->multicast_membership_interval = 260 * HZ;
 
+       br->multicast_querier_delay_time = 0;
+
        spin_lock_init(&br->multicast_lock);
        setup_timer(&br->multicast_router_timer,
                    br_multicast_local_router_expired, 0);
@@ -1830,6 +1844,8 @@ unlock:
 
 int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
 {
+       unsigned long max_delay;
+
        val = !!val;
 
        spin_lock_bh(&br->multicast_lock);
@@ -1837,8 +1853,14 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
                goto unlock;
 
        br->multicast_querier = val;
-       if (val)
-               br_multicast_start_querier(br);
+       if (!val)
+               goto unlock;
+
+       max_delay = br->multicast_query_response_interval;
+       if (!timer_pending(&br->multicast_querier_timer))
+               br->multicast_querier_delay_time = jiffies + max_delay;
+
+       br_multicast_start_querier(br);
 
 unlock:
        spin_unlock_bh(&br->multicast_lock);
index 3be89b3ce17b5a314215609790cadec6e5453727..2f7da41851bffc64d20c0de3db6977a800718747 100644 (file)
@@ -267,6 +267,7 @@ struct net_bridge
        unsigned long                   multicast_query_interval;
        unsigned long                   multicast_query_response_interval;
        unsigned long                   multicast_startup_query_interval;
+       unsigned long                   multicast_querier_delay_time;
 
        spinlock_t                      multicast_lock;
        struct net_bridge_mdb_htable __rcu *mdb;
@@ -501,6 +502,13 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
               (br->multicast_router == 1 &&
                timer_pending(&br->multicast_router_timer));
 }
+
+static inline bool br_multicast_querier_exists(struct net_bridge *br)
+{
+       return time_is_before_jiffies(br->multicast_querier_delay_time) &&
+              (br->multicast_querier ||
+               timer_pending(&br->multicast_querier_timer));
+}
 #else
 static inline int br_multicast_rcv(struct net_bridge *br,
                                   struct net_bridge_port *port,
@@ -557,6 +565,10 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
 {
        return 0;
 }
+static inline bool br_multicast_querier_exists(struct net_bridge *br)
+{
+       return false;
+}
 static inline void br_mdb_init(void)
 {
 }
index b7de821f98df2875dd5c4c7b08f32b2f3d7f98a2..9232c68941abb4b5b5ec23f5d6cd56054d8b4c67 100644 (file)
@@ -2767,6 +2767,7 @@ EXPORT_SYMBOL(neigh_app_ns);
 
 #ifdef CONFIG_SYSCTL
 static int zero;
+static int int_max = INT_MAX;
 static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
 
 static int proc_unres_qlen(struct ctl_table *ctl, int write,
@@ -2819,19 +2820,25 @@ static struct neigh_sysctl_table {
                        .procname       = "mcast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_UCAST_PROBE] = {
                        .procname       = "ucast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_APP_PROBE] = {
                        .procname       = "app_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_RETRANS_TIME] = {
                        .procname       = "retrans_time",
@@ -2874,7 +2881,9 @@ static struct neigh_sysctl_table {
                        .procname       = "proxy_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_ANYCAST_DELAY] = {
                        .procname       = "anycast_delay",
@@ -2916,19 +2925,25 @@ static struct neigh_sysctl_table {
                        .procname       = "gc_thresh1",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_GC_THRESH2] = {
                        .procname       = "gc_thresh2",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_GC_THRESH3] = {
                        .procname       = "gc_thresh3",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                {},
        },
index 20e02d2605ecb2f10f5f74ab6f00cbd8fb852615..2c3d0f53d198c5915669a967f273c5f5b13b12af 100644 (file)
@@ -309,7 +309,8 @@ EXPORT_SYMBOL(__alloc_skb);
  * @frag_size: size of fragment, or 0 if head was kmalloced
  *
  * Allocate a new &sk_buff. Caller provides space holding head and
- * skb_shared_info. @data must have been allocated by kmalloc()
+ * skb_shared_info. @data must have been allocated by kmalloc() only if
+ * @frag_size is 0, otherwise data should come from the page allocator.
  * The return is the new skb buffer.
  * On a failure the return is %NULL, and @data is not freed.
  * Notes :
@@ -739,7 +740,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 
        skb_copy_secmark(new, old);
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        new->napi_id    = old->napi_id;
 #endif
 }
index 548d716c5f62ac8c9d90d0959d19022714f9585d..2c097c5a35dd8550d8a3041ae41e6afec35bf48b 100644 (file)
@@ -900,7 +900,7 @@ set_rcvbuf:
                sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool);
                break;
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        case SO_BUSY_POLL:
                /* allow unprivileged users to decrease the value */
                if ((val > sk->sk_ll_usec) && !capable(CAP_NET_ADMIN))
@@ -1170,7 +1170,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE);
                break;
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        case SO_BUSY_POLL:
                v.val = sk->sk_ll_usec;
                break;
@@ -2292,7 +2292,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
        sk->sk_stamp = ktime_set(-1L, 0);
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        sk->sk_napi_id          =       0;
        sk->sk_ll_usec          =       sysctl_net_busy_read;
 #endif
index 6609686166379765233cdbfab0e3d580a3d23051..31107abd278391dfe6752a46fea03ec22978b604 100644 (file)
@@ -21,7 +21,9 @@
 #include <net/net_ratelimit.h>
 #include <net/busy_poll.h>
 
+static int zero = 0;
 static int one = 1;
+static int ushort_max = USHRT_MAX;
 
 #ifdef CONFIG_RPS
 static int rps_sock_flow_sysctl(struct ctl_table *table, int write,
@@ -298,7 +300,7 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = flow_limit_table_len_sysctl
        },
 #endif /* CONFIG_NET_FLOW_LIMIT */
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        {
                .procname       = "busy_poll",
                .data           = &sysctl_net_busy_poll,
@@ -339,7 +341,9 @@ static struct ctl_table netns_core_table[] = {
                .data           = &init_net.core.sysctl_somaxconn,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .extra1         = &zero,
+               .extra2         = &ushort_max,
+               .proc_handler   = proc_dointvec_minmax
        },
        { }
 };
index 8d48c392adccec6dc1f2ca8e3c8fd5a6750283e5..34ca6d5a3a4b48f5dc8282a514115a278642f344 100644 (file)
@@ -772,7 +772,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
                ci = nla_data(tb[IFA_CACHEINFO]);
                if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
                        err = -EINVAL;
-                       goto errout;
+                       goto errout_free;
                }
                *pvalid_lft = ci->ifa_valid;
                *pprefered_lft = ci->ifa_prefered;
@@ -780,6 +780,8 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
 
        return ifa;
 
+errout_free:
+       inet_free_ifa(ifa);
 errout:
        return ERR_PTR(err);
 }
index 49616fed9340265b203c7b1fbf10390f92c38020..108a1e9c9eac388515530bb790d0e56e4dba0bfd 100644 (file)
@@ -2133,7 +2133,7 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
                max--;
 
        pointers = 0;
-       for (i = 1; i <= max; i++)
+       for (i = 1; i < max; i++)
                if (stat->nodesizes[i] != 0) {
                        seq_printf(seq, "  %u: %u",  i, stat->nodesizes[i]);
                        pointers += (1<<i) * stat->nodesizes[i];
index b2c123c44d6947afe1f6d588808643c5db3be9b8..610e324348d1cc5acdd861d8af916331d49244d7 100644 (file)
@@ -36,6 +36,8 @@ static int tcp_adv_win_scale_min = -31;
 static int tcp_adv_win_scale_max = 31;
 static int ip_ttl_min = 1;
 static int ip_ttl_max = 255;
+static int tcp_syn_retries_min = 1;
+static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
 static int ip_ping_group_range_min[] = { 0, 0 };
 static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
 
@@ -332,7 +334,9 @@ static struct ctl_table ipv4_table[] = {
                .data           = &sysctl_tcp_syn_retries,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &tcp_syn_retries_min,
+               .extra2         = &tcp_syn_retries_max
        },
        {
                .procname       = "tcp_synack_retries",
index cfdcf7b2daf68ff681608351e0bca7202923824b..da4241c8c7dafe0004a53ed85dfc270cd3be16ba 100644 (file)
@@ -813,8 +813,9 @@ static u32 inet6_addr_hash(const struct in6_addr *addr)
 /* On success it returns ifp with increased reference count */
 
 static struct inet6_ifaddr *
-ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
-             int scope, u32 flags)
+ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
+             const struct in6_addr *peer_addr, int pfxlen,
+             int scope, u32 flags, u32 valid_lft, u32 prefered_lft)
 {
        struct inet6_ifaddr *ifa = NULL;
        struct rt6_info *rt;
@@ -863,6 +864,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        }
 
        ifa->addr = *addr;
+       if (peer_addr)
+               ifa->peer_addr = *peer_addr;
 
        spin_lock_init(&ifa->lock);
        spin_lock_init(&ifa->state_lock);
@@ -872,6 +875,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        ifa->scope = scope;
        ifa->prefix_len = pfxlen;
        ifa->flags = flags | IFA_F_TENTATIVE;
+       ifa->valid_lft = valid_lft;
+       ifa->prefered_lft = prefered_lft;
        ifa->cstamp = ifa->tstamp = jiffies;
        ifa->tokenized = false;
 
@@ -1123,8 +1128,9 @@ retry:
 
        ift = !max_addresses ||
              ipv6_count_addresses(idev) < max_addresses ?
-               ipv6_add_addr(idev, &addr, tmp_plen, ipv6_addr_scope(&addr),
-                             addr_flags) : NULL;
+               ipv6_add_addr(idev, &addr, NULL, tmp_plen,
+                             ipv6_addr_scope(&addr), addr_flags,
+                             tmp_valid_lft, tmp_prefered_lft) : NULL;
        if (IS_ERR_OR_NULL(ift)) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
@@ -1136,8 +1142,6 @@ retry:
 
        spin_lock_bh(&ift->lock);
        ift->ifpub = ifp;
-       ift->valid_lft = tmp_valid_lft;
-       ift->prefered_lft = tmp_prefered_lft;
        ift->cstamp = now;
        ift->tstamp = tmp_tstamp;
        spin_unlock_bh(&ift->lock);
@@ -2179,16 +2183,19 @@ ok:
                         */
                        if (!max_addresses ||
                            ipv6_count_addresses(in6_dev) < max_addresses)
-                               ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
+                               ifp = ipv6_add_addr(in6_dev, &addr, NULL,
+                                                   pinfo->prefix_len,
                                                    addr_type&IPV6_ADDR_SCOPE_MASK,
-                                                   addr_flags);
+                                                   addr_flags, valid_lft,
+                                                   prefered_lft);
 
                        if (IS_ERR_OR_NULL(ifp)) {
                                in6_dev_put(in6_dev);
                                return;
                        }
 
-                       update_lft = create = 1;
+                       update_lft = 0;
+                       create = 1;
                        ifp->cstamp = jiffies;
                        ifp->tokenized = tokenized;
                        addrconf_dad_start(ifp);
@@ -2209,7 +2216,7 @@ ok:
                                stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ;
                        else
                                stored_lft = 0;
-                       if (!update_lft && stored_lft) {
+                       if (!update_lft && !create && stored_lft) {
                                if (valid_lft > MIN_VALID_LIFETIME ||
                                    valid_lft > stored_lft)
                                        update_lft = 1;
@@ -2455,17 +2462,10 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
                prefered_lft = timeout;
        }
 
-       ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
+       ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags,
+                           valid_lft, prefered_lft);
 
        if (!IS_ERR(ifp)) {
-               spin_lock_bh(&ifp->lock);
-               ifp->valid_lft = valid_lft;
-               ifp->prefered_lft = prefered_lft;
-               ifp->tstamp = jiffies;
-               if (peer_pfx)
-                       ifp->peer_addr = *peer_pfx;
-               spin_unlock_bh(&ifp->lock);
-
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
                                      expires, flags);
                /*
@@ -2557,7 +2557,8 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 {
        struct inet6_ifaddr *ifp;
 
-       ifp = ipv6_add_addr(idev, addr, plen, scope, IFA_F_PERMANENT);
+       ifp = ipv6_add_addr(idev, addr, NULL, plen,
+                           scope, IFA_F_PERMANENT, 0, 0);
        if (!IS_ERR(ifp)) {
                spin_lock_bh(&ifp->lock);
                ifp->flags &= ~IFA_F_TENTATIVE;
@@ -2683,7 +2684,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr
 #endif
 
 
-       ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);
+       ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, 0, 0);
        if (!IS_ERR(ifp)) {
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
                addrconf_dad_start(ifp);
index 5fc9c7a68d8d102aef37b7b13ab1dd772553a9cb..bff3d821c7ebb7cf7b05342a5e4a9b4ddb14cd4a 100644 (file)
@@ -1632,27 +1632,28 @@ static int fib6_age(struct rt6_info *rt, void *arg)
 
 static DEFINE_SPINLOCK(fib6_gc_lock);
 
-void fib6_run_gc(unsigned long expires, struct net *net)
+void fib6_run_gc(unsigned long expires, struct net *net, bool force)
 {
-       if (expires != ~0UL) {
+       unsigned long now;
+
+       if (force) {
                spin_lock_bh(&fib6_gc_lock);
-               gc_args.timeout = expires ? (int)expires :
-                       net->ipv6.sysctl.ip6_rt_gc_interval;
-       } else {
-               if (!spin_trylock_bh(&fib6_gc_lock)) {
-                       mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
-                       return;
-               }
-               gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
+       } else if (!spin_trylock_bh(&fib6_gc_lock)) {
+               mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
+               return;
        }
+       gc_args.timeout = expires ? (int)expires :
+                         net->ipv6.sysctl.ip6_rt_gc_interval;
 
        gc_args.more = icmp6_dst_gc();
 
        fib6_clean_all(net, fib6_age, 0, NULL);
+       now = jiffies;
+       net->ipv6.ip6_rt_last_gc = now;
 
        if (gc_args.more)
                mod_timer(&net->ipv6.ip6_fib_timer,
-                         round_jiffies(jiffies
+                         round_jiffies(now
                                        + net->ipv6.sysctl.ip6_rt_gc_interval));
        else
                del_timer(&net->ipv6.ip6_fib_timer);
@@ -1661,7 +1662,7 @@ void fib6_run_gc(unsigned long expires, struct net *net)
 
 static void fib6_gc_timer_cb(unsigned long arg)
 {
-       fib6_run_gc(0, (struct net *)arg);
+       fib6_run_gc(0, (struct net *)arg, true);
 }
 
 static int __net_init fib6_net_init(struct net *net)
index 583e8d435f9a2c47437d3897b7167ac4a4025a40..03986d31fa417a357b72e529e28fea0de0294a9e 100644 (file)
@@ -259,10 +259,12 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
 {
        struct mr6_table *mrt, *next;
 
+       rtnl_lock();
        list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
                list_del(&mrt->list);
                ip6mr_free_table(mrt);
        }
+       rtnl_unlock();
        fib_rules_unregister(net->ipv6.mr6_rules_ops);
 }
 #else
@@ -289,7 +291,10 @@ static int __net_init ip6mr_rules_init(struct net *net)
 
 static void __net_exit ip6mr_rules_exit(struct net *net)
 {
+       rtnl_lock();
        ip6mr_free_table(net->ipv6.mrt6);
+       net->ipv6.mrt6 = NULL;
+       rtnl_unlock();
 }
 #endif
 
index 24c03396e0083b751d2a924b69b2dc731f1b957f..79aa9652ed86d9cac754366c075800fbbe4aca1b 100644 (file)
@@ -1576,7 +1576,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
        switch (event) {
        case NETDEV_CHANGEADDR:
                neigh_changeaddr(&nd_tbl, dev);
-               fib6_run_gc(~0UL, net);
+               fib6_run_gc(0, net, false);
                idev = in6_dev_get(dev);
                if (!idev)
                        break;
@@ -1586,7 +1586,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
                break;
        case NETDEV_DOWN:
                neigh_ifdown(&nd_tbl, dev);
-               fib6_run_gc(~0UL, net);
+               fib6_run_gc(0, net, false);
                break;
        case NETDEV_NOTIFY_PEERS:
                ndisc_send_unsol_na(dev);
index a8c891aa24645e9a45d2f8e47712b0698a29b216..b70f8979003b5e23c4b1e78e44713ba3d3520de9 100644 (file)
@@ -1311,7 +1311,6 @@ static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
 
 static int ip6_dst_gc(struct dst_ops *ops)
 {
-       unsigned long now = jiffies;
        struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
        int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
        int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
@@ -1321,13 +1320,12 @@ static int ip6_dst_gc(struct dst_ops *ops)
        int entries;
 
        entries = dst_entries_get_fast(ops);
-       if (time_after(rt_last_gc + rt_min_interval, now) &&
+       if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
            entries <= rt_max_size)
                goto out;
 
        net->ipv6.ip6_rt_gc_expire++;
-       fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
-       net->ipv6.ip6_rt_last_gc = now;
+       fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, entries > rt_max_size);
        entries = dst_entries_get_slow(ops);
        if (entries < ops->gc_thresh)
                net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
@@ -2827,7 +2825,7 @@ int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
        net = (struct net *)ctl->extra1;
        delay = net->ipv6.sysctl.flush_delay;
        proc_dointvec(ctl, write, buffer, lenp, ppos);
-       fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
+       fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
        return 0;
 }
 
index 9da862070dd84fe596f77582c82af6eec8ad660c..ab8bd2cabfa090a4fa50524e7a76064891e535d6 100644 (file)
@@ -2081,6 +2081,7 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, const struct xfrm_policy *
                        pol->sadb_x_policy_type = IPSEC_POLICY_NONE;
        }
        pol->sadb_x_policy_dir = dir+1;
+       pol->sadb_x_policy_reserved = 0;
        pol->sadb_x_policy_id = xp->index;
        pol->sadb_x_policy_priority = xp->priority;
 
@@ -3137,7 +3138,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
        pol->sadb_x_policy_dir = XFRM_POLICY_OUT + 1;
+       pol->sadb_x_policy_reserved = 0;
        pol->sadb_x_policy_id = xp->index;
+       pol->sadb_x_policy_priority = xp->priority;
 
        /* Set sadb_comb's. */
        if (x->id.proto == IPPROTO_AH)
@@ -3525,6 +3528,7 @@ static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
        pol->sadb_x_policy_dir = dir + 1;
+       pol->sadb_x_policy_reserved = 0;
        pol->sadb_x_policy_id = 0;
        pol->sadb_x_policy_priority = 0;
 
index 8184d121ff0904a285529ff234f75c3f15f522e5..43dd7525bfcba54c02dbd9dde2bd89cfc2d29c97 100644 (file)
@@ -666,6 +666,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
                        if (sta->sdata->dev != dev)
                                continue;
 
+                       sinfo.filled = 0;
+                       sta_set_sinfo(sta, &sinfo);
                        i = 0;
                        ADD_STA_STATS(sta);
                }
index 3b7bfc01ee36e922927958be79e1ec7414c8a3d6..22290a929b94595445865baecdb692aff5e0be9c 100644 (file)
@@ -229,6 +229,10 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
        enum nl80211_mesh_power_mode pm;
        bool do_buffer;
 
+       /* For non-assoc STA, prevent buffering or frame transmission */
+       if (sta->sta_state < IEEE80211_STA_ASSOC)
+               return;
+
        /*
         * use peer-specific power mode if peering is established and the
         * peer's power mode is known
index 7fc5d0d8149a53f2a20377499841657dd9a97c7c..340126204343a063902bb205675cc14bea743a4c 100644 (file)
@@ -99,10 +99,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        }
        mutex_unlock(&local->sta_mtx);
 
-       /* remove all interfaces */
+       /* remove all interfaces that were created in the driver */
        list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!ieee80211_sdata_running(sdata))
+               if (!ieee80211_sdata_running(sdata) ||
+                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR)
                        continue;
+
                drv_remove_interface(local, sdata);
        }
 
index ac7ef5414bdede030d289a81946eaabc7b5d7a88..e6512e2ffd200223cd5cb75090802a98f544bb7d 100644 (file)
@@ -290,7 +290,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
        struct minstrel_rate *msr, *mr;
        unsigned int ndx;
        bool mrr_capable;
-       bool prev_sample = mi->prev_sample;
+       bool prev_sample;
        int delta;
        int sampling_ratio;
 
@@ -314,6 +314,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                        (mi->sample_count + mi->sample_deferred / 2);
 
        /* delta < 0: no sampling required */
+       prev_sample = mi->prev_sample;
        mi->prev_sample = false;
        if (delta < 0 || (!mrr_capable && prev_sample))
                return;
index 5b2d3012b9830aef8d9101c26ba761402993b382..f5aed963b22e62cd997872d1068bfb6c45eeda7a 100644 (file)
@@ -804,10 +804,18 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 
        sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
        info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+       rate->count = 1;
+
+       if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
+               int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);
+               rate->idx = mp->cck_rates[idx];
+               rate->flags = 0;
+               return;
+       }
+
        rate->idx = sample_idx % MCS_GROUP_RATES +
                    (sample_group->streams - 1) * MCS_GROUP_RATES;
        rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
-       rate->count = 1;
 }
 
 static void
index 23dbcfc69b3b7f09ffc35c81d03dddc38d36da5a..2c5a79bd3777f5c313d3205a1154ef6b714a8d4d 100644 (file)
@@ -936,8 +936,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 
-       /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
-       if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
+       /*
+        * Drop duplicate 802.11 retransmissions
+        * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
+        */
+       if (rx->skb->len >= 24 && rx->sta &&
+           !ieee80211_is_ctl(hdr->frame_control) &&
+           !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
+           !is_multicast_ether_addr(hdr->addr1)) {
                if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
                             rx->sta->last_seq_ctrl[rx->seqno_idx] ==
                             hdr->seq_ctrl)) {
index c63b618cd619eb01d0fe99413162a84edd09ac3c..4fd1ca94fd4a140b374385ded878af60b503b529 100644 (file)
@@ -293,6 +293,11 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
                       sizeof(exp->tuple.dst.u3) - len);
 
        exp->tuple.dst.u.all = *dst;
+
+#ifdef CONFIG_NF_NAT_NEEDED
+       memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
+       memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
+#endif
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_init);
 
index f8b71911037ab172f3df8f6a82cb8d22191ab1d6..20b15916f40363ff789d2d7312dd5fe4dedf69ab 100644 (file)
@@ -172,7 +172,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
 
                /* Ignore non-transparent sockets,
                   if XT_SOCKET_TRANSPARENT is used */
-               if (info && info->flags & XT_SOCKET_TRANSPARENT)
+               if (info->flags & XT_SOCKET_TRANSPARENT)
                        transparent = ((sk->sk_state != TCP_TIME_WAIT &&
                                        inet_sk(sk)->transparent) ||
                                       (sk->sk_state == TCP_TIME_WAIT &&
@@ -196,7 +196,11 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
 static bool
 socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
 {
-       return socket_match(skb, par, NULL);
+       static struct xt_socket_mtinfo1 xt_info_v0 = {
+               .flags = 0,
+       };
+
+       return socket_match(skb, par, &xt_info_v0);
 }
 
 static bool
@@ -314,7 +318,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 
                /* Ignore non-transparent sockets,
                   if XT_SOCKET_TRANSPARENT is used */
-               if (info && info->flags & XT_SOCKET_TRANSPARENT)
+               if (info->flags & XT_SOCKET_TRANSPARENT)
                        transparent = ((sk->sk_state != TCP_TIME_WAIT &&
                                        inet_sk(sk)->transparent) ||
                                       (sk->sk_state == TCP_TIME_WAIT &&
index c15042f987bd8f5697338b88cc77ed6553a0d609..a1100640495d3d3b106e850e9af6a9cc4e1ed547 100644 (file)
@@ -691,8 +691,8 @@ static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
 {
        struct netlbl_domhsh_walk_arg *cb_arg = arg;
 
-       if (entry->type == NETLBL_NLTYPE_CIPSOV4 &&
-           entry->type_def.cipsov4->doi == cb_arg->doi)
+       if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
+           entry->def.cipso->doi == cb_arg->doi)
                return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
 
        return 0;
index 6bb1d42f0fac04c02a69ee1790d40baf7af53824..85d842e6e43187998232441f5e2228244cb1cb95 100644 (file)
@@ -84,15 +84,15 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry)
 #endif /* IPv6 */
 
        ptr = container_of(entry, struct netlbl_dom_map, rcu);
-       if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
+       if (ptr->def.type == NETLBL_NLTYPE_ADDRSELECT) {
                netlbl_af4list_foreach_safe(iter4, tmp4,
-                                           &ptr->type_def.addrsel->list4) {
+                                           &ptr->def.addrsel->list4) {
                        netlbl_af4list_remove_entry(iter4);
                        kfree(netlbl_domhsh_addr4_entry(iter4));
                }
 #if IS_ENABLED(CONFIG_IPV6)
                netlbl_af6list_foreach_safe(iter6, tmp6,
-                                           &ptr->type_def.addrsel->list6) {
+                                           &ptr->def.addrsel->list6) {
                        netlbl_af6list_remove_entry(iter6);
                        kfree(netlbl_domhsh_addr6_entry(iter6));
                }
@@ -213,21 +213,21 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
                if (addr4 != NULL) {
                        struct netlbl_domaddr4_map *map4;
                        map4 = netlbl_domhsh_addr4_entry(addr4);
-                       type = map4->type;
-                       cipsov4 = map4->type_def.cipsov4;
+                       type = map4->def.type;
+                       cipsov4 = map4->def.cipso;
                        netlbl_af4list_audit_addr(audit_buf, 0, NULL,
                                                  addr4->addr, addr4->mask);
 #if IS_ENABLED(CONFIG_IPV6)
                } else if (addr6 != NULL) {
                        struct netlbl_domaddr6_map *map6;
                        map6 = netlbl_domhsh_addr6_entry(addr6);
-                       type = map6->type;
+                       type = map6->def.type;
                        netlbl_af6list_audit_addr(audit_buf, 0, NULL,
                                                  &addr6->addr, &addr6->mask);
 #endif /* IPv6 */
                } else {
-                       type = entry->type;
-                       cipsov4 = entry->type_def.cipsov4;
+                       type = entry->def.type;
+                       cipsov4 = entry->def.cipso;
                }
                switch (type) {
                case NETLBL_NLTYPE_UNLABELED:
@@ -265,26 +265,25 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
        if (entry == NULL)
                return -EINVAL;
 
-       switch (entry->type) {
+       switch (entry->def.type) {
        case NETLBL_NLTYPE_UNLABELED:
-               if (entry->type_def.cipsov4 != NULL ||
-                   entry->type_def.addrsel != NULL)
+               if (entry->def.cipso != NULL || entry->def.addrsel != NULL)
                        return -EINVAL;
                break;
        case NETLBL_NLTYPE_CIPSOV4:
-               if (entry->type_def.cipsov4 == NULL)
+               if (entry->def.cipso == NULL)
                        return -EINVAL;
                break;
        case NETLBL_NLTYPE_ADDRSELECT:
-               netlbl_af4list_foreach(iter4, &entry->type_def.addrsel->list4) {
+               netlbl_af4list_foreach(iter4, &entry->def.addrsel->list4) {
                        map4 = netlbl_domhsh_addr4_entry(iter4);
-                       switch (map4->type) {
+                       switch (map4->def.type) {
                        case NETLBL_NLTYPE_UNLABELED:
-                               if (map4->type_def.cipsov4 != NULL)
+                               if (map4->def.cipso != NULL)
                                        return -EINVAL;
                                break;
                        case NETLBL_NLTYPE_CIPSOV4:
-                               if (map4->type_def.cipsov4 == NULL)
+                               if (map4->def.cipso == NULL)
                                        return -EINVAL;
                                break;
                        default:
@@ -292,9 +291,9 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
                        }
                }
 #if IS_ENABLED(CONFIG_IPV6)
-               netlbl_af6list_foreach(iter6, &entry->type_def.addrsel->list6) {
+               netlbl_af6list_foreach(iter6, &entry->def.addrsel->list6) {
                        map6 = netlbl_domhsh_addr6_entry(iter6);
-                       switch (map6->type) {
+                       switch (map6->def.type) {
                        case NETLBL_NLTYPE_UNLABELED:
                                break;
                        default:
@@ -402,32 +401,31 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                        rcu_assign_pointer(netlbl_domhsh_def, entry);
                }
 
-               if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+               if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
                        netlbl_af4list_foreach_rcu(iter4,
-                                              &entry->type_def.addrsel->list4)
+                                                  &entry->def.addrsel->list4)
                                netlbl_domhsh_audit_add(entry, iter4, NULL,
                                                        ret_val, audit_info);
 #if IS_ENABLED(CONFIG_IPV6)
                        netlbl_af6list_foreach_rcu(iter6,
-                                              &entry->type_def.addrsel->list6)
+                                                  &entry->def.addrsel->list6)
                                netlbl_domhsh_audit_add(entry, NULL, iter6,
                                                        ret_val, audit_info);
 #endif /* IPv6 */
                } else
                        netlbl_domhsh_audit_add(entry, NULL, NULL,
                                                ret_val, audit_info);
-       } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
-                  entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+       } else if (entry_old->def.type == NETLBL_NLTYPE_ADDRSELECT &&
+                  entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
                struct list_head *old_list4;
                struct list_head *old_list6;
 
-               old_list4 = &entry_old->type_def.addrsel->list4;
-               old_list6 = &entry_old->type_def.addrsel->list6;
+               old_list4 = &entry_old->def.addrsel->list4;
+               old_list6 = &entry_old->def.addrsel->list6;
 
                /* we only allow the addition of address selectors if all of
                 * the selectors do not exist in the existing domain map */
-               netlbl_af4list_foreach_rcu(iter4,
-                                          &entry->type_def.addrsel->list4)
+               netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4)
                        if (netlbl_af4list_search_exact(iter4->addr,
                                                        iter4->mask,
                                                        old_list4)) {
@@ -435,8 +433,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                                goto add_return;
                        }
 #if IS_ENABLED(CONFIG_IPV6)
-               netlbl_af6list_foreach_rcu(iter6,
-                                          &entry->type_def.addrsel->list6)
+               netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6)
                        if (netlbl_af6list_search_exact(&iter6->addr,
                                                        &iter6->mask,
                                                        old_list6)) {
@@ -446,7 +443,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
 #endif /* IPv6 */
 
                netlbl_af4list_foreach_safe(iter4, tmp4,
-                                           &entry->type_def.addrsel->list4) {
+                                           &entry->def.addrsel->list4) {
                        netlbl_af4list_remove_entry(iter4);
                        iter4->valid = 1;
                        ret_val = netlbl_af4list_add(iter4, old_list4);
@@ -457,7 +454,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                }
 #if IS_ENABLED(CONFIG_IPV6)
                netlbl_af6list_foreach_safe(iter6, tmp6,
-                                           &entry->type_def.addrsel->list6) {
+                                           &entry->def.addrsel->list6) {
                        netlbl_af6list_remove_entry(iter6);
                        iter6->valid = 1;
                        ret_val = netlbl_af6list_add(iter6, old_list6);
@@ -538,18 +535,18 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
                struct netlbl_af4list *iter4;
                struct netlbl_domaddr4_map *map4;
 
-               switch (entry->type) {
+               switch (entry->def.type) {
                case NETLBL_NLTYPE_ADDRSELECT:
                        netlbl_af4list_foreach_rcu(iter4,
-                                            &entry->type_def.addrsel->list4) {
+                                            &entry->def.addrsel->list4) {
                                map4 = netlbl_domhsh_addr4_entry(iter4);
-                               cipso_v4_doi_putdef(map4->type_def.cipsov4);
+                               cipso_v4_doi_putdef(map4->def.cipso);
                        }
                        /* no need to check the IPv6 list since we currently
                         * support only unlabeled protocols for IPv6 */
                        break;
                case NETLBL_NLTYPE_CIPSOV4:
-                       cipso_v4_doi_putdef(entry->type_def.cipsov4);
+                       cipso_v4_doi_putdef(entry->def.cipso);
                        break;
                }
                call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
@@ -590,20 +587,21 @@ int netlbl_domhsh_remove_af4(const char *domain,
                entry_map = netlbl_domhsh_search(domain);
        else
                entry_map = netlbl_domhsh_search_def(domain);
-       if (entry_map == NULL || entry_map->type != NETLBL_NLTYPE_ADDRSELECT)
+       if (entry_map == NULL ||
+           entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
                goto remove_af4_failure;
 
        spin_lock(&netlbl_domhsh_lock);
        entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
-                                          &entry_map->type_def.addrsel->list4);
+                                          &entry_map->def.addrsel->list4);
        spin_unlock(&netlbl_domhsh_lock);
 
        if (entry_addr == NULL)
                goto remove_af4_failure;
-       netlbl_af4list_foreach_rcu(iter4, &entry_map->type_def.addrsel->list4)
+       netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
                goto remove_af4_single_addr;
 #if IS_ENABLED(CONFIG_IPV6)
-       netlbl_af6list_foreach_rcu(iter6, &entry_map->type_def.addrsel->list6)
+       netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
                goto remove_af4_single_addr;
 #endif /* IPv6 */
        /* the domain mapping is empty so remove it from the mapping table */
@@ -616,7 +614,7 @@ remove_af4_single_addr:
         * shouldn't be a problem */
        synchronize_rcu();
        entry = netlbl_domhsh_addr4_entry(entry_addr);
-       cipso_v4_doi_putdef(entry->type_def.cipsov4);
+       cipso_v4_doi_putdef(entry->def.cipso);
        kfree(entry);
        return 0;
 
@@ -693,8 +691,8 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
  * responsible for ensuring that rcu_read_[un]lock() is called.
  *
  */
-struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
-                                                      __be32 addr)
+struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
+                                                    __be32 addr)
 {
        struct netlbl_dom_map *dom_iter;
        struct netlbl_af4list *addr_iter;
@@ -702,15 +700,13 @@ struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
        dom_iter = netlbl_domhsh_search_def(domain);
        if (dom_iter == NULL)
                return NULL;
-       if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
-               return NULL;
 
-       addr_iter = netlbl_af4list_search(addr,
-                                         &dom_iter->type_def.addrsel->list4);
+       if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
+               return &dom_iter->def;
+       addr_iter = netlbl_af4list_search(addr, &dom_iter->def.addrsel->list4);
        if (addr_iter == NULL)
                return NULL;
-
-       return netlbl_domhsh_addr4_entry(addr_iter);
+       return &(netlbl_domhsh_addr4_entry(addr_iter)->def);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -725,7 +721,7 @@ struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
  * responsible for ensuring that rcu_read_[un]lock() is called.
  *
  */
-struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
                                                   const struct in6_addr *addr)
 {
        struct netlbl_dom_map *dom_iter;
@@ -734,15 +730,13 @@ struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
        dom_iter = netlbl_domhsh_search_def(domain);
        if (dom_iter == NULL)
                return NULL;
-       if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
-               return NULL;
 
-       addr_iter = netlbl_af6list_search(addr,
-                                         &dom_iter->type_def.addrsel->list6);
+       if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
+               return &dom_iter->def;
+       addr_iter = netlbl_af6list_search(addr, &dom_iter->def.addrsel->list6);
        if (addr_iter == NULL)
                return NULL;
-
-       return netlbl_domhsh_addr6_entry(addr_iter);
+       return &(netlbl_domhsh_addr6_entry(addr_iter)->def);
 }
 #endif /* IPv6 */
 
index 90872c4ca30f4ba9aad89089eff5dadfdff42717..b9be0eed89801ab194b8f6a97899e7bbf9c50ec3 100644 (file)
 #define NETLBL_DOMHSH_BITSIZE       7
 
 /* Domain mapping definition structures */
+struct netlbl_domaddr_map {
+       struct list_head list4;
+       struct list_head list6;
+};
+struct netlbl_dommap_def {
+       u32 type;
+       union {
+               struct netlbl_domaddr_map *addrsel;
+               struct cipso_v4_doi *cipso;
+       };
+};
 #define netlbl_domhsh_addr4_entry(iter) \
        container_of(iter, struct netlbl_domaddr4_map, list)
 struct netlbl_domaddr4_map {
-       u32 type;
-       union {
-               struct cipso_v4_doi *cipsov4;
-       } type_def;
+       struct netlbl_dommap_def def;
 
        struct netlbl_af4list list;
 };
 #define netlbl_domhsh_addr6_entry(iter) \
        container_of(iter, struct netlbl_domaddr6_map, list)
 struct netlbl_domaddr6_map {
-       u32 type;
-
-       /* NOTE: no 'type_def' union needed at present since we don't currently
-        *       support any IPv6 labeling protocols */
+       struct netlbl_dommap_def def;
 
        struct netlbl_af6list list;
 };
-struct netlbl_domaddr_map {
-       struct list_head list4;
-       struct list_head list6;
-};
+
 struct netlbl_dom_map {
        char *domain;
-       u32 type;
-       union {
-               struct cipso_v4_doi *cipsov4;
-               struct netlbl_domaddr_map *addrsel;
-       } type_def;
+       struct netlbl_dommap_def def;
 
        u32 valid;
        struct list_head list;
@@ -97,16 +95,16 @@ int netlbl_domhsh_remove_af4(const char *domain,
 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
-struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
-                                                      __be32 addr);
+struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
+                                                    __be32 addr);
+#if IS_ENABLED(CONFIG_IPV6)
+struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
+                                                  const struct in6_addr *addr);
+#endif /* IPv6 */
+
 int netlbl_domhsh_walk(u32 *skip_bkt,
                     u32 *skip_chain,
                     int (*callback) (struct netlbl_dom_map *entry, void *arg),
                     void *cb_arg);
 
-#if IS_ENABLED(CONFIG_IPV6)
-struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
-                                                 const struct in6_addr *addr);
-#endif /* IPv6 */
-
 #endif
index 7c94aedd0912777d6d0956f0f5b048f0f62ab97d..96a458e12f60ada2186c08ebbafe22c6e68ba06e 100644 (file)
@@ -122,7 +122,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
        }
 
        if (addr == NULL && mask == NULL)
-               entry->type = NETLBL_NLTYPE_UNLABELED;
+               entry->def.type = NETLBL_NLTYPE_UNLABELED;
        else if (addr != NULL && mask != NULL) {
                addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
                if (addrmap == NULL)
@@ -137,7 +137,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
                        map4 = kzalloc(sizeof(*map4), GFP_ATOMIC);
                        if (map4 == NULL)
                                goto cfg_unlbl_map_add_failure;
-                       map4->type = NETLBL_NLTYPE_UNLABELED;
+                       map4->def.type = NETLBL_NLTYPE_UNLABELED;
                        map4->list.addr = addr4->s_addr & mask4->s_addr;
                        map4->list.mask = mask4->s_addr;
                        map4->list.valid = 1;
@@ -154,7 +154,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
                        map6 = kzalloc(sizeof(*map6), GFP_ATOMIC);
                        if (map6 == NULL)
                                goto cfg_unlbl_map_add_failure;
-                       map6->type = NETLBL_NLTYPE_UNLABELED;
+                       map6->def.type = NETLBL_NLTYPE_UNLABELED;
                        map6->list.addr = *addr6;
                        map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0];
                        map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1];
@@ -174,8 +174,8 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
                        break;
                }
 
-               entry->type_def.addrsel = addrmap;
-               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->def.addrsel = addrmap;
+               entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
        } else {
                ret_val = -EINVAL;
                goto cfg_unlbl_map_add_failure;
@@ -355,8 +355,8 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
        }
 
        if (addr == NULL && mask == NULL) {
-               entry->type_def.cipsov4 = doi_def;
-               entry->type = NETLBL_NLTYPE_CIPSOV4;
+               entry->def.cipso = doi_def;
+               entry->def.type = NETLBL_NLTYPE_CIPSOV4;
        } else if (addr != NULL && mask != NULL) {
                addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
                if (addrmap == NULL)
@@ -367,8 +367,8 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
                addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
                if (addrinfo == NULL)
                        goto out_addrinfo;
-               addrinfo->type_def.cipsov4 = doi_def;
-               addrinfo->type = NETLBL_NLTYPE_CIPSOV4;
+               addrinfo->def.cipso = doi_def;
+               addrinfo->def.type = NETLBL_NLTYPE_CIPSOV4;
                addrinfo->list.addr = addr->s_addr & mask->s_addr;
                addrinfo->list.mask = mask->s_addr;
                addrinfo->list.valid = 1;
@@ -376,8 +376,8 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
                if (ret_val != 0)
                        goto cfg_cipsov4_map_add_failure;
 
-               entry->type_def.addrsel = addrmap;
-               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->def.addrsel = addrmap;
+               entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
        } else {
                ret_val = -EINVAL;
                goto out_addrmap;
@@ -657,14 +657,14 @@ int netlbl_sock_setattr(struct sock *sk,
        }
        switch (family) {
        case AF_INET:
-               switch (dom_entry->type) {
+               switch (dom_entry->def.type) {
                case NETLBL_NLTYPE_ADDRSELECT:
                        ret_val = -EDESTADDRREQ;
                        break;
                case NETLBL_NLTYPE_CIPSOV4:
                        ret_val = cipso_v4_sock_setattr(sk,
-                                                   dom_entry->type_def.cipsov4,
-                                                   secattr);
+                                                       dom_entry->def.cipso,
+                                                       secattr);
                        break;
                case NETLBL_NLTYPE_UNLABELED:
                        ret_val = 0;
@@ -754,23 +754,22 @@ int netlbl_conn_setattr(struct sock *sk,
 {
        int ret_val;
        struct sockaddr_in *addr4;
-       struct netlbl_domaddr4_map *af4_entry;
+       struct netlbl_dommap_def *entry;
 
        rcu_read_lock();
        switch (addr->sa_family) {
        case AF_INET:
                addr4 = (struct sockaddr_in *)addr;
-               af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
-                                                      addr4->sin_addr.s_addr);
-               if (af4_entry == NULL) {
+               entry = netlbl_domhsh_getentry_af4(secattr->domain,
+                                                  addr4->sin_addr.s_addr);
+               if (entry == NULL) {
                        ret_val = -ENOENT;
                        goto conn_setattr_return;
                }
-               switch (af4_entry->type) {
+               switch (entry->type) {
                case NETLBL_NLTYPE_CIPSOV4:
                        ret_val = cipso_v4_sock_setattr(sk,
-                                                  af4_entry->type_def.cipsov4,
-                                                  secattr);
+                                                       entry->cipso, secattr);
                        break;
                case NETLBL_NLTYPE_UNLABELED:
                        /* just delete the protocols we support for right now
@@ -812,36 +811,21 @@ int netlbl_req_setattr(struct request_sock *req,
                       const struct netlbl_lsm_secattr *secattr)
 {
        int ret_val;
-       struct netlbl_dom_map *dom_entry;
-       struct netlbl_domaddr4_map *af4_entry;
-       u32 proto_type;
-       struct cipso_v4_doi *proto_cv4;
+       struct netlbl_dommap_def *entry;
 
        rcu_read_lock();
-       dom_entry = netlbl_domhsh_getentry(secattr->domain);
-       if (dom_entry == NULL) {
-               ret_val = -ENOENT;
-               goto req_setattr_return;
-       }
        switch (req->rsk_ops->family) {
        case AF_INET:
-               if (dom_entry->type == NETLBL_NLTYPE_ADDRSELECT) {
-                       struct inet_request_sock *req_inet = inet_rsk(req);
-                       af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
-                                                           req_inet->rmt_addr);
-                       if (af4_entry == NULL) {
-                               ret_val = -ENOENT;
-                               goto req_setattr_return;
-                       }
-                       proto_type = af4_entry->type;
-                       proto_cv4 = af4_entry->type_def.cipsov4;
-               } else {
-                       proto_type = dom_entry->type;
-                       proto_cv4 = dom_entry->type_def.cipsov4;
+               entry = netlbl_domhsh_getentry_af4(secattr->domain,
+                                                  inet_rsk(req)->rmt_addr);
+               if (entry == NULL) {
+                       ret_val = -ENOENT;
+                       goto req_setattr_return;
                }
-               switch (proto_type) {
+               switch (entry->type) {
                case NETLBL_NLTYPE_CIPSOV4:
-                       ret_val = cipso_v4_req_setattr(req, proto_cv4, secattr);
+                       ret_val = cipso_v4_req_setattr(req,
+                                                      entry->cipso, secattr);
                        break;
                case NETLBL_NLTYPE_UNLABELED:
                        /* just delete the protocols we support for right now
@@ -899,23 +883,21 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
 {
        int ret_val;
        struct iphdr *hdr4;
-       struct netlbl_domaddr4_map *af4_entry;
+       struct netlbl_dommap_def *entry;
 
        rcu_read_lock();
        switch (family) {
        case AF_INET:
                hdr4 = ip_hdr(skb);
-               af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
-                                                      hdr4->daddr);
-               if (af4_entry == NULL) {
+               entry = netlbl_domhsh_getentry_af4(secattr->domain,hdr4->daddr);
+               if (entry == NULL) {
                        ret_val = -ENOENT;
                        goto skbuff_setattr_return;
                }
-               switch (af4_entry->type) {
+               switch (entry->type) {
                case NETLBL_NLTYPE_CIPSOV4:
-                       ret_val = cipso_v4_skbuff_setattr(skb,
-                                                  af4_entry->type_def.cipsov4,
-                                                  secattr);
+                       ret_val = cipso_v4_skbuff_setattr(skb, entry->cipso,
+                                                         secattr);
                        break;
                case NETLBL_NLTYPE_UNLABELED:
                        /* just delete the protocols we support for right now
index c5384ffc61469a422f1e5f4a9519131d95b56236..dd1c37d7acbcfa6d126a8056360b8d6a56985035 100644 (file)
@@ -104,7 +104,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                ret_val = -ENOMEM;
                goto add_failure;
        }
-       entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
+       entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
        if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
                size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
                entry->domain = kmalloc(tmp_size, GFP_KERNEL);
@@ -116,12 +116,12 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                            info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
        }
 
-       /* NOTE: internally we allow/use a entry->type value of
+       /* NOTE: internally we allow/use a entry->def.type value of
         *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
         *       to pass that as a protocol value because we need to know the
         *       "real" protocol */
 
-       switch (entry->type) {
+       switch (entry->def.type) {
        case NETLBL_NLTYPE_UNLABELED:
                break;
        case NETLBL_NLTYPE_CIPSOV4:
@@ -132,7 +132,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                cipsov4 = cipso_v4_doi_getdef(tmp_val);
                if (cipsov4 == NULL)
                        goto add_failure;
-               entry->type_def.cipsov4 = cipsov4;
+               entry->def.cipso = cipsov4;
                break;
        default:
                goto add_failure;
@@ -172,9 +172,9 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                map->list.addr = addr->s_addr & mask->s_addr;
                map->list.mask = mask->s_addr;
                map->list.valid = 1;
-               map->type = entry->type;
+               map->def.type = entry->def.type;
                if (cipsov4)
-                       map->type_def.cipsov4 = cipsov4;
+                       map->def.cipso = cipsov4;
 
                ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
                if (ret_val != 0) {
@@ -182,8 +182,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                        goto add_failure;
                }
 
-               entry->type = NETLBL_NLTYPE_ADDRSELECT;
-               entry->type_def.addrsel = addrmap;
+               entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->def.addrsel = addrmap;
 #if IS_ENABLED(CONFIG_IPV6)
        } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
                struct in6_addr *addr;
@@ -223,7 +223,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
                map->list.mask = *mask;
                map->list.valid = 1;
-               map->type = entry->type;
+               map->def.type = entry->def.type;
 
                ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
                if (ret_val != 0) {
@@ -231,8 +231,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                        goto add_failure;
                }
 
-               entry->type = NETLBL_NLTYPE_ADDRSELECT;
-               entry->type_def.addrsel = addrmap;
+               entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->def.addrsel = addrmap;
 #endif /* IPv6 */
        }
 
@@ -281,14 +281,13 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                        return ret_val;
        }
 
-       switch (entry->type) {
+       switch (entry->def.type) {
        case NETLBL_NLTYPE_ADDRSELECT:
                nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
                if (nla_a == NULL)
                        return -ENOMEM;
 
-               netlbl_af4list_foreach_rcu(iter4,
-                                          &entry->type_def.addrsel->list4) {
+               netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
                        struct netlbl_domaddr4_map *map4;
                        struct in_addr addr_struct;
 
@@ -310,13 +309,13 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                                return ret_val;
                        map4 = netlbl_domhsh_addr4_entry(iter4);
                        ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
-                                             map4->type);
+                                             map4->def.type);
                        if (ret_val != 0)
                                return ret_val;
-                       switch (map4->type) {
+                       switch (map4->def.type) {
                        case NETLBL_NLTYPE_CIPSOV4:
                                ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
-                                                 map4->type_def.cipsov4->doi);
+                                                     map4->def.cipso->doi);
                                if (ret_val != 0)
                                        return ret_val;
                                break;
@@ -325,8 +324,7 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                        nla_nest_end(skb, nla_b);
                }
 #if IS_ENABLED(CONFIG_IPV6)
-               netlbl_af6list_foreach_rcu(iter6,
-                                          &entry->type_def.addrsel->list6) {
+               netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
                        struct netlbl_domaddr6_map *map6;
 
                        nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
@@ -345,7 +343,7 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                                return ret_val;
                        map6 = netlbl_domhsh_addr6_entry(iter6);
                        ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
-                                             map6->type);
+                                             map6->def.type);
                        if (ret_val != 0)
                                return ret_val;
 
@@ -356,14 +354,14 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                nla_nest_end(skb, nla_a);
                break;
        case NETLBL_NLTYPE_UNLABELED:
-               ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+               ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
                break;
        case NETLBL_NLTYPE_CIPSOV4:
-               ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+               ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
                if (ret_val != 0)
                        return ret_val;
                ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
-                                     entry->type_def.cipsov4->doi);
+                                     entry->def.cipso->doi);
                break;
        }
 
index af3531926ee0c0339c6cc73725c50a1d7ec2a18d..8f0897407a2cf950240082cfde9ab07969f96404 100644 (file)
@@ -1541,7 +1541,7 @@ int __init netlbl_unlabel_defconf(void)
        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (entry == NULL)
                return -ENOMEM;
-       entry->type = NETLBL_NLTYPE_UNLABELED;
+       entry->def.type = NETLBL_NLTYPE_UNLABELED;
        ret_val = netlbl_domhsh_add_default(entry, &audit_info);
        if (ret_val != 0)
                return ret_val;
index 2fd6dbea327a8b39d2ec0ed10b927d74bcdab408..512718adb0d59df5120e047c69c973556d1c6fb6 100644 (file)
@@ -571,7 +571,7 @@ static int genl_family_rcv_msg(struct genl_family *family,
            !capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .dump = ops->dumpit,
                        .done = ops->done,
@@ -877,8 +877,10 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
 #ifdef CONFIG_MODULES
                if (res == NULL) {
                        genl_unlock();
+                       up_read(&cb_lock);
                        request_module("net-pf-%d-proto-%d-family-%s",
                                       PF_NETLINK, NETLINK_GENERIC, name);
+                       down_read(&cb_lock);
                        genl_lock();
                        res = genl_family_find_byname(name);
                }
index dc96a83aa6abb6659311e11ef13f97dc81c3b494..1d074dd1650ff2fd326dd141eedb828d812a12e6 100644 (file)
@@ -44,7 +44,7 @@ DEFINE_MUTEX(nfc_devlist_mutex);
 /* NFC device ID bitmap */
 static DEFINE_IDA(nfc_index_ida);
 
-int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name)
+int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name)
 {
        int rc = 0;
 
@@ -62,28 +62,28 @@ int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name)
                goto error;
        }
 
-       if (!dev->ops->fw_upload) {
+       if (!dev->ops->fw_download) {
                rc = -EOPNOTSUPP;
                goto error;
        }
 
-       dev->fw_upload_in_progress = true;
-       rc = dev->ops->fw_upload(dev, firmware_name);
+       dev->fw_download_in_progress = true;
+       rc = dev->ops->fw_download(dev, firmware_name);
        if (rc)
-               dev->fw_upload_in_progress = false;
+               dev->fw_download_in_progress = false;
 
 error:
        device_unlock(&dev->dev);
        return rc;
 }
 
-int nfc_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
+int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name)
 {
-       dev->fw_upload_in_progress = false;
+       dev->fw_download_in_progress = false;
 
-       return nfc_genl_fw_upload_done(dev, firmware_name);
+       return nfc_genl_fw_download_done(dev, firmware_name);
 }
-EXPORT_SYMBOL(nfc_fw_upload_done);
+EXPORT_SYMBOL(nfc_fw_download_done);
 
 /**
  * nfc_dev_up - turn on the NFC device
@@ -110,7 +110,7 @@ int nfc_dev_up(struct nfc_dev *dev)
                goto error;
        }
 
-       if (dev->fw_upload_in_progress) {
+       if (dev->fw_download_in_progress) {
                rc = -EBUSY;
                goto error;
        }
index 7b1c186736ebf924977ed8eb9040357ab88f3c3c..fe66908401f55ed5f608a75b559e5fad1ff15548 100644 (file)
@@ -809,14 +809,14 @@ static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
-static int hci_fw_upload(struct nfc_dev *nfc_dev, const char *firmware_name)
+static int hci_fw_download(struct nfc_dev *nfc_dev, const char *firmware_name)
 {
        struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
 
-       if (!hdev->ops->fw_upload)
+       if (!hdev->ops->fw_download)
                return -ENOTSUPP;
 
-       return hdev->ops->fw_upload(hdev, firmware_name);
+       return hdev->ops->fw_download(hdev, firmware_name);
 }
 
 static struct nfc_ops hci_nfc_ops = {
@@ -831,7 +831,7 @@ static struct nfc_ops hci_nfc_ops = {
        .im_transceive = hci_transceive,
        .tm_send = hci_tm_send,
        .check_presence = hci_check_presence,
-       .fw_upload = hci_fw_upload,
+       .fw_download = hci_fw_download,
        .discover_se = hci_discover_se,
        .enable_se = hci_enable_se,
        .disable_se = hci_disable_se,
index 2a2416080b4fbfcf2127a4cab2abc755b5188c06..a4f1e42e34818c91eeb2b527c7b547a718454459 100644 (file)
@@ -11,6 +11,7 @@ config NFC_NCI
 
 config NFC_NCI_SPI
        depends on NFC_NCI && SPI
+       select CRC_CCITT
        bool "NCI over SPI protocol support"
        default n
        help
index b05ad909778fe5978677f3f81a31360220f98eb7..f16fd59d41607d80aeeae916ae3d43153a0a5b4e 100644 (file)
@@ -1089,7 +1089,7 @@ exit:
        return rc;
 }
 
-static int nfc_genl_fw_upload(struct sk_buff *skb, struct genl_info *info)
+static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info)
 {
        struct nfc_dev *dev;
        int rc;
@@ -1108,13 +1108,13 @@ static int nfc_genl_fw_upload(struct sk_buff *skb, struct genl_info *info)
        nla_strlcpy(firmware_name, info->attrs[NFC_ATTR_FIRMWARE_NAME],
                    sizeof(firmware_name));
 
-       rc = nfc_fw_upload(dev, firmware_name);
+       rc = nfc_fw_download(dev, firmware_name);
 
        nfc_put_device(dev);
        return rc;
 }
 
-int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
+int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -1124,7 +1124,7 @@ int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
                return -ENOMEM;
 
        hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
-                         NFC_CMD_FW_UPLOAD);
+                         NFC_CMD_FW_DOWNLOAD);
        if (!hdr)
                goto free_msg;
 
@@ -1251,8 +1251,8 @@ static struct genl_ops nfc_genl_ops[] = {
                .policy = nfc_genl_policy,
        },
        {
-               .cmd = NFC_CMD_FW_UPLOAD,
-               .doit = nfc_genl_fw_upload,
+               .cmd = NFC_CMD_FW_DOWNLOAD,
+               .doit = nfc_genl_fw_download,
                .policy = nfc_genl_policy,
        },
        {
index ee85a1fc1b2443d88982ca6985574936b0359292..820a7850c36ac7e49012869a88472a96358e2220 100644 (file)
@@ -123,10 +123,10 @@ static inline void nfc_device_iter_exit(struct class_dev_iter *iter)
        class_dev_iter_exit(iter);
 }
 
-int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name);
-int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name);
+int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name);
+int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name);
 
-int nfc_fw_upload_done(struct nfc_dev *dev, const char *firmware_name);
+int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name);
 
 int nfc_dev_up(struct nfc_dev *dev);
 
index ca8e0a57d945dabeb51147f338cef363672040d5..1f9c31411f1998dec927fccf05362f09408558b4 100644 (file)
@@ -605,6 +605,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
                struct sockaddr_atmpvc pvc;
                int state;
 
+               memset(&pvc, 0, sizeof(pvc));
                pvc.sap_family = AF_ATMPVC;
                pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1;
                pvc.sap_addr.vpi = flow->vcc->vpi;
index 71a568862557c26cb9fd97bfbd26531b55ad4283..7a42c81a19ebe55f0b6a137f89c55b46314f8cd7 100644 (file)
@@ -1465,6 +1465,7 @@ static int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
        unsigned char *b = skb_tail_pointer(skb);
        struct tc_cbq_wrropt opt;
 
+       memset(&opt, 0, sizeof(opt));
        opt.flags = 0;
        opt.allot = cl->allot;
        opt.priority = cl->priority + 1;
index c2124ea29f4594304c3b7ecb02af411ed62fbebe..45e751527dfcc57ed533c4b259bbf5c56e093cfc 100644 (file)
@@ -100,7 +100,7 @@ struct htb_class {
        struct psched_ratecfg   ceil;
        s64                     buffer, cbuffer;/* token bucket depth/rate */
        s64                     mbuffer;        /* max wait time */
-       int                     prio;           /* these two are used only by leaves... */
+       u32                     prio;           /* these two are used only by leaves... */
        int                     quantum;        /* but stored for parent-to-leaf return */
 
        struct tcf_proto        *filter_list;   /* class attached filters */
index 829b460acb87e61e88928f596589b51b0947411d..b2d7c629eeb9f2de785600ed189080af9be02a3e 100644 (file)
 #include <linux/atalk.h>
 #include <net/busy_poll.h>
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 unsigned int sysctl_net_busy_read __read_mostly;
 unsigned int sysctl_net_busy_poll __read_mostly;
 #endif
index d304f41260f2d8be4822631be5deb86612b63860..af7ffd447fee2af42a642c3e608536a8459ecbe5 100644 (file)
@@ -120,7 +120,7 @@ static int gssp_rpc_create(struct net *net, struct rpc_clnt **_clnt)
        if (IS_ERR(clnt)) {
                dprintk("RPC:       failed to create AF_LOCAL gssproxy "
                                "client (errno %ld).\n", PTR_ERR(clnt));
-               result = -PTR_ERR(clnt);
+               result = PTR_ERR(clnt);
                *_clnt = NULL;
                goto out;
        }
@@ -328,7 +328,6 @@ void gssp_free_upcall_data(struct gssp_upcall_data *data)
        kfree(data->in_handle.data);
        kfree(data->out_handle.data);
        kfree(data->out_token.data);
-       kfree(data->mech_oid.data);
        free_svc_cred(&data->creds);
 }
 
index 357f613df7ff49d3460e37d3f338cb89c7029a69..3c85d1c8a0288db543fdb5cbec9d9ef5bd0f2f22 100644 (file)
@@ -430,7 +430,7 @@ static int dummy_enc_nameattr_array(struct xdr_stream *xdr,
 static int dummy_dec_nameattr_array(struct xdr_stream *xdr,
                                    struct gssx_name_attr_array *naa)
 {
-       struct gssx_name_attr dummy;
+       struct gssx_name_attr dummy = { .attr = {.len = 0} };
        u32 count, i;
        __be32 *p;
 
@@ -493,12 +493,13 @@ static int gssx_enc_name(struct xdr_stream *xdr,
        return err;
 }
 
+
 static int gssx_dec_name(struct xdr_stream *xdr,
                         struct gssx_name *name)
 {
-       struct xdr_netobj dummy_netobj;
-       struct gssx_name_attr_array dummy_name_attr_array;
-       struct gssx_option_array dummy_option_array;
+       struct xdr_netobj dummy_netobj = { .len = 0 };
+       struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 };
+       struct gssx_option_array dummy_option_array = { .count = 0 };
        int err;
 
        /* name->display_name */
index d0347d148b34320fb2a12a3ed20c6a2e5222352c..09fb638bcaa42ea88ff1bc7a6d34b6605f34a0c7 100644 (file)
@@ -1180,6 +1180,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
                gm = gss_mech_get_by_OID(&ud->mech_oid);
                if (!gm)
                        goto out;
+               rsci.cred.cr_gss_mech = gm;
 
                status = -EINVAL;
                /* mech-specific data: */
@@ -1195,7 +1196,6 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
        rscp = rsc_update(cd, &rsci, rscp);
        status = 0;
 out:
-       gss_mech_put(gm);
        rsc_free(&rsci);
        if (rscp)
                cache_put(&rscp->h, cd);
index 305374d4fb985ec4942040447f91e8d8277ea10d..7762b9f8a8b72581f00003ad266ab060754f43b9 100644 (file)
@@ -1193,7 +1193,9 @@ static int svc_tcp_has_wspace(struct svc_xprt *xprt)
        if (test_bit(XPT_LISTENER, &xprt->xpt_flags))
                return 1;
        required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg;
-       if (sk_stream_wspace(svsk->sk_sk) >= required)
+       if (sk_stream_wspace(svsk->sk_sk) >= required ||
+           (sk_stream_min_wspace(svsk->sk_sk) == 0 &&
+            atomic_read(&xprt->xpt_reserved) == 0))
                return 1;
        set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
        return 0;
index 19da5abe0fa6fb1ebcf185357bd46489310d9dc7..fd3fa57a410e18393aa6cc20136fcaa28c0f7e22 100644 (file)
@@ -355,8 +355,12 @@ static int tipc_open_listening_sock(struct tipc_server *s)
                return PTR_ERR(con);
 
        sock = tipc_create_listen_sock(con);
-       if (!sock)
+       if (!sock) {
+               idr_remove(&s->conn_idr, con->conid);
+               s->idr_in_use--;
+               kfree(con);
                return -EINVAL;
+       }
 
        tipc_register_callbacks(sock, con);
        return 0;
@@ -563,9 +567,14 @@ int tipc_server_start(struct tipc_server *s)
                kmem_cache_destroy(s->rcvbuf_cache);
                return ret;
        }
+       ret = tipc_open_listening_sock(s);
+       if (ret < 0) {
+               tipc_work_stop(s);
+               kmem_cache_destroy(s->rcvbuf_cache);
+               return ret;
+       }
        s->enabled = 1;
-
-       return tipc_open_listening_sock(s);
+       return ret;
 }
 
 void tipc_server_stop(struct tipc_server *s)
index 1cc47aca7f05baee3e7ffdf18a4e002b2d62279d..25d217d90807f05f6a56945cb89dcd7b3314a53d 100644 (file)
@@ -4770,9 +4770,9 @@ do {                                                                          \
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
                                  mask, NL80211_MESHCONF_FORWARDING,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, 1, 255,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
                                  mask, NL80211_MESHCONF_RSSI_THRESHOLD,
-                                 nla_get_u32);
+                                 nla_get_s32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16,
                                  mask, NL80211_MESHCONF_HT_OPMODE,
                                  nla_get_u16);
@@ -6613,12 +6613,14 @@ EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
 
 void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
 {
+       struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
        void *hdr = ((void **)skb->cb)[1];
        struct nlattr *data = ((void **)skb->cb)[2];
 
        nla_nest_end(skb, data);
        genlmsg_end(skb, hdr);
-       genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
+                               nl80211_testmode_mcgrp.id, gfp);
 }
 EXPORT_SYMBOL(cfg80211_testmode_event);
 #endif
@@ -10064,7 +10066,8 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 
        genlmsg_end(msg, hdr);
 
-       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
        return;
 
  nla_put_failure:
index 5a24c986f34be27e61613f0deb421a35efc61533..de06d5d1287f97b6f6c8a1fd6b3e59371d80ae3e 100644 (file)
@@ -2247,10 +2247,13 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 void wiphy_regulatory_register(struct wiphy *wiphy)
 {
+       struct regulatory_request *lr;
+
        if (!reg_dev_ignore_cell_hint(wiphy))
                reg_num_devs_support_basehint++;
 
-       wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
+       lr = get_last_request();
+       wiphy_update_regulatory(wiphy, lr->initiator);
 }
 
 void wiphy_regulatory_deregister(struct wiphy *wiphy)
@@ -2279,7 +2282,9 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
 static void reg_timeout_work(struct work_struct *work)
 {
        REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
+       rtnl_lock();
        restore_regulatory_settings(true);
+       rtnl_unlock();
 }
 
 int __init regulatory_init(void)
index 1d3cfb1a3f28b3a74a32c1c629ddbcba7fb30def..81c8a10d743c04fb76981498b42588f9b821f33f 100644 (file)
@@ -34,8 +34,10 @@ struct cfg80211_conn {
                CFG80211_CONN_SCAN_AGAIN,
                CFG80211_CONN_AUTHENTICATE_NEXT,
                CFG80211_CONN_AUTHENTICATING,
+               CFG80211_CONN_AUTH_FAILED,
                CFG80211_CONN_ASSOCIATE_NEXT,
                CFG80211_CONN_ASSOCIATING,
+               CFG80211_CONN_ASSOC_FAILED,
                CFG80211_CONN_DEAUTH,
                CFG80211_CONN_CONNECTED,
        } state;
@@ -164,6 +166,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                          NULL, 0,
                                          params->key, params->key_len,
                                          params->key_idx, NULL, 0);
+       case CFG80211_CONN_AUTH_FAILED:
+               return -ENOTCONN;
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -188,10 +192,17 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                             WLAN_REASON_DEAUTH_LEAVING,
                                             false);
                return err;
+       case CFG80211_CONN_ASSOC_FAILED:
+               cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
+                                    NULL, 0,
+                                    WLAN_REASON_DEAUTH_LEAVING, false);
+               return -ENOTCONN;
        case CFG80211_CONN_DEAUTH:
                cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                     NULL, 0,
                                     WLAN_REASON_DEAUTH_LEAVING, false);
+               /* free directly, disconnected event already sent */
+               cfg80211_sme_free(wdev);
                return 0;
        default:
                return 0;
@@ -371,7 +382,7 @@ bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
                return true;
        }
 
-       wdev->conn->state = CFG80211_CONN_DEAUTH;
+       wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
        schedule_work(&rdev->conn_work);
        return false;
 }
@@ -383,7 +394,13 @@ void cfg80211_sme_deauth(struct wireless_dev *wdev)
 
 void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
 {
-       cfg80211_sme_free(wdev);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (!wdev->conn)
+               return;
+
+       wdev->conn->state = CFG80211_CONN_AUTH_FAILED;
+       schedule_work(&rdev->conn_work);
 }
 
 void cfg80211_sme_disassoc(struct wireless_dev *wdev)
@@ -399,7 +416,13 @@ void cfg80211_sme_disassoc(struct wireless_dev *wdev)
 
 void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
 {
-       cfg80211_sme_disassoc(wdev);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (!wdev->conn)
+               return;
+
+       wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
+       schedule_work(&rdev->conn_work);
 }
 
 static int cfg80211_sme_connect(struct wireless_dev *wdev,
index 99db892d7299056568e5432bdd660ea14d3143c6..98969541cbcc9c62ff81afb9818d2399dd6e7eb0 100644 (file)
@@ -743,7 +743,7 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
        mutex_lock(&stream->device->lock);
        switch (_IOC_NR(cmd)) {
        case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
-               put_user(SNDRV_COMPRESS_VERSION,
+               retval = put_user(SNDRV_COMPRESS_VERSION,
                                (int __user *)arg) ? -EFAULT : 0;
                break;
        case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
index 7c11d46b84d3b3b0fd26b8bca560f6fb3017a8fc..48a9d004d6d938ac5365b52a83c6b67b7b18dcaa 100644 (file)
@@ -860,7 +860,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                }
        }
        if (id < 0 && quirk) {
-               for (q = quirk; q->subvendor; q++) {
+               for (q = quirk; q->subvendor || q->subdevice; q++) {
                        unsigned int vendorid =
                                q->subdevice | (q->subvendor << 16);
                        unsigned int mask = 0xffff0000 | q->subdevice_mask;
index e2f83591161bbf3e7bf5f70ef732b8cd57b38587..6d1924c19abfdb41d1dddc27e119630c24995abc 100644 (file)
@@ -417,9 +417,11 @@ static void stac_update_outputs(struct hda_codec *codec)
                        val &= ~spec->eapd_mask;
                else
                        val |= spec->eapd_mask;
-               if (spec->gpio_data != val)
+               if (spec->gpio_data != val) {
+                       spec->gpio_data = val;
                        stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir,
                                      val);
+               }
        }
 }
 
@@ -2817,6 +2819,7 @@ static const struct hda_pintbl ecs202_pin_configs[] = {
 
 /* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */
 static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3),
        SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1),
        SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2),
        SND_PCI_QUIRK(0x106b, 0x0700, "Mac", STAC_INTEL_MAC_V2),
@@ -3231,7 +3234,7 @@ static const struct hda_fixup stac927x_fixups[] = {
                        /* configure the analog microphone on some laptops */
                        { 0x0c, 0x90a79130 },
                        /* correct the front output jack as a hp out */
-                       { 0x0f, 0x0227011f },
+                       { 0x0f, 0x0221101f },
                        /* correct the front input jack as a mic */
                        { 0x0e, 0x02a79130 },
                        {}
@@ -3612,20 +3615,18 @@ static int stac_parse_auto_config(struct hda_codec *codec)
 static int stac_init(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       unsigned int gpio;
        int i;
 
        /* override some hints */
        stac_store_hints(codec);
 
        /* set up GPIO */
-       gpio = spec->gpio_data;
        /* turn on EAPD statically when spec->eapd_switch isn't set.
         * otherwise, unsol event will turn it on/off dynamically
         */
        if (!spec->eapd_switch)
-               gpio |= spec->eapd_mask;
-       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio);
+               spec->gpio_data |= spec->eapd_mask;
+       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
 
        snd_hda_gen_init(codec);
 
@@ -3915,6 +3916,7 @@ static void stac_setup_gpio(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
 
+       spec->gpio_mask |= spec->eapd_mask;
        if (spec->gpio_led) {
                if (!spec->vref_mute_led_nid) {
                        spec->gpio_mask |= spec->gpio_led;
index d6f7694fcad4f78ae1cb300d8d9fe3a4ef3b11d1..c8a2de103c5f3b6b0cb5172f858c687795154d19 100644 (file)
@@ -341,7 +341,7 @@ static struct platform_driver au1xac97c_driver = {
        .remove         = au1xac97c_drvremove,
 };
 
-module_platform_driver(&au1xac97c_driver);
+module_platform_driver(au1xac97c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver");
index efb1daecd0dd6136122aa8595c145630ff102b22..e82eb373a731402cb60699881aca15a84577f72f 100644 (file)
@@ -294,11 +294,12 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
        /* Request PB3 as reset pin */
        ret = devm_gpio_request_one(&pdev->dev,
                                    CONFIG_SND_BF5XX_RESET_GPIO_NUM,
-                                   GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET") {
+                                   GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET");
+       if (ret) {
                dev_err(&pdev->dev,
                        "Failed to request GPIO_%d for reset: %d\n",
                        CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret);
-               goto gpio_err;
+               return ret;
        }
 #endif
 
index 15c635e33f4d99a42b6386cbc7e7c54e2bf807ef..0c3e22d90a8d903fbf1495936c5a97a79ab8a77e 100644 (file)
@@ -9,7 +9,6 @@
 #ifndef _BF5XX_AC97_H
 #define _BF5XX_AC97_H
 
-extern struct snd_ac97_bus_ops bf5xx_ac97_ops;
 extern struct snd_ac97 *ac97;
 /* Frame format in memory, only support stereo currently */
 struct ac97_frame {
index ac73c607410a73d92ff84a817c22bf6a99c25d5f..04491f0e8d1bde2636f8772e3b7d3bb65284d44a 100644 (file)
@@ -102,13 +102,13 @@ static struct ep93xx_ac97_info *ep93xx_ac97_info;
 
 static struct ep93xx_dma_data ep93xx_ac97_pcm_out = {
        .name           = "ac97-pcm-out",
-       .dma_port       = EP93XX_DMA_AAC1,
+       .port           = EP93XX_DMA_AAC1,
        .direction      = DMA_MEM_TO_DEV,
 };
 
 static struct ep93xx_dma_data ep93xx_ac97_pcm_in = {
        .name           = "ac97-pcm-in",
-       .dma_port       = EP93XX_DMA_AAC1,
+       .port           = EP93XX_DMA_AAC1,
        .direction      = DMA_DEV_TO_MEM,
 };
 
index 3eeada57e87de68b43394e3440805de03932d890..566a367c94fa0ce71ac04f86686923ed63ece58d 100644 (file)
@@ -1612,7 +1612,7 @@ static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 
 static void max98088_sync_cache(struct snd_soc_codec *codec)
 {
-       u16 *reg_cache = codec->reg_cache;
+       u8 *reg_cache = codec->reg_cache;
        int i;
 
        if (!codec->cache_sync)
index d659d3adcfb34e01a04fbc8dfff6fdb9468ba3ad..6c8a9e7bee25c837cd35dc260847e1c778a811b6 100644 (file)
@@ -1527,6 +1527,9 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
        if (IS_ERR(sgtl5000->mclk)) {
                ret = PTR_ERR(sgtl5000->mclk);
                dev_err(&client->dev, "Failed to get mclock: %d\n", ret);
+               /* Defer the probe to see if the clk will be provided later */
+               if (ret == -ENOENT)
+                       return -EPROBE_DEFER;
                return ret;
        }
 
index f5e835662cdca30477738e39ffe7d57f6305db78..10adc4145d4639e5e44d3c587a595f476650b6fa 100644 (file)
@@ -410,6 +410,16 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
                        rec->command, rec->length);
                len = rec->length + 8;
 
+               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
+               if (!xfer) {
+                       dev_err(codec->dev, "Failed to allocate xfer\n");
+                       ret = -ENOMEM;
+                       goto abort;
+               }
+
+               xfer->codec = codec;
+               list_add_tail(&xfer->list, &xfer_list);
+
                out = kzalloc(len, GFP_KERNEL);
                if (!out) {
                        dev_err(codec->dev,
@@ -417,6 +427,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
                        ret = -ENOMEM;
                        goto abort1;
                }
+               xfer->t.rx_buf = out;
 
                img = kzalloc(len, GFP_KERNEL);
                if (!img) {
@@ -425,24 +436,13 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
                        ret = -ENOMEM;
                        goto abort1;
                }
+               xfer->t.tx_buf = img;
 
                byte_swap_64((u64 *)&rec->command, img, len);
 
-               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
-               if (!xfer) {
-                       dev_err(codec->dev, "Failed to allocate xfer\n");
-                       ret = -ENOMEM;
-                       goto abort1;
-               }
-
-               xfer->codec = codec;
-               list_add_tail(&xfer->list, &xfer_list);
-
                spi_message_init(&xfer->m);
                xfer->m.complete = wm0010_boot_xfer_complete;
                xfer->m.context = xfer;
-               xfer->t.tx_buf = img;
-               xfer->t.rx_buf = out;
                xfer->t.len = len;
                xfer->t.bits_per_word = 8;
 
index 0ec070cf7231ebcc39a057061af8995d7f7574ff..d82ee386eab564d352eccd4209dff767b222e6f3 100644 (file)
@@ -3908,10 +3908,8 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
 {
        /* create platform component name */
        platform->name = fmt_single_name(dev, &platform->id);
-       if (platform->name == NULL) {
-               kfree(platform);
+       if (platform->name == NULL)
                return -ENOMEM;
-       }
 
        platform->dev = dev;
        platform->driver = platform_drv;
index b94190820e8cfa1b6c24e925f176196cc5efff98..bd16010441cc16fdb26aba40ae5326c427705e81 100644 (file)
@@ -2733,7 +2733,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        }
 
        mutex_unlock(&card->dapm_mutex);
-       return 0;
+       return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
 
@@ -2861,7 +2861,6 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
        struct soc_enum *e =
                (struct soc_enum *)kcontrol->private_value;
        int change;
-       int ret = 0;
        int wi;
 
        if (ucontrol->value.enumerated.item[0] >= e->max)
@@ -2881,7 +2880,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
        }
 
        mutex_unlock(&card->dapm_mutex);
-       return ret;
+       return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
 
index e58233f7df616e6bb406f809cea23069c4059933..6c486625321bebb78b6f66370fda54a49a300fcb 100644 (file)
@@ -389,9 +389,9 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        ac97->capture_dma_data.slave_id = of_dma[1];
 
        ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
-       ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       ac97->capture_dma_data.maxburst = 4;
-       ac97->capture_dma_data.slave_id = of_dma[0];
+       ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       ac97->playback_dma_data.maxburst = 4;
+       ac97->playback_dma_data.slave_id = of_dma[1];
 
        ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
        if (ret)
index 5eaa12cdc6ebd3bfcbd502beb1aff881c111d406..551b3c93ce932c77e9e05de4bcf01f5af63d1c94 100644 (file)
@@ -323,8 +323,8 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
        }
 
        spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
-       spdif->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       spdif->capture_dma_data.maxburst = 4;
+       spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       spdif->playback_dma_data.maxburst = 4;
        spdif->playback_dma_data.slave_id = dmareq->start;
 
        pm_runtime_enable(&pdev->dev);
index 2aa4e13063a8d8d0ab3f5fea2c0849251739ff47..3d2551cc10f2f6fc191acea154ff2a2bc303b09e 100644 (file)
@@ -543,7 +543,7 @@ static snd_pcm_uframes_t usb6fire_pcm_pointer(
        snd_pcm_uframes_t ret;
 
        if (rt->panic || !sub)
-               return SNDRV_PCM_STATE_XRUN;
+               return SNDRV_PCM_POS_XRUN;
 
        spin_lock_irqsave(&sub->lock, flags);
        ret = sub->dma_off;
index 6430ed2a9f65d68d3d7741acd8475b5140c17f51..c21a3df9a0df1ef6900a468ee7af36ad7b57ab19 100644 (file)
@@ -503,7 +503,7 @@ static snd_pcm_uframes_t hiface_pcm_pointer(struct snd_pcm_substream *alsa_sub)
        snd_pcm_uframes_t dma_offset;
 
        if (rt->panic || !sub)
-               return SNDRV_PCM_STATE_XRUN;
+               return SNDRV_PCM_POS_XRUN;
 
        spin_lock_irqsave(&sub->lock, flags);
        dma_offset = sub->dma_off;
index ca9fa4d32e07e3421ce4446f68d9a0601e51ac28..07819bfa7dba30390fedad9e962813f0c95d38c9 100644 (file)
@@ -1026,9 +1026,10 @@ kvp_get_ip_info(int family, char *if_name, int op,
 
                                if (sn_offset == 0)
                                        strcpy(sn_str, cidr_mask);
-                               else
+                               else {
+                                       strcat((char *)ip_buffer->sub_net, ";");
                                        strcat(sn_str, cidr_mask);
-                               strcat((char *)ip_buffer->sub_net, ";");
+                               }
                                sn_offset += strlen(sn_str) + 1;
                        }