From 2108b86117d3ed3fefff11c2a213aaca44537925 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 3 Aug 2011 03:17:43 +0000 Subject: [PATCH] --- yaml --- r: 262629 b: refs/heads/master c: fc05a78efb8e91e884017bb0bc43f690aa5b4dcd h: refs/heads/master i: 262627: aa623665349764c70be6aaf77cc02e7b896d8848 v: v3 --- [refs] | 2 +- trunk/Documentation/ABI/testing/pstore | 6 - .../ABI/testing/sysfs-platform-ideapad-laptop | 17 - trunk/Documentation/CodingStyle | 23 +- trunk/Documentation/acpi/apei/einj.txt | 11 +- .../Documentation/device-mapper/dm-crypt.txt | 21 +- .../Documentation/device-mapper/dm-flakey.txt | 48 +- trunk/Documentation/device-mapper/dm-raid.txt | 138 +- .../devicetree/bindings/gpio/gpio_keys.txt | 2 +- .../devicetree/bindings/input/fsl-mma8450.txt | 11 - trunk/Documentation/dmaengine.txt | 234 +-- .../fault-injection/fault-injection.txt | 3 +- .../feature-removal-schedule.txt | 20 +- trunk/Documentation/frv/booting.txt | 13 +- trunk/Documentation/ioctl/ioctl-number.txt | 1 - trunk/Documentation/kernel-parameters.txt | 11 - trunk/Documentation/m68k/kernel-options.txt | 14 - trunk/Documentation/networking/bonding.txt | 2 +- trunk/Documentation/power/runtime_pm.txt | 10 +- trunk/MAINTAINERS | 18 +- trunk/arch/Kconfig | 3 - trunk/arch/alpha/Kconfig | 1 - trunk/arch/arm/kernel/process.c | 4 +- trunk/arch/avr32/Kconfig | 1 - .../arch/cris/arch-v10/drivers/sync_serial.c | 6 +- trunk/arch/cris/arch-v10/kernel/irq.c | 3 - trunk/arch/cris/include/asm/thread_info.h | 6 +- trunk/arch/frv/Kconfig | 1 - trunk/arch/ia64/Kconfig | 5 - trunk/arch/ia64/include/asm/gpio.h | 55 - trunk/arch/ia64/kernel/efi.c | 2 +- trunk/arch/m68k/Kconfig | 1 - trunk/arch/parisc/Kconfig | 1 - trunk/arch/parisc/include/asm/atomic.h | 4 +- trunk/arch/parisc/include/asm/futex.h | 66 +- trunk/arch/parisc/include/asm/unistd.h | 3 +- trunk/arch/parisc/kernel/syscall_table.S | 1 - trunk/arch/powerpc/Kconfig | 1 - trunk/arch/s390/Kconfig | 9 +- trunk/arch/s390/include/asm/ipl.h | 1 - trunk/arch/s390/include/asm/lowcore.h | 11 +- trunk/arch/s390/include/asm/processor.h | 2 + trunk/arch/s390/include/asm/system.h | 1 - trunk/arch/s390/kernel/asm-offsets.c | 10 +- trunk/arch/s390/kernel/base.S | 36 - trunk/arch/s390/kernel/compat_signal.c | 43 +- trunk/arch/s390/kernel/entry.S | 28 - trunk/arch/s390/kernel/entry64.S | 20 - trunk/arch/s390/kernel/ipl.c | 45 +- trunk/arch/s390/kernel/reipl64.S | 80 +- trunk/arch/s390/kernel/setup.c | 25 +- trunk/arch/s390/kernel/signal.c | 61 +- trunk/arch/s390/kernel/smp.c | 24 +- trunk/arch/s390/mm/maccess.c | 16 - trunk/arch/s390/mm/pgtable.c | 1 - trunk/arch/sh/Kconfig | 1 - trunk/arch/sh/kernel/idle.c | 6 +- trunk/arch/sparc/Kconfig | 1 - trunk/arch/sparc/include/asm/Kbuild | 5 - trunk/arch/sparc/include/asm/bitops_64.h | 49 +- trunk/arch/sparc/include/asm/div64.h | 1 + trunk/arch/sparc/include/asm/elf_64.h | 65 +- trunk/arch/sparc/include/asm/hypervisor.h | 13 - trunk/arch/sparc/include/asm/irq_regs.h | 1 + trunk/arch/sparc/include/asm/local.h | 6 + trunk/arch/sparc/include/asm/local64.h | 1 + trunk/arch/sparc/include/asm/tsb.h | 51 +- trunk/arch/sparc/kernel/cpu.c | 1 - trunk/arch/sparc/kernel/ds.c | 30 +- trunk/arch/sparc/kernel/entry.h | 14 - trunk/arch/sparc/kernel/head_64.S | 2 +- trunk/arch/sparc/kernel/hvapi.c | 6 - trunk/arch/sparc/kernel/hvcalls.S | 7 - trunk/arch/sparc/kernel/kernel.h | 15 - trunk/arch/sparc/kernel/ktlb.S | 24 +- trunk/arch/sparc/kernel/mdesc.c | 30 +- trunk/arch/sparc/kernel/setup_64.c | 186 -- trunk/arch/sparc/kernel/sparc_ksyms_64.c | 11 - trunk/arch/sparc/kernel/sstate.c | 9 +- trunk/arch/sparc/kernel/unaligned_64.c | 15 +- trunk/arch/sparc/kernel/vmlinux.lds.S | 21 +- trunk/arch/sparc/lib/Makefile | 4 +- trunk/arch/sparc/lib/NG2page.S | 61 + trunk/arch/sparc/lib/NGpage.S | 114 +- trunk/arch/sparc/lib/atomic32.c | 2 +- trunk/arch/sparc/lib/ffs.S | 84 - trunk/arch/sparc/lib/hweight.S | 51 - trunk/arch/sparc/mm/init_64.c | 40 +- trunk/arch/tile/Kconfig | 1 - trunk/arch/tile/include/asm/Kbuild | 38 - trunk/arch/tile/include/asm/bug.h | 1 + trunk/arch/tile/include/asm/bugs.h | 1 + trunk/arch/tile/include/asm/cputime.h | 1 + trunk/arch/tile/include/asm/device.h | 1 + trunk/arch/tile/include/asm/div64.h | 1 + .../arch/tile/include/asm/emergency-restart.h | 1 + trunk/arch/tile/include/asm/errno.h | 1 + trunk/arch/tile/include/asm/fb.h | 1 + trunk/arch/tile/include/asm/fcntl.h | 1 + trunk/arch/tile/include/asm/fixmap.h | 6 + trunk/arch/tile/include/asm/ioctl.h | 1 + trunk/arch/tile/include/asm/ioctls.h | 1 + trunk/arch/tile/include/asm/ipc.h | 1 + trunk/arch/tile/include/asm/ipcbuf.h | 1 + trunk/arch/tile/include/asm/irq_regs.h | 1 + trunk/arch/tile/include/asm/kdebug.h | 1 + trunk/arch/tile/include/asm/local.h | 1 + trunk/arch/tile/include/asm/module.h | 1 + trunk/arch/tile/include/asm/msgbuf.h | 1 + trunk/arch/tile/include/asm/mutex.h | 1 + trunk/arch/tile/include/asm/param.h | 1 + trunk/arch/tile/include/asm/parport.h | 1 + trunk/arch/tile/include/asm/poll.h | 1 + trunk/arch/tile/include/asm/posix_types.h | 1 + trunk/arch/tile/include/asm/resource.h | 1 + trunk/arch/tile/include/asm/scatterlist.h | 1 + trunk/arch/tile/include/asm/sembuf.h | 1 + trunk/arch/tile/include/asm/serial.h | 1 + trunk/arch/tile/include/asm/shmbuf.h | 1 + trunk/arch/tile/include/asm/shmparam.h | 1 + trunk/arch/tile/include/asm/socket.h | 1 + trunk/arch/tile/include/asm/sockios.h | 1 + trunk/arch/tile/include/asm/statfs.h | 1 + trunk/arch/tile/include/asm/termbits.h | 1 + trunk/arch/tile/include/asm/termios.h | 1 + trunk/arch/tile/include/asm/types.h | 1 + trunk/arch/tile/include/asm/ucontext.h | 1 + trunk/arch/tile/include/asm/xor.h | 1 + trunk/arch/tile/include/hv/drv_srom_intf.h | 41 - trunk/arch/tile/kernel/time.c | 5 +- trunk/arch/tile/mm/init.c | 3 +- trunk/arch/x86/Kconfig | 1 - trunk/arch/x86/include/asm/io.h | 3 +- trunk/arch/x86/include/asm/processor.h | 2 + trunk/arch/x86/kernel/acpi/cstate.c | 23 - trunk/arch/x86/kernel/process.c | 23 + trunk/arch/x86/kernel/process_32.c | 4 +- trunk/arch/x86/kernel/process_64.c | 4 +- trunk/arch/x86/platform/mrst/Makefile | 1 - trunk/arch/x86/platform/mrst/pmu.c | 817 --------- trunk/arch/x86/platform/mrst/pmu.h | 234 --- trunk/arch/x86/xen/Makefile | 2 +- trunk/arch/x86/xen/setup.c | 13 +- trunk/arch/x86/xen/trace.c | 1 - trunk/block/blk-core.c | 6 +- trunk/block/blk-timeout.c | 5 +- trunk/drivers/acpi/acpica/acglobal.h | 6 - trunk/drivers/acpi/acpica/aclocal.h | 1 - trunk/drivers/acpi/acpica/acpredef.h | 1 - trunk/drivers/acpi/acpica/nspredef.c | 19 +- trunk/drivers/acpi/acpica/nsrepair2.c | 15 - trunk/drivers/acpi/acpica/tbinstal.c | 27 +- trunk/drivers/acpi/apei/Kconfig | 11 +- trunk/drivers/acpi/apei/apei-base.c | 35 +- trunk/drivers/acpi/apei/apei-internal.h | 15 +- trunk/drivers/acpi/apei/einj.c | 43 +- trunk/drivers/acpi/apei/erst-dbg.c | 6 +- trunk/drivers/acpi/apei/erst.c | 32 +- trunk/drivers/acpi/apei/ghes.c | 431 +---- trunk/drivers/acpi/apei/hest.c | 17 +- trunk/drivers/acpi/battery.c | 86 +- trunk/drivers/acpi/bus.c | 14 +- trunk/drivers/acpi/dock.c | 4 +- trunk/drivers/acpi/ec_sys.c | 2 +- trunk/drivers/acpi/fan.c | 2 +- trunk/drivers/acpi/osl.c | 25 +- trunk/drivers/acpi/pci_irq.c | 58 - trunk/drivers/acpi/pci_root.c | 3 +- trunk/drivers/acpi/processor_thermal.c | 2 +- trunk/drivers/acpi/sbs.c | 13 +- trunk/drivers/acpi/sleep.c | 16 - trunk/drivers/acpi/sysfs.c | 4 +- trunk/drivers/acpi/thermal.c | 2 +- trunk/drivers/acpi/video.c | 2 +- trunk/drivers/ata/libata-acpi.c | 4 +- trunk/drivers/base/devtmpfs.c | 2 +- trunk/drivers/base/power/domain.c | 3 +- trunk/drivers/base/power/runtime.c | 10 +- trunk/drivers/char/Kconfig | 11 - trunk/drivers/char/Makefile | 2 - trunk/drivers/char/ramoops.c | 8 - trunk/drivers/char/tile-srom.c | 481 ----- trunk/drivers/char/tpm/tpm_tis.c | 7 +- trunk/drivers/connector/cn_proc.c | 8 +- trunk/drivers/cpuidle/cpuidle.c | 50 +- trunk/drivers/cpuidle/cpuidle.h | 1 - trunk/drivers/cpuidle/driver.c | 3 - trunk/drivers/cpuidle/governor.c | 3 - trunk/drivers/dma/TODO | 1 + trunk/drivers/dma/amba-pl08x.c | 246 ++- trunk/drivers/dma/at_hdmac.c | 4 +- trunk/drivers/dma/coh901318.c | 19 +- trunk/drivers/dma/dmaengine.c | 8 +- trunk/drivers/dma/ep93xx_dma.c | 2 +- trunk/drivers/dma/imx-sdma.c | 4 +- trunk/drivers/dma/intel_mid_dma.c | 2 + trunk/drivers/dma/ioat/dma_v3.c | 8 +- trunk/drivers/dma/ioat/pci.c | 11 - trunk/drivers/dma/ipu/ipu_idmac.c | 6 +- trunk/drivers/dma/mv_xor.c | 3 +- trunk/drivers/dma/mxs-dma.c | 13 +- trunk/drivers/dma/pch_dma.c | 127 +- trunk/drivers/dma/pl330.c | 64 +- trunk/drivers/dma/ste_dma40.c | 270 ++- trunk/drivers/dma/ste_dma40_ll.h | 3 + trunk/drivers/eisa/pci_eisa.c | 4 +- trunk/drivers/firmware/efivars.c | 243 +-- trunk/drivers/gpu/drm/drm_debugfs.c | 4 +- trunk/drivers/gpu/drm/drm_edid.c | 33 +- trunk/drivers/gpu/drm/drm_irq.c | 26 +- trunk/drivers/gpu/drm/i915/i915_debugfs.c | 189 -- trunk/drivers/gpu/drm/i915/i915_dma.c | 6 +- trunk/drivers/gpu/drm/i915/i915_drv.h | 1 - trunk/drivers/gpu/drm/i915/i915_gem.c | 2 +- trunk/drivers/gpu/drm/i915/i915_irq.c | 3 - trunk/drivers/gpu/drm/i915/i915_reg.h | 36 +- trunk/drivers/gpu/drm/i915/i915_suspend.c | 2 - trunk/drivers/gpu/drm/i915/intel_display.c | 138 +- trunk/drivers/gpu/drm/i915/intel_dp.c | 111 +- trunk/drivers/gpu/drm/i915/intel_drv.h | 23 - trunk/drivers/gpu/drm/i915/intel_hdmi.c | 158 +- trunk/drivers/gpu/drm/i915/intel_lvds.c | 8 - trunk/drivers/gpu/drm/i915/intel_panel.c | 4 - trunk/drivers/gpu/drm/i915/intel_ringbuffer.c | 3 - trunk/drivers/gpu/drm/radeon/Makefile | 1 - trunk/drivers/gpu/drm/radeon/atom.c | 3 - trunk/drivers/gpu/drm/radeon/evergreen_cs.c | 2 +- trunk/drivers/gpu/drm/radeon/r600_cs.c | 3 +- trunk/drivers/gpu/drm/radeon/radeon_combios.c | 21 +- .../gpu/drm/radeon/radeon_connectors.c | 54 +- trunk/drivers/gpu/drm/radeon/radeon_device.c | 5 +- trunk/drivers/gpu/drm/radeon/radeon_display.c | 9 - trunk/drivers/gpu/drm/radeon/radeon_drv.c | 4 +- trunk/drivers/gpu/drm/radeon/radeon_i2c.c | 32 +- trunk/drivers/gpu/drm/radeon/radeon_mode.h | 6 +- trunk/drivers/ide/cy82c693.c | 2 - trunk/drivers/ide/ide_platform.c | 6 +- trunk/drivers/input/keyboard/gpio_keys.c | 2 +- trunk/drivers/input/keyboard/lm8323.c | 9 +- trunk/drivers/input/keyboard/tegra-kbc.c | 5 +- trunk/drivers/input/misc/kxtj9.c | 1 - trunk/drivers/input/misc/mma8450.c | 8 - trunk/drivers/input/mouse/hgpk.c | 1 - trunk/drivers/input/serio/xilinx_ps2.c | 2 +- trunk/drivers/input/touchscreen/ad7879.c | 4 +- trunk/drivers/md/Kconfig | 5 +- trunk/drivers/md/dm-crypt.c | 62 +- trunk/drivers/md/dm-flakey.c | 270 +-- trunk/drivers/md/dm-io.c | 29 +- trunk/drivers/md/dm-ioctl.c | 89 +- trunk/drivers/md/dm-kcopyd.c | 42 +- trunk/drivers/md/dm-log-userspace-base.c | 3 +- trunk/drivers/md/dm-log.c | 32 +- trunk/drivers/md/dm-mpath.c | 147 +- trunk/drivers/md/dm-raid.c | 621 +------ trunk/drivers/md/dm-snap-persistent.c | 80 +- trunk/drivers/md/dm-snap.c | 84 +- trunk/drivers/md/dm-table.c | 155 +- trunk/drivers/md/dm.c | 75 +- trunk/drivers/md/dm.h | 2 - trunk/drivers/net/bnx2x/bnx2x_cmn.c | 10 +- trunk/drivers/net/bnx2x/bnx2x_hsi.h | 2 - trunk/drivers/net/bnx2x/bnx2x_link.c | 218 +-- trunk/drivers/net/bnx2x/bnx2x_link.h | 3 +- trunk/drivers/net/bnx2x/bnx2x_reg.h | 6 +- trunk/drivers/net/e1000/e1000_ethtool.c | 6 - trunk/drivers/net/e1000/e1000_hw.c | 3 - trunk/drivers/net/e1000e/es2lan.c | 2 - trunk/drivers/net/e1000e/ethtool.c | 11 +- trunk/drivers/net/e1000e/ich8lan.c | 7 +- trunk/drivers/net/e1000e/lib.c | 1 - trunk/drivers/net/e1000e/netdev.c | 2 +- trunk/drivers/net/e1000e/phy.c | 2 - trunk/drivers/net/igb/e1000_nvm.c | 1 - trunk/drivers/net/igb/igb_ethtool.c | 5 - trunk/drivers/net/igb/igb_main.c | 4 +- trunk/drivers/net/igbvf/netdev.c | 2 - trunk/drivers/net/irda/smsc-ircc2.c | 18 +- trunk/drivers/net/ixgb/ixgb_ee.c | 9 - trunk/drivers/net/ixgb/ixgb_hw.c | 2 - trunk/drivers/net/ixgbe/ixgbe_82599.c | 1 - trunk/drivers/net/ixgbe/ixgbe_common.c | 1 - trunk/drivers/net/ixgbe/ixgbe_ethtool.c | 5 - trunk/drivers/net/ixgbe/ixgbe_main.c | 3 +- trunk/drivers/net/ixgbe/ixgbe_phy.c | 3 - trunk/drivers/net/ixgbe/ixgbe_x540.c | 1 - trunk/drivers/net/macb.c | 3 - trunk/drivers/net/mlx4/en_port.c | 2 +- trunk/drivers/net/mlx4/main.c | 2 - trunk/drivers/net/mlx4/port.c | 9 +- trunk/drivers/net/niu.c | 4 +- trunk/drivers/net/r8169.c | 28 - trunk/drivers/net/sis190.c | 12 +- trunk/drivers/net/usb/cdc_ncm.c | 156 +- .../net/wireless/ath/ath9k/ar9002_hw.c | 6 +- .../net/wireless/ath/ath9k/ar9003_hw.c | 6 +- trunk/drivers/net/wireless/ath/ath9k/hw.c | 11 +- trunk/drivers/net/wireless/ath/ath9k/hw.h | 3 +- trunk/drivers/net/wireless/ath/ath9k/init.c | 2 - trunk/drivers/net/wireless/ath/ath9k/pci.c | 27 - .../drivers/net/wireless/iwlegacy/iwl-3945.c | 6 +- .../drivers/net/wireless/iwlegacy/iwl-4965.c | 8 +- trunk/drivers/net/wireless/iwlwifi/iwl-5000.c | 1 - trunk/drivers/net/wireless/iwlwifi/iwl-core.h | 2 - trunk/drivers/net/wireless/iwlwifi/iwl-pci.c | 18 +- .../drivers/net/wireless/iwlwifi/iwl-power.c | 3 +- trunk/drivers/net/wireless/rt2x00/rt2800lib.c | 3 +- trunk/drivers/net/wireless/rt2x00/rt2x00lib.h | 3 +- trunk/drivers/net/wireless/rt2x00/rt2x00mac.c | 5 +- trunk/drivers/net/wireless/rtlwifi/pci.c | 20 +- trunk/drivers/of/address.c | 2 +- trunk/drivers/of/base.c | 7 +- trunk/drivers/pci/hotplug/acpiphp_glue.c | 2 +- trunk/drivers/platform/x86/Kconfig | 8 - trunk/drivers/platform/x86/Makefile | 1 - trunk/drivers/platform/x86/acer-wmi.c | 40 +- trunk/drivers/platform/x86/acerhdf.c | 13 +- trunk/drivers/platform/x86/asus-laptop.c | 9 +- trunk/drivers/platform/x86/asus-nb-wmi.c | 27 +- trunk/drivers/platform/x86/asus-wmi.c | 239 +-- trunk/drivers/platform/x86/asus-wmi.h | 7 - trunk/drivers/platform/x86/dell-laptop.c | 1 + trunk/drivers/platform/x86/dell-wmi.c | 10 - trunk/drivers/platform/x86/eeepc-wmi.c | 27 - trunk/drivers/platform/x86/ideapad-laptop.c | 195 +- trunk/drivers/platform/x86/intel_ips.c | 4 +- trunk/drivers/platform/x86/intel_menlow.c | 2 - .../drivers/platform/x86/intel_mid_thermal.c | 26 +- .../drivers/platform/x86/intel_rar_register.c | 4 +- trunk/drivers/platform/x86/intel_scu_ipc.c | 2 +- trunk/drivers/platform/x86/msi-laptop.c | 10 - trunk/drivers/platform/x86/msi-wmi.c | 1 - trunk/drivers/platform/x86/samsung-laptop.c | 20 - trunk/drivers/platform/x86/samsung-q10.c | 196 -- trunk/drivers/platform/x86/thinkpad_acpi.c | 11 +- trunk/drivers/regulator/core.c | 190 +- trunk/drivers/regulator/dummy.c | 32 +- trunk/drivers/regulator/tps65910-regulator.c | 63 +- trunk/drivers/regulator/twl-regulator.c | 66 +- trunk/drivers/regulator/wm831x-dcdc.c | 126 +- trunk/drivers/regulator/wm831x-ldo.c | 25 +- trunk/drivers/regulator/wm8994-regulator.c | 4 +- trunk/drivers/rtc/rtc-omap.c | 2 +- trunk/drivers/s390/block/dasd.c | 9 +- trunk/drivers/s390/block/dasd_eckd.c | 9 - trunk/drivers/s390/block/dasd_proc.c | 4 +- trunk/drivers/s390/char/sclp_async.c | 9 +- trunk/drivers/s390/cio/qdio.h | 2 - trunk/drivers/s390/cio/qdio_debug.c | 12 +- trunk/drivers/s390/cio/qdio_main.c | 21 +- trunk/drivers/spi/spi-pl022.c | 11 +- trunk/drivers/target/iscsi/Kconfig | 1 - trunk/drivers/target/iscsi/iscsi_target.c | 15 +- .../target/iscsi/iscsi_target_configfs.c | 2 +- .../drivers/target/iscsi/iscsi_target_nego.c | 2 +- trunk/drivers/target/target_core_transport.c | 33 +- trunk/drivers/target/tcm_fc/tcm_fc.h | 5 - trunk/drivers/target/tcm_fc/tfc_cmd.c | 1 - trunk/drivers/target/tcm_fc/tfc_io.c | 121 +- trunk/drivers/thermal/Kconfig | 8 +- trunk/drivers/thermal/thermal_sys.c | 142 +- trunk/drivers/tty/serial/imx.c | 13 +- trunk/drivers/video/backlight/Kconfig | 2 +- trunk/drivers/video/backlight/aat2870_bl.c | 8 +- trunk/drivers/video/savage/savagefb.h | 2 +- trunk/drivers/watchdog/Kconfig | 3 + trunk/drivers/watchdog/nv_tco.c | 8 - trunk/drivers/watchdog/shwdt.c | 2 +- trunk/drivers/xen/Kconfig | 2 +- trunk/fs/9p/acl.c | 6 +- trunk/fs/9p/acl.h | 4 +- trunk/fs/9p/vfs_inode_dotl.c | 6 +- trunk/fs/Kconfig | 15 +- trunk/fs/block_dev.c | 5 - trunk/fs/btrfs/Makefile | 4 +- trunk/fs/btrfs/acl.c | 27 +- trunk/fs/btrfs/compression.c | 14 +- trunk/fs/btrfs/ctree.h | 30 +- trunk/fs/btrfs/dir-item.c | 30 +- trunk/fs/btrfs/extent-tree.c | 45 +- trunk/fs/btrfs/extent_io.c | 139 +- trunk/fs/btrfs/extent_io.h | 20 +- trunk/fs/btrfs/extent_map.c | 155 +- trunk/fs/btrfs/file-item.c | 7 +- trunk/fs/btrfs/file.c | 21 +- trunk/fs/btrfs/inode.c | 145 +- trunk/fs/btrfs/ioctl.c | 3 +- trunk/fs/btrfs/ref-cache.c | 68 + trunk/fs/btrfs/ref-cache.h | 52 + trunk/fs/btrfs/root-tree.c | 5 +- trunk/fs/btrfs/transaction.c | 65 +- trunk/fs/btrfs/tree-log.c | 12 +- trunk/fs/btrfs/volumes.c | 12 +- trunk/fs/cifs/sess.c | 3 +- trunk/fs/dcache.c | 70 +- trunk/fs/ext2/acl.c | 8 +- trunk/fs/ext3/acl.c | 9 +- trunk/fs/ext4/Makefile | 2 +- trunk/fs/ext4/acl.c | 9 +- trunk/fs/ext4/balloc.c | 48 - trunk/fs/ext4/block_validity.c | 21 - trunk/fs/ext4/ext4.h | 55 +- trunk/fs/ext4/extents.c | 129 +- trunk/fs/ext4/fsync.c | 26 +- trunk/fs/ext4/ialloc.c | 2 +- trunk/fs/ext4/indirect.c | 1482 --------------- trunk/fs/ext4/inode.c | 1596 ++++++++++++++++- trunk/fs/ext4/ioctl.c | 12 +- trunk/fs/ext4/mballoc.c | 230 +-- trunk/fs/ext4/mballoc.h | 1 + trunk/fs/ext4/namei.c | 21 +- trunk/fs/ext4/page-io.c | 6 +- trunk/fs/ext4/resize.c | 199 +- trunk/fs/ext4/super.c | 88 +- trunk/fs/ext4/truncate.h | 43 - trunk/fs/generic_acl.c | 13 +- trunk/fs/gfs2/acl.c | 6 +- trunk/fs/hppfs/hppfs.c | 1 - trunk/fs/inode.c | 13 +- trunk/fs/jbd2/checkpoint.c | 5 +- trunk/fs/jbd2/journal.c | 67 + trunk/fs/jffs2/acl.c | 4 +- trunk/fs/jffs2/acl.h | 2 +- trunk/fs/jffs2/fs.c | 2 +- trunk/fs/jffs2/os-linux.h | 2 +- trunk/fs/jfs/acl.c | 4 +- trunk/fs/jfs/xattr.c | 4 +- trunk/fs/namei.c | 41 +- trunk/fs/nfs/nfs3acl.c | 2 +- trunk/fs/nfs/nfs3proc.c | 6 +- trunk/fs/ocfs2/acl.c | 4 +- trunk/fs/posix_acl.c | 16 +- trunk/fs/proc/base.c | 12 +- trunk/fs/pstore/inode.c | 12 +- trunk/fs/pstore/internal.h | 2 +- trunk/fs/pstore/platform.c | 30 +- trunk/fs/reiserfs/xattr_acl.c | 10 +- trunk/fs/stack.c | 5 +- trunk/fs/xfs/linux-2.6/xfs_acl.c | 6 +- trunk/include/acpi/acpi_drivers.h | 2 +- trunk/include/acpi/acpixf.h | 3 +- trunk/include/acpi/apei.h | 5 - trunk/include/acpi/processor.h | 2 +- trunk/include/drm/drm_crtc.h | 3 - trunk/include/drm/i915_drm.h | 2 +- trunk/include/linux/acpi.h | 3 +- trunk/include/linux/amba/pl08x.h | 9 +- trunk/include/linux/bitmap.h | 1 - trunk/include/linux/cpuidle.h | 4 - trunk/include/linux/cryptohash.h | 2 +- trunk/include/linux/device-mapper.h | 43 - trunk/include/linux/dm-ioctl.h | 4 +- trunk/include/linux/dm-kcopyd.h | 15 - trunk/include/linux/efi.h | 6 - trunk/include/linux/fault-inject.h | 18 +- trunk/include/linux/fs.h | 9 +- trunk/include/linux/genalloc.h | 34 +- trunk/include/linux/gfp.h | 2 +- trunk/include/linux/idr.h | 4 - trunk/include/linux/input.h | 2 - trunk/include/linux/jbd2.h | 6 + trunk/include/linux/llist.h | 126 -- trunk/include/linux/memcontrol.h | 8 + trunk/include/linux/mfd/aat2870.h | 2 +- trunk/include/linux/mm.h | 1 - trunk/include/linux/nfs_fs.h | 4 +- trunk/include/linux/of.h | 15 +- trunk/include/linux/pci_ids.h | 10 - trunk/include/linux/posix_acl.h | 82 +- trunk/include/linux/pstore.h | 9 +- trunk/include/linux/radix-tree.h | 37 +- trunk/include/linux/regulator/consumer.h | 3 - trunk/include/linux/regulator/driver.h | 4 +- trunk/include/linux/shmem_fs.h | 17 +- trunk/include/linux/swapops.h | 23 - trunk/include/linux/thermal.h | 22 + trunk/include/net/cipso_ipv4.h | 2 +- trunk/include/net/dst.h | 17 +- trunk/include/net/netlabel.h | 2 +- trunk/include/trace/events/ext4.h | 87 +- trunk/include/trace/events/jbd2.h | 36 +- trunk/init/main.c | 7 +- trunk/ipc/shm.c | 16 +- trunk/kernel/debug/gdbstub.c | 22 +- trunk/kernel/debug/kdb/kdb_bt.c | 5 +- trunk/kernel/debug/kdb/kdb_cmds | 4 + trunk/kernel/debug/kdb/kdb_debugger.c | 21 +- trunk/kernel/debug/kdb/kdb_io.c | 36 +- trunk/kernel/debug/kdb/kdb_main.c | 4 +- trunk/kernel/debug/kdb/kdb_private.h | 3 +- trunk/kernel/futex.c | 54 +- trunk/kernel/kmod.c | 2 +- trunk/kernel/lockdep.c | 37 +- trunk/kernel/taskstats.c | 18 +- trunk/lib/Kconfig | 3 - trunk/lib/Makefile | 2 - trunk/lib/bitmap.c | 2 + trunk/lib/fault-inject.c | 20 +- trunk/lib/genalloc.c | 300 +--- trunk/lib/idr.c | 67 - trunk/lib/llist.c | 129 -- trunk/lib/radix-tree.c | 121 +- trunk/lib/sha1.c | 212 +-- trunk/mm/failslab.c | 14 +- trunk/mm/filemap.c | 106 +- trunk/mm/memcontrol.c | 66 +- trunk/mm/memory-failure.c | 92 - trunk/mm/mincore.c | 11 +- trunk/mm/oom_kill.c | 4 +- trunk/mm/page_alloc.c | 13 +- trunk/mm/shmem.c | 1493 ++++++++++----- trunk/mm/slab.c | 92 +- trunk/mm/swapfile.c | 20 +- trunk/mm/truncate.c | 8 - trunk/net/atm/br2684.c | 2 + trunk/net/core/skbuff.c | 17 +- trunk/net/ipv4/igmp.c | 2 +- trunk/net/ipv4/ip_output.c | 10 +- trunk/net/ipv4/route.c | 14 +- trunk/net/ipv6/addrconf.c | 2 +- trunk/net/ipv6/datagram.c | 11 +- trunk/net/ipv6/ip6_fib.c | 2 +- trunk/net/ipv6/ip6_output.c | 13 +- trunk/net/ipv6/route.c | 35 +- trunk/net/netfilter/ipvs/ip_vs_ctl.c | 1 - trunk/net/netlabel/Makefile | 2 + trunk/net/netlabel/netlabel_addrlist.c | 2 +- trunk/net/netlabel/netlabel_addrlist.h | 2 +- trunk/net/netlabel/netlabel_cipso_v4.c | 2 +- trunk/net/netlabel/netlabel_cipso_v4.h | 2 +- trunk/net/netlabel/netlabel_domainhash.c | 2 +- trunk/net/netlabel/netlabel_domainhash.h | 2 +- trunk/net/netlabel/netlabel_kapi.c | 2 +- trunk/net/netlabel/netlabel_mgmt.c | 2 +- trunk/net/netlabel/netlabel_mgmt.h | 2 +- trunk/net/netlabel/netlabel_unlabeled.c | 2 +- trunk/net/netlabel/netlabel_unlabeled.h | 2 +- trunk/net/netlabel/netlabel_user.c | 2 +- trunk/net/netlabel/netlabel_user.h | 2 +- trunk/net/sched/sch_sfq.c | 7 +- trunk/net/socket.c | 73 +- trunk/net/sunrpc/xprt.c | 1 - trunk/net/wireless/nl80211.c | 2 +- trunk/net/xfrm/xfrm_algo.c | 4 +- trunk/security/selinux/hooks.c | 2 +- trunk/security/selinux/include/netif.h | 2 +- trunk/security/selinux/include/netlabel.h | 2 +- trunk/security/selinux/include/netnode.h | 2 +- trunk/security/selinux/include/netport.h | 2 +- trunk/security/selinux/netif.c | 2 +- trunk/security/selinux/netlabel.c | 2 +- trunk/security/selinux/netnode.c | 2 +- trunk/security/selinux/netport.c | 2 +- trunk/security/selinux/selinuxfs.c | 2 +- trunk/security/selinux/ss/ebitmap.c | 2 +- trunk/security/selinux/ss/mls.c | 2 +- trunk/security/selinux/ss/mls.h | 2 +- trunk/security/selinux/ss/policydb.c | 2 +- trunk/security/selinux/ss/services.c | 2 +- trunk/security/smack/smack_lsm.c | 2 +- trunk/sound/core/pcm_compat.c | 2 +- trunk/sound/core/rtctimer.c | 2 +- trunk/sound/pci/asihpi/hpidspcd.c | 9 +- trunk/sound/pci/asihpi/hpioctl.c | 19 +- trunk/sound/pci/rme9652/hdspm.c | 109 +- trunk/sound/soc/txx9/txx9aclc.c | 1 - trunk/tools/power/x86/turbostat/turbostat.c | 46 +- .../x86_energy_perf_policy.c | 5 +- 568 files changed, 6671 insertions(+), 13699 deletions(-) delete mode 100644 trunk/Documentation/devicetree/bindings/input/fsl-mma8450.txt delete mode 100644 trunk/arch/ia64/include/asm/gpio.h create mode 100644 trunk/arch/sparc/include/asm/div64.h create mode 100644 trunk/arch/sparc/include/asm/irq_regs.h create mode 100644 trunk/arch/sparc/include/asm/local.h create mode 100644 trunk/arch/sparc/include/asm/local64.h create mode 100644 trunk/arch/sparc/lib/NG2page.S delete mode 100644 trunk/arch/sparc/lib/ffs.S delete mode 100644 trunk/arch/sparc/lib/hweight.S create mode 100644 trunk/arch/tile/include/asm/bug.h create mode 100644 trunk/arch/tile/include/asm/bugs.h create mode 100644 trunk/arch/tile/include/asm/cputime.h create mode 100644 trunk/arch/tile/include/asm/device.h create mode 100644 trunk/arch/tile/include/asm/div64.h create mode 100644 trunk/arch/tile/include/asm/emergency-restart.h create mode 100644 trunk/arch/tile/include/asm/errno.h create mode 100644 trunk/arch/tile/include/asm/fb.h create mode 100644 trunk/arch/tile/include/asm/fcntl.h create mode 100644 trunk/arch/tile/include/asm/ioctl.h create mode 100644 trunk/arch/tile/include/asm/ioctls.h create mode 100644 trunk/arch/tile/include/asm/ipc.h create mode 100644 trunk/arch/tile/include/asm/ipcbuf.h create mode 100644 trunk/arch/tile/include/asm/irq_regs.h create mode 100644 trunk/arch/tile/include/asm/kdebug.h create mode 100644 trunk/arch/tile/include/asm/local.h create mode 100644 trunk/arch/tile/include/asm/module.h create mode 100644 trunk/arch/tile/include/asm/msgbuf.h create mode 100644 trunk/arch/tile/include/asm/mutex.h create mode 100644 trunk/arch/tile/include/asm/param.h create mode 100644 trunk/arch/tile/include/asm/parport.h create mode 100644 trunk/arch/tile/include/asm/poll.h create mode 100644 trunk/arch/tile/include/asm/posix_types.h create mode 100644 trunk/arch/tile/include/asm/resource.h create mode 100644 trunk/arch/tile/include/asm/scatterlist.h create mode 100644 trunk/arch/tile/include/asm/sembuf.h create mode 100644 trunk/arch/tile/include/asm/serial.h create mode 100644 trunk/arch/tile/include/asm/shmbuf.h create mode 100644 trunk/arch/tile/include/asm/shmparam.h create mode 100644 trunk/arch/tile/include/asm/socket.h create mode 100644 trunk/arch/tile/include/asm/sockios.h create mode 100644 trunk/arch/tile/include/asm/statfs.h create mode 100644 trunk/arch/tile/include/asm/termbits.h create mode 100644 trunk/arch/tile/include/asm/termios.h create mode 100644 trunk/arch/tile/include/asm/types.h create mode 100644 trunk/arch/tile/include/asm/ucontext.h create mode 100644 trunk/arch/tile/include/asm/xor.h delete mode 100644 trunk/arch/tile/include/hv/drv_srom_intf.h delete mode 100644 trunk/arch/x86/platform/mrst/pmu.c delete mode 100644 trunk/arch/x86/platform/mrst/pmu.h delete mode 100644 trunk/drivers/char/tile-srom.c delete mode 100644 trunk/drivers/platform/x86/samsung-q10.c create mode 100644 trunk/fs/btrfs/ref-cache.c create mode 100644 trunk/fs/btrfs/ref-cache.h delete mode 100644 trunk/fs/ext4/indirect.c delete mode 100644 trunk/fs/ext4/truncate.h delete mode 100644 trunk/include/linux/llist.h delete mode 100644 trunk/lib/llist.c diff --git a/[refs] b/[refs] index f770d2bb0cf9..7bff59e62cb0 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: ce195d328485459b77672ef20485a8e4f21477b5 +refs/heads/master: fc05a78efb8e91e884017bb0bc43f690aa5b4dcd diff --git a/trunk/Documentation/ABI/testing/pstore b/trunk/Documentation/ABI/testing/pstore index ff1df4e3b059..ddf451ee2a08 100644 --- a/trunk/Documentation/ABI/testing/pstore +++ b/trunk/Documentation/ABI/testing/pstore @@ -39,9 +39,3 @@ Description: Generic interface to platform dependent persistent storage. multiple) files based on the record size of the underlying persistent storage until at least this amount is reached. Default is 10 Kbytes. - - Pstore only supports one backend at a time. If multiple - backends are available, the preferred backend may be - set by passing the pstore.backend= argument to the kernel at - boot time. - diff --git a/trunk/Documentation/ABI/testing/sysfs-platform-ideapad-laptop b/trunk/Documentation/ABI/testing/sysfs-platform-ideapad-laptop index ff53183c3848..807fca2ae2a4 100644 --- a/trunk/Documentation/ABI/testing/sysfs-platform-ideapad-laptop +++ b/trunk/Documentation/ABI/testing/sysfs-platform-ideapad-laptop @@ -4,20 +4,3 @@ KernelVersion: 2.6.37 Contact: "Ike Panhc " Description: Control the power of camera module. 1 means on, 0 means off. - -What: /sys/devices/platform/ideapad/cfg -Date: Jun 2011 -KernelVersion: 3.1 -Contact: "Ike Panhc " -Description: - Ideapad capability bits. - Bit 8-10: 1 - Intel graphic only - 2 - ATI graphic only - 3 - Nvidia graphic only - 4 - Intel and ATI graphic - 5 - Intel and Nvidia graphic - Bit 16: Bluetooth exist (1 for exist) - Bit 17: 3G exist (1 for exist) - Bit 18: Wifi exist (1 for exist) - Bit 19: Camera exist (1 for exist) - diff --git a/trunk/Documentation/CodingStyle b/trunk/Documentation/CodingStyle index c940239d9678..fa6e25b94a54 100644 --- a/trunk/Documentation/CodingStyle +++ b/trunk/Documentation/CodingStyle @@ -80,13 +80,22 @@ available tools. The limit on the length of lines is 80 columns and this is a strongly preferred limit. -Statements longer than 80 columns will be broken into sensible chunks, unless -exceeding 80 columns significantly increases readability and does not hide -information. Descendants are always substantially shorter than the parent and -are placed substantially to the right. The same applies to function headers -with a long argument list. However, never break user-visible strings such as -printk messages, because that breaks the ability to grep for them. - +Statements longer than 80 columns will be broken into sensible chunks. +Descendants are always substantially shorter than the parent and are placed +substantially to the right. The same applies to function headers with a long +argument list. Long strings are as well broken into shorter strings. The +only exception to this is where exceeding 80 columns significantly increases +readability and does not hide information. + +void fun(int a, int b, int c) +{ + if (condition) + printk(KERN_WARNING "Warning this is a long printk with " + "3 parameters a: %u b: %u " + "c: %u \n", a, b, c); + else + next_statement; +} Chapter 3: Placing Braces and Spaces diff --git a/trunk/Documentation/acpi/apei/einj.txt b/trunk/Documentation/acpi/apei/einj.txt index 5cc699ba5453..dfab71848dc8 100644 --- a/trunk/Documentation/acpi/apei/einj.txt +++ b/trunk/Documentation/acpi/apei/einj.txt @@ -48,19 +48,12 @@ directory apei/einj. The following files are provided. - param1 This file is used to set the first error parameter value. Effect of parameter depends on error_type specified. For memory error, this is - physical memory address. Only available if param_extension module - parameter is specified. + physical memory address. - param2 This file is used to set the second error parameter value. Effect of parameter depends on error_type specified. For memory error, this is - physical memory address mask. Only available if param_extension - module parameter is specified. - -Injecting parameter support is a BIOS version specific extension, that -is, it only works on some BIOS version. If you want to use it, please -make sure your BIOS version has the proper support and specify -"param_extension=y" in module parameter. + physical memory address mask. For more information about EINJ, please refer to ACPI specification version 4.0, section 17.5. diff --git a/trunk/Documentation/device-mapper/dm-crypt.txt b/trunk/Documentation/device-mapper/dm-crypt.txt index 2c656ae43ba7..6b5c42dbbe84 100644 --- a/trunk/Documentation/device-mapper/dm-crypt.txt +++ b/trunk/Documentation/device-mapper/dm-crypt.txt @@ -4,8 +4,7 @@ dm-crypt Device-Mapper's "crypt" target provides transparent encryption of block devices using the kernel crypto API. -Parameters: \ - [<#opt_params> ] +Parameters: Encryption cipher and an optional IV generation mode. @@ -38,24 +37,6 @@ Parameters: \ Starting sector within the device where the encrypted data begins. -<#opt_params> - Number of optional parameters. If there are no optional parameters, - the optional paramaters section can be skipped or #opt_params can be zero. - Otherwise #opt_params is the number of following arguments. - - Example of optional parameters section: - 1 allow_discards - -allow_discards - Block discard requests (a.k.a. TRIM) are passed through the crypt device. - The default is to ignore discard requests. - - WARNING: Assess the specific security risks carefully before enabling this - option. For example, allowing discards on encrypted devices may lead to - the leak of information about the ciphertext device (filesystem type, - used space etc.) if the discarded blocks can be located easily on the - device later. - Example scripts =============== LUKS (Linux Unified Key Setup) is now the preferred way to set up disk diff --git a/trunk/Documentation/device-mapper/dm-flakey.txt b/trunk/Documentation/device-mapper/dm-flakey.txt index 6ff5c2327227..c8efdfd19a65 100644 --- a/trunk/Documentation/device-mapper/dm-flakey.txt +++ b/trunk/Documentation/device-mapper/dm-flakey.txt @@ -1,53 +1,17 @@ dm-flakey ========= -This target is the same as the linear target except that it exhibits -unreliable behaviour periodically. It's been found useful in simulating -failing devices for testing purposes. +This target is the same as the linear target except that it returns I/O +errors periodically. It's been found useful in simulating failing +devices for testing purposes. Starting from the time the table is loaded, the device is available for - seconds, then exhibits unreliable behaviour for seconds, and then this cycle repeats. + seconds, then returns errors for seconds, +and then this cycle repeats. -Also, consider using this in combination with the dm-delay target too, -which can delay reads and writes and/or send them to different -underlying devices. - -Table parameters ----------------- - \ - [ []] - -Mandatory parameters: +Parameters: : Full pathname to the underlying block-device, or a "major:minor" device-number. : Starting sector within the device. : Number of seconds device is available. : Number of seconds device returns errors. - -Optional feature parameters: - If no feature parameters are present, during the periods of - unreliability, all I/O returns errors. - - drop_writes: - All write I/O is silently ignored. - Read I/O is handled correctly. - - corrupt_bio_byte : - During , replace of the data of - each matching bio with . - - : The offset of the byte to replace. - Counting starts at 1, to replace the first byte. - : Either 'r' to corrupt reads or 'w' to corrupt writes. - 'w' is incompatible with drop_writes. - : The value (from 0-255) to write. - : Perform the replacement only if bio->bi_rw has all the - selected flags set. - -Examples: - corrupt_bio_byte 32 r 1 0 - - replaces the 32nd byte of READ bios with the value 1 - - corrupt_bio_byte 224 w 0 32 - - replaces the 224th byte of REQ_META (=32) bios with the value 0 diff --git a/trunk/Documentation/device-mapper/dm-raid.txt b/trunk/Documentation/device-mapper/dm-raid.txt index 2a8c11331d2d..33b6b7071ac8 100644 --- a/trunk/Documentation/device-mapper/dm-raid.txt +++ b/trunk/Documentation/device-mapper/dm-raid.txt @@ -1,108 +1,70 @@ -dm-raid -------- +Device-mapper RAID (dm-raid) is a bridge from DM to MD. It +provides a way to use device-mapper interfaces to access the MD RAID +drivers. -The device-mapper RAID (dm-raid) target provides a bridge from DM to MD. -It allows the MD RAID drivers to be accessed using a device-mapper -interface. +As with all device-mapper targets, the nominal public interfaces are the +constructor (CTR) tables and the status outputs (both STATUSTYPE_INFO +and STATUSTYPE_TABLE). The CTR table looks like the following: -The target is named "raid" and it accepts the following parameters: - - <#raid_params> \ - <#raid_devs> [.. ] - -: - raid1 RAID1 mirroring - raid4 RAID4 dedicated parity disk - raid5_la RAID5 left asymmetric - - rotating parity 0 with data continuation - raid5_ra RAID5 right asymmetric - - rotating parity N with data continuation - raid5_ls RAID5 left symmetric - - rotating parity 0 with data restart - raid5_rs RAID5 right symmetric - - rotating parity N with data restart - raid6_zr RAID6 zero restart - - rotating parity zero (left-to-right) with data restart - raid6_nr RAID6 N restart - - rotating parity N (right-to-left) with data restart - raid6_nc RAID6 N continue - - rotating parity N (right-to-left) with data continuation - - Refererence: Chapter 4 of - http://www.snia.org/sites/default/files/SNIA_DDF_Technical_Position_v2.0.pdf - -<#raid_params>: The number of parameters that follow. - - consists of - Mandatory parameters: - : Chunk size in sectors. This parameter is often known as - "stripe size". It is the only mandatory parameter and - is placed first. - - followed by optional parameters (in any order): - [sync|nosync] Force or prevent RAID initialization. - - [rebuild ] Rebuild drive number idx (first drive is 0). - - [daemon_sleep ] - Interval between runs of the bitmap daemon that - clear bits. A longer interval means less bitmap I/O but - resyncing after a failure is likely to take longer. - - [min_recovery_rate ] Throttle RAID initialization - [max_recovery_rate ] Throttle RAID initialization - [write_mostly ] Drive index is write-mostly - [max_write_behind ] See '-write-behind=' (man mdadm) - [stripe_cache ] Stripe cache size (higher RAIDs only) - [region_size ] - The region_size multiplied by the number of regions is the - logical size of the array. The bitmap records the device - synchronisation state for each region. - -<#raid_devs>: The number of devices composing the array. - Each device consists of two entries. The first is the device - containing the metadata (if any); the second is the one containing the - data. - - If a drive has failed or is missing at creation time, a '-' can be - given for both the metadata and data drives for a given position. - - -Example tables --------------- -# RAID4 - 4 data drives, 1 parity (no metadata devices) +1: raid \ +2: <#raid_params> \ +3: <#raid_devs> .. + +Line 1 contains the standard first three arguments to any device-mapper +target - the start, length, and target type fields. The target type in +this case is "raid". + +Line 2 contains the arguments that define the particular raid +type/personality/level, the required arguments for that raid type, and +any optional arguments. Possible raid types include: raid4, raid5_la, +raid5_ls, raid5_rs, raid6_zr, raid6_nr, and raid6_nc. (raid1 is +planned for the future.) The list of required and optional parameters +is the same for all the current raid types. The required parameters are +positional, while the optional parameters are given as key/value pairs. +The possible parameters are as follows: + Chunk size in sectors. + [[no]sync] Force/Prevent RAID initialization + [rebuild ] Rebuild the drive indicated by the index + [daemon_sleep ] Time between bitmap daemon work to clear bits + [min_recovery_rate ] Throttle RAID initialization + [max_recovery_rate ] Throttle RAID initialization + [max_write_behind ] See '-write-behind=' (man mdadm) + [stripe_cache ] Stripe cache size for higher RAIDs + +Line 3 contains the list of devices that compose the array in +metadata/data device pairs. If the metadata is stored separately, a '-' +is given for the metadata device position. If a drive has failed or is +missing at creation time, a '-' can be given for both the metadata and +data drives for a given position. + +NB. Currently all metadata devices must be specified as '-'. + +Examples: +# RAID4 - 4 data drives, 1 parity # No metadata devices specified to hold superblock/bitmap info # Chunk size of 1MiB # (Lines separated for easy reading) - 0 1960893648 raid \ raid4 1 2048 \ 5 - 8:17 - 8:33 - 8:49 - 8:65 - 8:81 -# RAID4 - 4 data drives, 1 parity (with metadata devices) +# RAID4 - 4 data drives, 1 parity (no metadata devices) # Chunk size of 1MiB, force RAID initialization, # min recovery rate at 20 kiB/sec/disk - 0 1960893648 raid \ - raid4 4 2048 sync min_recovery_rate 20 \ - 5 8:17 8:18 8:33 8:34 8:49 8:50 8:65 8:66 8:81 8:82 + raid4 4 2048 min_recovery_rate 20 sync\ + 5 - 8:17 - 8:33 - 8:49 - 8:65 - 8:81 -'dmsetup table' displays the table used to construct the mapping. -The optional parameters are always printed in the order listed -above with "sync" or "nosync" always output ahead of the other -arguments, regardless of the order used when originally loading the table. -Arguments that can be repeated are ordered by value. +Performing a 'dmsetup table' should display the CTR table used to +construct the mapping (with possible reordering of optional +parameters). -'dmsetup status' yields information on the state and health of the -array. -The output is as follows: +Performing a 'dmsetup status' will yield information on the state and +health of the array. The output is as follows: 1: raid \ 2: <#devices> <1 health char for each dev> -Line 1 is the standard output produced by device-mapper. -Line 2 is produced by the raid target, and best explained by example: +Line 1 is standard DM output. Line 2 is best shown by example: 0 1960893648 raid raid4 5 AAAAA 2/490221568 Here we can see the RAID type is raid4, there are 5 devices - all of which are 'A'live, and the array is 2/490221568 complete with recovery. -Faulty or missing devices are marked 'D'. Devices that are out-of-sync -are marked 'a'. diff --git a/trunk/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/trunk/Documentation/devicetree/bindings/gpio/gpio_keys.txt index 5c2c02140a62..7190c99d7611 100644 --- a/trunk/Documentation/devicetree/bindings/gpio/gpio_keys.txt +++ b/trunk/Documentation/devicetree/bindings/gpio/gpio_keys.txt @@ -10,7 +10,7 @@ Optional properties: Each button (key) is represented as a sub-node of "gpio-keys": Subnode properties: - - gpios: OF device-tree gpio specification. + - gpios: OF devcie-tree gpio specificatin. - label: Descriptive name of the key. - linux,code: Keycode to emit. diff --git a/trunk/Documentation/devicetree/bindings/input/fsl-mma8450.txt b/trunk/Documentation/devicetree/bindings/input/fsl-mma8450.txt deleted file mode 100644 index a00c94ccbdee..000000000000 --- a/trunk/Documentation/devicetree/bindings/input/fsl-mma8450.txt +++ /dev/null @@ -1,11 +0,0 @@ -* Freescale MMA8450 3-Axis Accelerometer - -Required properties: -- compatible : "fsl,mma8450". - -Example: - -accelerometer: mma8450@1c { - compatible = "fsl,mma8450"; - reg = <0x1c>; -}; diff --git a/trunk/Documentation/dmaengine.txt b/trunk/Documentation/dmaengine.txt index 94b7e0f96b38..5a0cb1ef6164 100644 --- a/trunk/Documentation/dmaengine.txt +++ b/trunk/Documentation/dmaengine.txt @@ -10,181 +10,87 @@ NOTE: For DMA Engine usage in async_tx please see: Below is a guide to device driver writers on how to use the Slave-DMA API of the DMA Engine. This is applicable only for slave DMA usage only. -The slave DMA usage consists of following steps: +The slave DMA usage consists of following steps 1. Allocate a DMA slave channel 2. Set slave and controller specific parameters 3. Get a descriptor for transaction -4. Submit the transaction -5. Issue pending requests and wait for callback notification +4. Submit the transaction and wait for callback notification 1. Allocate a DMA slave channel - - Channel allocation is slightly different in the slave DMA context, - client drivers typically need a channel from a particular DMA - controller only and even in some cases a specific channel is desired. - To request a channel dma_request_channel() API is used. - - Interface: - struct dma_chan *dma_request_channel(dma_cap_mask_t mask, - dma_filter_fn filter_fn, - void *filter_param); - where dma_filter_fn is defined as: - typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param); - - The 'filter_fn' parameter is optional, but highly recommended for - slave and cyclic channels as they typically need to obtain a specific - DMA channel. - - When the optional 'filter_fn' parameter is NULL, dma_request_channel() - simply returns the first channel that satisfies the capability mask. - - Otherwise, the 'filter_fn' routine will be called once for each free - channel which has a capability in 'mask'. 'filter_fn' is expected to - return 'true' when the desired DMA channel is found. - - A channel allocated via this interface is exclusive to the caller, - until dma_release_channel() is called. +Channel allocation is slightly different in the slave DMA context, client +drivers typically need a channel from a particular DMA controller only and even +in some cases a specific channel is desired. To request a channel +dma_request_channel() API is used. + +Interface: +struct dma_chan *dma_request_channel(dma_cap_mask_t mask, + dma_filter_fn filter_fn, + void *filter_param); +where dma_filter_fn is defined as: +typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param); + +When the optional 'filter_fn' parameter is set to NULL dma_request_channel +simply returns the first channel that satisfies the capability mask. Otherwise, +when the mask parameter is insufficient for specifying the necessary channel, +the filter_fn routine can be used to disposition the available channels in the +system. The filter_fn routine is called once for each free channel in the +system. Upon seeing a suitable channel filter_fn returns DMA_ACK which flags +that channel to be the return value from dma_request_channel. A channel +allocated via this interface is exclusive to the caller, until +dma_release_channel() is called. 2. Set slave and controller specific parameters - - Next step is always to pass some specific information to the DMA - driver. Most of the generic information which a slave DMA can use - is in struct dma_slave_config. This allows the clients to specify - DMA direction, DMA addresses, bus widths, DMA burst lengths etc - for the peripheral. - - If some DMA controllers have more parameters to be sent then they - should try to embed struct dma_slave_config in their controller - specific structure. That gives flexibility to client to pass more - parameters, if required. - - Interface: - int dmaengine_slave_config(struct dma_chan *chan, - struct dma_slave_config *config) - - Please see the dma_slave_config structure definition in dmaengine.h - for a detailed explaination of the struct members. Please note - that the 'direction' member will be going away as it duplicates the - direction given in the prepare call. +Next step is always to pass some specific information to the DMA driver. Most of +the generic information which a slave DMA can use is in struct dma_slave_config. +It allows the clients to specify DMA direction, DMA addresses, bus widths, DMA +burst lengths etc. If some DMA controllers have more parameters to be sent then +they should try to embed struct dma_slave_config in their controller specific +structure. That gives flexibility to client to pass more parameters, if +required. + +Interface: +int dmaengine_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) 3. Get a descriptor for transaction - - For slave usage the various modes of slave transfers supported by the - DMA-engine are: - - slave_sg - DMA a list of scatter gather buffers from/to a peripheral - dma_cyclic - Perform a cyclic DMA operation from/to a peripheral till the +For slave usage the various modes of slave transfers supported by the +DMA-engine are: +slave_sg - DMA a list of scatter gather buffers from/to a peripheral +dma_cyclic - Perform a cyclic DMA operation from/to a peripheral till the operation is explicitly stopped. - - A non-NULL return of this transfer API represents a "descriptor" for - the given transaction. - - Interface: - struct dma_async_tx_descriptor *(*chan->device->device_prep_slave_sg)( - struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, +The non NULL return of this transfer API represents a "descriptor" for the given +transaction. + +Interface: +struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)( + struct dma_chan *chan, + struct scatterlist *dst_sg, unsigned int dst_nents, + struct scatterlist *src_sg, unsigned int src_nents, unsigned long flags); - - struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)( +struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_data_direction direction); - The peripheral driver is expected to have mapped the scatterlist for - the DMA operation prior to calling device_prep_slave_sg, and must - keep the scatterlist mapped until the DMA operation has completed. - The scatterlist must be mapped using the DMA struct device. So, - normal setup should look like this: - - nr_sg = dma_map_sg(chan->device->dev, sgl, sg_len); - if (nr_sg == 0) - /* error */ - - desc = chan->device->device_prep_slave_sg(chan, sgl, nr_sg, - direction, flags); - - Once a descriptor has been obtained, the callback information can be - added and the descriptor must then be submitted. Some DMA engine - drivers may hold a spinlock between a successful preparation and - submission so it is important that these two operations are closely - paired. - - Note: - Although the async_tx API specifies that completion callback - routines cannot submit any new operations, this is not the - case for slave/cyclic DMA. - - For slave DMA, the subsequent transaction may not be available - for submission prior to callback function being invoked, so - slave DMA callbacks are permitted to prepare and submit a new - transaction. - - For cyclic DMA, a callback function may wish to terminate the - DMA via dmaengine_terminate_all(). - - Therefore, it is important that DMA engine drivers drop any - locks before calling the callback function which may cause a - deadlock. - - Note that callbacks will always be invoked from the DMA - engines tasklet, never from interrupt context. - -4. Submit the transaction - - Once the descriptor has been prepared and the callback information - added, it must be placed on the DMA engine drivers pending queue. - - Interface: - dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc) - - This returns a cookie can be used to check the progress of DMA engine - activity via other DMA engine calls not covered in this document. - - dmaengine_submit() will not start the DMA operation, it merely adds - it to the pending queue. For this, see step 5, dma_async_issue_pending. - -5. Issue pending DMA requests and wait for callback notification - - The transactions in the pending queue can be activated by calling the - issue_pending API. If channel is idle then the first transaction in - queue is started and subsequent ones queued up. - - On completion of each DMA operation, the next in queue is started and - a tasklet triggered. The tasklet will then call the client driver - completion callback routine for notification, if set. - - Interface: - void dma_async_issue_pending(struct dma_chan *chan); - -Further APIs: - -1. int dmaengine_terminate_all(struct dma_chan *chan) - - This causes all activity for the DMA channel to be stopped, and may - discard data in the DMA FIFO which hasn't been fully transferred. - No callback functions will be called for any incomplete transfers. - -2. int dmaengine_pause(struct dma_chan *chan) - - This pauses activity on the DMA channel without data loss. - -3. int dmaengine_resume(struct dma_chan *chan) - - Resume a previously paused DMA channel. It is invalid to resume a - channel which is not currently paused. - -4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan, - dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used) - - This can be used to check the status of the channel. Please see - the documentation in include/linux/dmaengine.h for a more complete - description of this API. - - This can be used in conjunction with dma_async_is_complete() and - the cookie returned from 'descriptor->submit()' to check for - completion of a specific DMA transaction. - - Note: - Not all DMA engine drivers can return reliable information for - a running DMA channel. It is recommended that DMA engine users - pause or stop (via dmaengine_terminate_all) the channel before - using this API. +4. Submit the transaction and wait for callback notification +To schedule the transaction to be scheduled by dma device, the "descriptor" +returned in above (3) needs to be submitted. +To tell the dma driver that a transaction is ready to be serviced, the +descriptor->submit() callback needs to be invoked. This chains the descriptor to +the pending queue. +The transactions in the pending queue can be activated by calling the +issue_pending API. If channel is idle then the first transaction in queue is +started and subsequent ones queued up. +On completion of the DMA operation the next in queue is submitted and a tasklet +triggered. The tasklet would then call the client driver completion callback +routine for notification, if set. +Interface: +void dma_async_issue_pending(struct dma_chan *chan); + +============================================================================== + +Additional usage notes for dma driver writers +1/ Although DMA engine specifies that completion callback routines cannot submit +any new operations, but typically for slave DMA subsequent transaction may not +be available for submit prior to callback routine being called. This requirement +is not a requirement for DMA-slave devices. But they should take care to drop +the spin-lock they might be holding before calling the callback routine diff --git a/trunk/Documentation/fault-injection/fault-injection.txt b/trunk/Documentation/fault-injection/fault-injection.txt index 82a5d250d75e..7be15e44d481 100644 --- a/trunk/Documentation/fault-injection/fault-injection.txt +++ b/trunk/Documentation/fault-injection/fault-injection.txt @@ -143,7 +143,8 @@ o provide a way to configure fault attributes failslab, fail_page_alloc, and fail_make_request use this way. Helper functions: - fault_create_debugfs_attr(name, parent, attr); + init_fault_attr_dentries(entries, attr, name); + void cleanup_fault_attr_dentries(entries); - module parameters diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index c4a6e148732a..ea0bace0124a 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -296,6 +296,15 @@ Who: Ravikiran Thirumalai --------------------------- +What: CONFIG_THERMAL_HWMON +When: January 2009 +Why: This option was introduced just to allow older lm-sensors userspace + to keep working over the upgrade to 2.6.26. At the scheduled time of + removal fixed lm-sensors (2.x or 3.x) should be readily available. +Who: Rene Herman + +--------------------------- + What: Code that is now under CONFIG_WIRELESS_EXT_SYSFS (in net/core/net-sysfs.c) When: After the only user (hal) has seen a release with the patches @@ -581,14 +590,3 @@ Why: This driver has been superseded by g_mass_storage. Who: Alan Stern ---------------------------- - -What: threeg and interface sysfs files in /sys/devices/platform/acer-wmi -When: 2012 -Why: In 3.0, we can now autodetect internal 3G device and already have - the threeg rfkill device. So, we plan to remove threeg sysfs support - for it's no longer necessary. - - We also plan to remove interface sysfs file that exposed which ACPI-WMI - interface that was used by acer-wmi driver. It will replaced by - information log when acer-wmi initial. -Who: Lee, Chun-Yi diff --git a/trunk/Documentation/frv/booting.txt b/trunk/Documentation/frv/booting.txt index 37c4d84a0e57..ace200b7c214 100644 --- a/trunk/Documentation/frv/booting.txt +++ b/trunk/Documentation/frv/booting.txt @@ -106,20 +106,13 @@ separated by spaces: To use the first on-chip serial port at baud rate 115200, no parity, 8 bits, and no flow control. - (*) root= + (*) root=/dev/ - This specifies the device upon which the root filesystem resides. It - may be specified by major and minor number, device path, or even - partition uuid, if supported. For example: + This specifies the device upon which the root filesystem resides. For + example: /dev/nfs NFS root filesystem /dev/mtdblock3 Fourth RedBoot partition on the System Flash - PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF/PARTNROFF=1 - first partition after the partition with the given UUID - 253:0 Device with major 253 and minor 0 - - Authoritative information can be found in - "Documentation/kernel-parameters.txt". (*) rw diff --git a/trunk/Documentation/ioctl/ioctl-number.txt b/trunk/Documentation/ioctl/ioctl-number.txt index 845a191004b1..72ba8d51dbc1 100644 --- a/trunk/Documentation/ioctl/ioctl-number.txt +++ b/trunk/Documentation/ioctl/ioctl-number.txt @@ -292,7 +292,6 @@ Code Seq#(hex) Include File Comments 0xA0 all linux/sdp/sdp.h Industrial Device Project -0xA2 00-0F arch/tile/include/asm/hardwall.h 0xA3 80-8F Port ACL in development: 0xA3 90-9F linux/dtlk.h diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index e279b7242912..4ca93898fbd3 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -163,11 +163,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. See also Documentation/power/pm.txt, pci=noacpi - acpi_rsdp= [ACPI,EFI,KEXEC] - Pass the RSDP address to the kernel, mostly used - on machines running EFI runtime service to boot the - second kernel for kdump. - acpi_apic_instance= [ACPI, IOAPIC] Format: 2: use 2nd APIC table, if available @@ -551,9 +546,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. /proc//coredump_filter. See also Documentation/filesystems/proc.txt. - cpuidle.off=1 [CPU_IDLE] - disable the cpuidle sub-system - cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver Format: ,,,[,] @@ -2161,8 +2153,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. [HW,MOUSE] Controls Logitech smartscroll autorepeat. 0 = disabled, 1 = enabled (default). - pstore.backend= Specify the name of the pstore backend to use - pt. [PARIDE] See Documentation/blockdev/paride.txt. @@ -2248,7 +2238,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ro [KNL] Mount root device read-only on boot root= [KNL] Root filesystem - See name_to_dev_t comment in init/do_mounts.c. rootdelay= [KNL] Delay (in seconds) to pause before attempting to mount the root filesystem diff --git a/trunk/Documentation/m68k/kernel-options.txt b/trunk/Documentation/m68k/kernel-options.txt index 97d45f276fe6..c93bed66e25d 100644 --- a/trunk/Documentation/m68k/kernel-options.txt +++ b/trunk/Documentation/m68k/kernel-options.txt @@ -129,20 +129,6 @@ decimal 11 is the major of SCSI CD-ROMs, and the minor 0 stands for the first of these. You can find out all valid major numbers by looking into include/linux/major.h. -In addition to major and minor numbers, if the device containing your -root partition uses a partition table format with unique partition -identifiers, then you may use them. For instance, -"root=PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF". It is also -possible to reference another partition on the same device using a -known partition UUID as the starting point. For example, -if partition 5 of the device has the UUID of -00112233-4455-6677-8899-AABBCCDDEEFF then partition 3 may be found as -follows: - PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF/PARTNROFF=-2 - -Authoritative information can be found in -"Documentation/kernel-parameters.txt". - 2.2) ro, rw ----------- diff --git a/trunk/Documentation/networking/bonding.txt b/trunk/Documentation/networking/bonding.txt index 5dd960d75174..675612ff41ae 100644 --- a/trunk/Documentation/networking/bonding.txt +++ b/trunk/Documentation/networking/bonding.txt @@ -599,7 +599,7 @@ num_unsol_na affect only the active-backup mode. These options were added for bonding versions 3.3.0 and 3.4.0 respectively. - From Linux 3.0 and bonding version 3.7.1, these notifications + From Linux 2.6.40 and bonding version 3.7.1, these notifications are generated by the ipv4 and ipv6 code and the numbers of repetitions cannot be set independently. diff --git a/trunk/Documentation/power/runtime_pm.txt b/trunk/Documentation/power/runtime_pm.txt index 4ce5450ab6e8..14dd3c6ad97e 100644 --- a/trunk/Documentation/power/runtime_pm.txt +++ b/trunk/Documentation/power/runtime_pm.txt @@ -54,10 +54,11 @@ referred to as subsystem-level callbacks in what follows. By default, the callbacks are always invoked in process context with interrupts enabled. However, subsystems can use the pm_runtime_irq_safe() helper function to tell the PM core that a device's ->runtime_suspend() and ->runtime_resume() -callbacks should be invoked in atomic context with interrupts disabled. -This implies that these callback routines must not block or sleep, but it also -means that the synchronous helper functions listed at the end of Section 4 can -be used within an interrupt handler or in an atomic context. +callbacks should be invoked in atomic context with interrupts disabled +(->runtime_idle() is still invoked the default way). This implies that these +callback routines must not block or sleep, but it also means that the +synchronous helper functions listed at the end of Section 4 can be used within +an interrupt handler or in an atomic context. The subsystem-level suspend callback is _entirely_ _responsible_ for handling the suspend of the device as appropriate, which may, but need not include @@ -482,7 +483,6 @@ pm_runtime_suspend() pm_runtime_autosuspend() pm_runtime_resume() pm_runtime_get_sync() -pm_runtime_put_sync() pm_runtime_put_sync_suspend() 5. Runtime PM Initialization, Device Probing and Removal diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 51d42fbc8dc4..c9c6324a7a9f 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2643,8 +2643,9 @@ S: Maintained F: arch/x86/math-emu/ FRAME RELAY DLCI/FRAD (Sangoma drivers too) +M: Mike McLagan L: netdev@vger.kernel.org -S: Orphan +S: Maintained F: drivers/net/wan/dlci.c F: drivers/net/wan/sdla.c @@ -3366,12 +3367,6 @@ F: drivers/net/ixgb/ F: drivers/net/ixgbe/ F: drivers/net/ixgbevf/ -INTEL MRST PMU DRIVER -M: Len Brown -L: linux-pm@lists.linux-foundation.org -S: Supported -F: arch/x86/platform/mrst/pmu.* - INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT L: linux-wireless@vger.kernel.org S: Orphan @@ -4414,10 +4409,10 @@ F: net/*/netfilter/ F: net/netfilter/ NETLABEL -M: Paul Moore +M: Paul Moore W: http://netlabel.sf.net L: netdev@vger.kernel.org -S: Maintained +S: Supported F: Documentation/netlabel/ F: include/net/netlabel.h F: net/netlabel/ @@ -4462,6 +4457,7 @@ F: include/linux/netdevice.h NETWORKING [IPv4/IPv6] M: "David S. Miller" M: Alexey Kuznetsov +M: "Pekka Savola (ipv6)" M: James Morris M: Hideaki YOSHIFUJI M: Patrick McHardy @@ -4474,7 +4470,7 @@ F: include/net/ip* F: arch/x86/net/* NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK) -M: Paul Moore +M: Paul Moore L: netdev@vger.kernel.org S: Maintained @@ -4726,7 +4722,6 @@ S: Maintained F: drivers/of F: include/linux/of*.h K: of_get_property -K: of_match_table OPENRISC ARCHITECTURE M: Jonas Bonn @@ -6323,7 +6318,6 @@ F: include/linux/sysv_fs.h TARGET SUBSYSTEM M: Nicholas A. Bellinger L: linux-scsi@vger.kernel.org -L: target-devel@vger.kernel.org L: http://groups.google.com/group/linux-iscsi-target-dev W: http://www.linux-iscsi.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master diff --git a/trunk/arch/Kconfig b/trunk/arch/Kconfig index 4b0669cbb3b0..26b0e2397a57 100644 --- a/trunk/arch/Kconfig +++ b/trunk/arch/Kconfig @@ -178,7 +178,4 @@ config HAVE_ARCH_MUTEX_CPU_RELAX config HAVE_RCU_TABLE_FREE bool -config ARCH_HAVE_NMI_SAFE_CMPXCHG - bool - source "kernel/gcov/Kconfig" diff --git a/trunk/arch/alpha/Kconfig b/trunk/arch/alpha/Kconfig index 60cde53d266c..ca2da8da6e9c 100644 --- a/trunk/arch/alpha/Kconfig +++ b/trunk/arch/alpha/Kconfig @@ -14,7 +14,6 @@ config ALPHA select AUTO_IRQ_AFFINITY if SMP select GENERIC_IRQ_SHOW select ARCH_WANT_OPTIONAL_GPIOLIB - select ARCH_HAVE_NMI_SAFE_CMPXCHG help The Alpha is a 64-bit general-purpose processor designed and marketed by the Digital Equipment Corporation of blessed memory, diff --git a/trunk/arch/arm/kernel/process.c b/trunk/arch/arm/kernel/process.c index 1a347f481e5e..5e1e54197227 100644 --- a/trunk/arch/arm/kernel/process.c +++ b/trunk/arch/arm/kernel/process.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -197,8 +196,7 @@ void cpu_idle(void) cpu_relax(); } else { stop_critical_timings(); - if (cpuidle_idle_call()) - pm_idle(); + pm_idle(); start_critical_timings(); /* * This will eventually be removed - pm_idle diff --git a/trunk/arch/avr32/Kconfig b/trunk/arch/avr32/Kconfig index 197e96f70405..e9d689b7c833 100644 --- a/trunk/arch/avr32/Kconfig +++ b/trunk/arch/avr32/Kconfig @@ -10,7 +10,6 @@ config AVR32 select GENERIC_IRQ_PROBE select HARDIRQS_SW_RESEND select GENERIC_IRQ_SHOW - select ARCH_HAVE_NMI_SAFE_CMPXCHG help AVR32 is a high-performance 32-bit RISC microprocessor core, designed for cost-sensitive embedded applications, with particular diff --git a/trunk/arch/cris/arch-v10/drivers/sync_serial.c b/trunk/arch/cris/arch-v10/drivers/sync_serial.c index 466af40c5822..850265373611 100644 --- a/trunk/arch/cris/arch-v10/drivers/sync_serial.c +++ b/trunk/arch/cris/arch-v10/drivers/sync_serial.c @@ -158,7 +158,7 @@ static int sync_serial_open(struct inode *inode, struct file *file); static int sync_serial_release(struct inode *inode, struct file *file); static unsigned int sync_serial_poll(struct file *filp, poll_table *wait); -static long sync_serial_ioctl(struct file *file, +static int sync_serial_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static ssize_t sync_serial_write(struct file *file, const char *buf, size_t count, loff_t *ppos); @@ -625,11 +625,11 @@ static int sync_serial_open(struct inode *inode, struct file *file) *R_IRQ_MASK1_SET = 1 << port->data_avail_bit; DEBUG(printk(KERN_DEBUG "sser%d rec started\n", dev)); } - err = 0; + ret = 0; out: mutex_unlock(&sync_serial_mutex); - return err; + return ret; } static int sync_serial_release(struct inode *inode, struct file *file) diff --git a/trunk/arch/cris/arch-v10/kernel/irq.c b/trunk/arch/cris/arch-v10/kernel/irq.c index ba0e5965d6e3..907cfb5a873d 100644 --- a/trunk/arch/cris/arch-v10/kernel/irq.c +++ b/trunk/arch/cris/arch-v10/kernel/irq.c @@ -20,9 +20,6 @@ #define crisv10_mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr)); #define crisv10_unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr)); -extern void kgdb_init(void); -extern void breakpoint(void); - /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is * global just so that the kernel gdb can use it. */ diff --git a/trunk/arch/cris/include/asm/thread_info.h b/trunk/arch/cris/include/asm/thread_info.h index 332f19c54557..29b74a105830 100644 --- a/trunk/arch/cris/include/asm/thread_info.h +++ b/trunk/arch/cris/include/asm/thread_info.h @@ -11,6 +11,8 @@ #ifdef __KERNEL__ +#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR + #ifndef __ASSEMBLY__ #include #include @@ -65,10 +67,8 @@ struct thread_info { #define init_thread_info (init_thread_union.thread_info) -#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR /* thread information allocation */ -#define alloc_thread_info_node(tsk, node) \ - ((struct thread_info *) __get_free_pages(GFP_KERNEL, 1)) +#define alloc_thread_info(tsk, node) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #endif /* !__ASSEMBLY__ */ diff --git a/trunk/arch/frv/Kconfig b/trunk/arch/frv/Kconfig index bad27a6ff407..cb884e489425 100644 --- a/trunk/arch/frv/Kconfig +++ b/trunk/arch/frv/Kconfig @@ -7,7 +7,6 @@ config FRV select HAVE_PERF_EVENTS select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_SHOW - select ARCH_HAVE_NMI_SAFE_CMPXCHG config ZONE_DMA bool diff --git a/trunk/arch/ia64/Kconfig b/trunk/arch/ia64/Kconfig index 124854714958..137b277f7e56 100644 --- a/trunk/arch/ia64/Kconfig +++ b/trunk/arch/ia64/Kconfig @@ -27,8 +27,6 @@ config IA64 select GENERIC_PENDING_IRQ if SMP select IRQ_PER_CPU select GENERIC_IRQ_SHOW - select ARCH_WANT_OPTIONAL_GPIOLIB - select ARCH_HAVE_NMI_SAFE_CMPXCHG default y help The Itanium Processor Family is Intel's 64-bit successor to @@ -91,9 +89,6 @@ config GENERIC_TIME_VSYSCALL config HAVE_SETUP_PER_CPU_AREA def_bool y -config GENERIC_GPIO - def_bool y - config DMI bool default y diff --git a/trunk/arch/ia64/include/asm/gpio.h b/trunk/arch/ia64/include/asm/gpio.h deleted file mode 100644 index 590a20debc4e..000000000000 --- a/trunk/arch/ia64/include/asm/gpio.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Generic GPIO API implementation for IA-64. - * - * A stright copy of that for PowerPC which was: - * - * Copyright (c) 2007-2008 MontaVista Software, Inc. - * - * Author: Anton Vorontsov - * - * 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. - */ - -#ifndef _ASM_IA64_GPIO_H -#define _ASM_IA64_GPIO_H - -#include -#include - -#ifdef CONFIG_GPIOLIB - -/* - * We don't (yet) implement inlined/rapid versions for on-chip gpios. - * Just call gpiolib. - */ -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(unsigned int gpio) -{ - return __gpio_to_irq(gpio); -} - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* _ASM_IA64_GPIO_H */ diff --git a/trunk/arch/ia64/kernel/efi.c b/trunk/arch/ia64/kernel/efi.c index c38d22e5e902..6fc03aff046c 100644 --- a/trunk/arch/ia64/kernel/efi.c +++ b/trunk/arch/ia64/kernel/efi.c @@ -156,7 +156,7 @@ prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, \ #define STUB_SET_VARIABLE(prefix, adjust_arg) \ static efi_status_t \ prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, \ - u32 attr, unsigned long data_size, \ + unsigned long attr, unsigned long data_size, \ void *data) \ { \ struct ia64_fpreg fr[6]; \ diff --git a/trunk/arch/m68k/Kconfig b/trunk/arch/m68k/Kconfig index 9e8ee9d2b8ca..284cd3771eaa 100644 --- a/trunk/arch/m68k/Kconfig +++ b/trunk/arch/m68k/Kconfig @@ -6,7 +6,6 @@ config M68K select GENERIC_ATOMIC64 if MMU select HAVE_GENERIC_HARDIRQS if !MMU select GENERIC_IRQ_SHOW if !MMU - select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS config RWSEM_GENERIC_SPINLOCK bool diff --git a/trunk/arch/parisc/Kconfig b/trunk/arch/parisc/Kconfig index e077b0bf56ca..65adc86a230e 100644 --- a/trunk/arch/parisc/Kconfig +++ b/trunk/arch/parisc/Kconfig @@ -15,7 +15,6 @@ config PARISC select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_PROBE select IRQ_PER_CPU - select ARCH_HAVE_NMI_SAFE_CMPXCHG help The PA-RISC microprocessor is designed by Hewlett-Packard and used diff --git a/trunk/arch/parisc/include/asm/atomic.h b/trunk/arch/parisc/include/asm/atomic.h index 4054b31e0fa9..b1dc71f5534e 100644 --- a/trunk/arch/parisc/include/asm/atomic.h +++ b/trunk/arch/parisc/include/asm/atomic.h @@ -258,10 +258,10 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) #define ATOMIC64_INIT(i) ((atomic64_t) { (i) }) -static __inline__ s64 +static __inline__ int __atomic64_add_return(s64 i, atomic64_t *v) { - s64 ret; + int ret; unsigned long flags; _atomic_spin_lock_irqsave(v, flags); diff --git a/trunk/arch/parisc/include/asm/futex.h b/trunk/arch/parisc/include/asm/futex.h index 2388bdb32832..67a33cc27ef2 100644 --- a/trunk/arch/parisc/include/asm/futex.h +++ b/trunk/arch/parisc/include/asm/futex.h @@ -5,14 +5,11 @@ #include #include -#include #include static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) { - unsigned long int flags; - u32 val; int op = (encoded_op >> 28) & 7; int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; @@ -21,58 +18,21 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr))) + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) return -EFAULT; pagefault_disable(); - _atomic_spin_lock_irqsave(uaddr, flags); - switch (op) { case FUTEX_OP_SET: - /* *(int *)UADDR2 = OPARG; */ - ret = get_user(oldval, uaddr); - if (!ret) - ret = put_user(oparg, uaddr); - break; case FUTEX_OP_ADD: - /* *(int *)UADDR2 += OPARG; */ - ret = get_user(oldval, uaddr); - if (!ret) { - val = oldval + oparg; - ret = put_user(val, uaddr); - } - break; case FUTEX_OP_OR: - /* *(int *)UADDR2 |= OPARG; */ - ret = get_user(oldval, uaddr); - if (!ret) { - val = oldval | oparg; - ret = put_user(val, uaddr); - } - break; case FUTEX_OP_ANDN: - /* *(int *)UADDR2 &= ~OPARG; */ - ret = get_user(oldval, uaddr); - if (!ret) { - val = oldval & ~oparg; - ret = put_user(val, uaddr); - } - break; case FUTEX_OP_XOR: - /* *(int *)UADDR2 ^= OPARG; */ - ret = get_user(oldval, uaddr); - if (!ret) { - val = oldval ^ oparg; - ret = put_user(val, uaddr); - } - break; default: ret = -ENOSYS; } - _atomic_spin_unlock_irqrestore(uaddr, flags); - pagefault_enable(); if (!ret) { @@ -94,9 +54,7 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { - int ret; u32 val; - unsigned long flags; /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is * our gateway page, and causes no end of trouble... @@ -107,24 +65,12 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) return -EFAULT; - /* HPPA has no cmpxchg in hardware and therefore the - * best we can do here is use an array of locks. The - * lock selected is based on a hash of the userspace - * address. This should scale to a couple of CPUs. - */ - - _atomic_spin_lock_irqsave(uaddr, flags); - - ret = get_user(val, uaddr); - - if (!ret && val == oldval) - ret = put_user(newval, uaddr); - + if (get_user(val, uaddr)) + return -EFAULT; + if (val == oldval && put_user(newval, uaddr)) + return -EFAULT; *uval = val; - - _atomic_spin_unlock_irqrestore(uaddr, flags); - - return ret; + return 0; } #endif /*__KERNEL__*/ diff --git a/trunk/arch/parisc/include/asm/unistd.h b/trunk/arch/parisc/include/asm/unistd.h index d61de64f990a..3392de3e7be0 100644 --- a/trunk/arch/parisc/include/asm/unistd.h +++ b/trunk/arch/parisc/include/asm/unistd.h @@ -821,9 +821,8 @@ #define __NR_open_by_handle_at (__NR_Linux + 326) #define __NR_syncfs (__NR_Linux + 327) #define __NR_setns (__NR_Linux + 328) -#define __NR_sendmmsg (__NR_Linux + 329) -#define __NR_Linux_syscalls (__NR_sendmmsg + 1) +#define __NR_Linux_syscalls (__NR_setns + 1) #define __IGNORE_select /* newselect */ diff --git a/trunk/arch/parisc/kernel/syscall_table.S b/trunk/arch/parisc/kernel/syscall_table.S index e66366fd2abc..34a4f5a2fffb 100644 --- a/trunk/arch/parisc/kernel/syscall_table.S +++ b/trunk/arch/parisc/kernel/syscall_table.S @@ -427,7 +427,6 @@ ENTRY_COMP(open_by_handle_at) ENTRY_SAME(syncfs) ENTRY_SAME(setns) - ENTRY_COMP(sendmmsg) /* Nothing yet */ diff --git a/trunk/arch/powerpc/Kconfig b/trunk/arch/powerpc/Kconfig index 6926b61acfea..374c475e56a3 100644 --- a/trunk/arch/powerpc/Kconfig +++ b/trunk/arch/powerpc/Kconfig @@ -136,7 +136,6 @@ config PPC select HAVE_SYSCALL_TRACEPOINTS select HAVE_BPF_JIT if (PPC64 && NET) select HAVE_ARCH_JUMP_LABEL - select ARCH_HAVE_NMI_SAFE_CMPXCHG config EARLY_PRINTK bool diff --git a/trunk/arch/s390/Kconfig b/trunk/arch/s390/Kconfig index ed5cb5af5281..c03fef7a9c22 100644 --- a/trunk/arch/s390/Kconfig +++ b/trunk/arch/s390/Kconfig @@ -81,7 +81,6 @@ config S390 select INIT_ALL_POSSIBLE select HAVE_IRQ_WORK select HAVE_PERF_EVENTS - select ARCH_HAVE_NMI_SAFE_CMPXCHG select HAVE_KERNEL_GZIP select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_LZMA @@ -274,11 +273,11 @@ config MARCH_Z10 on older machines. config MARCH_Z196 - bool "IBM zEnterprise 114 and 196" + bool "IBM zEnterprise 196" help - Select this to enable optimizations for IBM zEnterprise 114 and 196 - (2818 and 2817 series). The kernel will be slightly faster but will - not work on older machines. + Select this to enable optimizations for IBM zEnterprise 196 + (2817 series). The kernel will be slightly faster but will not work + on older machines. endchoice diff --git a/trunk/arch/s390/include/asm/ipl.h b/trunk/arch/s390/include/asm/ipl.h index 97cc4403fabf..5e95d95450b3 100644 --- a/trunk/arch/s390/include/asm/ipl.h +++ b/trunk/arch/s390/include/asm/ipl.h @@ -167,6 +167,5 @@ enum diag308_rc { }; extern int diag308(unsigned long subcode, void *addr); -extern void diag308_reset(void); #endif /* _ASM_S390_IPL_H */ diff --git a/trunk/arch/s390/include/asm/lowcore.h b/trunk/arch/s390/include/asm/lowcore.h index e85c911aabf0..f26280d9e88d 100644 --- a/trunk/arch/s390/include/asm/lowcore.h +++ b/trunk/arch/s390/include/asm/lowcore.h @@ -18,7 +18,6 @@ void system_call(void); void pgm_check_handler(void); void mcck_int_handler(void); void io_int_handler(void); -void psw_restart_int_handler(void); #ifdef CONFIG_32BIT @@ -151,10 +150,7 @@ struct _lowcore { */ __u32 ipib; /* 0x0e00 */ __u32 ipib_checksum; /* 0x0e04 */ - - /* 64 bit save area */ - __u64 save_area_64; /* 0x0e08 */ - __u8 pad_0x0e10[0x0f00-0x0e10]; /* 0x0e10 */ + __u8 pad_0x0e08[0x0f00-0x0e08]; /* 0x0e08 */ /* Extended facility list */ __u64 stfle_fac_list[32]; /* 0x0f00 */ @@ -290,10 +286,7 @@ struct _lowcore { */ __u64 ipib; /* 0x0e00 */ __u32 ipib_checksum; /* 0x0e08 */ - - /* 64 bit save area */ - __u64 save_area_64; /* 0x0e0c */ - __u8 pad_0x0e14[0x0f00-0x0e14]; /* 0x0e14 */ + __u8 pad_0x0e0c[0x0f00-0x0e0c]; /* 0x0e0c */ /* Extended facility list */ __u64 stfle_fac_list[32]; /* 0x0f00 */ diff --git a/trunk/arch/s390/include/asm/processor.h b/trunk/arch/s390/include/asm/processor.h index a4b6229e5d4b..55dfcc8bdc0d 100644 --- a/trunk/arch/s390/include/asm/processor.h +++ b/trunk/arch/s390/include/asm/processor.h @@ -119,12 +119,14 @@ struct stack_frame { * Do necessary setup to start up a new thread. */ #define start_thread(regs, new_psw, new_stackp) do { \ + set_fs(USER_DS); \ regs->psw.mask = psw_user_bits; \ regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ regs->gprs[15] = new_stackp; \ } while (0) #define start_thread31(regs, new_psw, new_stackp) do { \ + set_fs(USER_DS); \ regs->psw.mask = psw_user32_bits; \ regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ regs->gprs[15] = new_stackp; \ diff --git a/trunk/arch/s390/include/asm/system.h b/trunk/arch/s390/include/asm/system.h index 6582f69f2389..d382629a0172 100644 --- a/trunk/arch/s390/include/asm/system.h +++ b/trunk/arch/s390/include/asm/system.h @@ -113,7 +113,6 @@ extern void pfault_fini(void); extern void cmma_init(void); extern int memcpy_real(void *, void *, size_t); -extern void copy_to_absolute_zero(void *dest, void *src, size_t count); #define finish_arch_switch(prev) do { \ set_fs(current->thread.mm_segment); \ diff --git a/trunk/arch/s390/kernel/asm-offsets.c b/trunk/arch/s390/kernel/asm-offsets.c index 532fd4322156..05d8f38734ec 100644 --- a/trunk/arch/s390/kernel/asm-offsets.c +++ b/trunk/arch/s390/kernel/asm-offsets.c @@ -27,9 +27,12 @@ int main(void) BLANK(); DEFINE(__TASK_pid, offsetof(struct task_struct, pid)); BLANK(); - DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause)); - DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address)); - DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid)); + DEFINE(__THREAD_per_cause, + offsetof(struct task_struct, thread.per_event.cause)); + DEFINE(__THREAD_per_address, + offsetof(struct task_struct, thread.per_event.address)); + DEFINE(__THREAD_per_paid, + offsetof(struct task_struct, thread.per_event.paid)); BLANK(); DEFINE(__TI_task, offsetof(struct thread_info, task)); DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain)); @@ -139,7 +142,6 @@ int main(void) DEFINE(__LC_FPREGS_SAVE_AREA, offsetof(struct _lowcore, floating_pt_save_area)); DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area)); DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area)); - DEFINE(__LC_SAVE_AREA_64, offsetof(struct _lowcore, save_area_64)); #ifdef CONFIG_32BIT DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr)); #else /* CONFIG_32BIT */ diff --git a/trunk/arch/s390/kernel/base.S b/trunk/arch/s390/kernel/base.S index 255435663bf8..209938c1dfc8 100644 --- a/trunk/arch/s390/kernel/base.S +++ b/trunk/arch/s390/kernel/base.S @@ -76,42 +76,6 @@ s390_base_pgm_handler_fn: .quad 0 .previous -# -# Calls diag 308 subcode 1 and continues execution -# -# The following conditions must be ensured before calling this function: -# * Prefix register = 0 -# * Lowcore protection is disabled -# -ENTRY(diag308_reset) - larl %r4,.Lctlregs # Save control registers - stctg %c0,%c15,0(%r4) - larl %r4,.Lrestart_psw # Setup restart PSW at absolute 0 - lghi %r3,0 - lg %r4,0(%r4) # Save PSW - sturg %r4,%r3 # Use sturg, because of large pages - lghi %r1,1 - diag %r1,%r1,0x308 -.Lrestart_part2: - lhi %r0,0 # Load r0 with zero - lhi %r1,2 # Use mode 2 = ESAME (dump) - sigp %r1,%r0,0x12 # Switch to ESAME mode - sam64 # Switch to 64 bit addressing mode - larl %r4,.Lctlregs # Restore control registers - lctlg %c0,%c15,0(%r4) - br %r14 -.align 16 -.Lrestart_psw: - .long 0x00080000,0x80000000 + .Lrestart_part2 - - .section .bss -.align 8 -.Lctlregs: - .rept 16 - .quad 0 - .endr - .previous - #else /* CONFIG_64BIT */ ENTRY(s390_base_mcck_handler) diff --git a/trunk/arch/s390/kernel/compat_signal.c b/trunk/arch/s390/kernel/compat_signal.c index a9a285b8c4ad..eee999853a7c 100644 --- a/trunk/arch/s390/kernel/compat_signal.c +++ b/trunk/arch/s390/kernel/compat_signal.c @@ -380,13 +380,20 @@ asmlinkage long sys32_sigreturn(void) goto badframe; if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32)) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); - set_current_blocked(&set); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + if (restore_sigregs32(regs, &frame->sregs)) goto badframe; if (restore_sigregs_gprs_high(regs, frame->gprs_high)) goto badframe; + return regs->gprs[2]; + badframe: force_sig(SIGSEGV, current); return 0; @@ -406,22 +413,31 @@ asmlinkage long sys32_rt_sigreturn(void) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); - set_current_blocked(&set); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + if (restore_sigregs32(regs, &frame->uc.uc_mcontext)) goto badframe; if (restore_sigregs_gprs_high(regs, frame->gprs_high)) goto badframe; + err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp); st.ss_sp = compat_ptr(ss_sp); err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size); err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags); if (err) goto badframe; + set_fs (KERNEL_DS); do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]); set_fs (old_fs); + return regs->gprs[2]; + badframe: force_sig(SIGSEGV, current); return 0; @@ -589,10 +605,10 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, * OK, we're invoking a handler */ -int handle_signal32(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) +int +handle_signal32(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { - sigset_t blocked; int ret; /* Set up the stack frame */ @@ -600,12 +616,15 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, ret = setup_rt_frame32(sig, ka, info, oldset, regs); else ret = setup_frame32(sig, ka, oldset, regs); - if (ret) - return ret; - sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(&blocked, sig); - set_current_blocked(&blocked); - return 0; + + if (ret == 0) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + return ret; } diff --git a/trunk/arch/s390/kernel/entry.S b/trunk/arch/s390/kernel/entry.S index 02ec8fe7d03f..3eab7cfab07c 100644 --- a/trunk/arch/s390/kernel/entry.S +++ b/trunk/arch/s390/kernel/entry.S @@ -849,34 +849,6 @@ restart_crash: restart_go: #endif -# -# PSW restart interrupt handler -# -ENTRY(psw_restart_int_handler) - st %r15,__LC_SAVE_AREA_64(%r0) # save r15 - basr %r15,0 -0: l %r15,.Lrestart_stack-0b(%r15) # load restart stack - l %r15,0(%r15) - ahi %r15,-SP_SIZE # make room for pt_regs - stm %r0,%r14,SP_R0(%r15) # store gprs %r0-%r14 to stack - mvc SP_R15(4,%r15),__LC_SAVE_AREA_64(%r0)# store saved %r15 to stack - mvc SP_PSW(8,%r15),__LC_RST_OLD_PSW(%r0) # store restart old psw - xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # set backchain to 0 - basr %r14,0 -1: l %r14,.Ldo_restart-1b(%r14) - basr %r14,%r14 - - basr %r14,0 # load disabled wait PSW if -2: lpsw restart_psw_crash-2b(%r14) # do_restart returns - .align 4 -.Ldo_restart: - .long do_restart -.Lrestart_stack: - .long restart_stack - .align 8 -restart_psw_crash: - .long 0x000a0000,0x00000000 + restart_psw_crash - .section .kprobes.text, "ax" #ifdef CONFIG_CHECK_STACK diff --git a/trunk/arch/s390/kernel/entry64.S b/trunk/arch/s390/kernel/entry64.S index 5f729d627cef..7a0fd426ca92 100644 --- a/trunk/arch/s390/kernel/entry64.S +++ b/trunk/arch/s390/kernel/entry64.S @@ -865,26 +865,6 @@ restart_crash: restart_go: #endif -# -# PSW restart interrupt handler -# -ENTRY(psw_restart_int_handler) - stg %r15,__LC_SAVE_AREA_64(%r0) # save r15 - larl %r15,restart_stack # load restart stack - lg %r15,0(%r15) - aghi %r15,-SP_SIZE # make room for pt_regs - stmg %r0,%r14,SP_R0(%r15) # store gprs %r0-%r14 to stack - mvc SP_R15(8,%r15),__LC_SAVE_AREA_64(%r0)# store saved %r15 to stack - mvc SP_PSW(16,%r15),__LC_RST_OLD_PSW(%r0)# store restart old psw - xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # set backchain to 0 - brasl %r14,do_restart - - larl %r14,restart_psw_crash # load disabled wait PSW if - lpswe 0(%r14) # do_restart returns - .align 8 -restart_psw_crash: - .quad 0x0002000080000000,0x0000000000000000 + restart_psw_crash - .section .kprobes.text, "ax" #ifdef CONFIG_CHECK_STACK diff --git a/trunk/arch/s390/kernel/ipl.c b/trunk/arch/s390/kernel/ipl.c index 04361d5a4279..a689070be287 100644 --- a/trunk/arch/s390/kernel/ipl.c +++ b/trunk/arch/s390/kernel/ipl.c @@ -45,13 +45,11 @@ * - halt * - power off * - reipl - * - restart */ #define ON_PANIC_STR "on_panic" #define ON_HALT_STR "on_halt" #define ON_POFF_STR "on_poff" #define ON_REIPL_STR "on_reboot" -#define ON_RESTART_STR "on_restart" struct shutdown_action; struct shutdown_trigger { @@ -1546,20 +1544,17 @@ static char vmcmd_on_reboot[128]; static char vmcmd_on_panic[128]; static char vmcmd_on_halt[128]; static char vmcmd_on_poff[128]; -static char vmcmd_on_restart[128]; DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot); DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic); DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt); DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff); -DEFINE_IPL_ATTR_STR_RW(vmcmd, on_restart, "%s\n", "%s\n", vmcmd_on_restart); static struct attribute *vmcmd_attrs[] = { &sys_vmcmd_on_reboot_attr.attr, &sys_vmcmd_on_panic_attr.attr, &sys_vmcmd_on_halt_attr.attr, &sys_vmcmd_on_poff_attr.attr, - &sys_vmcmd_on_restart_attr.attr, NULL, }; @@ -1581,8 +1576,6 @@ static void vmcmd_run(struct shutdown_trigger *trigger) cmd = vmcmd_on_halt; else if (strcmp(trigger->name, ON_POFF_STR) == 0) cmd = vmcmd_on_poff; - else if (strcmp(trigger->name, ON_RESTART_STR) == 0) - cmd = vmcmd_on_restart; else return; @@ -1714,34 +1707,6 @@ static void do_panic(void) stop_run(&on_panic_trigger); } -/* on restart */ - -static struct shutdown_trigger on_restart_trigger = {ON_RESTART_STR, - &reipl_action}; - -static ssize_t on_restart_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - return sprintf(page, "%s\n", on_restart_trigger.action->name); -} - -static ssize_t on_restart_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - return set_trigger(buf, &on_restart_trigger, len); -} - -static struct kobj_attribute on_restart_attr = - __ATTR(on_restart, 0644, on_restart_show, on_restart_store); - -void do_restart(void) -{ - smp_send_stop(); - on_restart_trigger.action->fn(&on_restart_trigger); - stop_run(&on_restart_trigger); -} - /* on halt */ static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action}; @@ -1818,9 +1783,7 @@ static void __init shutdown_triggers_init(void) if (sysfs_create_file(&shutdown_actions_kset->kobj, &on_poff_attr.attr)) goto fail; - if (sysfs_create_file(&shutdown_actions_kset->kobj, - &on_restart_attr.attr)) - goto fail; + return; fail: panic("shutdown_triggers_init failed\n"); @@ -1996,12 +1959,6 @@ static void do_reset_calls(void) { struct reset_call *reset; -#ifdef CONFIG_64BIT - if (diag308_set_works) { - diag308_reset(); - return; - } -#endif list_for_each_entry(reset, &rcall, list) reset->fn(); } diff --git a/trunk/arch/s390/kernel/reipl64.S b/trunk/arch/s390/kernel/reipl64.S index e690975403f4..78eb7cfbd3d1 100644 --- a/trunk/arch/s390/kernel/reipl64.S +++ b/trunk/arch/s390/kernel/reipl64.S @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp 2000,2011 + * Copyright IBM Corp 2000,2009 * Author(s): Holger Smolinski , * Denis Joseph Barrow, */ @@ -7,64 +7,6 @@ #include #include -# -# store_status -# -# Prerequisites to run this function: -# - Prefix register is set to zero -# - Original prefix register is stored in "dump_prefix_page" -# - Lowcore protection is off -# -ENTRY(store_status) - /* Save register one and load save area base */ - stg %r1,__LC_SAVE_AREA_64(%r0) - lghi %r1,SAVE_AREA_BASE - /* General purpose registers */ - stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - lg %r2,__LC_SAVE_AREA_64(%r0) - stg %r2,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE+8(%r1) - /* Control registers */ - stctg %c0,%c15,__LC_CREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - /* Access registers */ - stam %a0,%a15,__LC_AREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - /* Floating point registers */ - std %f0, 0x00 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f1, 0x08 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f2, 0x10 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f3, 0x18 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f4, 0x20 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f5, 0x28 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f6, 0x30 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f7, 0x38 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f8, 0x40 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f9, 0x48 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f10,0x50 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f11,0x58 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f12,0x60 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f13,0x68 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f14,0x70 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - std %f15,0x78 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) - /* Floating point control register */ - stfpc __LC_FP_CREG_SAVE_AREA-SAVE_AREA_BASE(%r1) - /* CPU timer */ - stpt __LC_CPU_TIMER_SAVE_AREA-SAVE_AREA_BASE(%r1) - /* Saved prefix register */ - larl %r2,dump_prefix_page - mvc __LC_PREFIX_SAVE_AREA-SAVE_AREA_BASE(4,%r1),0(%r2) - /* Clock comparator - seven bytes */ - larl %r2,.Lclkcmp - stckc 0(%r2) - mvc __LC_CLOCK_COMP_SAVE_AREA-SAVE_AREA_BASE + 1(7,%r1),1(%r2) - /* Program status word */ - epsw %r2,%r3 - st %r2,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 0(%r1) - st %r3,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 4(%r1) - larl %r2,store_status - stg %r2,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 8(%r1) - br %r14 -.align 8 -.Lclkcmp: .quad 0x0000000000000000 - # # do_reipl_asm # Parameter: r2 = schid of reipl device @@ -73,7 +15,22 @@ ENTRY(store_status) ENTRY(do_reipl_asm) basr %r13,0 .Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) -.Lpg1: brasl %r14,store_status +.Lpg1: # do store status of all registers + + stg %r1,.Lregsave-.Lpg0(%r13) + lghi %r1,0x1000 + stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) + lg %r0,.Lregsave-.Lpg0(%r13) + stg %r0,__LC_GPREGS_SAVE_AREA-0x1000+8(%r1) + stctg %c0,%c15,__LC_CREGS_SAVE_AREA-0x1000(%r1) + stam %a0,%a15,__LC_AREGS_SAVE_AREA-0x1000(%r1) + lg %r10,.Ldump_pfx-.Lpg0(%r13) + mvc __LC_PREFIX_SAVE_AREA-0x1000(4,%r1),0(%r10) + stfpc __LC_FP_CREG_SAVE_AREA-0x1000(%r1) + stckc .Lclkcmp-.Lpg0(%r13) + mvc __LC_CLOCK_COMP_SAVE_AREA-0x1000(7,%r1),.Lclkcmp-.Lpg0(%r13) + stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) + stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) lctlg %c6,%c6,.Lall-.Lpg0(%r13) lgr %r1,%r2 @@ -110,7 +67,10 @@ ENTRY(do_reipl_asm) st %r14,.Ldispsw+12-.Lpg0(%r13) lpswe .Ldispsw-.Lpg0(%r13) .align 8 +.Lclkcmp: .quad 0x0000000000000000 .Lall: .quad 0x00000000ff000000 +.Ldump_pfx: .quad dump_prefix_page +.Lregsave: .quad 0x0000000000000000 .align 16 /* * These addresses have to be 31 bit otherwise diff --git a/trunk/arch/s390/kernel/setup.c b/trunk/arch/s390/kernel/setup.c index 7b371c37061d..0c35dee10b00 100644 --- a/trunk/arch/s390/kernel/setup.c +++ b/trunk/arch/s390/kernel/setup.c @@ -346,7 +346,7 @@ setup_lowcore(void) lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0); lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; lc->restart_psw.addr = - PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler; + PSW_ADDR_AMODE | (unsigned long) restart_int_handler; if (user_mode != HOME_SPACE_MODE) lc->restart_psw.mask |= PSW_ASC_HOME; lc->external_new_psw.mask = psw_kernel_bits; @@ -529,27 +529,6 @@ static void __init setup_memory_end(void) memory_end = memory_size; } -void *restart_stack __attribute__((__section__(".data"))); - -/* - * Setup new PSW and allocate stack for PSW restart interrupt - */ -static void __init setup_restart_psw(void) -{ - psw_t psw; - - restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0); - restart_stack += ASYNC_SIZE; - - /* - * Setup restart PSW for absolute zero lowcore. This is necesary - * if PSW restart is done on an offline CPU that has lowcore zero - */ - psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; - psw.addr = PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler; - copy_to_absolute_zero(&S390_lowcore.restart_psw, &psw, sizeof(psw)); -} - static void __init setup_memory(void) { @@ -752,7 +731,6 @@ static void __init setup_hwcaps(void) strcpy(elf_platform, "z10"); break; case 0x2817: - case 0x2818: strcpy(elf_platform, "z196"); break; } @@ -814,7 +792,6 @@ setup_arch(char **cmdline_p) setup_addressing_mode(); setup_memory(); setup_resources(); - setup_restart_psw(); setup_lowcore(); cpu_init(); diff --git a/trunk/arch/s390/kernel/signal.c b/trunk/arch/s390/kernel/signal.c index 9a40e1cc5ec3..abbb3c3c7aab 100644 --- a/trunk/arch/s390/kernel/signal.c +++ b/trunk/arch/s390/kernel/signal.c @@ -57,15 +57,17 @@ typedef struct */ SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask) { - sigset_t blocked; - - current->saved_sigmask = current->blocked; mask &= _BLOCKABLE; - siginitset(&blocked, mask); - set_current_blocked(&blocked); + spin_lock_irq(¤t->sighand->siglock); + current->saved_sigmask = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + set_current_state(TASK_INTERRUPTIBLE); schedule(); - set_restore_sigmask(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } @@ -170,11 +172,18 @@ SYSCALL_DEFINE0(sigreturn) goto badframe; if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE)) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); - set_current_blocked(&set); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + if (restore_sigregs(regs, &frame->sregs)) goto badframe; + return regs->gprs[2]; + badframe: force_sig(SIGSEGV, current); return 0; @@ -190,14 +199,21 @@ SYSCALL_DEFINE0(rt_sigreturn) goto badframe; if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); - set_current_blocked(&set); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + if (restore_sigregs(regs, &frame->uc.uc_mcontext)) goto badframe; + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]) == -EFAULT) goto badframe; return regs->gprs[2]; + badframe: force_sig(SIGSEGV, current); return 0; @@ -369,11 +385,14 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return -EFAULT; } -static int handle_signal(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, - struct pt_regs *regs) +/* + * OK, we're invoking a handler + */ + +static int +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { - sigset_t blocked; int ret; /* Set up the stack frame */ @@ -381,13 +400,17 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, ret = setup_rt_frame(sig, ka, info, oldset, regs); else ret = setup_frame(sig, ka, oldset, regs); - if (ret) - return ret; - sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(&blocked, sig); - set_current_blocked(&blocked); - return 0; + + if (ret == 0) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + + return ret; } /* diff --git a/trunk/arch/s390/kernel/smp.c b/trunk/arch/s390/kernel/smp.c index 6ab16ac64d29..a6d85c0a7f20 100644 --- a/trunk/arch/s390/kernel/smp.c +++ b/trunk/arch/s390/kernel/smp.c @@ -452,27 +452,23 @@ static void __init smp_detect_cpus(void) */ int __cpuinit start_secondary(void *cpuvoid) { + /* Setup the cpu */ cpu_init(); preempt_disable(); + /* Enable TOD clock interrupts on the secondary cpu. */ init_cpu_timer(); + /* Enable cpu timer interrupts on the secondary cpu. */ init_cpu_vtimer(); + /* Enable pfault pseudo page faults on this cpu. */ pfault_init(); + /* call cpu notifiers */ notify_cpu_starting(smp_processor_id()); + /* Mark this cpu as online */ ipi_call_lock(); set_cpu_online(smp_processor_id(), true); ipi_call_unlock(); - __ctl_clear_bit(0, 28); /* Disable lowcore protection */ - S390_lowcore.restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; - S390_lowcore.restart_psw.addr = - PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler; - __ctl_set_bit(0, 28); /* Enable lowcore protection */ - /* - * Wait until the cpu which brought this one up marked it - * active before enabling interrupts. - */ - while (!cpumask_test_cpu(smp_processor_id(), cpu_active_mask)) - cpu_relax(); + /* Switch on interrupts */ local_irq_enable(); /* cpu_idle will call schedule for us */ cpu_idle(); @@ -511,11 +507,7 @@ static int __cpuinit smp_alloc_lowcore(int cpu) memset((char *)lowcore + 512, 0, sizeof(*lowcore) - 512); lowcore->async_stack = async_stack + ASYNC_SIZE; lowcore->panic_stack = panic_stack + PAGE_SIZE; - lowcore->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; - lowcore->restart_psw.addr = - PSW_ADDR_AMODE | (unsigned long) restart_int_handler; - if (user_mode != HOME_SPACE_MODE) - lowcore->restart_psw.mask |= PSW_ASC_HOME; + #ifndef CONFIG_64BIT if (MACHINE_HAS_IEEE) { unsigned long save_area; diff --git a/trunk/arch/s390/mm/maccess.c b/trunk/arch/s390/mm/maccess.c index 5dbbaa6e594c..51e5cd9b906a 100644 --- a/trunk/arch/s390/mm/maccess.c +++ b/trunk/arch/s390/mm/maccess.c @@ -85,19 +85,3 @@ int memcpy_real(void *dest, void *src, size_t count) arch_local_irq_restore(flags); return rc; } - -/* - * Copy memory to absolute zero - */ -void copy_to_absolute_zero(void *dest, void *src, size_t count) -{ - unsigned long cr0; - - BUG_ON((unsigned long) dest + count >= sizeof(struct _lowcore)); - preempt_disable(); - __ctl_store(cr0, 0, 0); - __ctl_clear_bit(0, 28); /* disable lowcore protection */ - memcpy_real(dest + store_prefix(), src, count); - __ctl_load(cr0, 0, 0); - preempt_enable(); -} diff --git a/trunk/arch/s390/mm/pgtable.c b/trunk/arch/s390/mm/pgtable.c index 4d1f2bce87b3..2adb23938a7f 100644 --- a/trunk/arch/s390/mm/pgtable.c +++ b/trunk/arch/s390/mm/pgtable.c @@ -528,7 +528,6 @@ static inline void page_table_free_pgste(unsigned long *table) static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, unsigned long vmaddr) { - return NULL; } static inline void page_table_free_pgste(unsigned long *table) diff --git a/trunk/arch/sh/Kconfig b/trunk/arch/sh/Kconfig index ff9177c8f643..748ff1920068 100644 --- a/trunk/arch/sh/Kconfig +++ b/trunk/arch/sh/Kconfig @@ -11,7 +11,6 @@ config SUPERH select HAVE_DMA_ATTRS select HAVE_IRQ_WORK select HAVE_PERF_EVENTS - select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A) select PERF_USE_VMALLOC select HAVE_KERNEL_GZIP select HAVE_KERNEL_BZIP2 diff --git a/trunk/arch/sh/kernel/idle.c b/trunk/arch/sh/kernel/idle.c index 32114e0941ae..84db0d6ccd0d 100644 --- a/trunk/arch/sh/kernel/idle.c +++ b/trunk/arch/sh/kernel/idle.c @@ -16,13 +16,12 @@ #include #include #include -#include #include #include #include #include -static void (*pm_idle)(void); +void (*pm_idle)(void) = NULL; static int hlt_counter; @@ -101,8 +100,7 @@ void cpu_idle(void) local_irq_disable(); /* Don't trace irqs off for idle */ stop_critical_timings(); - if (cpuidle_idle_call()) - pm_idle(); + pm_idle(); /* * Sanity check to ensure that pm_idle() returns * with IRQs enabled diff --git a/trunk/arch/sparc/Kconfig b/trunk/arch/sparc/Kconfig index 42c67beadcae..1074dddcb104 100644 --- a/trunk/arch/sparc/Kconfig +++ b/trunk/arch/sparc/Kconfig @@ -54,7 +54,6 @@ config SPARC64 select HAVE_PERF_EVENTS select PERF_USE_VMALLOC select IRQ_PREFLOW_FASTEOI - select ARCH_HAVE_NMI_SAFE_CMPXCHG config ARCH_DEFCONFIG string diff --git a/trunk/arch/sparc/include/asm/Kbuild b/trunk/arch/sparc/include/asm/Kbuild index 2c2e38821f60..3c93f08ce187 100644 --- a/trunk/arch/sparc/include/asm/Kbuild +++ b/trunk/arch/sparc/include/asm/Kbuild @@ -16,8 +16,3 @@ header-y += traps.h header-y += uctx.h header-y += utrap.h header-y += watchdog.h - -generic-y += div64.h -generic-y += local64.h -generic-y += irq_regs.h -generic-y += local.h diff --git a/trunk/arch/sparc/include/asm/bitops_64.h b/trunk/arch/sparc/include/asm/bitops_64.h index 29011cc0e4be..325e295d60de 100644 --- a/trunk/arch/sparc/include/asm/bitops_64.h +++ b/trunk/arch/sparc/include/asm/bitops_64.h @@ -26,28 +26,61 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr); #define smp_mb__before_clear_bit() barrier() #define smp_mb__after_clear_bit() barrier() +#include +#include #include #include #include #ifdef __KERNEL__ -extern int ffs(int x); -extern unsigned long __ffs(unsigned long); - -#include #include +#include /* * hweightN: returns the hamming weight (i.e. the number * of bits set) of a N-bit word */ -extern unsigned long __arch_hweight64(__u64 w); -extern unsigned int __arch_hweight32(unsigned int w); -extern unsigned int __arch_hweight16(unsigned int w); -extern unsigned int __arch_hweight8(unsigned int w); +#ifdef ULTRA_HAS_POPULATION_COUNT + +static inline unsigned int __arch_hweight64(unsigned long w) +{ + unsigned int res; + + __asm__ ("popc %1,%0" : "=r" (res) : "r" (w)); + return res; +} + +static inline unsigned int __arch_hweight32(unsigned int w) +{ + unsigned int res; + + __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff)); + return res; +} +static inline unsigned int __arch_hweight16(unsigned int w) +{ + unsigned int res; + + __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff)); + return res; +} + +static inline unsigned int __arch_hweight8(unsigned int w) +{ + unsigned int res; + + __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff)); + return res; +} + +#else + +#include + +#endif #include #include #endif /* __KERNEL__ */ diff --git a/trunk/arch/sparc/include/asm/div64.h b/trunk/arch/sparc/include/asm/div64.h new file mode 100644 index 000000000000..6cd978cefb28 --- /dev/null +++ b/trunk/arch/sparc/include/asm/div64.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/sparc/include/asm/elf_64.h b/trunk/arch/sparc/include/asm/elf_64.h index 7df8b7f544d4..64f7a00b3747 100644 --- a/trunk/arch/sparc/include/asm/elf_64.h +++ b/trunk/arch/sparc/include/asm/elf_64.h @@ -59,33 +59,15 @@ #define R_SPARC_6 45 /* Bits present in AT_HWCAP, primarily for Sparc32. */ -#define HWCAP_SPARC_FLUSH 0x00000001 -#define HWCAP_SPARC_STBAR 0x00000002 -#define HWCAP_SPARC_SWAP 0x00000004 -#define HWCAP_SPARC_MULDIV 0x00000008 -#define HWCAP_SPARC_V9 0x00000010 -#define HWCAP_SPARC_ULTRA3 0x00000020 -#define HWCAP_SPARC_BLKINIT 0x00000040 -#define HWCAP_SPARC_N2 0x00000080 - -/* Solaris compatible AT_HWCAP bits. */ -#define AV_SPARC_MUL32 0x00000100 /* 32x32 multiply is efficient */ -#define AV_SPARC_DIV32 0x00000200 /* 32x32 divide is efficient */ -#define AV_SPARC_FSMULD 0x00000400 /* 'fsmuld' is efficient */ -#define AV_SPARC_V8PLUS 0x00000800 /* v9 insn available to 32bit */ -#define AV_SPARC_POPC 0x00001000 /* 'popc' is efficient */ -#define AV_SPARC_VIS 0x00002000 /* VIS insns available */ -#define AV_SPARC_VIS2 0x00004000 /* VIS2 insns available */ -#define AV_SPARC_ASI_BLK_INIT 0x00008000 /* block init ASIs available */ -#define AV_SPARC_FMAF 0x00010000 /* fused multiply-add */ -#define AV_SPARC_VIS3 0x00020000 /* VIS3 insns available */ -#define AV_SPARC_HPC 0x00040000 /* HPC insns available */ -#define AV_SPARC_RANDOM 0x00080000 /* 'random' insn available */ -#define AV_SPARC_TRANS 0x00100000 /* transaction insns available */ -#define AV_SPARC_FJFMAU 0x00200000 /* unfused multiply-add */ -#define AV_SPARC_IMA 0x00400000 /* integer multiply-add */ -#define AV_SPARC_ASI_CACHE_SPARING \ - 0x00800000 /* cache sparing ASIs available */ + +#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 +#define HWCAP_SPARC_ULTRA3 32 +#define HWCAP_SPARC_BLKINIT 64 +#define HWCAP_SPARC_N2 128 #define CORE_DUMP_USE_REGSET @@ -180,8 +162,33 @@ typedef struct { #define ELF_ET_DYN_BASE 0x0000010000000000UL #define COMPAT_ELF_ET_DYN_BASE 0x0000000070000000UL -extern unsigned long sparc64_elf_hwcap; -#define ELF_HWCAP sparc64_elf_hwcap + +/* This yields a mask that user programs can use to figure out what + instruction set this cpu supports. */ + +/* On Ultra, we support all of the v8 capabilities. */ +static inline unsigned int sparc64_elf_hwcap(void) +{ + unsigned int cap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | + HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | + HWCAP_SPARC_V9); + + if (tlb_type == cheetah || tlb_type == cheetah_plus) + cap |= HWCAP_SPARC_ULTRA3; + else if (tlb_type == hypervisor) { + if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || + sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || + sun4v_chip_type == SUN4V_CHIP_NIAGARA3) + cap |= HWCAP_SPARC_BLKINIT; + if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || + sun4v_chip_type == SUN4V_CHIP_NIAGARA3) + cap |= HWCAP_SPARC_N2; + } + + return cap; +} + +#define ELF_HWCAP sparc64_elf_hwcap() /* This yields a string that ld.so will use to load implementation specific libraries for optimization. This is more specific in diff --git a/trunk/arch/sparc/include/asm/hypervisor.h b/trunk/arch/sparc/include/asm/hypervisor.h index 015a761eaa32..7a5f80df15d0 100644 --- a/trunk/arch/sparc/include/asm/hypervisor.h +++ b/trunk/arch/sparc/include/asm/hypervisor.h @@ -2927,13 +2927,6 @@ extern unsigned long sun4v_ncs_request(unsigned long request, #define HV_FAST_FIRE_GET_PERFREG 0x120 #define HV_FAST_FIRE_SET_PERFREG 0x121 -#define HV_FAST_REBOOT_DATA_SET 0x172 - -#ifndef __ASSEMBLY__ -extern unsigned long sun4v_reboot_data_set(unsigned long ra, - unsigned long len); -#endif - /* Function numbers for HV_CORE_TRAP. */ #define HV_CORE_SET_VER 0x00 #define HV_CORE_PUTCHAR 0x01 @@ -2947,17 +2940,11 @@ extern unsigned long sun4v_reboot_data_set(unsigned long ra, #define HV_GRP_CORE 0x0001 #define HV_GRP_INTR 0x0002 #define HV_GRP_SOFT_STATE 0x0003 -#define HV_GRP_TM 0x0080 #define HV_GRP_PCI 0x0100 #define HV_GRP_LDOM 0x0101 #define HV_GRP_SVC_CHAN 0x0102 #define HV_GRP_NCS 0x0103 #define HV_GRP_RNG 0x0104 -#define HV_GRP_PBOOT 0x0105 -#define HV_GRP_TPM 0x0107 -#define HV_GRP_SDIO 0x0108 -#define HV_GRP_SDIO_ERR 0x0109 -#define HV_GRP_REBOOT_DATA 0x0110 #define HV_GRP_NIAG_PERF 0x0200 #define HV_GRP_FIRE_PERF 0x0201 #define HV_GRP_N2_CPU 0x0202 diff --git a/trunk/arch/sparc/include/asm/irq_regs.h b/trunk/arch/sparc/include/asm/irq_regs.h new file mode 100644 index 000000000000..3dd9c0b70270 --- /dev/null +++ b/trunk/arch/sparc/include/asm/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/sparc/include/asm/local.h b/trunk/arch/sparc/include/asm/local.h new file mode 100644 index 000000000000..bc80815a435c --- /dev/null +++ b/trunk/arch/sparc/include/asm/local.h @@ -0,0 +1,6 @@ +#ifndef _SPARC_LOCAL_H +#define _SPARC_LOCAL_H + +#include + +#endif diff --git a/trunk/arch/sparc/include/asm/local64.h b/trunk/arch/sparc/include/asm/local64.h new file mode 100644 index 000000000000..36c93b5cc239 --- /dev/null +++ b/trunk/arch/sparc/include/asm/local64.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/sparc/include/asm/tsb.h b/trunk/arch/sparc/include/asm/tsb.h index 1a8afd1ad04f..83c571d8c8a7 100644 --- a/trunk/arch/sparc/include/asm/tsb.h +++ b/trunk/arch/sparc/include/asm/tsb.h @@ -133,6 +133,29 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; sub TSB, 0x8, TSB; \ TSB_STORE(TSB, TAG); +#define KTSB_LOAD_QUAD(TSB, REG) \ + ldda [TSB] ASI_NUCLEUS_QUAD_LDD, REG; + +#define KTSB_STORE(ADDR, VAL) \ + stxa VAL, [ADDR] ASI_N; + +#define KTSB_LOCK_TAG(TSB, REG1, REG2) \ +99: lduwa [TSB] ASI_N, REG1; \ + sethi %hi(TSB_TAG_LOCK_HIGH), REG2;\ + andcc REG1, REG2, %g0; \ + bne,pn %icc, 99b; \ + nop; \ + casa [TSB] ASI_N, REG1, REG2;\ + cmp REG1, REG2; \ + bne,pn %icc, 99b; \ + nop; \ + +#define KTSB_WRITE(TSB, TTE, TAG) \ + add TSB, 0x8, TSB; \ + stxa TTE, [TSB] ASI_N; \ + sub TSB, 0x8, TSB; \ + stxa TAG, [TSB] ASI_N; + /* Do a kernel page table walk. Leaves physical PTE pointer in * REG1. Jumps to FAIL_LABEL on early page table walk termination. * VADDR will not be clobbered, but REG2 will. @@ -216,8 +239,6 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; (KERNEL_TSB_SIZE_BYTES / 16) #define KERNEL_TSB4M_NENTRIES 4096 -#define KTSB_PHYS_SHIFT 15 - /* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL * on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries * and the found TTE will be left in REG1. REG3 and REG4 must @@ -226,22 +247,13 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; * VADDR and TAG will be preserved and not clobbered by this macro. */ #define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ -661: sethi %hi(swapper_tsb), REG1; \ + sethi %hi(swapper_tsb), REG1; \ or REG1, %lo(swapper_tsb), REG1; \ - .section .swapper_tsb_phys_patch, "ax"; \ - .word 661b; \ - .previous; \ -661: nop; \ - .section .tsb_ldquad_phys_patch, "ax"; \ - .word 661b; \ - sllx REG1, KTSB_PHYS_SHIFT, REG1; \ - sllx REG1, KTSB_PHYS_SHIFT, REG1; \ - .previous; \ srlx VADDR, PAGE_SHIFT, REG2; \ and REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \ sllx REG2, 4, REG2; \ add REG1, REG2, REG2; \ - TSB_LOAD_QUAD(REG2, REG3); \ + KTSB_LOAD_QUAD(REG2, REG3); \ cmp REG3, TAG; \ be,a,pt %xcc, OK_LABEL; \ mov REG4, REG1; @@ -251,21 +263,12 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; * we can make use of that for the index computation. */ #define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ -661: sethi %hi(swapper_4m_tsb), REG1; \ + sethi %hi(swapper_4m_tsb), REG1; \ or REG1, %lo(swapper_4m_tsb), REG1; \ - .section .swapper_4m_tsb_phys_patch, "ax"; \ - .word 661b; \ - .previous; \ -661: nop; \ - .section .tsb_ldquad_phys_patch, "ax"; \ - .word 661b; \ - sllx REG1, KTSB_PHYS_SHIFT, REG1; \ - sllx REG1, KTSB_PHYS_SHIFT, REG1; \ - .previous; \ and TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \ sllx REG2, 4, REG2; \ add REG1, REG2, REG2; \ - TSB_LOAD_QUAD(REG2, REG3); \ + KTSB_LOAD_QUAD(REG2, REG3); \ cmp REG3, TAG; \ be,a,pt %xcc, OK_LABEL; \ mov REG4, REG1; diff --git a/trunk/arch/sparc/kernel/cpu.c b/trunk/arch/sparc/kernel/cpu.c index 9810fd881058..17cf290dc2bc 100644 --- a/trunk/arch/sparc/kernel/cpu.c +++ b/trunk/arch/sparc/kernel/cpu.c @@ -396,7 +396,6 @@ static int show_cpuinfo(struct seq_file *m, void *__unused) , cpu_data(0).clock_tick #endif ); - cpucap_info(m); #ifdef CONFIG_SMP smp_bogo(m); #endif diff --git a/trunk/arch/sparc/kernel/ds.c b/trunk/arch/sparc/kernel/ds.c index 490e5418740d..dd1342c0a3be 100644 --- a/trunk/arch/sparc/kernel/ds.c +++ b/trunk/arch/sparc/kernel/ds.c @@ -15,15 +15,12 @@ #include #include -#include #include #include #include #include #include -#include "kernel.h" - #define DRV_MODULE_NAME "ds" #define PFX DRV_MODULE_NAME ": " #define DRV_MODULE_VERSION "1.0" @@ -831,32 +828,18 @@ void ldom_set_var(const char *var, const char *value) } } -static char full_boot_str[256] __attribute__((aligned(32))); -static int reboot_data_supported; - void ldom_reboot(const char *boot_command) { /* Don't bother with any of this if the boot_command * is empty. */ if (boot_command && strlen(boot_command)) { - unsigned long len; + char full_boot_str[256]; strcpy(full_boot_str, "boot "); strcpy(full_boot_str + strlen("boot "), boot_command); - len = strlen(full_boot_str); - if (reboot_data_supported) { - unsigned long ra = kimage_addr_to_ra(full_boot_str); - unsigned long hv_ret; - - hv_ret = sun4v_reboot_data_set(ra, len); - if (hv_ret != HV_EOK) - pr_err("SUN4V: Unable to set reboot data " - "hv_ret=%lu\n", hv_ret); - } else { - ldom_set_var("reboot-command", full_boot_str); - } + ldom_set_var("reboot-command", full_boot_str); } sun4v_mach_sir(); } @@ -1254,15 +1237,6 @@ static struct vio_driver ds_driver = { static int __init ds_init(void) { - unsigned long hv_ret, major, minor; - - hv_ret = sun4v_get_version(HV_GRP_REBOOT_DATA, &major, &minor); - if (hv_ret == HV_EOK) { - pr_info("SUN4V: Reboot data supported (maj=%lu,min=%lu).\n", - major, minor); - reboot_data_supported = 1; - } - kthread_run(ds_thread, NULL, "kldomd"); return vio_register_driver(&ds_driver); diff --git a/trunk/arch/sparc/kernel/entry.h b/trunk/arch/sparc/kernel/entry.h index e27f8ea8656e..d1f1361c4167 100644 --- a/trunk/arch/sparc/kernel/entry.h +++ b/trunk/arch/sparc/kernel/entry.h @@ -42,20 +42,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr, extern void fpload(unsigned long *fpregs, unsigned long *fsr); #else /* CONFIG_SPARC32 */ -struct popc_3insn_patch_entry { - unsigned int addr; - unsigned int insns[3]; -}; -extern struct popc_3insn_patch_entry __popc_3insn_patch, - __popc_3insn_patch_end; - -struct popc_6insn_patch_entry { - unsigned int addr; - unsigned int insns[6]; -}; -extern struct popc_6insn_patch_entry __popc_6insn_patch, - __popc_6insn_patch_end; - extern void __init per_cpu_patch(void); extern void __init sun4v_patch(void); extern void __init boot_cpu_id_too_large(int cpu); diff --git a/trunk/arch/sparc/kernel/head_64.S b/trunk/arch/sparc/kernel/head_64.S index 0eac1b2fc53d..c752603a7c0d 100644 --- a/trunk/arch/sparc/kernel/head_64.S +++ b/trunk/arch/sparc/kernel/head_64.S @@ -559,7 +559,7 @@ niagara2_patch: nop call niagara_patch_bzero nop - call niagara_patch_pageops + call niagara2_patch_pageops nop ba,a,pt %xcc, 80f diff --git a/trunk/arch/sparc/kernel/hvapi.c b/trunk/arch/sparc/kernel/hvapi.c index c2d055d8ba9e..d306e648c33c 100644 --- a/trunk/arch/sparc/kernel/hvapi.c +++ b/trunk/arch/sparc/kernel/hvapi.c @@ -28,17 +28,11 @@ static struct api_info api_table[] = { { .group = HV_GRP_CORE, .flags = FLAG_PRE_API }, { .group = HV_GRP_INTR, }, { .group = HV_GRP_SOFT_STATE, }, - { .group = HV_GRP_TM, }, { .group = HV_GRP_PCI, .flags = FLAG_PRE_API }, { .group = HV_GRP_LDOM, }, { .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API }, { .group = HV_GRP_NCS, .flags = FLAG_PRE_API }, { .group = HV_GRP_RNG, }, - { .group = HV_GRP_PBOOT, }, - { .group = HV_GRP_TPM, }, - { .group = HV_GRP_SDIO, }, - { .group = HV_GRP_SDIO_ERR, }, - { .group = HV_GRP_REBOOT_DATA, }, { .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API }, { .group = HV_GRP_FIRE_PERF, }, { .group = HV_GRP_N2_CPU, }, diff --git a/trunk/arch/sparc/kernel/hvcalls.S b/trunk/arch/sparc/kernel/hvcalls.S index 58d60de4d65b..8a5f35ffb15e 100644 --- a/trunk/arch/sparc/kernel/hvcalls.S +++ b/trunk/arch/sparc/kernel/hvcalls.S @@ -798,10 +798,3 @@ ENTRY(sun4v_niagara2_setperf) retl nop ENDPROC(sun4v_niagara2_setperf) - -ENTRY(sun4v_reboot_data_set) - mov HV_FAST_REBOOT_DATA_SET, %o5 - ta HV_FAST_TRAP - retl - nop -ENDPROC(sun4v_reboot_data_set) diff --git a/trunk/arch/sparc/kernel/kernel.h b/trunk/arch/sparc/kernel/kernel.h index fd6c36b1df74..6f6544cfa0ef 100644 --- a/trunk/arch/sparc/kernel/kernel.h +++ b/trunk/arch/sparc/kernel/kernel.h @@ -4,27 +4,12 @@ #include #include -#include -#include /* cpu.c */ extern const char *sparc_pmu_type; extern unsigned int fsr_storage; extern int ncpus_probed; -#ifdef CONFIG_SPARC64 -/* setup_64.c */ -struct seq_file; -extern void cpucap_info(struct seq_file *); - -static inline unsigned long kimage_addr_to_ra(const char *p) -{ - unsigned long val = (unsigned long) p; - - return kern_base + (val - KERNBASE); -} -#endif - #ifdef CONFIG_SPARC32 /* cpu.c */ extern void cpu_probe(void); diff --git a/trunk/arch/sparc/kernel/ktlb.S b/trunk/arch/sparc/kernel/ktlb.S index 79f310364849..1d361477d7d6 100644 --- a/trunk/arch/sparc/kernel/ktlb.S +++ b/trunk/arch/sparc/kernel/ktlb.S @@ -47,16 +47,16 @@ kvmap_itlb_tsb_miss: kvmap_itlb_vmalloc_addr: KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath) - TSB_LOCK_TAG(%g1, %g2, %g7) + KTSB_LOCK_TAG(%g1, %g2, %g7) /* Load and check PTE. */ ldxa [%g5] ASI_PHYS_USE_EC, %g5 mov 1, %g7 sllx %g7, TSB_TAG_INVALID_BIT, %g7 brgez,a,pn %g5, kvmap_itlb_longpath - TSB_STORE(%g1, %g7) + KTSB_STORE(%g1, %g7) - TSB_WRITE(%g1, %g5, %g6) + KTSB_WRITE(%g1, %g5, %g6) /* fallthrough to TLB load */ @@ -102,9 +102,9 @@ kvmap_itlb_longpath: kvmap_itlb_obp: OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath) - TSB_LOCK_TAG(%g1, %g2, %g7) + KTSB_LOCK_TAG(%g1, %g2, %g7) - TSB_WRITE(%g1, %g5, %g6) + KTSB_WRITE(%g1, %g5, %g6) ba,pt %xcc, kvmap_itlb_load nop @@ -112,17 +112,17 @@ kvmap_itlb_obp: kvmap_dtlb_obp: OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath) - TSB_LOCK_TAG(%g1, %g2, %g7) + KTSB_LOCK_TAG(%g1, %g2, %g7) - TSB_WRITE(%g1, %g5, %g6) + KTSB_WRITE(%g1, %g5, %g6) ba,pt %xcc, kvmap_dtlb_load nop .align 32 kvmap_dtlb_tsb4m_load: - TSB_LOCK_TAG(%g1, %g2, %g7) - TSB_WRITE(%g1, %g5, %g6) + KTSB_LOCK_TAG(%g1, %g2, %g7) + KTSB_WRITE(%g1, %g5, %g6) ba,pt %xcc, kvmap_dtlb_load nop @@ -222,16 +222,16 @@ kvmap_linear_patch: kvmap_dtlb_vmalloc_addr: KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath) - TSB_LOCK_TAG(%g1, %g2, %g7) + KTSB_LOCK_TAG(%g1, %g2, %g7) /* Load and check PTE. */ ldxa [%g5] ASI_PHYS_USE_EC, %g5 mov 1, %g7 sllx %g7, TSB_TAG_INVALID_BIT, %g7 brgez,a,pn %g5, kvmap_dtlb_longpath - TSB_STORE(%g1, %g7) + KTSB_STORE(%g1, %g7) - TSB_WRITE(%g1, %g5, %g6) + KTSB_WRITE(%g1, %g5, %g6) /* fallthrough to TLB load */ diff --git a/trunk/arch/sparc/kernel/mdesc.c b/trunk/arch/sparc/kernel/mdesc.c index acaebb63c4fd..42f28c7420e1 100644 --- a/trunk/arch/sparc/kernel/mdesc.c +++ b/trunk/arch/sparc/kernel/mdesc.c @@ -508,8 +508,6 @@ const char *mdesc_node_name(struct mdesc_handle *hp, u64 node) } EXPORT_SYMBOL(mdesc_node_name); -static u64 max_cpus = 64; - static void __init report_platform_properties(void) { struct mdesc_handle *hp = mdesc_grab(); @@ -545,10 +543,8 @@ static void __init report_platform_properties(void) if (v) printk("PLATFORM: watchdog-max-timeout [%llu ms]\n", *v); v = mdesc_get_property(hp, pn, "max-cpus", NULL); - if (v) { - max_cpus = *v; - printk("PLATFORM: max-cpus [%llu]\n", max_cpus); - } + if (v) + printk("PLATFORM: max-cpus [%llu]\n", *v); #ifdef CONFIG_SMP { @@ -719,7 +715,7 @@ static void __cpuinit set_proc_ids(struct mdesc_handle *hp) } static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask, - unsigned long def, unsigned long max) + unsigned char def) { u64 val; @@ -730,9 +726,6 @@ static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask, if (!val || val >= 64) goto use_default; - if (val > max) - val = max; - *mask = ((1U << val) * 64U) - 1U; return; @@ -743,28 +736,19 @@ static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask, static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp, struct trap_per_cpu *tb) { - static int printed; const u64 *val; val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL); - get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7, ilog2(max_cpus * 2)); + get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7); val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL); - get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7, 8); + get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7); val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL); - get_one_mondo_bits(val, &tb->resum_qmask, 6, 7); + get_one_mondo_bits(val, &tb->resum_qmask, 6); val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL); - get_one_mondo_bits(val, &tb->nonresum_qmask, 2, 2); - if (!printed++) { - pr_info("SUN4V: Mondo queue sizes " - "[cpu(%u) dev(%u) r(%u) nr(%u)]\n", - tb->cpu_mondo_qmask + 1, - tb->dev_mondo_qmask + 1, - tb->resum_qmask + 1, - tb->nonresum_qmask + 1); - } + get_one_mondo_bits(val, &tb->nonresum_qmask, 2); } static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask) diff --git a/trunk/arch/sparc/kernel/setup_64.c b/trunk/arch/sparc/kernel/setup_64.c index 3e9daea1653d..c4dd0999da86 100644 --- a/trunk/arch/sparc/kernel/setup_64.c +++ b/trunk/arch/sparc/kernel/setup_64.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -47,8 +46,6 @@ #include #include #include -#include -#include #ifdef CONFIG_IP_PNP #include @@ -272,40 +269,6 @@ void __init sun4v_patch(void) sun4v_hvapi_init(); } -static void __init popc_patch(void) -{ - struct popc_3insn_patch_entry *p3; - struct popc_6insn_patch_entry *p6; - - p3 = &__popc_3insn_patch; - while (p3 < &__popc_3insn_patch_end) { - unsigned long i, addr = p3->addr; - - for (i = 0; i < 3; i++) { - *(unsigned int *) (addr + (i * 4)) = p3->insns[i]; - wmb(); - __asm__ __volatile__("flush %0" - : : "r" (addr + (i * 4))); - } - - p3++; - } - - p6 = &__popc_6insn_patch; - while (p6 < &__popc_6insn_patch_end) { - unsigned long i, addr = p6->addr; - - for (i = 0; i < 6; i++) { - *(unsigned int *) (addr + (i * 4)) = p6->insns[i]; - wmb(); - __asm__ __volatile__("flush %0" - : : "r" (addr + (i * 4))); - } - - p6++; - } -} - #ifdef CONFIG_SMP void __init boot_cpu_id_too_large(int cpu) { @@ -315,154 +278,6 @@ void __init boot_cpu_id_too_large(int cpu) } #endif -/* On Ultra, we support all of the v8 capabilities. */ -unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | - HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | - HWCAP_SPARC_V9); -EXPORT_SYMBOL(sparc64_elf_hwcap); - -static const char *hwcaps[] = { - "flush", "stbar", "swap", "muldiv", "v9", - "ultra3", "blkinit", "n2", - - /* These strings are as they appear in the machine description - * 'hwcap-list' property for cpu nodes. - */ - "mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2", - "ASIBlkInit", "fmaf", "vis3", "hpc", "random", "trans", "fjfmau", - "ima", "cspare", -}; - -void cpucap_info(struct seq_file *m) -{ - unsigned long caps = sparc64_elf_hwcap; - int i, printed = 0; - - seq_puts(m, "cpucaps\t\t: "); - for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { - unsigned long bit = 1UL << i; - if (caps & bit) { - seq_printf(m, "%s%s", - printed ? "," : "", hwcaps[i]); - printed++; - } - } - seq_putc(m, '\n'); -} - -static void __init report_hwcaps(unsigned long caps) -{ - int i, printed = 0; - - printk(KERN_INFO "CPU CAPS: ["); - for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { - unsigned long bit = 1UL << i; - if (caps & bit) { - printk(KERN_CONT "%s%s", - printed ? "," : "", hwcaps[i]); - if (++printed == 8) { - printk(KERN_CONT "]\n"); - printk(KERN_INFO "CPU CAPS: ["); - printed = 0; - } - } - } - printk(KERN_CONT "]\n"); -} - -static unsigned long __init mdesc_cpu_hwcap_list(void) -{ - struct mdesc_handle *hp; - unsigned long caps = 0; - const char *prop; - int len; - u64 pn; - - hp = mdesc_grab(); - if (!hp) - return 0; - - pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "cpu"); - if (pn == MDESC_NODE_NULL) - goto out; - - prop = mdesc_get_property(hp, pn, "hwcap-list", &len); - if (!prop) - goto out; - - while (len) { - int i, plen; - - for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { - unsigned long bit = 1UL << i; - - if (!strcmp(prop, hwcaps[i])) { - caps |= bit; - break; - } - } - - plen = strlen(prop) + 1; - prop += plen; - len -= plen; - } - -out: - mdesc_release(hp); - return caps; -} - -/* This yields a mask that user programs can use to figure out what - * instruction set this cpu supports. - */ -static void __init init_sparc64_elf_hwcap(void) -{ - unsigned long cap = sparc64_elf_hwcap; - unsigned long mdesc_caps; - - if (tlb_type == cheetah || tlb_type == cheetah_plus) - cap |= HWCAP_SPARC_ULTRA3; - else if (tlb_type == hypervisor) { - if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || - sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || - sun4v_chip_type == SUN4V_CHIP_NIAGARA3) - cap |= HWCAP_SPARC_BLKINIT; - if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || - sun4v_chip_type == SUN4V_CHIP_NIAGARA3) - cap |= HWCAP_SPARC_N2; - } - - cap |= (AV_SPARC_MUL32 | AV_SPARC_DIV32 | AV_SPARC_V8PLUS); - - mdesc_caps = mdesc_cpu_hwcap_list(); - if (!mdesc_caps) { - if (tlb_type == spitfire) - cap |= AV_SPARC_VIS; - if (tlb_type == cheetah || tlb_type == cheetah_plus) - cap |= AV_SPARC_VIS | AV_SPARC_VIS2; - if (tlb_type == cheetah_plus) - cap |= AV_SPARC_POPC; - if (tlb_type == hypervisor) { - if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1) - cap |= AV_SPARC_ASI_BLK_INIT; - if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || - sun4v_chip_type == SUN4V_CHIP_NIAGARA3) - cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 | - AV_SPARC_ASI_BLK_INIT | - AV_SPARC_POPC); - if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3) - cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC | - AV_SPARC_FMAF); - } - } - sparc64_elf_hwcap = cap | mdesc_caps; - - report_hwcaps(sparc64_elf_hwcap); - - if (sparc64_elf_hwcap & AV_SPARC_POPC) - popc_patch(); -} - void __init setup_arch(char **cmdline_p) { /* Initialize PROM console and command line. */ @@ -522,7 +337,6 @@ void __init setup_arch(char **cmdline_p) init_cur_cpu_trap(current_thread_info()); paging_init(); - init_sparc64_elf_hwcap(); } extern int stop_a_enabled; diff --git a/trunk/arch/sparc/kernel/sparc_ksyms_64.c b/trunk/arch/sparc/kernel/sparc_ksyms_64.c index 83b47ab02d96..372ad59c4cba 100644 --- a/trunk/arch/sparc/kernel/sparc_ksyms_64.c +++ b/trunk/arch/sparc/kernel/sparc_ksyms_64.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -39,15 +38,5 @@ EXPORT_SYMBOL(sun4v_niagara_setperf); EXPORT_SYMBOL(sun4v_niagara2_getperf); EXPORT_SYMBOL(sun4v_niagara2_setperf); -/* from hweight.S */ -EXPORT_SYMBOL(__arch_hweight8); -EXPORT_SYMBOL(__arch_hweight16); -EXPORT_SYMBOL(__arch_hweight32); -EXPORT_SYMBOL(__arch_hweight64); - -/* from ffs_ffz.S */ -EXPORT_SYMBOL(ffs); -EXPORT_SYMBOL(__ffs); - /* Exporting a symbol from /init/main.c */ EXPORT_SYMBOL(saved_command_line); diff --git a/trunk/arch/sparc/kernel/sstate.c b/trunk/arch/sparc/kernel/sstate.c index c59af546f522..8cdbe5946b43 100644 --- a/trunk/arch/sparc/kernel/sstate.c +++ b/trunk/arch/sparc/kernel/sstate.c @@ -14,10 +14,15 @@ #include #include -#include "kernel.h" - static int hv_supports_soft_state; +static unsigned long kimage_addr_to_ra(const char *p) +{ + unsigned long val = (unsigned long) p; + + return kern_base + (val - KERNBASE); +} + static void do_set_sstate(unsigned long state, const char *msg) { unsigned long err; diff --git a/trunk/arch/sparc/kernel/unaligned_64.c b/trunk/arch/sparc/kernel/unaligned_64.c index 76e4ac1a13e1..35cff1673aa4 100644 --- a/trunk/arch/sparc/kernel/unaligned_64.c +++ b/trunk/arch/sparc/kernel/unaligned_64.c @@ -22,7 +22,6 @@ #include #include #include -#include #include enum direction { @@ -374,11 +373,16 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) } } +static char popc_helper[] = { +0, 1, 1, 2, 1, 2, 2, 3, +1, 2, 2, 3, 2, 3, 3, 4, +}; + int handle_popc(u32 insn, struct pt_regs *regs) { - int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; - int ret, rd = ((insn >> 25) & 0x1f); u64 value; + int ret, i, rd = ((insn >> 25) & 0x1f); + int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); if (insn & 0x2000) { @@ -388,7 +392,10 @@ int handle_popc(u32 insn, struct pt_regs *regs) maybe_flush_windows(0, insn & 0x1f, rd, from_kernel); value = fetch_reg(insn & 0x1f, regs); } - ret = hweight64(value); + for (ret = 0, i = 0; i < 16; i++) { + ret += popc_helper[value & 0xf]; + value >>= 4; + } if (rd < 16) { if (rd) regs->u_regs[rd] = ret; diff --git a/trunk/arch/sparc/kernel/vmlinux.lds.S b/trunk/arch/sparc/kernel/vmlinux.lds.S index 0e1605697b49..c0220759003e 100644 --- a/trunk/arch/sparc/kernel/vmlinux.lds.S +++ b/trunk/arch/sparc/kernel/vmlinux.lds.S @@ -107,26 +107,7 @@ SECTIONS *(.sun4v_2insn_patch) __sun4v_2insn_patch_end = .; } - .swapper_tsb_phys_patch : { - __swapper_tsb_phys_patch = .; - *(.swapper_tsb_phys_patch) - __swapper_tsb_phys_patch_end = .; - } - .swapper_4m_tsb_phys_patch : { - __swapper_4m_tsb_phys_patch = .; - *(.swapper_4m_tsb_phys_patch) - __swapper_4m_tsb_phys_patch_end = .; - } - .popc_3insn_patch : { - __popc_3insn_patch = .; - *(.popc_3insn_patch) - __popc_3insn_patch_end = .; - } - .popc_6insn_patch : { - __popc_6insn_patch = .; - *(.popc_6insn_patch) - __popc_6insn_patch_end = .; - } + PERCPU_SECTION(SMP_CACHE_BYTES) . = ALIGN(PAGE_SIZE); diff --git a/trunk/arch/sparc/lib/Makefile b/trunk/arch/sparc/lib/Makefile index a3fc4375a150..7f01b8fce8bc 100644 --- a/trunk/arch/sparc/lib/Makefile +++ b/trunk/arch/sparc/lib/Makefile @@ -31,13 +31,13 @@ lib-$(CONFIG_SPARC64) += NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o lib-$(CONFIG_SPARC64) += NGpatch.o NGpage.o NGbzero.o lib-$(CONFIG_SPARC64) += NG2memcpy.o NG2copy_from_user.o NG2copy_to_user.o -lib-$(CONFIG_SPARC64) += NG2patch.o +lib-$(CONFIG_SPARC64) += NG2patch.o NG2page.o lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o -lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o +lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o obj-y += iomap.o obj-$(CONFIG_SPARC32) += atomic32.o diff --git a/trunk/arch/sparc/lib/NG2page.S b/trunk/arch/sparc/lib/NG2page.S new file mode 100644 index 000000000000..73b6b7c72cbf --- /dev/null +++ b/trunk/arch/sparc/lib/NG2page.S @@ -0,0 +1,61 @@ +/* NG2page.S: Niagara-2 optimized clear and copy page. + * + * Copyright (C) 2007 (davem@davemloft.net) + */ + +#include +#include +#include + + .text + .align 32 + + /* This is heavily simplified from the sun4u variants + * because Niagara-2 does not have any D-cache aliasing issues. + */ +NG2copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ + prefetch [%o1 + 0x00], #one_read + prefetch [%o1 + 0x40], #one_read + VISEntryHalf + set PAGE_SIZE, %g7 + sub %o0, %o1, %g3 +1: stxa %g0, [%o1 + %g3] ASI_BLK_INIT_QUAD_LDD_P + subcc %g7, 64, %g7 + ldda [%o1] ASI_BLK_P, %f0 + stda %f0, [%o1 + %g3] ASI_BLK_P + add %o1, 64, %o1 + bne,pt %xcc, 1b + prefetch [%o1 + 0x40], #one_read + membar #Sync + VISExitHalf + retl + nop + +#define BRANCH_ALWAYS 0x10680000 +#define NOP 0x01000000 +#define NG_DO_PATCH(OLD, NEW) \ + sethi %hi(NEW), %g1; \ + or %g1, %lo(NEW), %g1; \ + sethi %hi(OLD), %g2; \ + or %g2, %lo(OLD), %g2; \ + sub %g1, %g2, %g1; \ + sethi %hi(BRANCH_ALWAYS), %g3; \ + sll %g1, 11, %g1; \ + srl %g1, 11 + 2, %g1; \ + or %g3, %lo(BRANCH_ALWAYS), %g3; \ + or %g3, %g1, %g3; \ + stw %g3, [%g2]; \ + sethi %hi(NOP), %g3; \ + or %g3, %lo(NOP), %g3; \ + stw %g3, [%g2 + 0x4]; \ + flush %g2; + + .globl niagara2_patch_pageops + .type niagara2_patch_pageops,#function +niagara2_patch_pageops: + NG_DO_PATCH(copy_user_page, NG2copy_user_page) + NG_DO_PATCH(_clear_page, NGclear_page) + NG_DO_PATCH(clear_user_page, NGclear_user_page) + retl + nop + .size niagara2_patch_pageops,.-niagara2_patch_pageops diff --git a/trunk/arch/sparc/lib/NGpage.S b/trunk/arch/sparc/lib/NGpage.S index b9e790b9c6b8..428920de05ba 100644 --- a/trunk/arch/sparc/lib/NGpage.S +++ b/trunk/arch/sparc/lib/NGpage.S @@ -16,91 +16,55 @@ */ NGcopy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ - save %sp, -192, %sp - rd %asi, %g3 - wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi + prefetch [%o1 + 0x00], #one_read + mov 8, %g1 + mov 16, %g2 + mov 24, %g3 set PAGE_SIZE, %g7 - prefetch [%i1 + 0x00], #one_read - prefetch [%i1 + 0x40], #one_read -1: prefetch [%i1 + 0x80], #one_read - prefetch [%i1 + 0xc0], #one_read - ldda [%i1 + 0x00] %asi, %o2 - ldda [%i1 + 0x10] %asi, %o4 - ldda [%i1 + 0x20] %asi, %l2 - ldda [%i1 + 0x30] %asi, %l4 - stxa %o2, [%i0 + 0x00] %asi - stxa %o3, [%i0 + 0x08] %asi - stxa %o4, [%i0 + 0x10] %asi - stxa %o5, [%i0 + 0x18] %asi - stxa %l2, [%i0 + 0x20] %asi - stxa %l3, [%i0 + 0x28] %asi - stxa %l4, [%i0 + 0x30] %asi - stxa %l5, [%i0 + 0x38] %asi - ldda [%i1 + 0x40] %asi, %o2 - ldda [%i1 + 0x50] %asi, %o4 - ldda [%i1 + 0x60] %asi, %l2 - ldda [%i1 + 0x70] %asi, %l4 - stxa %o2, [%i0 + 0x40] %asi - stxa %o3, [%i0 + 0x48] %asi - stxa %o4, [%i0 + 0x50] %asi - stxa %o5, [%i0 + 0x58] %asi - stxa %l2, [%i0 + 0x60] %asi - stxa %l3, [%i0 + 0x68] %asi - stxa %l4, [%i0 + 0x70] %asi - stxa %l5, [%i0 + 0x78] %asi - add %i1, 128, %i1 - subcc %g7, 128, %g7 +1: ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2 + ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4 + prefetch [%o1 + 0x40], #one_read + add %o1, 32, %o1 + stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P + stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P + ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2 + stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P + stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P + ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4 + add %o1, 32, %o1 + add %o0, 32, %o0 + stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P + stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P + stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P + stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P + subcc %g7, 64, %g7 bne,pt %xcc, 1b - add %i0, 128, %i0 - wr %g3, 0x0, %asi + add %o0, 32, %o0 membar #Sync - ret - restore + retl + nop - .align 32 + .globl NGclear_page, NGclear_user_page NGclear_page: /* %o0=dest */ NGclear_user_page: /* %o0=dest, %o1=vaddr */ - rd %asi, %g3 - wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi + mov 8, %g1 + mov 16, %g2 + mov 24, %g3 set PAGE_SIZE, %g7 -1: stxa %g0, [%o0 + 0x00] %asi - stxa %g0, [%o0 + 0x08] %asi - stxa %g0, [%o0 + 0x10] %asi - stxa %g0, [%o0 + 0x18] %asi - stxa %g0, [%o0 + 0x20] %asi - stxa %g0, [%o0 + 0x28] %asi - stxa %g0, [%o0 + 0x30] %asi - stxa %g0, [%o0 + 0x38] %asi - stxa %g0, [%o0 + 0x40] %asi - stxa %g0, [%o0 + 0x48] %asi - stxa %g0, [%o0 + 0x50] %asi - stxa %g0, [%o0 + 0x58] %asi - stxa %g0, [%o0 + 0x60] %asi - stxa %g0, [%o0 + 0x68] %asi - stxa %g0, [%o0 + 0x70] %asi - stxa %g0, [%o0 + 0x78] %asi - stxa %g0, [%o0 + 0x80] %asi - stxa %g0, [%o0 + 0x88] %asi - stxa %g0, [%o0 + 0x90] %asi - stxa %g0, [%o0 + 0x98] %asi - stxa %g0, [%o0 + 0xa0] %asi - stxa %g0, [%o0 + 0xa8] %asi - stxa %g0, [%o0 + 0xb0] %asi - stxa %g0, [%o0 + 0xb8] %asi - stxa %g0, [%o0 + 0xc0] %asi - stxa %g0, [%o0 + 0xc8] %asi - stxa %g0, [%o0 + 0xd0] %asi - stxa %g0, [%o0 + 0xd8] %asi - stxa %g0, [%o0 + 0xe0] %asi - stxa %g0, [%o0 + 0xe8] %asi - stxa %g0, [%o0 + 0xf0] %asi - stxa %g0, [%o0 + 0xf8] %asi - subcc %g7, 256, %g7 +1: stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P + stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P + stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P + stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P + add %o0, 32, %o0 + stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P + stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P + stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P + stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P + subcc %g7, 64, %g7 bne,pt %xcc, 1b - add %o0, 256, %o0 - wr %g3, 0x0, %asi + add %o0, 32, %o0 membar #Sync retl nop diff --git a/trunk/arch/sparc/lib/atomic32.c b/trunk/arch/sparc/lib/atomic32.c index 1d32b54089aa..8600eb2461b5 100644 --- a/trunk/arch/sparc/lib/atomic32.c +++ b/trunk/arch/sparc/lib/atomic32.c @@ -65,7 +65,7 @@ int __atomic_add_unless(atomic_t *v, int a, int u) if (ret != u) v->counter += a; spin_unlock_irqrestore(ATOMIC_HASH(v), flags); - return ret; + return ret != u; } EXPORT_SYMBOL(__atomic_add_unless); diff --git a/trunk/arch/sparc/lib/ffs.S b/trunk/arch/sparc/lib/ffs.S deleted file mode 100644 index b39389f69899..000000000000 --- a/trunk/arch/sparc/lib/ffs.S +++ /dev/null @@ -1,84 +0,0 @@ -#include - - .register %g2,#scratch - - .text - .align 32 - -ENTRY(ffs) - brnz,pt %o0, 1f - mov 1, %o1 - retl - clr %o0 - nop - nop -ENTRY(__ffs) - sllx %o0, 32, %g1 /* 1 */ - srlx %o0, 32, %g2 - - clr %o1 /* 2 */ - movrz %g1, %g2, %o0 - - movrz %g1, 32, %o1 /* 3 */ -1: clr %o2 - - sllx %o0, (64 - 16), %g1 /* 4 */ - srlx %o0, 16, %g2 - - movrz %g1, %g2, %o0 /* 5 */ - clr %o3 - - movrz %g1, 16, %o2 /* 6 */ - clr %o4 - - and %o0, 0xff, %g1 /* 7 */ - srlx %o0, 8, %g2 - - movrz %g1, %g2, %o0 /* 8 */ - clr %o5 - - movrz %g1, 8, %o3 /* 9 */ - add %o2, %o1, %o2 - - and %o0, 0xf, %g1 /* 10 */ - srlx %o0, 4, %g2 - - movrz %g1, %g2, %o0 /* 11 */ - add %o2, %o3, %o2 - - movrz %g1, 4, %o4 /* 12 */ - - and %o0, 0x3, %g1 /* 13 */ - srlx %o0, 2, %g2 - - movrz %g1, %g2, %o0 /* 14 */ - add %o2, %o4, %o2 - - movrz %g1, 2, %o5 /* 15 */ - - and %o0, 0x1, %g1 /* 16 */ - - add %o2, %o5, %o2 /* 17 */ - xor %g1, 0x1, %g1 - - retl /* 18 */ - add %o2, %g1, %o0 -ENDPROC(ffs) -ENDPROC(__ffs) - - .section .popc_6insn_patch, "ax" - .word ffs - brz,pn %o0, 98f - neg %o0, %g1 - xnor %o0, %g1, %o1 - popc %o1, %o0 -98: retl - nop - .word __ffs - neg %o0, %g1 - xnor %o0, %g1, %o1 - popc %o1, %o0 - retl - sub %o0, 1, %o0 - nop - .previous diff --git a/trunk/arch/sparc/lib/hweight.S b/trunk/arch/sparc/lib/hweight.S deleted file mode 100644 index 95414e0a6808..000000000000 --- a/trunk/arch/sparc/lib/hweight.S +++ /dev/null @@ -1,51 +0,0 @@ -#include - - .text - .align 32 -ENTRY(__arch_hweight8) - ba,pt %xcc, __sw_hweight8 - nop - nop -ENDPROC(__arch_hweight8) - .section .popc_3insn_patch, "ax" - .word __arch_hweight8 - sllx %o0, 64-8, %g1 - retl - popc %g1, %o0 - .previous - -ENTRY(__arch_hweight16) - ba,pt %xcc, __sw_hweight16 - nop - nop -ENDPROC(__arch_hweight16) - .section .popc_3insn_patch, "ax" - .word __arch_hweight16 - sllx %o0, 64-16, %g1 - retl - popc %g1, %o0 - .previous - -ENTRY(__arch_hweight32) - ba,pt %xcc, __sw_hweight32 - nop - nop -ENDPROC(__arch_hweight32) - .section .popc_3insn_patch, "ax" - .word __arch_hweight32 - sllx %o0, 64-32, %g1 - retl - popc %g1, %o0 - .previous - -ENTRY(__arch_hweight64) - ba,pt %xcc, __sw_hweight64 - nop - nop -ENDPROC(__arch_hweight64) - .section .popc_3insn_patch, "ax" - .word __arch_hweight64 - retl - popc %o0, %o0 - nop - .previous diff --git a/trunk/arch/sparc/mm/init_64.c b/trunk/arch/sparc/mm/init_64.c index adfac23d976a..3fd8e18bed80 100644 --- a/trunk/arch/sparc/mm/init_64.c +++ b/trunk/arch/sparc/mm/init_64.c @@ -1597,42 +1597,6 @@ static void __init tsb_phys_patch(void) static struct hv_tsb_descr ktsb_descr[NUM_KTSB_DESCR]; extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES]; -static void patch_one_ktsb_phys(unsigned int *start, unsigned int *end, unsigned long pa) -{ - pa >>= KTSB_PHYS_SHIFT; - - while (start < end) { - unsigned int *ia = (unsigned int *)(unsigned long)*start; - - ia[0] = (ia[0] & ~0x3fffff) | (pa >> 10); - __asm__ __volatile__("flush %0" : : "r" (ia)); - - ia[1] = (ia[1] & ~0x3ff) | (pa & 0x3ff); - __asm__ __volatile__("flush %0" : : "r" (ia + 1)); - - start++; - } -} - -static void ktsb_phys_patch(void) -{ - extern unsigned int __swapper_tsb_phys_patch; - extern unsigned int __swapper_tsb_phys_patch_end; - extern unsigned int __swapper_4m_tsb_phys_patch; - extern unsigned int __swapper_4m_tsb_phys_patch_end; - unsigned long ktsb_pa; - - ktsb_pa = kern_base + ((unsigned long)&swapper_tsb[0] - KERNBASE); - patch_one_ktsb_phys(&__swapper_tsb_phys_patch, - &__swapper_tsb_phys_patch_end, ktsb_pa); -#ifndef CONFIG_DEBUG_PAGEALLOC - ktsb_pa = (kern_base + - ((unsigned long)&swapper_4m_tsb[0] - KERNBASE)); - patch_one_ktsb_phys(&__swapper_4m_tsb_phys_patch, - &__swapper_4m_tsb_phys_patch_end, ktsb_pa); -#endif -} - static void __init sun4v_ktsb_init(void) { unsigned long ktsb_pa; @@ -1752,10 +1716,8 @@ void __init paging_init(void) sun4u_pgprot_init(); if (tlb_type == cheetah_plus || - tlb_type == hypervisor) { + tlb_type == hypervisor) tsb_phys_patch(); - ktsb_phys_patch(); - } if (tlb_type == hypervisor) { sun4v_patch_tlb_handlers(); diff --git a/trunk/arch/tile/Kconfig b/trunk/arch/tile/Kconfig index b30f71ac0d06..0249b8b4db54 100644 --- a/trunk/arch/tile/Kconfig +++ b/trunk/arch/tile/Kconfig @@ -12,7 +12,6 @@ config TILE select GENERIC_PENDING_IRQ if SMP select GENERIC_IRQ_SHOW select SYS_HYPERVISOR - select ARCH_HAVE_NMI_SAFE_CMPXCHG if !M386 # FIXME: investigate whether we need/want these options. # select HAVE_IOREMAP_PROT diff --git a/trunk/arch/tile/include/asm/Kbuild b/trunk/arch/tile/include/asm/Kbuild index aec60dc06007..849ab2fa1f5c 100644 --- a/trunk/arch/tile/include/asm/Kbuild +++ b/trunk/arch/tile/include/asm/Kbuild @@ -2,41 +2,3 @@ include include/asm-generic/Kbuild.asm header-y += ucontext.h header-y += hardwall.h - -generic-y += bug.h -generic-y += bugs.h -generic-y += cputime.h -generic-y += device.h -generic-y += div64.h -generic-y += emergency-restart.h -generic-y += errno.h -generic-y += fb.h -generic-y += fcntl.h -generic-y += ioctl.h -generic-y += ioctls.h -generic-y += ipc.h -generic-y += ipcbuf.h -generic-y += irq_regs.h -generic-y += kdebug.h -generic-y += local.h -generic-y += module.h -generic-y += msgbuf.h -generic-y += mutex.h -generic-y += param.h -generic-y += parport.h -generic-y += poll.h -generic-y += posix_types.h -generic-y += resource.h -generic-y += scatterlist.h -generic-y += sembuf.h -generic-y += serial.h -generic-y += shmbuf.h -generic-y += shmparam.h -generic-y += socket.h -generic-y += sockios.h -generic-y += statfs.h -generic-y += termbits.h -generic-y += termios.h -generic-y += types.h -generic-y += ucontext.h -generic-y += xor.h diff --git a/trunk/arch/tile/include/asm/bug.h b/trunk/arch/tile/include/asm/bug.h new file mode 100644 index 000000000000..b12fd89e42e9 --- /dev/null +++ b/trunk/arch/tile/include/asm/bug.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/bugs.h b/trunk/arch/tile/include/asm/bugs.h new file mode 100644 index 000000000000..61791e1ad9f5 --- /dev/null +++ b/trunk/arch/tile/include/asm/bugs.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/cputime.h b/trunk/arch/tile/include/asm/cputime.h new file mode 100644 index 000000000000..6d68ad7e0ea3 --- /dev/null +++ b/trunk/arch/tile/include/asm/cputime.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/device.h b/trunk/arch/tile/include/asm/device.h new file mode 100644 index 000000000000..f0a4c256403b --- /dev/null +++ b/trunk/arch/tile/include/asm/device.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/div64.h b/trunk/arch/tile/include/asm/div64.h new file mode 100644 index 000000000000..6cd978cefb28 --- /dev/null +++ b/trunk/arch/tile/include/asm/div64.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/emergency-restart.h b/trunk/arch/tile/include/asm/emergency-restart.h new file mode 100644 index 000000000000..3711bd9d50bd --- /dev/null +++ b/trunk/arch/tile/include/asm/emergency-restart.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/errno.h b/trunk/arch/tile/include/asm/errno.h new file mode 100644 index 000000000000..4c82b503d92f --- /dev/null +++ b/trunk/arch/tile/include/asm/errno.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/fb.h b/trunk/arch/tile/include/asm/fb.h new file mode 100644 index 000000000000..3a4988e8df45 --- /dev/null +++ b/trunk/arch/tile/include/asm/fb.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/fcntl.h b/trunk/arch/tile/include/asm/fcntl.h new file mode 100644 index 000000000000..46ab12db5739 --- /dev/null +++ b/trunk/arch/tile/include/asm/fcntl.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/fixmap.h b/trunk/arch/tile/include/asm/fixmap.h index c66f7933beaa..51537ff9265a 100644 --- a/trunk/arch/tile/include/asm/fixmap.h +++ b/trunk/arch/tile/include/asm/fixmap.h @@ -75,6 +75,12 @@ extern void __set_fixmap(enum fixed_addresses idx, #define set_fixmap(idx, phys) \ __set_fixmap(idx, phys, PAGE_KERNEL) +/* + * Some hardware wants to get fixmapped without caching. + */ +#define set_fixmap_nocache(idx, phys) \ + __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE) + #define clear_fixmap(idx) \ __set_fixmap(idx, 0, __pgprot(0)) diff --git a/trunk/arch/tile/include/asm/ioctl.h b/trunk/arch/tile/include/asm/ioctl.h new file mode 100644 index 000000000000..b279fe06dfe5 --- /dev/null +++ b/trunk/arch/tile/include/asm/ioctl.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/ioctls.h b/trunk/arch/tile/include/asm/ioctls.h new file mode 100644 index 000000000000..ec34c760665e --- /dev/null +++ b/trunk/arch/tile/include/asm/ioctls.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/ipc.h b/trunk/arch/tile/include/asm/ipc.h new file mode 100644 index 000000000000..a46e3d9c2a3f --- /dev/null +++ b/trunk/arch/tile/include/asm/ipc.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/ipcbuf.h b/trunk/arch/tile/include/asm/ipcbuf.h new file mode 100644 index 000000000000..84c7e51cb6d0 --- /dev/null +++ b/trunk/arch/tile/include/asm/ipcbuf.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/irq_regs.h b/trunk/arch/tile/include/asm/irq_regs.h new file mode 100644 index 000000000000..3dd9c0b70270 --- /dev/null +++ b/trunk/arch/tile/include/asm/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/kdebug.h b/trunk/arch/tile/include/asm/kdebug.h new file mode 100644 index 000000000000..6ece1b037665 --- /dev/null +++ b/trunk/arch/tile/include/asm/kdebug.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/local.h b/trunk/arch/tile/include/asm/local.h new file mode 100644 index 000000000000..c11c530f74d0 --- /dev/null +++ b/trunk/arch/tile/include/asm/local.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/module.h b/trunk/arch/tile/include/asm/module.h new file mode 100644 index 000000000000..1e4b79fe8584 --- /dev/null +++ b/trunk/arch/tile/include/asm/module.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/msgbuf.h b/trunk/arch/tile/include/asm/msgbuf.h new file mode 100644 index 000000000000..809134c644a6 --- /dev/null +++ b/trunk/arch/tile/include/asm/msgbuf.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/mutex.h b/trunk/arch/tile/include/asm/mutex.h new file mode 100644 index 000000000000..ff6101aa2c71 --- /dev/null +++ b/trunk/arch/tile/include/asm/mutex.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/param.h b/trunk/arch/tile/include/asm/param.h new file mode 100644 index 000000000000..965d45427975 --- /dev/null +++ b/trunk/arch/tile/include/asm/param.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/parport.h b/trunk/arch/tile/include/asm/parport.h new file mode 100644 index 000000000000..cf252af64590 --- /dev/null +++ b/trunk/arch/tile/include/asm/parport.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/poll.h b/trunk/arch/tile/include/asm/poll.h new file mode 100644 index 000000000000..c98509d3149e --- /dev/null +++ b/trunk/arch/tile/include/asm/poll.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/posix_types.h b/trunk/arch/tile/include/asm/posix_types.h new file mode 100644 index 000000000000..22cae6230ceb --- /dev/null +++ b/trunk/arch/tile/include/asm/posix_types.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/resource.h b/trunk/arch/tile/include/asm/resource.h new file mode 100644 index 000000000000..04bc4db8921b --- /dev/null +++ b/trunk/arch/tile/include/asm/resource.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/scatterlist.h b/trunk/arch/tile/include/asm/scatterlist.h new file mode 100644 index 000000000000..35d786fe93ae --- /dev/null +++ b/trunk/arch/tile/include/asm/scatterlist.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/sembuf.h b/trunk/arch/tile/include/asm/sembuf.h new file mode 100644 index 000000000000..7673b83cfef7 --- /dev/null +++ b/trunk/arch/tile/include/asm/sembuf.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/serial.h b/trunk/arch/tile/include/asm/serial.h new file mode 100644 index 000000000000..a0cb0caff152 --- /dev/null +++ b/trunk/arch/tile/include/asm/serial.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/shmbuf.h b/trunk/arch/tile/include/asm/shmbuf.h new file mode 100644 index 000000000000..83c05fc2de38 --- /dev/null +++ b/trunk/arch/tile/include/asm/shmbuf.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/shmparam.h b/trunk/arch/tile/include/asm/shmparam.h new file mode 100644 index 000000000000..93f30deb95d0 --- /dev/null +++ b/trunk/arch/tile/include/asm/shmparam.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/socket.h b/trunk/arch/tile/include/asm/socket.h new file mode 100644 index 000000000000..6b71384b9d8b --- /dev/null +++ b/trunk/arch/tile/include/asm/socket.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/sockios.h b/trunk/arch/tile/include/asm/sockios.h new file mode 100644 index 000000000000..def6d4746ee7 --- /dev/null +++ b/trunk/arch/tile/include/asm/sockios.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/statfs.h b/trunk/arch/tile/include/asm/statfs.h new file mode 100644 index 000000000000..0b91fe198c20 --- /dev/null +++ b/trunk/arch/tile/include/asm/statfs.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/termbits.h b/trunk/arch/tile/include/asm/termbits.h new file mode 100644 index 000000000000..3935b106de79 --- /dev/null +++ b/trunk/arch/tile/include/asm/termbits.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/termios.h b/trunk/arch/tile/include/asm/termios.h new file mode 100644 index 000000000000..280d78a9d966 --- /dev/null +++ b/trunk/arch/tile/include/asm/termios.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/types.h b/trunk/arch/tile/include/asm/types.h new file mode 100644 index 000000000000..b9e79bc580dd --- /dev/null +++ b/trunk/arch/tile/include/asm/types.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/ucontext.h b/trunk/arch/tile/include/asm/ucontext.h new file mode 100644 index 000000000000..9bc07b9f30fb --- /dev/null +++ b/trunk/arch/tile/include/asm/ucontext.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/asm/xor.h b/trunk/arch/tile/include/asm/xor.h new file mode 100644 index 000000000000..c82eb12a5b18 --- /dev/null +++ b/trunk/arch/tile/include/asm/xor.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/tile/include/hv/drv_srom_intf.h b/trunk/arch/tile/include/hv/drv_srom_intf.h deleted file mode 100644 index 6395faa6d9e6..000000000000 --- a/trunk/arch/tile/include/hv/drv_srom_intf.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. 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 - * as published by the Free Software Foundation, version 2. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file drv_srom_intf.h - * Interface definitions for the SPI Flash ROM driver. - */ - -#ifndef _SYS_HV_INCLUDE_DRV_SROM_INTF_H -#define _SYS_HV_INCLUDE_DRV_SROM_INTF_H - -/** Read this offset to get the total device size. */ -#define SROM_TOTAL_SIZE_OFF 0xF0000000 - -/** Read this offset to get the device sector size. */ -#define SROM_SECTOR_SIZE_OFF 0xF0000004 - -/** Read this offset to get the device page size. */ -#define SROM_PAGE_SIZE_OFF 0xF0000008 - -/** Write this offset to flush any pending writes. */ -#define SROM_FLUSH_OFF 0xF1000000 - -/** Write this offset, plus the byte offset of the start of a sector, to - * erase a sector. Any write data is ignored, but there must be at least - * one byte of write data. Only applies when the driver is in MTD mode. - */ -#define SROM_ERASE_OFF 0xF2000000 - -#endif /* _SYS_HV_INCLUDE_DRV_SROM_INTF_H */ diff --git a/trunk/arch/tile/kernel/time.c b/trunk/arch/tile/kernel/time.c index f6f50f2a5e37..c4be58cc5d50 100644 --- a/trunk/arch/tile/kernel/time.c +++ b/trunk/arch/tile/kernel/time.c @@ -78,6 +78,7 @@ static struct clocksource cycle_counter_cs = { .rating = 300, .read = clocksource_get_cycles, .mask = CLOCKSOURCE_MASK(64), + .shift = 22, /* typical value, e.g. x86 tsc uses this */ .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -90,6 +91,8 @@ void __init setup_clock(void) cycles_per_sec = hv_sysconf(HV_SYSCONF_CPU_SPEED); sched_clock_mult = clocksource_hz2mult(cycles_per_sec, SCHED_CLOCK_SHIFT); + cycle_counter_cs.mult = + clocksource_hz2mult(cycles_per_sec, cycle_counter_cs.shift); } void __init calibrate_delay(void) @@ -104,7 +107,7 @@ void __init calibrate_delay(void) void __init time_init(void) { /* Initialize and register the clock source. */ - clocksource_register_hz(&cycle_counter_cs, cycles_per_sec); + clocksource_register(&cycle_counter_cs); /* Start up the tile-timer interrupt source on the boot cpu. */ setup_tile_timer(); diff --git a/trunk/arch/tile/mm/init.c b/trunk/arch/tile/mm/init.c index 7309988c9794..4e10c4023028 100644 --- a/trunk/arch/tile/mm/init.c +++ b/trunk/arch/tile/mm/init.c @@ -836,7 +836,8 @@ void __init mem_init(void) #endif #ifdef CONFIG_FLATMEM - BUG_ON(!mem_map); + if (!mem_map) + BUG(); #endif #ifdef CONFIG_HIGHMEM diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig index 6a47bb22657f..7cf916fc1ce7 100644 --- a/trunk/arch/x86/Kconfig +++ b/trunk/arch/x86/Kconfig @@ -72,7 +72,6 @@ config X86 select USE_GENERIC_SMP_HELPERS if SMP select HAVE_BPF_JIT if (X86_64 && NET) select CLKEVT_I8253 - select ARCH_HAVE_NMI_SAFE_CMPXCHG config INSTRUCTION_DECODER def_bool (KPROBES || PERF_EVENTS) diff --git a/trunk/arch/x86/include/asm/io.h b/trunk/arch/x86/include/asm/io.h index d8e8eefbe24c..d02804d650c4 100644 --- a/trunk/arch/x86/include/asm/io.h +++ b/trunk/arch/x86/include/asm/io.h @@ -40,6 +40,8 @@ #include #include +#include + #define build_mmio_read(name, size, type, reg, barrier) \ static inline type name(const volatile void __iomem *addr) \ { type ret; asm volatile("mov" size " %1,%0":reg (ret) \ @@ -332,7 +334,6 @@ extern void fixup_early_ioremap(void); extern bool is_early_ioremap_ptep(pte_t *ptep); #ifdef CONFIG_XEN -#include struct bio_vec; extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, diff --git a/trunk/arch/x86/include/asm/processor.h b/trunk/arch/x86/include/asm/processor.h index 0d1171c97729..219371546afd 100644 --- a/trunk/arch/x86/include/asm/processor.h +++ b/trunk/arch/x86/include/asm/processor.h @@ -751,6 +751,8 @@ static inline void __sti_mwait(unsigned long eax, unsigned long ecx) :: "a" (eax), "c" (ecx)); } +extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx); + extern void select_idle_routine(const struct cpuinfo_x86 *c); extern void init_amd_e400_c1e_mask(void); diff --git a/trunk/arch/x86/kernel/acpi/cstate.c b/trunk/arch/x86/kernel/acpi/cstate.c index f50e7fb2a201..5812404a0d4c 100644 --- a/trunk/arch/x86/kernel/acpi/cstate.c +++ b/trunk/arch/x86/kernel/acpi/cstate.c @@ -149,29 +149,6 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu, } EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe); -/* - * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, - * which can obviate IPI to trigger checking of need_resched. - * We execute MONITOR against need_resched and enter optimized wait state - * through MWAIT. Whenever someone changes need_resched, we would be woken - * up from MWAIT (without an IPI). - * - * New with Core Duo processors, MWAIT can take some hints based on CPU - * capability. - */ -void mwait_idle_with_hints(unsigned long ax, unsigned long cx) -{ - if (!need_resched()) { - if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) - clflush((void *)¤t_thread_info()->flags); - - __monitor((void *)¤t_thread_info()->flags, 0, 0); - smp_mb(); - if (!need_resched()) - __mwait(ax, cx); - } -} - void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx) { unsigned int cpu = smp_processor_id(); diff --git a/trunk/arch/x86/kernel/process.c b/trunk/arch/x86/kernel/process.c index e7e3b019c439..e1ba8cb24e4e 100644 --- a/trunk/arch/x86/kernel/process.c +++ b/trunk/arch/x86/kernel/process.c @@ -438,6 +438,29 @@ void cpu_idle_wait(void) } EXPORT_SYMBOL_GPL(cpu_idle_wait); +/* + * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, + * which can obviate IPI to trigger checking of need_resched. + * We execute MONITOR against need_resched and enter optimized wait state + * through MWAIT. Whenever someone changes need_resched, we would be woken + * up from MWAIT (without an IPI). + * + * New with Core Duo processors, MWAIT can take some hints based on CPU + * capability. + */ +void mwait_idle_with_hints(unsigned long ax, unsigned long cx) +{ + if (!need_resched()) { + if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) + clflush((void *)¤t_thread_info()->flags); + + __monitor((void *)¤t_thread_info()->flags, 0, 0); + smp_mb(); + if (!need_resched()) + __mwait(ax, cx); + } +} + /* Default MONITOR/MWAIT with no hints, used for default C1 state */ static void mwait_idle(void) { diff --git a/trunk/arch/x86/kernel/process_32.c b/trunk/arch/x86/kernel/process_32.c index 7a3b65107a27..a3d0dc59067b 100644 --- a/trunk/arch/x86/kernel/process_32.c +++ b/trunk/arch/x86/kernel/process_32.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -110,8 +109,7 @@ void cpu_idle(void) local_irq_disable(); /* Don't trace irqs off for idle */ stop_critical_timings(); - if (cpuidle_idle_call()) - pm_idle(); + pm_idle(); start_critical_timings(); } tick_nohz_restart_sched_tick(); diff --git a/trunk/arch/x86/kernel/process_64.c b/trunk/arch/x86/kernel/process_64.c index f693e44e1bf6..ca6f7ab8df33 100644 --- a/trunk/arch/x86/kernel/process_64.c +++ b/trunk/arch/x86/kernel/process_64.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -137,8 +136,7 @@ void cpu_idle(void) enter_idle(); /* Don't trace irqs off for idle */ stop_critical_timings(); - if (cpuidle_idle_call()) - pm_idle(); + pm_idle(); start_critical_timings(); /* In many cases the interrupt that ended idle diff --git a/trunk/arch/x86/platform/mrst/Makefile b/trunk/arch/x86/platform/mrst/Makefile index 1ea38775a6d3..f61ccdd49341 100644 --- a/trunk/arch/x86/platform/mrst/Makefile +++ b/trunk/arch/x86/platform/mrst/Makefile @@ -1,4 +1,3 @@ obj-$(CONFIG_X86_MRST) += mrst.o obj-$(CONFIG_X86_MRST) += vrtc.o obj-$(CONFIG_EARLY_PRINTK_MRST) += early_printk_mrst.o -obj-$(CONFIG_X86_MRST) += pmu.o diff --git a/trunk/arch/x86/platform/mrst/pmu.c b/trunk/arch/x86/platform/mrst/pmu.c deleted file mode 100644 index 9281da7d91bd..000000000000 --- a/trunk/arch/x86/platform/mrst/pmu.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * mrst/pmu.c - driver for MRST Power Management Unit - * - * Copyright (c) 2011, Intel Corporation. - * - * 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, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pmu.h" - -#define IPCMSG_FW_REVISION 0xF4 - -struct mrst_device { - u16 pci_dev_num; /* DEBUG only */ - u16 lss; - u16 latest_request; - unsigned int pci_state_counts[PCI_D3cold + 1]; /* DEBUG only */ -}; - -/* - * comlete list of MRST PCI devices - */ -static struct mrst_device mrst_devs[] = { -/* 0 */ { 0x0800, LSS_SPI0 }, /* Moorestown SPI Ctrl 0 */ -/* 1 */ { 0x0801, LSS_SPI1 }, /* Moorestown SPI Ctrl 1 */ -/* 2 */ { 0x0802, LSS_I2C0 }, /* Moorestown I2C 0 */ -/* 3 */ { 0x0803, LSS_I2C1 }, /* Moorestown I2C 1 */ -/* 4 */ { 0x0804, LSS_I2C2 }, /* Moorestown I2C 2 */ -/* 5 */ { 0x0805, LSS_KBD }, /* Moorestown Keyboard Ctrl */ -/* 6 */ { 0x0806, LSS_USB_HC }, /* Moorestown USB Ctrl */ -/* 7 */ { 0x0807, LSS_SD_HC0 }, /* Moorestown SD Host Ctrl 0 */ -/* 8 */ { 0x0808, LSS_SD_HC1 }, /* Moorestown SD Host Ctrl 1 */ -/* 9 */ { 0x0809, LSS_NAND }, /* Moorestown NAND Ctrl */ -/* 10 */ { 0x080a, LSS_AUDIO }, /* Moorestown Audio Ctrl */ -/* 11 */ { 0x080b, LSS_IMAGING }, /* Moorestown ISP */ -/* 12 */ { 0x080c, LSS_SECURITY }, /* Moorestown Security Controller */ -/* 13 */ { 0x080d, LSS_DISPLAY }, /* Moorestown External Displays */ -/* 14 */ { 0x080e, 0 }, /* Moorestown SCU IPC */ -/* 15 */ { 0x080f, LSS_GPIO }, /* Moorestown GPIO Controller */ -/* 16 */ { 0x0810, 0 }, /* Moorestown Power Management Unit */ -/* 17 */ { 0x0811, LSS_USB_OTG }, /* Moorestown OTG Ctrl */ -/* 18 */ { 0x0812, LSS_SPI2 }, /* Moorestown SPI Ctrl 2 */ -/* 19 */ { 0x0813, 0 }, /* Moorestown SC DMA */ -/* 20 */ { 0x0814, LSS_AUDIO_LPE }, /* Moorestown LPE DMA */ -/* 21 */ { 0x0815, LSS_AUDIO_SSP }, /* Moorestown SSP0 */ - -/* 22 */ { 0x084F, LSS_SD_HC2 }, /* Moorestown SD Host Ctrl 2 */ - -/* 23 */ { 0x4102, 0 }, /* Lincroft */ -/* 24 */ { 0x4110, 0 }, /* Lincroft */ -}; - -/* n.b. We ignore PCI-id 0x815 in LSS9 b/c MeeGo has no driver for it */ -static u16 mrst_lss9_pci_ids[] = {0x080a, 0x0814, 0}; -static u16 mrst_lss10_pci_ids[] = {0x0800, 0x0801, 0x0802, 0x0803, - 0x0804, 0x0805, 0x080f, 0}; - -/* handle concurrent SMP invokations of pmu_pci_set_power_state() */ -static spinlock_t mrst_pmu_power_state_lock; - -static unsigned int wake_counters[MRST_NUM_LSS]; /* DEBUG only */ -static unsigned int pmu_irq_stats[INT_INVALID + 1]; /* DEBUG only */ - -static int graphics_is_off; -static int lss_s0i3_enabled; -static bool mrst_pmu_s0i3_enable; - -/* debug counters */ -static u32 pmu_wait_ready_calls; -static u32 pmu_wait_ready_udelays; -static u32 pmu_wait_ready_udelays_max; -static u32 pmu_wait_done_calls; -static u32 pmu_wait_done_udelays; -static u32 pmu_wait_done_udelays_max; -static u32 pmu_set_power_state_entry; -static u32 pmu_set_power_state_send_cmd; - -static struct mrst_device *pci_id_2_mrst_dev(u16 pci_dev_num) -{ - int index = 0; - - if ((pci_dev_num >= 0x0800) && (pci_dev_num <= 0x815)) - index = pci_dev_num - 0x800; - else if (pci_dev_num == 0x084F) - index = 22; - else if (pci_dev_num == 0x4102) - index = 23; - else if (pci_dev_num == 0x4110) - index = 24; - - if (pci_dev_num != mrst_devs[index].pci_dev_num) { - WARN_ONCE(1, FW_BUG "Unknown PCI device 0x%04X\n", pci_dev_num); - return 0; - } - - return &mrst_devs[index]; -} - -/** - * mrst_pmu_validate_cstates - * @dev: cpuidle_device - * - * Certain states are not appropriate for governor to pick in some cases. - * This function will be called as cpuidle_device's prepare callback and - * thus tells governor to ignore such states when selecting the next state - * to enter. - */ - -#define IDLE_STATE4_IS_C6 4 -#define IDLE_STATE5_IS_S0I3 5 - -int mrst_pmu_invalid_cstates(void) -{ - int cpu = smp_processor_id(); - - /* - * Demote to C4 if the PMU is busy. - * Since LSS changes leave the busy bit clear... - * busy means either the PMU is waiting for an ACK-C6 that - * isn't coming due to an MWAIT that returned immediately; - * or we returned from S0i3 successfully, and the PMU - * is not done sending us interrupts. - */ - if (pmu_read_busy_status()) - return 1 << IDLE_STATE4_IS_C6 | 1 << IDLE_STATE5_IS_S0I3; - - /* - * Disallow S0i3 if: PMU is not initialized, or CPU1 is active, - * or if device LSS is insufficient, or the GPU is active, - * or if it has been explicitly disabled. - */ - if (!pmu_reg || !cpumask_equal(cpu_online_mask, cpumask_of(cpu)) || - !lss_s0i3_enabled || !graphics_is_off || !mrst_pmu_s0i3_enable) - return 1 << IDLE_STATE5_IS_S0I3; - else - return 0; -} - -/* - * pmu_update_wake_counters(): read PM_WKS, update wake_counters[] - * DEBUG only. - */ -static void pmu_update_wake_counters(void) -{ - int lss; - u32 wake_status; - - wake_status = pmu_read_wks(); - - for (lss = 0; lss < MRST_NUM_LSS; ++lss) { - if (wake_status & (1 << lss)) - wake_counters[lss]++; - } -} - -int mrst_pmu_s0i3_entry(void) -{ - int status; - - /* Clear any possible error conditions */ - pmu_write_ics(0x300); - - /* set wake control to current D-states */ - pmu_write_wssc(S0I3_SSS_TARGET); - - status = mrst_s0i3_entry(PM_S0I3_COMMAND, &pmu_reg->pm_cmd); - pmu_update_wake_counters(); - return status; -} - -/* poll for maximum of 5ms for busy bit to clear */ -static int pmu_wait_ready(void) -{ - int udelays; - - pmu_wait_ready_calls++; - - for (udelays = 0; udelays < 500; ++udelays) { - if (udelays > pmu_wait_ready_udelays_max) - pmu_wait_ready_udelays_max = udelays; - - if (pmu_read_busy_status() == 0) - return 0; - - udelay(10); - pmu_wait_ready_udelays++; - } - - /* - * if this fires, observe - * /sys/kernel/debug/mrst_pmu_wait_ready_calls - * /sys/kernel/debug/mrst_pmu_wait_ready_udelays - */ - WARN_ONCE(1, "SCU not ready for 5ms"); - return -EBUSY; -} -/* poll for maximum of 50ms us for busy bit to clear */ -static int pmu_wait_done(void) -{ - int udelays; - - pmu_wait_done_calls++; - - for (udelays = 0; udelays < 500; ++udelays) { - if (udelays > pmu_wait_done_udelays_max) - pmu_wait_done_udelays_max = udelays; - - if (pmu_read_busy_status() == 0) - return 0; - - udelay(100); - pmu_wait_done_udelays++; - } - - /* - * if this fires, observe - * /sys/kernel/debug/mrst_pmu_wait_done_calls - * /sys/kernel/debug/mrst_pmu_wait_done_udelays - */ - WARN_ONCE(1, "SCU not done for 50ms"); - return -EBUSY; -} - -u32 mrst_pmu_msi_is_disabled(void) -{ - return pmu_msi_is_disabled(); -} - -void mrst_pmu_enable_msi(void) -{ - pmu_msi_enable(); -} - -/** - * pmu_irq - pmu driver interrupt handler - * Context: interrupt context - */ -static irqreturn_t pmu_irq(int irq, void *dummy) -{ - union pmu_pm_ics pmu_ics; - - pmu_ics.value = pmu_read_ics(); - - if (!pmu_ics.bits.pending) - return IRQ_NONE; - - switch (pmu_ics.bits.cause) { - case INT_SPURIOUS: - case INT_CMD_DONE: - case INT_CMD_ERR: - case INT_WAKE_RX: - case INT_SS_ERROR: - case INT_S0IX_MISS: - case INT_NO_ACKC6: - pmu_irq_stats[pmu_ics.bits.cause]++; - break; - default: - pmu_irq_stats[INT_INVALID]++; - } - - pmu_write_ics(pmu_ics.value); /* Clear pending interrupt */ - - return IRQ_HANDLED; -} - -/* - * Translate PCI power management to MRST LSS D-states - */ -static int pci_2_mrst_state(int lss, pci_power_t pci_state) -{ - switch (pci_state) { - case PCI_D0: - if (SSMSK(D0i1, lss) & D0I1_ACG_SSS_TARGET) - return D0i1; - else - return D0; - case PCI_D1: - return D0i1; - case PCI_D2: - return D0i2; - case PCI_D3hot: - case PCI_D3cold: - return D0i3; - default: - WARN(1, "pci_state %d\n", pci_state); - return 0; - } -} - -static int pmu_issue_command(u32 pm_ssc) -{ - union pmu_pm_set_cfg_cmd_t command; - - if (pmu_read_busy_status()) { - pr_debug("pmu is busy, Operation not permitted\n"); - return -1; - } - - /* - * enable interrupts in PMU so that interrupts are - * propagated when ioc bit for a particular set - * command is set - */ - - pmu_irq_enable(); - - /* Configure the sub systems for pmu2 */ - - pmu_write_ssc(pm_ssc); - - /* - * Send the set config command for pmu its configured - * for mode CM_IMMEDIATE & hence with No Trigger - */ - - command.pmu2_params.d_param.cfg_mode = CM_IMMEDIATE; - command.pmu2_params.d_param.cfg_delay = 0; - command.pmu2_params.d_param.rsvd = 0; - - /* construct the command to send SET_CFG to particular PMU */ - command.pmu2_params.d_param.cmd = SET_CFG_CMD; - command.pmu2_params.d_param.ioc = 0; - command.pmu2_params.d_param.mode_id = 0; - command.pmu2_params.d_param.sys_state = SYS_STATE_S0I0; - - /* write the value of PM_CMD into particular PMU */ - pr_debug("pmu command being written %x\n", - command.pmu_pm_set_cfg_cmd_value); - - pmu_write_cmd(command.pmu_pm_set_cfg_cmd_value); - - return 0; -} - -static u16 pmu_min_lss_pci_req(u16 *ids, u16 pci_state) -{ - u16 existing_request; - int i; - - for (i = 0; ids[i]; ++i) { - struct mrst_device *mrst_dev; - - mrst_dev = pci_id_2_mrst_dev(ids[i]); - if (unlikely(!mrst_dev)) - continue; - - existing_request = mrst_dev->latest_request; - if (existing_request < pci_state) - pci_state = existing_request; - } - return pci_state; -} - -/** - * pmu_pci_set_power_state - Callback function is used by all the PCI devices - * for a platform specific device power on/shutdown. - */ - -int pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t pci_state) -{ - u32 old_sss, new_sss; - int status = 0; - struct mrst_device *mrst_dev; - - pmu_set_power_state_entry++; - - BUG_ON(pdev->vendor != PCI_VENDOR_ID_INTEL); - BUG_ON(pci_state < PCI_D0 || pci_state > PCI_D3cold); - - mrst_dev = pci_id_2_mrst_dev(pdev->device); - if (unlikely(!mrst_dev)) - return -ENODEV; - - mrst_dev->pci_state_counts[pci_state]++; /* count invocations */ - - /* PMU driver calls self as part of PCI initialization, ignore */ - if (pdev->device == PCI_DEV_ID_MRST_PMU) - return 0; - - BUG_ON(!pmu_reg); /* SW bug if called before initialized */ - - spin_lock(&mrst_pmu_power_state_lock); - - if (pdev->d3_delay) { - dev_dbg(&pdev->dev, "d3_delay %d, should be 0\n", - pdev->d3_delay); - pdev->d3_delay = 0; - } - /* - * If Lincroft graphics, simply remember state - */ - if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY - && !((pdev->class & PCI_SUB_CLASS_MASK) >> 8)) { - if (pci_state == PCI_D0) - graphics_is_off = 0; - else - graphics_is_off = 1; - goto ret; - } - - if (!mrst_dev->lss) - goto ret; /* device with no LSS */ - - if (mrst_dev->latest_request == pci_state) - goto ret; /* no change */ - - mrst_dev->latest_request = pci_state; /* record latest request */ - - /* - * LSS9 and LSS10 contain multiple PCI devices. - * Use the lowest numbered (highest power) state in the LSS - */ - if (mrst_dev->lss == 9) - pci_state = pmu_min_lss_pci_req(mrst_lss9_pci_ids, pci_state); - else if (mrst_dev->lss == 10) - pci_state = pmu_min_lss_pci_req(mrst_lss10_pci_ids, pci_state); - - status = pmu_wait_ready(); - if (status) - goto ret; - - old_sss = pmu_read_sss(); - new_sss = old_sss & ~SSMSK(3, mrst_dev->lss); - new_sss |= SSMSK(pci_2_mrst_state(mrst_dev->lss, pci_state), - mrst_dev->lss); - - if (new_sss == old_sss) - goto ret; /* nothing to do */ - - pmu_set_power_state_send_cmd++; - - status = pmu_issue_command(new_sss); - - if (unlikely(status != 0)) { - dev_err(&pdev->dev, "Failed to Issue a PM command\n"); - goto ret; - } - - if (pmu_wait_done()) - goto ret; - - lss_s0i3_enabled = - ((pmu_read_sss() & S0I3_SSS_TARGET) == S0I3_SSS_TARGET); -ret: - spin_unlock(&mrst_pmu_power_state_lock); - return status; -} - -#ifdef CONFIG_DEBUG_FS -static char *d0ix_names[] = {"D0", "D0i1", "D0i2", "D0i3"}; - -static inline const char *d0ix_name(int state) -{ - return d0ix_names[(int) state]; -} - -static int debug_mrst_pmu_show(struct seq_file *s, void *unused) -{ - struct pci_dev *pdev = NULL; - u32 cur_pmsss; - int lss; - - seq_printf(s, "0x%08X D0I1_ACG_SSS_TARGET\n", D0I1_ACG_SSS_TARGET); - - cur_pmsss = pmu_read_sss(); - - seq_printf(s, "0x%08X S0I3_SSS_TARGET\n", S0I3_SSS_TARGET); - - seq_printf(s, "0x%08X Current SSS ", cur_pmsss); - seq_printf(s, lss_s0i3_enabled ? "\n" : "[BLOCKS s0i3]\n"); - - if (cpumask_equal(cpu_online_mask, cpumask_of(0))) - seq_printf(s, "cpu0 is only cpu online\n"); - else - seq_printf(s, "cpu0 is NOT only cpu online [BLOCKS S0i3]\n"); - - seq_printf(s, "GFX: %s\n", graphics_is_off ? "" : "[BLOCKS s0i3]"); - - - for_each_pci_dev(pdev) { - int pos; - u16 pmcsr; - struct mrst_device *mrst_dev; - int i; - - mrst_dev = pci_id_2_mrst_dev(pdev->device); - - seq_printf(s, "%s %04x/%04X %-16.16s ", - dev_name(&pdev->dev), - pdev->vendor, pdev->device, - dev_driver_string(&pdev->dev)); - - if (unlikely (!mrst_dev)) { - seq_printf(s, " UNKNOWN\n"); - continue; - } - - if (mrst_dev->lss) - seq_printf(s, "LSS %2d %-4s ", mrst_dev->lss, - d0ix_name(((cur_pmsss >> - (mrst_dev->lss * 2)) & 0x3))); - else - seq_printf(s, " "); - - /* PCI PM config space setting */ - pos = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pos != 0) { - pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr); - seq_printf(s, "PCI-%-4s", - pci_power_name(pmcsr & PCI_PM_CTRL_STATE_MASK)); - } else { - seq_printf(s, " "); - } - - seq_printf(s, " %s ", pci_power_name(mrst_dev->latest_request)); - for (i = 0; i <= PCI_D3cold; ++i) - seq_printf(s, "%d ", mrst_dev->pci_state_counts[i]); - - if (mrst_dev->lss) { - unsigned int lssmask; - - lssmask = SSMSK(D0i3, mrst_dev->lss); - - if ((lssmask & S0I3_SSS_TARGET) && - ((lssmask & cur_pmsss) != - (lssmask & S0I3_SSS_TARGET))) - seq_printf(s , "[BLOCKS s0i3]"); - } - - seq_printf(s, "\n"); - } - seq_printf(s, "Wake Counters:\n"); - for (lss = 0; lss < MRST_NUM_LSS; ++lss) - seq_printf(s, "LSS%d %d\n", lss, wake_counters[lss]); - - seq_printf(s, "Interrupt Counters:\n"); - seq_printf(s, - "INT_SPURIOUS \t%8u\n" "INT_CMD_DONE \t%8u\n" - "INT_CMD_ERR \t%8u\n" "INT_WAKE_RX \t%8u\n" - "INT_SS_ERROR \t%8u\n" "INT_S0IX_MISS\t%8u\n" - "INT_NO_ACKC6 \t%8u\n" "INT_INVALID \t%8u\n", - pmu_irq_stats[INT_SPURIOUS], pmu_irq_stats[INT_CMD_DONE], - pmu_irq_stats[INT_CMD_ERR], pmu_irq_stats[INT_WAKE_RX], - pmu_irq_stats[INT_SS_ERROR], pmu_irq_stats[INT_S0IX_MISS], - pmu_irq_stats[INT_NO_ACKC6], pmu_irq_stats[INT_INVALID]); - - seq_printf(s, "mrst_pmu_wait_ready_calls %8d\n", - pmu_wait_ready_calls); - seq_printf(s, "mrst_pmu_wait_ready_udelays %8d\n", - pmu_wait_ready_udelays); - seq_printf(s, "mrst_pmu_wait_ready_udelays_max %8d\n", - pmu_wait_ready_udelays_max); - seq_printf(s, "mrst_pmu_wait_done_calls %8d\n", - pmu_wait_done_calls); - seq_printf(s, "mrst_pmu_wait_done_udelays %8d\n", - pmu_wait_done_udelays); - seq_printf(s, "mrst_pmu_wait_done_udelays_max %8d\n", - pmu_wait_done_udelays_max); - seq_printf(s, "mrst_pmu_set_power_state_entry %8d\n", - pmu_set_power_state_entry); - seq_printf(s, "mrst_pmu_set_power_state_send_cmd %8d\n", - pmu_set_power_state_send_cmd); - seq_printf(s, "SCU busy: %d\n", pmu_read_busy_status()); - - return 0; -} - -static int debug_mrst_pmu_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_mrst_pmu_show, NULL); -} - -static const struct file_operations devices_state_operations = { - .open = debug_mrst_pmu_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif /* DEBUG_FS */ - -/* - * Validate SCU PCI shim PCI vendor capability byte - * against LSS hard-coded in mrst_devs[] above. - * DEBUG only. - */ -static void pmu_scu_firmware_debug(void) -{ - struct pci_dev *pdev = NULL; - - for_each_pci_dev(pdev) { - struct mrst_device *mrst_dev; - u8 pci_config_lss; - int pos; - - mrst_dev = pci_id_2_mrst_dev(pdev->device); - if (unlikely(!mrst_dev)) { - printk(KERN_ERR FW_BUG "pmu: Unknown " - "PCI device 0x%04X\n", pdev->device); - continue; - } - - if (mrst_dev->lss == 0) - continue; /* no LSS in our table */ - - pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR); - if (!pos != 0) { - printk(KERN_ERR FW_BUG "pmu: 0x%04X " - "missing PCI Vendor Capability\n", - pdev->device); - continue; - } - pci_read_config_byte(pdev, pos + 4, &pci_config_lss); - if (!(pci_config_lss & PCI_VENDOR_CAP_LOG_SS_MASK)) { - printk(KERN_ERR FW_BUG "pmu: 0x%04X " - "invalid PCI Vendor Capability 0x%x " - " expected LSS 0x%X\n", - pdev->device, pci_config_lss, mrst_dev->lss); - continue; - } - pci_config_lss &= PCI_VENDOR_CAP_LOG_ID_MASK; - - if (mrst_dev->lss == pci_config_lss) - continue; - - printk(KERN_ERR FW_BUG "pmu: 0x%04X LSS = %d, expected %d\n", - pdev->device, pci_config_lss, mrst_dev->lss); - } -} - -/** - * pmu_probe - */ -static int __devinit pmu_probe(struct pci_dev *pdev, - const struct pci_device_id *pci_id) -{ - int ret; - struct mrst_pmu_reg *pmu; - - /* Init the device */ - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "Unable to Enable PCI device\n"); - return ret; - } - - ret = pci_request_regions(pdev, MRST_PMU_DRV_NAME); - if (ret < 0) { - dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n"); - goto out_err1; - } - - /* Map the memory of PMU reg base */ - pmu = pci_iomap(pdev, 0, 0); - if (!pmu) { - dev_err(&pdev->dev, "Unable to map the PMU address space\n"); - ret = -ENOMEM; - goto out_err2; - } - -#ifdef CONFIG_DEBUG_FS - /* /sys/kernel/debug/mrst_pmu */ - (void) debugfs_create_file("mrst_pmu", S_IFREG | S_IRUGO, - NULL, NULL, &devices_state_operations); -#endif - pmu_reg = pmu; /* success */ - - if (request_irq(pdev->irq, pmu_irq, 0, MRST_PMU_DRV_NAME, NULL)) { - dev_err(&pdev->dev, "Registering isr has failed\n"); - ret = -1; - goto out_err3; - } - - pmu_scu_firmware_debug(); - - pmu_write_wkc(S0I3_WAKE_SOURCES); /* Enable S0i3 wakeup sources */ - - pmu_wait_ready(); - - pmu_write_ssc(D0I1_ACG_SSS_TARGET); /* Enable Auto-Clock_Gating */ - pmu_write_cmd(0x201); - - spin_lock_init(&mrst_pmu_power_state_lock); - - /* Enable the hardware interrupt */ - pmu_irq_enable(); - return 0; - -out_err3: - free_irq(pdev->irq, NULL); - pci_iounmap(pdev, pmu_reg); - pmu_reg = NULL; -out_err2: - pci_release_region(pdev, 0); -out_err1: - pci_disable_device(pdev); - return ret; -} - -static void __devexit pmu_remove(struct pci_dev *pdev) -{ - dev_err(&pdev->dev, "Mid PM pmu_remove called\n"); - - /* Freeing up the irq */ - free_irq(pdev->irq, NULL); - - pci_iounmap(pdev, pmu_reg); - pmu_reg = NULL; - - /* disable the current PCI device */ - pci_release_region(pdev, 0); - pci_disable_device(pdev); -} - -static DEFINE_PCI_DEVICE_TABLE(pmu_pci_ids) = { - { PCI_VDEVICE(INTEL, PCI_DEV_ID_MRST_PMU), 0 }, - { } -}; - -MODULE_DEVICE_TABLE(pci, pmu_pci_ids); - -static struct pci_driver driver = { - .name = MRST_PMU_DRV_NAME, - .id_table = pmu_pci_ids, - .probe = pmu_probe, - .remove = __devexit_p(pmu_remove), -}; - -/** - * pmu_pci_register - register the PMU driver as PCI device - */ -static int __init pmu_pci_register(void) -{ - return pci_register_driver(&driver); -} - -/* Register and probe via fs_initcall() to preceed device_initcall() */ -fs_initcall(pmu_pci_register); - -static void __exit mid_pci_cleanup(void) -{ - pci_unregister_driver(&driver); -} - -static int ia_major; -static int ia_minor; - -static int pmu_sfi_parse_oem(struct sfi_table_header *table) -{ - struct sfi_table_simple *sb; - - sb = (struct sfi_table_simple *)table; - ia_major = (sb->pentry[1] >> 0) & 0xFFFF; - ia_minor = (sb->pentry[1] >> 16) & 0xFFFF; - printk(KERN_INFO "mrst_pmu: IA FW version v%x.%x\n", - ia_major, ia_minor); - - return 0; -} - -static int __init scu_fw_check(void) -{ - int ret; - u32 fw_version; - - if (!pmu_reg) - return 0; /* this driver didn't probe-out */ - - sfi_table_parse("OEMB", NULL, NULL, pmu_sfi_parse_oem); - - if (ia_major < 0x6005 || ia_minor < 0x1525) { - WARN(1, "mrst_pmu: IA FW version too old\n"); - return -1; - } - - ret = intel_scu_ipc_command(IPCMSG_FW_REVISION, 0, NULL, 0, - &fw_version, 1); - - if (ret) { - WARN(1, "mrst_pmu: IPC FW version? %d\n", ret); - } else { - int scu_major = (fw_version >> 8) & 0xFF; - int scu_minor = (fw_version >> 0) & 0xFF; - - printk(KERN_INFO "mrst_pmu: firmware v%x\n", fw_version); - - if ((scu_major >= 0xC0) && (scu_minor >= 0x49)) { - printk(KERN_INFO "mrst_pmu: enabling S0i3\n"); - mrst_pmu_s0i3_enable = true; - } else { - WARN(1, "mrst_pmu: S0i3 disabled, old firmware %X.%X", - scu_major, scu_minor); - } - } - return 0; -} -late_initcall(scu_fw_check); -module_exit(mid_pci_cleanup); diff --git a/trunk/arch/x86/platform/mrst/pmu.h b/trunk/arch/x86/platform/mrst/pmu.h deleted file mode 100644 index bfbfe64b167b..000000000000 --- a/trunk/arch/x86/platform/mrst/pmu.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * mrst/pmu.h - private definitions for MRST Power Management Unit mrst/pmu.c - * - * Copyright (c) 2011, Intel Corporation. - * - * 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, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _MRST_PMU_H_ -#define _MRST_PMU_H_ - -#define PCI_DEV_ID_MRST_PMU 0x0810 -#define MRST_PMU_DRV_NAME "mrst_pmu" -#define PCI_SUB_CLASS_MASK 0xFF00 - -#define PCI_VENDOR_CAP_LOG_ID_MASK 0x7F -#define PCI_VENDOR_CAP_LOG_SS_MASK 0x80 - -#define SUB_SYS_ALL_D0I1 0x01155555 -#define S0I3_WAKE_SOURCES 0x00001FFF - -#define PM_S0I3_COMMAND \ - ((0 << 31) | /* Reserved */ \ - (0 << 30) | /* Core must be idle */ \ - (0xc2 << 22) | /* ACK C6 trigger */ \ - (3 << 19) | /* Trigger on DMI message */ \ - (3 << 16) | /* Enter S0i3 */ \ - (0 << 13) | /* Numeric mode ID (sw) */ \ - (3 << 9) | /* Trigger mode */ \ - (0 << 8) | /* Do not interrupt */ \ - (1 << 0)) /* Set configuration */ - -#define LSS_DMI 0 -#define LSS_SD_HC0 1 -#define LSS_SD_HC1 2 -#define LSS_NAND 3 -#define LSS_IMAGING 4 -#define LSS_SECURITY 5 -#define LSS_DISPLAY 6 -#define LSS_USB_HC 7 -#define LSS_USB_OTG 8 -#define LSS_AUDIO 9 -#define LSS_AUDIO_LPE 9 -#define LSS_AUDIO_SSP 9 -#define LSS_I2C0 10 -#define LSS_I2C1 10 -#define LSS_I2C2 10 -#define LSS_KBD 10 -#define LSS_SPI0 10 -#define LSS_SPI1 10 -#define LSS_SPI2 10 -#define LSS_GPIO 10 -#define LSS_SRAM 11 /* used by SCU, do not touch */ -#define LSS_SD_HC2 12 -/* LSS hardware bits 15,14,13 are hardwired to 0, thus unusable */ -#define MRST_NUM_LSS 13 - -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - -#define SSMSK(mask, lss) ((mask) << ((lss) * 2)) -#define D0 0 -#define D0i1 1 -#define D0i2 2 -#define D0i3 3 - -#define S0I3_SSS_TARGET ( \ - SSMSK(D0i1, LSS_DMI) | \ - SSMSK(D0i3, LSS_SD_HC0) | \ - SSMSK(D0i3, LSS_SD_HC1) | \ - SSMSK(D0i3, LSS_NAND) | \ - SSMSK(D0i3, LSS_SD_HC2) | \ - SSMSK(D0i3, LSS_IMAGING) | \ - SSMSK(D0i3, LSS_SECURITY) | \ - SSMSK(D0i3, LSS_DISPLAY) | \ - SSMSK(D0i3, LSS_USB_HC) | \ - SSMSK(D0i3, LSS_USB_OTG) | \ - SSMSK(D0i3, LSS_AUDIO) | \ - SSMSK(D0i1, LSS_I2C0)) - -/* - * D0i1 on Langwell is Autonomous Clock Gating (ACG). - * Enable ACG on every LSS except camera and audio - */ -#define D0I1_ACG_SSS_TARGET \ - (SUB_SYS_ALL_D0I1 & ~SSMSK(D0i1, LSS_IMAGING) & ~SSMSK(D0i1, LSS_AUDIO)) - -enum cm_mode { - CM_NOP, /* ignore the config mode value */ - CM_IMMEDIATE, - CM_DELAY, - CM_TRIGGER, - CM_INVALID -}; - -enum sys_state { - SYS_STATE_S0I0, - SYS_STATE_S0I1, - SYS_STATE_S0I2, - SYS_STATE_S0I3, - SYS_STATE_S3, - SYS_STATE_S5 -}; - -#define SET_CFG_CMD 1 - -enum int_status { - INT_SPURIOUS = 0, - INT_CMD_DONE = 1, - INT_CMD_ERR = 2, - INT_WAKE_RX = 3, - INT_SS_ERROR = 4, - INT_S0IX_MISS = 5, - INT_NO_ACKC6 = 6, - INT_INVALID = 7, -}; - -/* PMU register interface */ -static struct mrst_pmu_reg { - u32 pm_sts; /* 0x00 */ - u32 pm_cmd; /* 0x04 */ - u32 pm_ics; /* 0x08 */ - u32 _resv1; /* 0x0C */ - u32 pm_wkc[2]; /* 0x10 */ - u32 pm_wks[2]; /* 0x18 */ - u32 pm_ssc[4]; /* 0x20 */ - u32 pm_sss[4]; /* 0x30 */ - u32 pm_wssc[4]; /* 0x40 */ - u32 pm_c3c4; /* 0x50 */ - u32 pm_c5c6; /* 0x54 */ - u32 pm_msi_disable; /* 0x58 */ -} *pmu_reg; - -static inline u32 pmu_read_sts(void) { return readl(&pmu_reg->pm_sts); } -static inline u32 pmu_read_ics(void) { return readl(&pmu_reg->pm_ics); } -static inline u32 pmu_read_wks(void) { return readl(&pmu_reg->pm_wks[0]); } -static inline u32 pmu_read_sss(void) { return readl(&pmu_reg->pm_sss[0]); } - -static inline void pmu_write_cmd(u32 arg) { writel(arg, &pmu_reg->pm_cmd); } -static inline void pmu_write_ics(u32 arg) { writel(arg, &pmu_reg->pm_ics); } -static inline void pmu_write_wkc(u32 arg) { writel(arg, &pmu_reg->pm_wkc[0]); } -static inline void pmu_write_ssc(u32 arg) { writel(arg, &pmu_reg->pm_ssc[0]); } -static inline void pmu_write_wssc(u32 arg) - { writel(arg, &pmu_reg->pm_wssc[0]); } - -static inline void pmu_msi_enable(void) { writel(0, &pmu_reg->pm_msi_disable); } -static inline u32 pmu_msi_is_disabled(void) - { return readl(&pmu_reg->pm_msi_disable); } - -union pmu_pm_ics { - struct { - u32 cause:8; - u32 enable:1; - u32 pending:1; - u32 reserved:22; - } bits; - u32 value; -}; - -static inline void pmu_irq_enable(void) -{ - union pmu_pm_ics pmu_ics; - - pmu_ics.value = pmu_read_ics(); - pmu_ics.bits.enable = 1; - pmu_write_ics(pmu_ics.value); -} - -union pmu_pm_status { - struct { - u32 pmu_rev:8; - u32 pmu_busy:1; - u32 mode_id:4; - u32 Reserved:19; - } pmu_status_parts; - u32 pmu_status_value; -}; - -static inline int pmu_read_busy_status(void) -{ - union pmu_pm_status result; - - result.pmu_status_value = pmu_read_sts(); - - return result.pmu_status_parts.pmu_busy; -} - -/* pmu set config parameters */ -struct cfg_delay_param_t { - u32 cmd:8; - u32 ioc:1; - u32 cfg_mode:4; - u32 mode_id:3; - u32 sys_state:3; - u32 cfg_delay:8; - u32 rsvd:5; -}; - -struct cfg_trig_param_t { - u32 cmd:8; - u32 ioc:1; - u32 cfg_mode:4; - u32 mode_id:3; - u32 sys_state:3; - u32 cfg_trig_type:3; - u32 cfg_trig_val:8; - u32 cmbi:1; - u32 rsvd1:1; -}; - -union pmu_pm_set_cfg_cmd_t { - union { - struct cfg_delay_param_t d_param; - struct cfg_trig_param_t t_param; - } pmu2_params; - u32 pmu_pm_set_cfg_cmd_value; -}; - -#ifdef FUTURE_PATCH -extern int mrst_s0i3_entry(u32 regval, u32 *regaddr); -#else -static inline int mrst_s0i3_entry(u32 regval, u32 *regaddr) { return -1; } -#endif -#endif diff --git a/trunk/arch/x86/xen/Makefile b/trunk/arch/x86/xen/Makefile index 3326204e251f..45e94aca5bce 100644 --- a/trunk/arch/x86/xen/Makefile +++ b/trunk/arch/x86/xen/Makefile @@ -15,7 +15,7 @@ obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ grant-table.o suspend.o platform-pci-unplug.o \ p2m.o -obj-$(CONFIG_FTRACE) += trace.o +obj-$(CONFIG_FUNCTION_TRACER) += trace.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o diff --git a/trunk/arch/x86/xen/setup.c b/trunk/arch/x86/xen/setup.c index df118a825f39..60aeeb56948f 100644 --- a/trunk/arch/x86/xen/setup.c +++ b/trunk/arch/x86/xen/setup.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -93,6 +92,8 @@ static unsigned long __init xen_release_chunk(phys_addr_t start_addr, if (end <= start) return 0; + printk(KERN_INFO "xen_release_chunk: looking at area pfn %lx-%lx: ", + start, end); for(pfn = start; pfn < end; pfn++) { unsigned long mfn = pfn_to_mfn(pfn); @@ -105,14 +106,14 @@ static unsigned long __init xen_release_chunk(phys_addr_t start_addr, ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); - WARN(ret != 1, "Failed to release pfn %lx err=%d\n", pfn, ret); + WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n", + start, end, ret); if (ret == 1) { __set_phys_to_machine(pfn, INVALID_P2M_ENTRY); len++; } } - printk(KERN_INFO "Freeing %lx-%lx pfn range: %lu pages freed\n", - start, end, len); + printk(KERN_CONT "%ld pages freed\n", len); return len; } @@ -138,7 +139,7 @@ static unsigned long __init xen_return_unused_memory(unsigned long max_pfn, if (last_end < max_addr) released += xen_release_chunk(last_end, max_addr); - printk(KERN_INFO "released %lu pages of unused memory\n", released); + printk(KERN_INFO "released %ld pages of unused memory\n", released); return released; } @@ -425,7 +426,7 @@ void __init xen_arch_setup(void) #ifdef CONFIG_X86_32 boot_cpu_data.hlt_works_ok = 1; #endif - disable_cpuidle(); + pm_idle = default_idle; boot_option_idle_override = IDLE_HALT; fiddle_vdso(); diff --git a/trunk/arch/x86/xen/trace.c b/trunk/arch/x86/xen/trace.c index 520022d1a181..734beba2a08c 100644 --- a/trunk/arch/x86/xen/trace.c +++ b/trunk/arch/x86/xen/trace.c @@ -1,5 +1,4 @@ #include -#include #define N(x) [__HYPERVISOR_##x] = "("#x")" static const char *xen_hypercall_names[] = { diff --git a/trunk/block/blk-core.c b/trunk/block/blk-core.c index b627558c461f..b850bedad229 100644 --- a/trunk/block/blk-core.c +++ b/trunk/block/blk-core.c @@ -1368,10 +1368,8 @@ static bool should_fail_request(struct hd_struct *part, unsigned int bytes) static int __init fail_make_request_debugfs(void) { - struct dentry *dir = fault_create_debugfs_attr("fail_make_request", - NULL, &fail_make_request); - - return IS_ERR(dir) ? PTR_ERR(dir) : 0; + return init_fault_attr_dentries(&fail_make_request, + "fail_make_request"); } late_initcall(fail_make_request_debugfs); diff --git a/trunk/block/blk-timeout.c b/trunk/block/blk-timeout.c index 780354888958..4f0c06c7a338 100644 --- a/trunk/block/blk-timeout.c +++ b/trunk/block/blk-timeout.c @@ -28,10 +28,7 @@ int blk_should_fake_timeout(struct request_queue *q) static int __init fail_io_timeout_debugfs(void) { - struct dentry *dir = fault_create_debugfs_attr("fail_io_timeout", - NULL, &fail_io_timeout); - - return IS_ERR(dir) ? PTR_ERR(dir) : 0; + return init_fault_attr_dentries(&fail_io_timeout, "fail_io_timeout"); } late_initcall(fail_io_timeout_debugfs); diff --git a/trunk/drivers/acpi/acpica/acglobal.h b/trunk/drivers/acpi/acpica/acglobal.h index 76dc02f15574..73863d86f022 100644 --- a/trunk/drivers/acpi/acpica/acglobal.h +++ b/trunk/drivers/acpi/acpica/acglobal.h @@ -126,12 +126,6 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE); */ u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE); -/* - * Disable runtime checking and repair of values returned by control methods. - * Use only if the repair is causing a problem on a particular machine. - */ -u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE); - /* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */ struct acpi_table_fadt acpi_gbl_FADT; diff --git a/trunk/drivers/acpi/acpica/aclocal.h b/trunk/drivers/acpi/acpica/aclocal.h index 5552125d8340..c7f743ca395b 100644 --- a/trunk/drivers/acpi/acpica/aclocal.h +++ b/trunk/drivers/acpi/acpica/aclocal.h @@ -357,7 +357,6 @@ struct acpi_predefined_data { char *pathname; const union acpi_predefined_info *predefined; union acpi_operand_object *parent_package; - struct acpi_namespace_node *node; u32 flags; u8 node_flags; }; diff --git a/trunk/drivers/acpi/acpica/acpredef.h b/trunk/drivers/acpi/acpica/acpredef.h index c445cca490ea..94e73c97cf85 100644 --- a/trunk/drivers/acpi/acpica/acpredef.h +++ b/trunk/drivers/acpi/acpica/acpredef.h @@ -468,7 +468,6 @@ static const union acpi_predefined_info predefined_names[] = {{"_SWS", 0, ACPI_RTYPE_INTEGER}}, {{"_TC1", 0, ACPI_RTYPE_INTEGER}}, {{"_TC2", 0, ACPI_RTYPE_INTEGER}}, - {{"_TDL", 0, ACPI_RTYPE_INTEGER}}, {{"_TIP", 1, ACPI_RTYPE_INTEGER}}, {{"_TIV", 1, ACPI_RTYPE_INTEGER}}, {{"_TMP", 0, ACPI_RTYPE_INTEGER}}, diff --git a/trunk/drivers/acpi/acpica/nspredef.c b/trunk/drivers/acpi/acpica/nspredef.c index c845c8089f39..9fb03fa8ffde 100644 --- a/trunk/drivers/acpi/acpica/nspredef.c +++ b/trunk/drivers/acpi/acpica/nspredef.c @@ -193,20 +193,14 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, } /* - * Return value validation and possible repair. + * 1) We have a return value, but if one wasn't expected, just exit, this is + * not a problem. For example, if the "Implicit Return" feature is + * enabled, methods will always return a value. * - * 1) Don't perform return value validation/repair if this feature - * has been disabled via a global option. - * - * 2) We have a return value, but if one wasn't expected, just exit, - * this is not a problem. For example, if the "Implicit Return" - * feature is enabled, methods will always return a value. - * - * 3) If the return value can be of any type, then we cannot perform - * any validation, just exit. + * 2) If the return value can be of any type, then we cannot perform any + * validation, exit. */ - if (acpi_gbl_disable_auto_repair || - (!predefined->info.expected_btypes) || + if ((!predefined->info.expected_btypes) || (predefined->info.expected_btypes == ACPI_RTYPE_ALL)) { goto cleanup; } @@ -218,7 +212,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, goto cleanup; } data->predefined = predefined; - data->node = node; data->node_flags = node->flags; data->pathname = pathname; diff --git a/trunk/drivers/acpi/acpica/nsrepair2.c b/trunk/drivers/acpi/acpica/nsrepair2.c index 024c4f263f87..973883babee1 100644 --- a/trunk/drivers/acpi/acpica/nsrepair2.c +++ b/trunk/drivers/acpi/acpica/nsrepair2.c @@ -503,21 +503,6 @@ acpi_ns_repair_TSS(struct acpi_predefined_data *data, { union acpi_operand_object *return_object = *return_object_ptr; acpi_status status; - struct acpi_namespace_node *node; - - /* - * We can only sort the _TSS return package if there is no _PSS in the - * same scope. This is because if _PSS is present, the ACPI specification - * dictates that the _TSS Power Dissipation field is to be ignored, and - * therefore some BIOSs leave garbage values in the _TSS Power field(s). - * In this case, it is best to just return the _TSS package as-is. - * (May, 2011) - */ - status = - acpi_ns_get_node(data->node, "^_PSS", ACPI_NS_NO_UPSEARCH, &node); - if (ACPI_SUCCESS(status)) { - return (AE_OK); - } status = acpi_ns_check_sorted_list(data, return_object, 5, 1, ACPI_SORT_DESCENDING, diff --git a/trunk/drivers/acpi/acpica/tbinstal.c b/trunk/drivers/acpi/acpica/tbinstal.c index 62365f6075dd..48db0944ce4a 100644 --- a/trunk/drivers/acpi/acpica/tbinstal.c +++ b/trunk/drivers/acpi/acpica/tbinstal.c @@ -126,29 +126,12 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) } /* - * Validate the incoming table signature. - * - * 1) Originally, we checked the table signature for "SSDT" or "PSDT". - * 2) We added support for OEMx tables, signature "OEM". - * 3) Valid tables were encountered with a null signature, so we just - * gave up on validating the signature, (05/2008). - * 4) We encountered non-AML tables such as the MADT, which caused - * interpreter errors and kernel faults. So now, we once again allow - * only "SSDT", "OEMx", and now, also a null signature. (05/2011). + * Originally, we checked the table signature for "SSDT" or "PSDT" here. + * Next, we added support for OEMx tables, signature "OEM". + * Valid tables were encountered with a null signature, so we've just + * given up on validating the signature, since it seems to be a waste + * of code. The original code was removed (05/2008). */ - if ((table_desc->pointer->signature[0] != 0x00) && - (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)) - && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) { - ACPI_ERROR((AE_INFO, - "Table has invalid signature [%4.4s] (0x%8.8X), must be SSDT or OEMx", - acpi_ut_valid_acpi_name(*(u32 *)table_desc-> - pointer-> - signature) ? table_desc-> - pointer->signature : "????", - *(u32 *)table_desc->pointer->signature)); - - return_ACPI_STATUS(AE_BAD_SIGNATURE); - } (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); diff --git a/trunk/drivers/acpi/apei/Kconfig b/trunk/drivers/acpi/apei/Kconfig index c34aa51af4ee..f739a70b1c70 100644 --- a/trunk/drivers/acpi/apei/Kconfig +++ b/trunk/drivers/acpi/apei/Kconfig @@ -10,11 +10,9 @@ config ACPI_APEI error injection. config ACPI_APEI_GHES - bool "APEI Generic Hardware Error Source" + tristate "APEI Generic Hardware Error Source" depends on ACPI_APEI && X86 select ACPI_HED - select LLIST - select GENERIC_ALLOCATOR help Generic Hardware Error Source provides a way to report platform hardware errors (such as that from chipset). It @@ -32,13 +30,6 @@ config ACPI_APEI_PCIEAER PCIe AER errors may be reported via APEI firmware first mode. Turn on this option to enable the corresponding support. -config ACPI_APEI_MEMORY_FAILURE - bool "APEI memory error recovering support" - depends on ACPI_APEI && MEMORY_FAILURE - help - Memory errors may be reported via APEI firmware first mode. - Turn on this option to enable the memory recovering support. - config ACPI_APEI_EINJ tristate "APEI Error INJection (EINJ)" depends on ACPI_APEI && DEBUG_FS diff --git a/trunk/drivers/acpi/apei/apei-base.c b/trunk/drivers/acpi/apei/apei-base.c index 8041248fce9b..4a904a4bf05f 100644 --- a/trunk/drivers/acpi/apei/apei-base.c +++ b/trunk/drivers/acpi/apei/apei-base.c @@ -157,10 +157,9 @@ EXPORT_SYMBOL_GPL(apei_exec_noop); * Interpret the specified action. Go through whole action table, * execute all instructions belong to the action. */ -int __apei_exec_run(struct apei_exec_context *ctx, u8 action, - bool optional) +int apei_exec_run(struct apei_exec_context *ctx, u8 action) { - int rc = -ENOENT; + int rc; u32 i, ip; struct acpi_whea_header *entry; apei_exec_ins_func_t run; @@ -199,9 +198,9 @@ int __apei_exec_run(struct apei_exec_context *ctx, u8 action, goto rewind; } - return !optional && rc < 0 ? rc : 0; + return 0; } -EXPORT_SYMBOL_GPL(__apei_exec_run); +EXPORT_SYMBOL_GPL(apei_exec_run); typedef int (*apei_exec_entry_func_t)(struct apei_exec_context *ctx, struct acpi_whea_header *entry, @@ -604,29 +603,3 @@ struct dentry *apei_get_debugfs_dir(void) return dapei; } EXPORT_SYMBOL_GPL(apei_get_debugfs_dir); - -int apei_osc_setup(void) -{ - static u8 whea_uuid_str[] = "ed855e0c-6c90-47bf-a62a-26de0fc5ad5c"; - acpi_handle handle; - u32 capbuf[3]; - struct acpi_osc_context context = { - .uuid_str = whea_uuid_str, - .rev = 1, - .cap.length = sizeof(capbuf), - .cap.pointer = capbuf, - }; - - capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; - capbuf[OSC_SUPPORT_TYPE] = 0; - capbuf[OSC_CONTROL_TYPE] = 0; - - if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)) - || ACPI_FAILURE(acpi_run_osc(handle, &context))) - return -EIO; - else { - kfree(context.ret.pointer); - return 0; - } -} -EXPORT_SYMBOL_GPL(apei_osc_setup); diff --git a/trunk/drivers/acpi/apei/apei-internal.h b/trunk/drivers/acpi/apei/apei-internal.h index f57050e7a5e7..ef0581f2094d 100644 --- a/trunk/drivers/acpi/apei/apei-internal.h +++ b/trunk/drivers/acpi/apei/apei-internal.h @@ -50,18 +50,7 @@ static inline u64 apei_exec_ctx_get_output(struct apei_exec_context *ctx) return ctx->value; } -int __apei_exec_run(struct apei_exec_context *ctx, u8 action, bool optional); - -static inline int apei_exec_run(struct apei_exec_context *ctx, u8 action) -{ - return __apei_exec_run(ctx, action, 0); -} - -/* It is optional whether the firmware provides the action */ -static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 action) -{ - return __apei_exec_run(ctx, action, 1); -} +int apei_exec_run(struct apei_exec_context *ctx, u8 action); /* Common instruction implementation */ @@ -124,6 +113,4 @@ void apei_estatus_print(const char *pfx, const struct acpi_hest_generic_status *estatus); int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus); int apei_estatus_check(const struct acpi_hest_generic_status *estatus); - -int apei_osc_setup(void); #endif diff --git a/trunk/drivers/acpi/apei/einj.c b/trunk/drivers/acpi/apei/einj.c index 589b96c38704..f74b2ea11f21 100644 --- a/trunk/drivers/acpi/apei/einj.c +++ b/trunk/drivers/acpi/apei/einj.c @@ -46,8 +46,7 @@ * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the * EINJ table through an unpublished extension. Use with caution as * most will ignore the parameter and make their own choice of address - * for error injection. This extension is used only if - * param_extension module parameter is specified. + * for error injection. */ struct einj_parameter { u64 type; @@ -66,9 +65,6 @@ struct einj_parameter { ((struct acpi_whea_header *)((char *)(tab) + \ sizeof(struct acpi_table_einj))) -static bool param_extension; -module_param(param_extension, bool, 0); - static struct acpi_table_einj *einj_tab; static struct apei_resources einj_resources; @@ -289,7 +285,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) einj_exec_ctx_init(&ctx); - rc = apei_exec_run_optional(&ctx, ACPI_EINJ_BEGIN_OPERATION); + rc = apei_exec_run(&ctx, ACPI_EINJ_BEGIN_OPERATION); if (rc) return rc; apei_exec_ctx_set_input(&ctx, type); @@ -327,7 +323,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) rc = __einj_error_trigger(trigger_paddr); if (rc) return rc; - rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION); + rc = apei_exec_run(&ctx, ACPI_EINJ_END_OPERATION); return rc; } @@ -493,6 +489,14 @@ static int __init einj_init(void) einj_debug_dir, NULL, &error_type_fops); if (!fentry) goto err_cleanup; + fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param1); + if (!fentry) + goto err_cleanup; + fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param2); + if (!fentry) + goto err_cleanup; fentry = debugfs_create_file("error_inject", S_IWUSR, einj_debug_dir, NULL, &error_inject_fops); if (!fentry) @@ -509,23 +513,12 @@ static int __init einj_init(void) rc = apei_exec_pre_map_gars(&ctx); if (rc) goto err_release; - if (param_extension) { - param_paddr = einj_get_parameter_address(); - if (param_paddr) { - einj_param = ioremap(param_paddr, sizeof(*einj_param)); - rc = -ENOMEM; - if (!einj_param) - goto err_unmap; - fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param1); - if (!fentry) - goto err_unmap; - fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param2); - if (!fentry) - goto err_unmap; - } else - pr_warn(EINJ_PFX "Parameter extension is not supported.\n"); + param_paddr = einj_get_parameter_address(); + if (param_paddr) { + einj_param = ioremap(param_paddr, sizeof(*einj_param)); + rc = -ENOMEM; + if (!einj_param) + goto err_unmap; } pr_info(EINJ_PFX "Error INJection is initialized.\n"); @@ -533,8 +526,6 @@ static int __init einj_init(void) return 0; err_unmap: - if (einj_param) - iounmap(einj_param); apei_exec_post_unmap_gars(&ctx); err_release: apei_resources_release(&einj_resources); diff --git a/trunk/drivers/acpi/apei/erst-dbg.c b/trunk/drivers/acpi/apei/erst-dbg.c index 903549df809b..a4cfb64c86a1 100644 --- a/trunk/drivers/acpi/apei/erst-dbg.c +++ b/trunk/drivers/acpi/apei/erst-dbg.c @@ -33,7 +33,7 @@ #define ERST_DBG_PFX "ERST DBG: " -#define ERST_DBG_RECORD_LEN_MAX 0x4000 +#define ERST_DBG_RECORD_LEN_MAX 4096 static void *erst_dbg_buf; static unsigned int erst_dbg_buf_len; @@ -213,10 +213,6 @@ static struct miscdevice erst_dbg_dev = { static __init int erst_dbg_init(void) { - if (erst_disable) { - pr_info(ERST_DBG_PFX "ERST support is disabled.\n"); - return -ENODEV; - } return misc_register(&erst_dbg_dev); } diff --git a/trunk/drivers/acpi/apei/erst.c b/trunk/drivers/acpi/apei/erst.c index 2ca59dc69f7f..e6cef8e1b534 100644 --- a/trunk/drivers/acpi/apei/erst.c +++ b/trunk/drivers/acpi/apei/erst.c @@ -642,7 +642,7 @@ static int __erst_write_to_storage(u64 offset) int rc; erst_exec_ctx_init(&ctx); - rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_WRITE); + rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE); if (rc) return rc; apei_exec_ctx_set_input(&ctx, offset); @@ -666,7 +666,7 @@ static int __erst_write_to_storage(u64 offset) if (rc) return rc; val = apei_exec_ctx_get_output(&ctx); - rc = apei_exec_run_optional(&ctx, ACPI_ERST_END); + rc = apei_exec_run(&ctx, ACPI_ERST_END); if (rc) return rc; @@ -681,7 +681,7 @@ static int __erst_read_from_storage(u64 record_id, u64 offset) int rc; erst_exec_ctx_init(&ctx); - rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_READ); + rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ); if (rc) return rc; apei_exec_ctx_set_input(&ctx, offset); @@ -709,7 +709,7 @@ static int __erst_read_from_storage(u64 record_id, u64 offset) if (rc) return rc; val = apei_exec_ctx_get_output(&ctx); - rc = apei_exec_run_optional(&ctx, ACPI_ERST_END); + rc = apei_exec_run(&ctx, ACPI_ERST_END); if (rc) return rc; @@ -724,7 +724,7 @@ static int __erst_clear_from_storage(u64 record_id) int rc; erst_exec_ctx_init(&ctx); - rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_CLEAR); + rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR); if (rc) return rc; apei_exec_ctx_set_input(&ctx, record_id); @@ -748,7 +748,7 @@ static int __erst_clear_from_storage(u64 record_id) if (rc) return rc; val = apei_exec_ctx_get_output(&ctx); - rc = apei_exec_run_optional(&ctx, ACPI_ERST_END); + rc = apei_exec_run(&ctx, ACPI_ERST_END); if (rc) return rc; @@ -932,11 +932,8 @@ static int erst_check_table(struct acpi_table_erst *erst_tab) static int erst_open_pstore(struct pstore_info *psi); static int erst_close_pstore(struct pstore_info *psi); static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, - struct timespec *time, struct pstore_info *psi); -static u64 erst_writer(enum pstore_type_id type, unsigned int part, - size_t size, struct pstore_info *psi); -static int erst_clearer(enum pstore_type_id type, u64 id, - struct pstore_info *psi); + struct timespec *time); +static u64 erst_writer(enum pstore_type_id type, size_t size); static struct pstore_info erst_info = { .owner = THIS_MODULE, @@ -945,7 +942,7 @@ static struct pstore_info erst_info = { .close = erst_close_pstore, .read = erst_reader, .write = erst_writer, - .erase = erst_clearer + .erase = erst_clear }; #define CPER_CREATOR_PSTORE \ @@ -986,7 +983,7 @@ static int erst_close_pstore(struct pstore_info *psi) } static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, - struct timespec *time, struct pstore_info *psi) + struct timespec *time) { int rc; ssize_t len = 0; @@ -1040,8 +1037,7 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, return (rc < 0) ? rc : (len - sizeof(*rcd)); } -static u64 erst_writer(enum pstore_type_id type, unsigned int part, - size_t size, struct pstore_info *psi) +static u64 erst_writer(enum pstore_type_id type, size_t size) { struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); @@ -1084,12 +1080,6 @@ static u64 erst_writer(enum pstore_type_id type, unsigned int part, return rcd->hdr.record_id; } -static int erst_clearer(enum pstore_type_id type, u64 id, - struct pstore_info *psi) -{ - return erst_clear(id); -} - static int __init erst_init(void) { int rc = 0; diff --git a/trunk/drivers/acpi/apei/ghes.c b/trunk/drivers/acpi/apei/ghes.c index 0784f99a4665..f703b2881153 100644 --- a/trunk/drivers/acpi/apei/ghes.c +++ b/trunk/drivers/acpi/apei/ghes.c @@ -12,7 +12,7 @@ * For more information about Generic Hardware Error Source, please * refer to ACPI Specification version 4.0, section 17.3.2.6 * - * Copyright 2010,2011 Intel Corp. + * Copyright 2010 Intel Corp. * Author: Huang Ying * * This program is free software; you can redistribute it and/or @@ -42,9 +42,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -56,30 +53,6 @@ #define GHES_PFX "GHES: " #define GHES_ESTATUS_MAX_SIZE 65536 -#define GHES_ESOURCE_PREALLOC_MAX_SIZE 65536 - -#define GHES_ESTATUS_POOL_MIN_ALLOC_ORDER 3 - -/* This is just an estimation for memory pool allocation */ -#define GHES_ESTATUS_CACHE_AVG_SIZE 512 - -#define GHES_ESTATUS_CACHES_SIZE 4 - -#define GHES_ESTATUS_IN_CACHE_MAX_NSEC 10000000000ULL -/* Prevent too many caches are allocated because of RCU */ -#define GHES_ESTATUS_CACHE_ALLOCED_MAX (GHES_ESTATUS_CACHES_SIZE * 3 / 2) - -#define GHES_ESTATUS_CACHE_LEN(estatus_len) \ - (sizeof(struct ghes_estatus_cache) + (estatus_len)) -#define GHES_ESTATUS_FROM_CACHE(estatus_cache) \ - ((struct acpi_hest_generic_status *) \ - ((struct ghes_estatus_cache *)(estatus_cache) + 1)) - -#define GHES_ESTATUS_NODE_LEN(estatus_len) \ - (sizeof(struct ghes_estatus_node) + (estatus_len)) -#define GHES_ESTATUS_FROM_NODE(estatus_node) \ - ((struct acpi_hest_generic_status *) \ - ((struct ghes_estatus_node *)(estatus_node) + 1)) /* * One struct ghes is created for each generic hardware error source. @@ -104,22 +77,6 @@ struct ghes { }; }; -struct ghes_estatus_node { - struct llist_node llnode; - struct acpi_hest_generic *generic; -}; - -struct ghes_estatus_cache { - u32 estatus_len; - atomic_t count; - struct acpi_hest_generic *generic; - unsigned long long time_in; - struct rcu_head rcu; -}; - -int ghes_disable; -module_param_named(disable, ghes_disable, bool, 0); - static int ghes_panic_timeout __read_mostly = 30; /* @@ -164,22 +121,6 @@ static struct vm_struct *ghes_ioremap_area; static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi); static DEFINE_SPINLOCK(ghes_ioremap_lock_irq); -/* - * printk is not safe in NMI context. So in NMI handler, we allocate - * required memory from lock-less memory allocator - * (ghes_estatus_pool), save estatus into it, put them into lock-less - * list (ghes_estatus_llist), then delay printk into IRQ context via - * irq_work (ghes_proc_irq_work). ghes_estatus_size_request record - * required pool size by all NMI error source. - */ -static struct gen_pool *ghes_estatus_pool; -static unsigned long ghes_estatus_pool_size_request; -static struct llist_head ghes_estatus_llist; -static struct irq_work ghes_proc_irq_work; - -struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE]; -static atomic_t ghes_estatus_cache_alloced; - static int ghes_ioremap_init(void) { ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES, @@ -239,55 +180,6 @@ static void ghes_iounmap_irq(void __iomem *vaddr_ptr) __flush_tlb_one(vaddr); } -static int ghes_estatus_pool_init(void) -{ - ghes_estatus_pool = gen_pool_create(GHES_ESTATUS_POOL_MIN_ALLOC_ORDER, -1); - if (!ghes_estatus_pool) - return -ENOMEM; - return 0; -} - -static void ghes_estatus_pool_free_chunk_page(struct gen_pool *pool, - struct gen_pool_chunk *chunk, - void *data) -{ - free_page(chunk->start_addr); -} - -static void ghes_estatus_pool_exit(void) -{ - gen_pool_for_each_chunk(ghes_estatus_pool, - ghes_estatus_pool_free_chunk_page, NULL); - gen_pool_destroy(ghes_estatus_pool); -} - -static int ghes_estatus_pool_expand(unsigned long len) -{ - unsigned long i, pages, size, addr; - int ret; - - ghes_estatus_pool_size_request += PAGE_ALIGN(len); - size = gen_pool_size(ghes_estatus_pool); - if (size >= ghes_estatus_pool_size_request) - return 0; - pages = (ghes_estatus_pool_size_request - size) / PAGE_SIZE; - for (i = 0; i < pages; i++) { - addr = __get_free_page(GFP_KERNEL); - if (!addr) - return -ENOMEM; - ret = gen_pool_add(ghes_estatus_pool, addr, PAGE_SIZE, -1); - if (ret) - return ret; - } - - return 0; -} - -static void ghes_estatus_pool_shrink(unsigned long len) -{ - ghes_estatus_pool_size_request -= PAGE_ALIGN(len); -} - static struct ghes *ghes_new(struct acpi_hest_generic *generic) { struct ghes *ghes; @@ -449,196 +341,43 @@ static void ghes_clear_estatus(struct ghes *ghes) ghes->flags &= ~GHES_TO_CLEAR; } -static void ghes_do_proc(const struct acpi_hest_generic_status *estatus) +static void ghes_do_proc(struct ghes *ghes) { - int sev, sec_sev; + int sev, processed = 0; struct acpi_hest_generic_data *gdata; - sev = ghes_severity(estatus->error_severity); - apei_estatus_for_each_section(estatus, gdata) { - sec_sev = ghes_severity(gdata->error_severity); + sev = ghes_severity(ghes->estatus->error_severity); + apei_estatus_for_each_section(ghes->estatus, gdata) { +#ifdef CONFIG_X86_MCE if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, CPER_SEC_PLATFORM_MEM)) { - struct cper_sec_mem_err *mem_err; - mem_err = (struct cper_sec_mem_err *)(gdata+1); -#ifdef CONFIG_X86_MCE - apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED, - mem_err); -#endif -#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE - if (sev == GHES_SEV_RECOVERABLE && - sec_sev == GHES_SEV_RECOVERABLE && - mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { - unsigned long pfn; - pfn = mem_err->physical_addr >> PAGE_SHIFT; - memory_failure_queue(pfn, 0, 0); - } -#endif + apei_mce_report_mem_error( + sev == GHES_SEV_CORRECTED, + (struct cper_sec_mem_err *)(gdata+1)); + processed = 1; } +#endif } } -static void __ghes_print_estatus(const char *pfx, - const struct acpi_hest_generic *generic, - const struct acpi_hest_generic_status *estatus) +static void ghes_print_estatus(const char *pfx, struct ghes *ghes) { + /* Not more than 2 messages every 5 seconds */ + static DEFINE_RATELIMIT_STATE(ratelimit, 5*HZ, 2); + if (pfx == NULL) { - if (ghes_severity(estatus->error_severity) <= + if (ghes_severity(ghes->estatus->error_severity) <= GHES_SEV_CORRECTED) pfx = KERN_WARNING HW_ERR; else pfx = KERN_ERR HW_ERR; } - printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", - pfx, generic->header.source_id); - apei_estatus_print(pfx, estatus); -} - -static int ghes_print_estatus(const char *pfx, - const struct acpi_hest_generic *generic, - const struct acpi_hest_generic_status *estatus) -{ - /* Not more than 2 messages every 5 seconds */ - static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2); - static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5*HZ, 2); - struct ratelimit_state *ratelimit; - - if (ghes_severity(estatus->error_severity) <= GHES_SEV_CORRECTED) - ratelimit = &ratelimit_corrected; - else - ratelimit = &ratelimit_uncorrected; - if (__ratelimit(ratelimit)) { - __ghes_print_estatus(pfx, generic, estatus); - return 1; + if (__ratelimit(&ratelimit)) { + printk( + "%s""Hardware error from APEI Generic Hardware Error Source: %d\n", + pfx, ghes->generic->header.source_id); + apei_estatus_print(pfx, ghes->estatus); } - return 0; -} - -/* - * GHES error status reporting throttle, to report more kinds of - * errors, instead of just most frequently occurred errors. - */ -static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus) -{ - u32 len; - int i, cached = 0; - unsigned long long now; - struct ghes_estatus_cache *cache; - struct acpi_hest_generic_status *cache_estatus; - - len = apei_estatus_len(estatus); - rcu_read_lock(); - for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) { - cache = rcu_dereference(ghes_estatus_caches[i]); - if (cache == NULL) - continue; - if (len != cache->estatus_len) - continue; - cache_estatus = GHES_ESTATUS_FROM_CACHE(cache); - if (memcmp(estatus, cache_estatus, len)) - continue; - atomic_inc(&cache->count); - now = sched_clock(); - if (now - cache->time_in < GHES_ESTATUS_IN_CACHE_MAX_NSEC) - cached = 1; - break; - } - rcu_read_unlock(); - return cached; -} - -static struct ghes_estatus_cache *ghes_estatus_cache_alloc( - struct acpi_hest_generic *generic, - struct acpi_hest_generic_status *estatus) -{ - int alloced; - u32 len, cache_len; - struct ghes_estatus_cache *cache; - struct acpi_hest_generic_status *cache_estatus; - - alloced = atomic_add_return(1, &ghes_estatus_cache_alloced); - if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) { - atomic_dec(&ghes_estatus_cache_alloced); - return NULL; - } - len = apei_estatus_len(estatus); - cache_len = GHES_ESTATUS_CACHE_LEN(len); - cache = (void *)gen_pool_alloc(ghes_estatus_pool, cache_len); - if (!cache) { - atomic_dec(&ghes_estatus_cache_alloced); - return NULL; - } - cache_estatus = GHES_ESTATUS_FROM_CACHE(cache); - memcpy(cache_estatus, estatus, len); - cache->estatus_len = len; - atomic_set(&cache->count, 0); - cache->generic = generic; - cache->time_in = sched_clock(); - return cache; -} - -static void ghes_estatus_cache_free(struct ghes_estatus_cache *cache) -{ - u32 len; - - len = apei_estatus_len(GHES_ESTATUS_FROM_CACHE(cache)); - len = GHES_ESTATUS_CACHE_LEN(len); - gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len); - atomic_dec(&ghes_estatus_cache_alloced); -} - -static void ghes_estatus_cache_rcu_free(struct rcu_head *head) -{ - struct ghes_estatus_cache *cache; - - cache = container_of(head, struct ghes_estatus_cache, rcu); - ghes_estatus_cache_free(cache); -} - -static void ghes_estatus_cache_add( - struct acpi_hest_generic *generic, - struct acpi_hest_generic_status *estatus) -{ - int i, slot = -1, count; - unsigned long long now, duration, period, max_period = 0; - struct ghes_estatus_cache *cache, *slot_cache = NULL, *new_cache; - - new_cache = ghes_estatus_cache_alloc(generic, estatus); - if (new_cache == NULL) - return; - rcu_read_lock(); - now = sched_clock(); - for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) { - cache = rcu_dereference(ghes_estatus_caches[i]); - if (cache == NULL) { - slot = i; - slot_cache = NULL; - break; - } - duration = now - cache->time_in; - if (duration >= GHES_ESTATUS_IN_CACHE_MAX_NSEC) { - slot = i; - slot_cache = cache; - break; - } - count = atomic_read(&cache->count); - period = duration; - do_div(period, (count + 1)); - if (period > max_period) { - max_period = period; - slot = i; - slot_cache = cache; - } - } - /* new_cache must be put into array after its contents are written */ - smp_wmb(); - if (slot != -1 && cmpxchg(ghes_estatus_caches + slot, - slot_cache, new_cache) == slot_cache) { - if (slot_cache) - call_rcu(&slot_cache->rcu, ghes_estatus_cache_rcu_free); - } else - ghes_estatus_cache_free(new_cache); - rcu_read_unlock(); } static int ghes_proc(struct ghes *ghes) @@ -648,11 +387,9 @@ static int ghes_proc(struct ghes *ghes) rc = ghes_read_estatus(ghes, 0); if (rc) goto out; - if (!ghes_estatus_cached(ghes->estatus)) { - if (ghes_print_estatus(NULL, ghes->generic, ghes->estatus)) - ghes_estatus_cache_add(ghes->generic, ghes->estatus); - } - ghes_do_proc(ghes->estatus); + ghes_print_estatus(NULL, ghes); + ghes_do_proc(ghes); + out: ghes_clear_estatus(ghes); return 0; @@ -710,45 +447,6 @@ static int ghes_notify_sci(struct notifier_block *this, return ret; } -static void ghes_proc_in_irq(struct irq_work *irq_work) -{ - struct llist_node *llnode, *next, *tail = NULL; - struct ghes_estatus_node *estatus_node; - struct acpi_hest_generic *generic; - struct acpi_hest_generic_status *estatus; - u32 len, node_len; - - /* - * Because the time order of estatus in list is reversed, - * revert it back to proper order. - */ - llnode = llist_del_all(&ghes_estatus_llist); - while (llnode) { - next = llnode->next; - llnode->next = tail; - tail = llnode; - llnode = next; - } - llnode = tail; - while (llnode) { - next = llnode->next; - estatus_node = llist_entry(llnode, struct ghes_estatus_node, - llnode); - estatus = GHES_ESTATUS_FROM_NODE(estatus_node); - len = apei_estatus_len(estatus); - node_len = GHES_ESTATUS_NODE_LEN(len); - ghes_do_proc(estatus); - if (!ghes_estatus_cached(estatus)) { - generic = estatus_node->generic; - if (ghes_print_estatus(NULL, generic, estatus)) - ghes_estatus_cache_add(generic, estatus); - } - gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node, - node_len); - llnode = next; - } -} - static int ghes_notify_nmi(struct notifier_block *this, unsigned long cmd, void *data) { @@ -778,8 +476,7 @@ static int ghes_notify_nmi(struct notifier_block *this, if (sev_global >= GHES_SEV_PANIC) { oops_begin(); - __ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global->generic, - ghes_global->estatus); + ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global); /* reboot to log the error! */ if (panic_timeout == 0) panic_timeout = ghes_panic_timeout; @@ -787,34 +484,12 @@ static int ghes_notify_nmi(struct notifier_block *this, } list_for_each_entry_rcu(ghes, &ghes_nmi, list) { -#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - u32 len, node_len; - struct ghes_estatus_node *estatus_node; - struct acpi_hest_generic_status *estatus; -#endif if (!(ghes->flags & GHES_TO_CLEAR)) continue; -#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - if (ghes_estatus_cached(ghes->estatus)) - goto next; - /* Save estatus for further processing in IRQ context */ - len = apei_estatus_len(ghes->estatus); - node_len = GHES_ESTATUS_NODE_LEN(len); - estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, - node_len); - if (estatus_node) { - estatus_node->generic = ghes->generic; - estatus = GHES_ESTATUS_FROM_NODE(estatus_node); - memcpy(estatus, ghes->estatus, len); - llist_add(&estatus_node->llnode, &ghes_estatus_llist); - } -next: -#endif + /* Do not print estatus because printk is not NMI safe */ + ghes_do_proc(ghes); ghes_clear_estatus(ghes); } -#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - irq_work_queue(&ghes_proc_irq_work); -#endif out: raw_spin_unlock(&ghes_nmi_lock); @@ -829,26 +504,10 @@ static struct notifier_block ghes_notifier_nmi = { .notifier_call = ghes_notify_nmi, }; -static unsigned long ghes_esource_prealloc_size( - const struct acpi_hest_generic *generic) -{ - unsigned long block_length, prealloc_records, prealloc_size; - - block_length = min_t(unsigned long, generic->error_block_length, - GHES_ESTATUS_MAX_SIZE); - prealloc_records = max_t(unsigned long, - generic->records_to_preallocate, 1); - prealloc_size = min_t(unsigned long, block_length * prealloc_records, - GHES_ESOURCE_PREALLOC_MAX_SIZE); - - return prealloc_size; -} - static int __devinit ghes_probe(struct platform_device *ghes_dev) { struct acpi_hest_generic *generic; struct ghes *ghes = NULL; - unsigned long len; int rc = -EINVAL; generic = *(struct acpi_hest_generic **)ghes_dev->dev.platform_data; @@ -914,8 +573,6 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev) mutex_unlock(&ghes_list_mutex); break; case ACPI_HEST_NOTIFY_NMI: - len = ghes_esource_prealloc_size(generic); - ghes_estatus_pool_expand(len); mutex_lock(&ghes_list_mutex); if (list_empty(&ghes_nmi)) register_die_notifier(&ghes_notifier_nmi); @@ -940,7 +597,6 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev) { struct ghes *ghes; struct acpi_hest_generic *generic; - unsigned long len; ghes = platform_get_drvdata(ghes_dev); generic = ghes->generic; @@ -971,8 +627,6 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev) * freed after NMI handler finishes. */ synchronize_rcu(); - len = ghes_esource_prealloc_size(generic); - ghes_estatus_pool_shrink(len); break; default: BUG(); @@ -1008,43 +662,15 @@ static int __init ghes_init(void) return -EINVAL; } - if (ghes_disable) { - pr_info(GHES_PFX "GHES is not enabled!\n"); - return -EINVAL; - } - - init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq); - rc = ghes_ioremap_init(); if (rc) goto err; - rc = ghes_estatus_pool_init(); - if (rc) - goto err_ioremap_exit; - - rc = ghes_estatus_pool_expand(GHES_ESTATUS_CACHE_AVG_SIZE * - GHES_ESTATUS_CACHE_ALLOCED_MAX); - if (rc) - goto err_pool_exit; - rc = platform_driver_register(&ghes_platform_driver); if (rc) - goto err_pool_exit; - - rc = apei_osc_setup(); - if (rc == 0 && osc_sb_apei_support_acked) - pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit and WHEA _OSC.\n"); - else if (rc == 0 && !osc_sb_apei_support_acked) - pr_info(GHES_PFX "APEI firmware first mode is enabled by WHEA _OSC.\n"); - else if (rc && osc_sb_apei_support_acked) - pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit.\n"); - else - pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n"); + goto err_ioremap_exit; return 0; -err_pool_exit: - ghes_estatus_pool_exit(); err_ioremap_exit: ghes_ioremap_exit(); err: @@ -1054,7 +680,6 @@ static int __init ghes_init(void) static void __exit ghes_exit(void) { platform_driver_unregister(&ghes_platform_driver); - ghes_estatus_pool_exit(); ghes_ioremap_exit(); } diff --git a/trunk/drivers/acpi/apei/hest.c b/trunk/drivers/acpi/apei/hest.c index 05fee06f4d6e..181bc2f7bb74 100644 --- a/trunk/drivers/acpi/apei/hest.c +++ b/trunk/drivers/acpi/apei/hest.c @@ -231,17 +231,16 @@ void __init acpi_hest_init(void) goto err; } - if (!ghes_disable) { - rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); - if (rc) - goto err; - rc = hest_ghes_dev_register(ghes_count); - if (rc) - goto err; + rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); + if (rc) + goto err; + + rc = hest_ghes_dev_register(ghes_count); + if (!rc) { + pr_info(HEST_PFX "Table parsing has been initialized.\n"); + return; } - pr_info(HEST_PFX "Table parsing has been initialized.\n"); - return; err: hest_disable = 1; } diff --git a/trunk/drivers/acpi/battery.c b/trunk/drivers/acpi/battery.c index 7711d94a0409..2c661353e8f2 100644 --- a/trunk/drivers/acpi/battery.c +++ b/trunk/drivers/acpi/battery.c @@ -55,9 +55,6 @@ #define ACPI_BATTERY_NOTIFY_INFO 0x81 #define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82 -/* Battery power unit: 0 means mW, 1 means mA */ -#define ACPI_BATTERY_POWER_UNIT_MA 1 - #define _COMPONENT ACPI_BATTERY_COMPONENT ACPI_MODULE_NAME("battery"); @@ -94,12 +91,16 @@ MODULE_DEVICE_TABLE(acpi, battery_device_ids); enum { ACPI_BATTERY_ALARM_PRESENT, ACPI_BATTERY_XINFO_PRESENT, + /* For buggy DSDTs that report negative 16-bit values for either + * charging or discharging current and/or report 0 as 65536 + * due to bad math. + */ + ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, }; struct acpi_battery { struct mutex lock; - struct mutex sysfs_lock; struct power_supply bat; struct acpi_device *device; struct notifier_block pm_nb; @@ -300,8 +301,7 @@ static enum power_supply_property energy_battery_props[] = { #ifdef CONFIG_ACPI_PROCFS_POWER inline char *acpi_battery_units(struct acpi_battery *battery) { - return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ? - "mA" : "mW"; + return (battery->power_unit)?"mA":"mW"; } #endif @@ -461,17 +461,9 @@ static int acpi_battery_get_state(struct acpi_battery *battery) battery->update_time = jiffies; kfree(buffer.pointer); - /* For buggy DSDTs that report negative 16-bit values for either - * charging or discharging current and/or report 0 as 65536 - * due to bad math. - */ - if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA && - battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN && - (s16)(battery->rate_now) < 0) { + if (test_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags) && + battery->rate_now != -1) battery->rate_now = abs((s16)battery->rate_now); - printk_once(KERN_WARNING FW_BUG "battery: (dis)charge rate" - " invalid.\n"); - } if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) && battery->capacity_now >= 0 && battery->capacity_now <= 100) @@ -552,7 +544,7 @@ static int sysfs_add_battery(struct acpi_battery *battery) { int result; - if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) { + if (battery->power_unit) { battery->bat.properties = charge_battery_props; battery->bat.num_properties = ARRAY_SIZE(charge_battery_props); @@ -574,16 +566,18 @@ static int sysfs_add_battery(struct acpi_battery *battery) static void sysfs_remove_battery(struct acpi_battery *battery) { - mutex_lock(&battery->sysfs_lock); - if (!battery->bat.dev) { - mutex_unlock(&battery->sysfs_lock); + if (!battery->bat.dev) return; - } - device_remove_file(battery->bat.dev, &alarm_attr); power_supply_unregister(&battery->bat); battery->bat.dev = NULL; - mutex_unlock(&battery->sysfs_lock); +} + +static void acpi_battery_quirks(struct acpi_battery *battery) +{ + if (dmi_name_in_vendors("Acer") && battery->power_unit) { + set_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags); + } } /* @@ -598,7 +592,7 @@ static void sysfs_remove_battery(struct acpi_battery *battery) * * Handle this correctly so that they won't break userspace. */ -static void acpi_battery_quirks(struct acpi_battery *battery) +static void acpi_battery_quirks2(struct acpi_battery *battery) { if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) return ; @@ -629,15 +623,13 @@ static int acpi_battery_update(struct acpi_battery *battery) result = acpi_battery_get_info(battery); if (result) return result; + acpi_battery_quirks(battery); acpi_battery_init_alarm(battery); } - if (!battery->bat.dev) { - result = sysfs_add_battery(battery); - if (result) - return result; - } + if (!battery->bat.dev) + sysfs_add_battery(battery); result = acpi_battery_get_state(battery); - acpi_battery_quirks(battery); + acpi_battery_quirks2(battery); return result; } @@ -871,7 +863,7 @@ DECLARE_FILE_FUNCTIONS(alarm); }, \ } -static const struct battery_file { +static struct battery_file { struct file_operations ops; mode_t mode; const char *name; @@ -956,12 +948,9 @@ static int battery_notify(struct notifier_block *nb, struct acpi_battery *battery = container_of(nb, struct acpi_battery, pm_nb); switch (mode) { - case PM_POST_HIBERNATION: case PM_POST_SUSPEND: - if (battery->bat.dev) { - sysfs_remove_battery(battery); - sysfs_add_battery(battery); - } + sysfs_remove_battery(battery); + sysfs_add_battery(battery); break; } @@ -983,38 +972,28 @@ static int acpi_battery_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); device->driver_data = battery; mutex_init(&battery->lock); - mutex_init(&battery->sysfs_lock); if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, "_BIX", &handle))) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); - result = acpi_battery_update(battery); - if (result) - goto fail; + acpi_battery_update(battery); #ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); #endif - if (result) { + if (!result) { + printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", + ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), + device->status.battery_present ? "present" : "absent"); + } else { #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif - goto fail; + kfree(battery); } - printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", - ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), - device->status.battery_present ? "present" : "absent"); - battery->pm_nb.notifier_call = battery_notify; register_pm_notifier(&battery->pm_nb); return result; - -fail: - sysfs_remove_battery(battery); - mutex_destroy(&battery->lock); - mutex_destroy(&battery->sysfs_lock); - kfree(battery); - return result; } static int acpi_battery_remove(struct acpi_device *device, int type) @@ -1030,7 +1009,6 @@ static int acpi_battery_remove(struct acpi_device *device, int type) #endif sysfs_remove_battery(battery); mutex_destroy(&battery->lock); - mutex_destroy(&battery->sysfs_lock); kfree(battery); return 0; } diff --git a/trunk/drivers/acpi/bus.c b/trunk/drivers/acpi/bus.c index 437ddbf0c49a..d1e06c182cdb 100644 --- a/trunk/drivers/acpi/bus.c +++ b/trunk/drivers/acpi/bus.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -520,7 +519,6 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) } EXPORT_SYMBOL(acpi_run_osc); -bool osc_sb_apei_support_acked; static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; static void acpi_bus_osc_support(void) { @@ -543,19 +541,11 @@ static void acpi_bus_osc_support(void) #if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT; #endif - - if (!ghes_disable) - capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_APEI_SUPPORT; if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) return; - if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) { - u32 *capbuf_ret = context.ret.pointer; - if (context.ret.length > OSC_SUPPORT_TYPE) - osc_sb_apei_support_acked = - capbuf_ret[OSC_SUPPORT_TYPE] & OSC_SB_APEI_SUPPORT; + if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) kfree(context.ret.pointer); - } - /* do we need to check other returned cap? Sounds no */ + /* do we need to check the returned cap? Sounds no */ } /* -------------------------------------------------------------------------- diff --git a/trunk/drivers/acpi/dock.c b/trunk/drivers/acpi/dock.c index 19a61136d848..1864ad3cf895 100644 --- a/trunk/drivers/acpi/dock.c +++ b/trunk/drivers/acpi/dock.c @@ -77,7 +77,7 @@ struct dock_dependent_device { struct list_head list; struct list_head hotplug_list; acpi_handle handle; - const struct acpi_dock_ops *ops; + struct acpi_dock_ops *ops; void *context; }; @@ -589,7 +589,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier); * the dock driver after _DCK is executed. */ int -register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, +register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops, void *context) { struct dock_dependent_device *dd; diff --git a/trunk/drivers/acpi/ec_sys.c b/trunk/drivers/acpi/ec_sys.c index 22f918bacd35..05b44201a614 100644 --- a/trunk/drivers/acpi/ec_sys.c +++ b/trunk/drivers/acpi/ec_sys.c @@ -92,7 +92,7 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf, return count; } -static const struct file_operations acpi_ec_io_ops = { +static struct file_operations acpi_ec_io_ops = { .owner = THIS_MODULE, .open = acpi_ec_open_io, .read = acpi_ec_read_io, diff --git a/trunk/drivers/acpi/fan.c b/trunk/drivers/acpi/fan.c index 0f0356ca1a9e..467479f07c1f 100644 --- a/trunk/drivers/acpi/fan.c +++ b/trunk/drivers/acpi/fan.c @@ -110,7 +110,7 @@ fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) return result; } -static const struct thermal_cooling_device_ops fan_cooling_ops = { +static struct thermal_cooling_device_ops fan_cooling_ops = { .get_max_state = fan_get_max_state, .get_cur_state = fan_get_cur_state, .set_cur_state = fan_set_cur_state, diff --git a/trunk/drivers/acpi/osl.c b/trunk/drivers/acpi/osl.c index fa32f584229f..372f9b70f7f4 100644 --- a/trunk/drivers/acpi/osl.c +++ b/trunk/drivers/acpi/osl.c @@ -155,7 +155,7 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported) { if (!strcmp("Linux", interface)) { - printk_once(KERN_NOTICE FW_BUG PREFIX + printk(KERN_NOTICE FW_BUG PREFIX "BIOS _OSI(Linux) query %s%s\n", osi_linux.enable ? "honored" : "ignored", osi_linux.cmdline ? " via cmdline" : @@ -237,23 +237,8 @@ void acpi_os_vprintf(const char *fmt, va_list args) #endif } -#ifdef CONFIG_KEXEC -static unsigned long acpi_rsdp; -static int __init setup_acpi_rsdp(char *arg) -{ - acpi_rsdp = simple_strtoul(arg, NULL, 16); - return 0; -} -early_param("acpi_rsdp", setup_acpi_rsdp); -#endif - acpi_physical_address __init acpi_os_get_root_pointer(void) { -#ifdef CONFIG_KEXEC - if (acpi_rsdp) - return acpi_rsdp; -#endif - if (efi_enabled) { if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) return efi.acpi20; @@ -1098,13 +1083,7 @@ struct osi_setup_entry { bool enable; }; -static struct osi_setup_entry __initdata - osi_setup_entries[OSI_STRING_ENTRIES_MAX] = { - {"Module Device", true}, - {"Processor Device", true}, - {"3.0 _SCP Extensions", true}, - {"Processor Aggregator Device", true}, -}; +static struct osi_setup_entry __initdata osi_setup_entries[OSI_STRING_ENTRIES_MAX]; void __init acpi_osi_setup(char *str) { diff --git a/trunk/drivers/acpi/pci_irq.c b/trunk/drivers/acpi/pci_irq.c index 7f9eba9a0b02..f907cfbfa13c 100644 --- a/trunk/drivers/acpi/pci_irq.c +++ b/trunk/drivers/acpi/pci_irq.c @@ -303,61 +303,6 @@ void acpi_pci_irq_del_prt(struct pci_bus *bus) /* -------------------------------------------------------------------------- PCI Interrupt Routing Support -------------------------------------------------------------------------- */ -#ifdef CONFIG_X86_IO_APIC -extern int noioapicquirk; -extern int noioapicreroute; - -static int bridge_has_boot_interrupt_variant(struct pci_bus *bus) -{ - struct pci_bus *bus_it; - - for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) { - if (!bus_it->self) - return 0; - if (bus_it->self->irq_reroute_variant) - return bus_it->self->irq_reroute_variant; - } - return 0; -} - -/* - * Some chipsets (e.g. Intel 6700PXH) generate a legacy INTx when the IRQ - * entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel does - * during interrupt handling). When this INTx generation cannot be disabled, - * we reroute these interrupts to their legacy equivalent to get rid of - * spurious interrupts. - */ -static int acpi_reroute_boot_interrupt(struct pci_dev *dev, - struct acpi_prt_entry *entry) -{ - if (noioapicquirk || noioapicreroute) { - return 0; - } else { - switch (bridge_has_boot_interrupt_variant(dev->bus)) { - case 0: - /* no rerouting necessary */ - return 0; - case INTEL_IRQ_REROUTE_VARIANT: - /* - * Remap according to INTx routing table in 6700PXH - * specs, intel order number 302628-002, section - * 2.15.2. Other chipsets (80332, ...) have the same - * mapping and are handled here as well. - */ - dev_info(&dev->dev, "PCI IRQ %d -> rerouted to legacy " - "IRQ %d\n", entry->index, - (entry->index % 4) + 16); - entry->index = (entry->index % 4) + 16; - return 1; - default: - dev_warn(&dev->dev, "Cannot reroute IRQ %d to legacy " - "IRQ: unknown mapping\n", entry->index); - return -1; - } - } -} -#endif /* CONFIG_X86_IO_APIC */ - static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) { struct acpi_prt_entry *entry; @@ -366,9 +311,6 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) entry = acpi_pci_irq_find_prt_entry(dev, pin); if (entry) { -#ifdef CONFIG_X86_IO_APIC - acpi_reroute_boot_interrupt(dev, entry); -#endif /* CONFIG_X86_IO_APIC */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n", pci_name(dev), pin_name(pin))); return entry; diff --git a/trunk/drivers/acpi/pci_root.c b/trunk/drivers/acpi/pci_root.c index 2672c798272f..d06078d660ad 100644 --- a/trunk/drivers/acpi/pci_root.c +++ b/trunk/drivers/acpi/pci_root.c @@ -485,8 +485,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) root->secondary.end = 0xFF; printk(KERN_WARNING FW_BUG PREFIX "no secondary bus range in _CRS\n"); - status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, - NULL, &bus); + status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus); if (ACPI_SUCCESS(status)) root->secondary.start = bus; else if (status == AE_NOT_FOUND) diff --git a/trunk/drivers/acpi/processor_thermal.c b/trunk/drivers/acpi/processor_thermal.c index 870550d6a4bf..79cb65332894 100644 --- a/trunk/drivers/acpi/processor_thermal.c +++ b/trunk/drivers/acpi/processor_thermal.c @@ -244,7 +244,7 @@ processor_set_cur_state(struct thermal_cooling_device *cdev, return result; } -const struct thermal_cooling_device_ops processor_cooling_ops = { +struct thermal_cooling_device_ops processor_cooling_ops = { .get_max_state = processor_get_max_state, .get_cur_state = processor_get_cur_state, .set_cur_state = processor_set_cur_state, diff --git a/trunk/drivers/acpi/sbs.c b/trunk/drivers/acpi/sbs.c index 6e36d0c0057c..50658ff887d9 100644 --- a/trunk/drivers/acpi/sbs.c +++ b/trunk/drivers/acpi/sbs.c @@ -130,9 +130,6 @@ struct acpi_sbs { #define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger) -static int acpi_sbs_remove(struct acpi_device *device, int type); -static int acpi_battery_get_state(struct acpi_battery *battery); - static inline int battery_scale(int log) { int scale = 1; @@ -198,8 +195,6 @@ static int acpi_sbs_battery_get_property(struct power_supply *psy, if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT) return -ENODEV; - - acpi_battery_get_state(battery); switch (psp) { case POWER_SUPPLY_PROP_STATUS: if (battery->rate_now < 0) @@ -230,17 +225,11 @@ static int acpi_sbs_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_POWER_NOW: val->intval = abs(battery->rate_now) * acpi_battery_ipscale(battery) * 1000; - val->intval *= (acpi_battery_mode(battery)) ? - (battery->voltage_now * - acpi_battery_vscale(battery) / 1000) : 1; break; case POWER_SUPPLY_PROP_CURRENT_AVG: case POWER_SUPPLY_PROP_POWER_AVG: val->intval = abs(battery->rate_avg) * acpi_battery_ipscale(battery) * 1000; - val->intval *= (acpi_battery_mode(battery)) ? - (battery->voltage_now * - acpi_battery_vscale(battery) / 1000) : 1; break; case POWER_SUPPLY_PROP_CAPACITY: val->intval = battery->state_of_charge; @@ -914,6 +903,8 @@ static void acpi_sbs_callback(void *context) } } +static int acpi_sbs_remove(struct acpi_device *device, int type); + static int acpi_sbs_add(struct acpi_device *device) { struct acpi_sbs *sbs; diff --git a/trunk/drivers/acpi/sleep.c b/trunk/drivers/acpi/sleep.c index 3ed80b2ca907..6c949602cbd1 100644 --- a/trunk/drivers/acpi/sleep.c +++ b/trunk/drivers/acpi/sleep.c @@ -428,22 +428,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), }, }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus A8N-SLI DELUXE", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus A8N-SLI Premium", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"), - }, - }, {}, }; #endif /* CONFIG_SUSPEND */ diff --git a/trunk/drivers/acpi/sysfs.c b/trunk/drivers/acpi/sysfs.c index c538d0ef10ff..77255f250dbb 100644 --- a/trunk/drivers/acpi/sysfs.c +++ b/trunk/drivers/acpi/sysfs.c @@ -149,12 +149,12 @@ static int param_get_debug_level(char *buffer, const struct kernel_param *kp) return result; } -static const struct kernel_param_ops param_ops_debug_layer = { +static struct kernel_param_ops param_ops_debug_layer = { .set = param_set_uint, .get = param_get_debug_layer, }; -static const struct kernel_param_ops param_ops_debug_level = { +static struct kernel_param_ops param_ops_debug_level = { .set = param_set_uint, .get = param_get_debug_level, }; diff --git a/trunk/drivers/acpi/thermal.c b/trunk/drivers/acpi/thermal.c index 48fbc647b178..2607e17b520f 100644 --- a/trunk/drivers/acpi/thermal.c +++ b/trunk/drivers/acpi/thermal.c @@ -812,7 +812,7 @@ acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, thermal_zone_unbind_cooling_device); } -static const struct thermal_zone_device_ops acpi_thermal_zone_ops = { +static struct thermal_zone_device_ops acpi_thermal_zone_ops = { .bind = acpi_thermal_bind_cooling_device, .unbind = acpi_thermal_unbind_cooling_device, .get_temp = thermal_get_temp, diff --git a/trunk/drivers/acpi/video.c b/trunk/drivers/acpi/video.c index 08a44b532f7c..ada4b4d9bdc8 100644 --- a/trunk/drivers/acpi/video.c +++ b/trunk/drivers/acpi/video.c @@ -307,7 +307,7 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st return acpi_video_device_lcd_set_level(video, level); } -static const struct thermal_cooling_device_ops video_cooling_ops = { +static struct thermal_cooling_device_ops video_cooling_ops = { .get_max_state = video_get_max_state, .get_cur_state = video_get_cur_state, .set_cur_state = video_set_cur_state, diff --git a/trunk/drivers/ata/libata-acpi.c b/trunk/drivers/ata/libata-acpi.c index bb7c5f1085cc..e0a5b555cee1 100644 --- a/trunk/drivers/ata/libata-acpi.c +++ b/trunk/drivers/ata/libata-acpi.c @@ -218,12 +218,12 @@ static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) ata_acpi_uevent(dev->link->ap, dev, event); } -static const struct acpi_dock_ops ata_acpi_dev_dock_ops = { +static struct acpi_dock_ops ata_acpi_dev_dock_ops = { .handler = ata_acpi_dev_notify_dock, .uevent = ata_acpi_dev_uevent, }; -static const struct acpi_dock_ops ata_acpi_ap_dock_ops = { +static struct acpi_dock_ops ata_acpi_ap_dock_ops = { .handler = ata_acpi_ap_notify_dock, .uevent = ata_acpi_ap_uevent, }; diff --git a/trunk/drivers/base/devtmpfs.c b/trunk/drivers/base/devtmpfs.c index 33e1bed68fdd..b89fffc1d777 100644 --- a/trunk/drivers/base/devtmpfs.c +++ b/trunk/drivers/base/devtmpfs.c @@ -166,7 +166,7 @@ static int create_path(const char *nodepath) { char *path; char *s; - int err = 0; + int err; /* parent directories do not exist, create them */ path = kstrdup(nodepath, GFP_KERNEL); diff --git a/trunk/drivers/base/power/domain.c b/trunk/drivers/base/power/domain.c index e18566a0fedd..be8714aa9dd6 100644 --- a/trunk/drivers/base/power/domain.c +++ b/trunk/drivers/base/power/domain.c @@ -80,6 +80,7 @@ static void genpd_set_active(struct generic_pm_domain *genpd) int pm_genpd_poweron(struct generic_pm_domain *genpd) { struct generic_pm_domain *parent = genpd->parent; + DEFINE_WAIT(wait); int ret = 0; start: @@ -111,7 +112,7 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd) } if (genpd->power_on) { - ret = genpd->power_on(genpd); + int ret = genpd->power_on(genpd); if (ret) goto out; } diff --git a/trunk/drivers/base/power/runtime.c b/trunk/drivers/base/power/runtime.c index acb3f83b8079..8dc247c974af 100644 --- a/trunk/drivers/base/power/runtime.c +++ b/trunk/drivers/base/power/runtime.c @@ -226,17 +226,11 @@ static int rpm_idle(struct device *dev, int rpmflags) callback = NULL; if (callback) { - if (dev->power.irq_safe) - spin_unlock(&dev->power.lock); - else - spin_unlock_irq(&dev->power.lock); + spin_unlock_irq(&dev->power.lock); callback(dev); - if (dev->power.irq_safe) - spin_lock(&dev->power.lock); - else - spin_lock_irq(&dev->power.lock); + spin_lock_irq(&dev->power.lock); } dev->power.idle_notification = false; diff --git a/trunk/drivers/char/Kconfig b/trunk/drivers/char/Kconfig index 423fd56bf612..49502bc5360a 100644 --- a/trunk/drivers/char/Kconfig +++ b/trunk/drivers/char/Kconfig @@ -616,16 +616,5 @@ config MSM_SMD_PKT Enables userspace clients to read and write to some packet SMD ports via device interface for MSM chipset. -config TILE_SROM - bool "Character-device access via hypervisor to the Tilera SPI ROM" - depends on TILE - default y - ---help--- - This device provides character-level read-write access - to the SROM, typically via the "0", "1", and "2" devices - in /dev/srom/. The Tilera hypervisor makes the flash - device appear much like a simple EEPROM, and knows - how to partition a single ROM for multiple purposes. - endmenu diff --git a/trunk/drivers/char/Makefile b/trunk/drivers/char/Makefile index 32762ba769c2..7a00672bd85d 100644 --- a/trunk/drivers/char/Makefile +++ b/trunk/drivers/char/Makefile @@ -63,5 +63,3 @@ obj-$(CONFIG_RAMOOPS) += ramoops.o obj-$(CONFIG_JS_RTC) += js-rtc.o js-rtc-y = rtc.o - -obj-$(CONFIG_TILE_SROM) += tile-srom.o diff --git a/trunk/drivers/char/ramoops.c b/trunk/drivers/char/ramoops.c index 810aff9e750f..fca0c51bbc90 100644 --- a/trunk/drivers/char/ramoops.c +++ b/trunk/drivers/char/ramoops.c @@ -147,14 +147,6 @@ static int __init ramoops_probe(struct platform_device *pdev) cxt->phys_addr = pdata->mem_address; cxt->record_size = pdata->record_size; cxt->dump_oops = pdata->dump_oops; - /* - * Update the module parameter variables as well so they are visible - * through /sys/module/ramoops/parameters/ - */ - mem_size = pdata->mem_size; - mem_address = pdata->mem_address; - record_size = pdata->record_size; - dump_oops = pdata->dump_oops; if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) { pr_err("request mem region failed\n"); diff --git a/trunk/drivers/char/tile-srom.c b/trunk/drivers/char/tile-srom.c deleted file mode 100644 index cf3ee008dca2..000000000000 --- a/trunk/drivers/char/tile-srom.c +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. 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 - * as published by the Free Software Foundation, version 2. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * SPI Flash ROM driver - * - * This source code is derived from code provided in "Linux Device - * Drivers, Third Edition", by Jonathan Corbet, Alessandro Rubini, and - * Greg Kroah-Hartman, published by O'Reilly Media, Inc. - */ - -#include -#include -#include -#include /* printk() */ -#include /* kmalloc() */ -#include /* everything... */ -#include /* error codes */ -#include /* size_t */ -#include -#include /* O_ACCMODE */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Size of our hypervisor I/O requests. We break up large transfers - * so that we don't spend large uninterrupted spans of time in the - * hypervisor. Erasing an SROM sector takes a significant fraction of - * a second, so if we allowed the user to, say, do one I/O to write the - * entire ROM, we'd get soft lockup timeouts, or worse. - */ -#define SROM_CHUNK_SIZE ((size_t)4096) - -/* - * When hypervisor is busy (e.g. erasing), poll the status periodically. - */ - -/* - * Interval to poll the state in msec - */ -#define SROM_WAIT_TRY_INTERVAL 20 - -/* - * Maximum times to poll the state - */ -#define SROM_MAX_WAIT_TRY_TIMES 1000 - -struct srom_dev { - int hv_devhdl; /* Handle for hypervisor device */ - u32 total_size; /* Size of this device */ - u32 sector_size; /* Size of a sector */ - u32 page_size; /* Size of a page */ - struct mutex lock; /* Allow only one accessor at a time */ -}; - -static int srom_major; /* Dynamic major by default */ -module_param(srom_major, int, 0); -MODULE_AUTHOR("Tilera Corporation"); -MODULE_LICENSE("GPL"); - -static int srom_devs; /* Number of SROM partitions */ -static struct cdev srom_cdev; -static struct class *srom_class; -static struct srom_dev *srom_devices; - -/* - * Handle calling the hypervisor and managing EAGAIN/EBUSY. - */ - -static ssize_t _srom_read(int hv_devhdl, void *buf, - loff_t off, size_t count) -{ - int retval, retries = SROM_MAX_WAIT_TRY_TIMES; - for (;;) { - retval = hv_dev_pread(hv_devhdl, 0, (HV_VirtAddr)buf, - count, off); - if (retval >= 0) - return retval; - if (retval == HV_EAGAIN) - continue; - if (retval == HV_EBUSY && --retries > 0) { - msleep(SROM_WAIT_TRY_INTERVAL); - continue; - } - pr_err("_srom_read: error %d\n", retval); - return -EIO; - } -} - -static ssize_t _srom_write(int hv_devhdl, const void *buf, - loff_t off, size_t count) -{ - int retval, retries = SROM_MAX_WAIT_TRY_TIMES; - for (;;) { - retval = hv_dev_pwrite(hv_devhdl, 0, (HV_VirtAddr)buf, - count, off); - if (retval >= 0) - return retval; - if (retval == HV_EAGAIN) - continue; - if (retval == HV_EBUSY && --retries > 0) { - msleep(SROM_WAIT_TRY_INTERVAL); - continue; - } - pr_err("_srom_write: error %d\n", retval); - return -EIO; - } -} - -/** - * srom_open() - Device open routine. - * @inode: Inode for this device. - * @filp: File for this specific open of the device. - * - * Returns zero, or an error code. - */ -static int srom_open(struct inode *inode, struct file *filp) -{ - filp->private_data = &srom_devices[iminor(inode)]; - return 0; -} - - -/** - * srom_release() - Device release routine. - * @inode: Inode for this device. - * @filp: File for this specific open of the device. - * - * Returns zero, or an error code. - */ -static int srom_release(struct inode *inode, struct file *filp) -{ - struct srom_dev *srom = filp->private_data; - char dummy; - - /* Make sure we've flushed anything written to the ROM. */ - mutex_lock(&srom->lock); - if (srom->hv_devhdl >= 0) - _srom_write(srom->hv_devhdl, &dummy, SROM_FLUSH_OFF, 1); - mutex_unlock(&srom->lock); - - filp->private_data = NULL; - - return 0; -} - - -/** - * srom_read() - Read data from the device. - * @filp: File for this specific open of the device. - * @buf: User's data buffer. - * @count: Number of bytes requested. - * @f_pos: File position. - * - * Returns number of bytes read, or an error code. - */ -static ssize_t srom_read(struct file *filp, char __user *buf, - size_t count, loff_t *f_pos) -{ - int retval = 0; - void *kernbuf; - struct srom_dev *srom = filp->private_data; - - kernbuf = kmalloc(SROM_CHUNK_SIZE, GFP_KERNEL); - if (!kernbuf) - return -ENOMEM; - - if (mutex_lock_interruptible(&srom->lock)) { - retval = -ERESTARTSYS; - kfree(kernbuf); - return retval; - } - - while (count) { - int hv_retval; - int bytes_this_pass = min(count, SROM_CHUNK_SIZE); - - hv_retval = _srom_read(srom->hv_devhdl, kernbuf, - *f_pos, bytes_this_pass); - if (hv_retval > 0) { - if (copy_to_user(buf, kernbuf, hv_retval) != 0) { - retval = -EFAULT; - break; - } - } else if (hv_retval <= 0) { - if (retval == 0) - retval = hv_retval; - break; - } - - retval += hv_retval; - *f_pos += hv_retval; - buf += hv_retval; - count -= hv_retval; - } - - mutex_unlock(&srom->lock); - kfree(kernbuf); - - return retval; -} - -/** - * srom_write() - Write data to the device. - * @filp: File for this specific open of the device. - * @buf: User's data buffer. - * @count: Number of bytes requested. - * @f_pos: File position. - * - * Returns number of bytes written, or an error code. - */ -static ssize_t srom_write(struct file *filp, const char __user *buf, - size_t count, loff_t *f_pos) -{ - int retval = 0; - void *kernbuf; - struct srom_dev *srom = filp->private_data; - - kernbuf = kmalloc(SROM_CHUNK_SIZE, GFP_KERNEL); - if (!kernbuf) - return -ENOMEM; - - if (mutex_lock_interruptible(&srom->lock)) { - retval = -ERESTARTSYS; - kfree(kernbuf); - return retval; - } - - while (count) { - int hv_retval; - int bytes_this_pass = min(count, SROM_CHUNK_SIZE); - - if (copy_from_user(kernbuf, buf, bytes_this_pass) != 0) { - retval = -EFAULT; - break; - } - - hv_retval = _srom_write(srom->hv_devhdl, kernbuf, - *f_pos, bytes_this_pass); - if (hv_retval <= 0) { - if (retval == 0) - retval = hv_retval; - break; - } - - retval += hv_retval; - *f_pos += hv_retval; - buf += hv_retval; - count -= hv_retval; - } - - mutex_unlock(&srom->lock); - kfree(kernbuf); - - return retval; -} - -/* Provide our own implementation so we can use srom->total_size. */ -loff_t srom_llseek(struct file *filp, loff_t offset, int origin) -{ - struct srom_dev *srom = filp->private_data; - - if (mutex_lock_interruptible(&srom->lock)) - return -ERESTARTSYS; - - switch (origin) { - case SEEK_END: - offset += srom->total_size; - break; - case SEEK_CUR: - offset += filp->f_pos; - break; - } - - if (offset < 0 || offset > srom->total_size) { - offset = -EINVAL; - } else { - filp->f_pos = offset; - filp->f_version = 0; - } - - mutex_unlock(&srom->lock); - - return offset; -} - -static ssize_t total_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct srom_dev *srom = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", srom->total_size); -} - -static ssize_t sector_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct srom_dev *srom = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", srom->sector_size); -} - -static ssize_t page_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct srom_dev *srom = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", srom->page_size); -} - -static struct device_attribute srom_dev_attrs[] = { - __ATTR(total_size, S_IRUGO, total_show, NULL), - __ATTR(sector_size, S_IRUGO, sector_show, NULL), - __ATTR(page_size, S_IRUGO, page_show, NULL), - __ATTR_NULL -}; - -static char *srom_devnode(struct device *dev, mode_t *mode) -{ - *mode = S_IRUGO | S_IWUSR; - return kasprintf(GFP_KERNEL, "srom/%s", dev_name(dev)); -} - -/* - * The fops - */ -static const struct file_operations srom_fops = { - .owner = THIS_MODULE, - .llseek = srom_llseek, - .read = srom_read, - .write = srom_write, - .open = srom_open, - .release = srom_release, -}; - -/** - * srom_setup_minor() - Initialize per-minor information. - * @srom: Per-device SROM state. - * @index: Device to set up. - */ -static int srom_setup_minor(struct srom_dev *srom, int index) -{ - struct device *dev; - int devhdl = srom->hv_devhdl; - - mutex_init(&srom->lock); - - if (_srom_read(devhdl, &srom->total_size, - SROM_TOTAL_SIZE_OFF, sizeof(srom->total_size)) < 0) - return -EIO; - if (_srom_read(devhdl, &srom->sector_size, - SROM_SECTOR_SIZE_OFF, sizeof(srom->sector_size)) < 0) - return -EIO; - if (_srom_read(devhdl, &srom->page_size, - SROM_PAGE_SIZE_OFF, sizeof(srom->page_size)) < 0) - return -EIO; - - dev = device_create(srom_class, &platform_bus, - MKDEV(srom_major, index), srom, "%d", index); - return IS_ERR(dev) ? PTR_ERR(dev) : 0; -} - -/** srom_init() - Initialize the driver's module. */ -static int srom_init(void) -{ - int result, i; - dev_t dev = MKDEV(srom_major, 0); - - /* - * Start with a plausible number of partitions; the krealloc() call - * below will yield about log(srom_devs) additional allocations. - */ - srom_devices = kzalloc(4 * sizeof(struct srom_dev), GFP_KERNEL); - - /* Discover the number of srom partitions. */ - for (i = 0; ; i++) { - int devhdl; - char buf[20]; - struct srom_dev *new_srom_devices = - krealloc(srom_devices, (i+1) * sizeof(struct srom_dev), - GFP_KERNEL | __GFP_ZERO); - if (!new_srom_devices) { - result = -ENOMEM; - goto fail_mem; - } - srom_devices = new_srom_devices; - sprintf(buf, "srom/0/%d", i); - devhdl = hv_dev_open((HV_VirtAddr)buf, 0); - if (devhdl < 0) { - if (devhdl != HV_ENODEV) - pr_notice("srom/%d: hv_dev_open failed: %d.\n", - i, devhdl); - break; - } - srom_devices[i].hv_devhdl = devhdl; - } - srom_devs = i; - - /* Bail out early if we have no partitions at all. */ - if (srom_devs == 0) { - result = -ENODEV; - goto fail_mem; - } - - /* Register our major, and accept a dynamic number. */ - if (srom_major) - result = register_chrdev_region(dev, srom_devs, "srom"); - else { - result = alloc_chrdev_region(&dev, 0, srom_devs, "srom"); - srom_major = MAJOR(dev); - } - if (result < 0) - goto fail_mem; - - /* Register a character device. */ - cdev_init(&srom_cdev, &srom_fops); - srom_cdev.owner = THIS_MODULE; - srom_cdev.ops = &srom_fops; - result = cdev_add(&srom_cdev, dev, srom_devs); - if (result < 0) - goto fail_chrdev; - - /* Create a sysfs class. */ - srom_class = class_create(THIS_MODULE, "srom"); - if (IS_ERR(srom_class)) { - result = PTR_ERR(srom_class); - goto fail_cdev; - } - srom_class->dev_attrs = srom_dev_attrs; - srom_class->devnode = srom_devnode; - - /* Do per-partition initialization */ - for (i = 0; i < srom_devs; i++) { - result = srom_setup_minor(srom_devices + i, i); - if (result < 0) - goto fail_class; - } - - return 0; - -fail_class: - for (i = 0; i < srom_devs; i++) - device_destroy(srom_class, MKDEV(srom_major, i)); - class_destroy(srom_class); -fail_cdev: - cdev_del(&srom_cdev); -fail_chrdev: - unregister_chrdev_region(dev, srom_devs); -fail_mem: - kfree(srom_devices); - return result; -} - -/** srom_cleanup() - Clean up the driver's module. */ -static void srom_cleanup(void) -{ - int i; - for (i = 0; i < srom_devs; i++) - device_destroy(srom_class, MKDEV(srom_major, i)); - class_destroy(srom_class); - cdev_del(&srom_cdev); - unregister_chrdev_region(MKDEV(srom_major, 0), srom_devs); - kfree(srom_devices); -} - -module_init(srom_init); -module_exit(srom_cleanup); diff --git a/trunk/drivers/char/tpm/tpm_tis.c b/trunk/drivers/char/tpm/tpm_tis.c index 3f4051a7c5a7..7fc2f108f490 100644 --- a/trunk/drivers/char/tpm/tpm_tis.c +++ b/trunk/drivers/char/tpm/tpm_tis.c @@ -80,7 +80,7 @@ enum tis_defaults { static LIST_HEAD(tis_chips); static DEFINE_SPINLOCK(tis_lock); -#if defined(CONFIG_PNP) && defined(CONFIG_ACPI) +#ifdef CONFIG_PNP static int is_itpm(struct pnp_dev *dev) { struct acpi_device *acpi = pnp_acpi_device(dev); @@ -93,11 +93,6 @@ static int is_itpm(struct pnp_dev *dev) return 0; } -#else -static inline int is_itpm(struct pnp_dev *dev) -{ - return 0; -} #endif static int check_locality(struct tpm_chip *chip, int l) diff --git a/trunk/drivers/connector/cn_proc.c b/trunk/drivers/connector/cn_proc.c index e55814bc0d06..3ee1fdb31ea7 100644 --- a/trunk/drivers/connector/cn_proc.c +++ b/trunk/drivers/connector/cn_proc.c @@ -57,7 +57,6 @@ void proc_fork_connector(struct task_struct *task) struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; struct timespec ts; - struct task_struct *parent; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -68,11 +67,8 @@ void proc_fork_connector(struct task_struct *task) ktime_get_ts(&ts); /* get high res monotonic timestamp */ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_FORK; - rcu_read_lock(); - parent = rcu_dereference(task->real_parent); - ev->event_data.fork.parent_pid = parent->pid; - ev->event_data.fork.parent_tgid = parent->tgid; - rcu_read_unlock(); + ev->event_data.fork.parent_pid = task->real_parent->pid; + ev->event_data.fork.parent_tgid = task->real_parent->tgid; ev->event_data.fork.child_pid = task->pid; ev->event_data.fork.child_tgid = task->tgid; diff --git a/trunk/drivers/cpuidle/cpuidle.c b/trunk/drivers/cpuidle/cpuidle.c index d4c542372886..bf5092455a8f 100644 --- a/trunk/drivers/cpuidle/cpuidle.c +++ b/trunk/drivers/cpuidle/cpuidle.c @@ -25,19 +25,9 @@ DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices); DEFINE_MUTEX(cpuidle_lock); LIST_HEAD(cpuidle_detected_devices); +static void (*pm_idle_old)(void); static int enabled_devices; -static int off __read_mostly; -static int initialized __read_mostly; - -int cpuidle_disabled(void) -{ - return off; -} -void disable_cpuidle(void) -{ - off = 1; -} #if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT) static void cpuidle_kick_cpus(void) @@ -56,23 +46,25 @@ static int __cpuidle_register_device(struct cpuidle_device *dev); * cpuidle_idle_call - the main idle loop * * NOTE: no locks or semaphores should be used here - * return non-zero on failure */ -int cpuidle_idle_call(void) +static void cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_state *target_state; int next_state; - if (off) - return -ENODEV; - - if (!initialized) - return -ENODEV; - /* check if the device is ready */ - if (!dev || !dev->enabled) - return -EBUSY; + if (!dev || !dev->enabled) { + if (pm_idle_old) + pm_idle_old(); + else +#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE) + default_idle(); +#else + local_irq_enable(); +#endif + return; + } #if 0 /* shows regressions, re-enable for 2.6.29 */ @@ -97,7 +89,7 @@ int cpuidle_idle_call(void) next_state = cpuidle_curr_governor->select(dev); if (need_resched()) { local_irq_enable(); - return 0; + return; } target_state = &dev->states[next_state]; @@ -122,8 +114,6 @@ int cpuidle_idle_call(void) /* give the governor an opportunity to reflect on the outcome */ if (cpuidle_curr_governor->reflect) cpuidle_curr_governor->reflect(dev); - - return 0; } /** @@ -131,10 +121,10 @@ int cpuidle_idle_call(void) */ void cpuidle_install_idle_handler(void) { - if (enabled_devices) { + if (enabled_devices && (pm_idle != cpuidle_idle_call)) { /* Make sure all changes finished before we switch to new idle */ smp_wmb(); - initialized = 1; + pm_idle = cpuidle_idle_call; } } @@ -143,8 +133,8 @@ void cpuidle_install_idle_handler(void) */ void cpuidle_uninstall_idle_handler(void) { - if (enabled_devices) { - initialized = 0; + if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) { + pm_idle = pm_idle_old; cpuidle_kick_cpus(); } } @@ -437,8 +427,7 @@ static int __init cpuidle_init(void) { int ret; - if (cpuidle_disabled()) - return -ENODEV; + pm_idle_old = pm_idle; ret = cpuidle_add_class_sysfs(&cpu_sysdev_class); if (ret) @@ -449,5 +438,4 @@ static int __init cpuidle_init(void) return 0; } -module_param(off, int, 0444); core_initcall(cpuidle_init); diff --git a/trunk/drivers/cpuidle/cpuidle.h b/trunk/drivers/cpuidle/cpuidle.h index 38c3fd8b9d76..33e50d556f17 100644 --- a/trunk/drivers/cpuidle/cpuidle.h +++ b/trunk/drivers/cpuidle/cpuidle.h @@ -13,7 +13,6 @@ extern struct list_head cpuidle_governors; extern struct list_head cpuidle_detected_devices; extern struct mutex cpuidle_lock; extern spinlock_t cpuidle_driver_lock; -extern int cpuidle_disabled(void); /* idle loop */ extern void cpuidle_install_idle_handler(void); diff --git a/trunk/drivers/cpuidle/driver.c b/trunk/drivers/cpuidle/driver.c index 3f7e3cedd133..fd1601e3d125 100644 --- a/trunk/drivers/cpuidle/driver.c +++ b/trunk/drivers/cpuidle/driver.c @@ -26,9 +26,6 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) if (!drv) return -EINVAL; - if (cpuidle_disabled()) - return -ENODEV; - spin_lock(&cpuidle_driver_lock); if (cpuidle_curr_driver) { spin_unlock(&cpuidle_driver_lock); diff --git a/trunk/drivers/cpuidle/governor.c b/trunk/drivers/cpuidle/governor.c index ea2f8e7aa24a..724c164d31c9 100644 --- a/trunk/drivers/cpuidle/governor.c +++ b/trunk/drivers/cpuidle/governor.c @@ -81,9 +81,6 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) if (!gov || !gov->select) return -EINVAL; - if (cpuidle_disabled()) - return -ENODEV; - mutex_lock(&cpuidle_lock); if (__cpuidle_find_governor(gov->name) == NULL) { ret = 0; diff --git a/trunk/drivers/dma/TODO b/trunk/drivers/dma/TODO index 734ed0206cd5..a4af8589330c 100644 --- a/trunk/drivers/dma/TODO +++ b/trunk/drivers/dma/TODO @@ -9,5 +9,6 @@ TODO for slave dma - mxs-dma.c - dw_dmac - intel_mid_dma + - ste_dma40 4. Check other subsystems for dma drivers and merge/move to dmaengine 5. Remove dma_slave_config's dma direction. diff --git a/trunk/drivers/dma/amba-pl08x.c b/trunk/drivers/dma/amba-pl08x.c index 196a7378d332..e6d7228b1479 100644 --- a/trunk/drivers/dma/amba-pl08x.c +++ b/trunk/drivers/dma/amba-pl08x.c @@ -156,10 +156,14 @@ struct pl08x_driver_data { #define PL08X_BOUNDARY_SHIFT (10) /* 1KB 0x400 */ #define PL08X_BOUNDARY_SIZE (1 << PL08X_BOUNDARY_SHIFT) +/* Minimum period between work queue runs */ +#define PL08X_WQ_PERIODMIN 20 + /* Size (bytes) of each LLI buffer allocated for one transfer */ # define PL08X_LLI_TSFR_SIZE 0x2000 /* Maximum times we call dma_pool_alloc on this pool without freeing */ +#define PL08X_MAX_ALLOCS 0x40 #define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli)) #define PL08X_ALIGN 8 @@ -491,10 +495,10 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, struct pl08x_lli_build_data { struct pl08x_txd *txd; + struct pl08x_driver_data *pl08x; struct pl08x_bus_data srcbus; struct pl08x_bus_data dstbus; size_t remainder; - u32 lli_bus; }; /* @@ -547,7 +551,8 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, llis_va[num_llis].src = bd->srcbus.addr; llis_va[num_llis].dst = bd->dstbus.addr; llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); - llis_va[num_llis].lli |= bd->lli_bus; + if (bd->pl08x->lli_buses & PL08X_AHB2) + llis_va[num_llis].lli |= PL080_LLI_LM_AHB2; if (cctl & PL080_CONTROL_SRC_INCR) bd->srcbus.addr += len; @@ -600,9 +605,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, cctl = txd->cctl; bd.txd = txd; + bd.pl08x = pl08x; bd.srcbus.addr = txd->src_addr; bd.dstbus.addr = txd->dst_addr; - bd.lli_bus = (pl08x->lli_buses & PL08X_AHB2) ? PL080_LLI_LM_AHB2 : 0; /* Find maximum width of the source bus */ bd.srcbus.maxwidth = @@ -617,15 +622,25 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* Set up the bus widths to the maximum */ bd.srcbus.buswidth = bd.srcbus.maxwidth; bd.dstbus.buswidth = bd.dstbus.maxwidth; + dev_vdbg(&pl08x->adev->dev, + "%s source bus is %d bytes wide, dest bus is %d bytes wide\n", + __func__, bd.srcbus.buswidth, bd.dstbus.buswidth); + /* * Bytes transferred == tsize * MIN(buswidths), not max(buswidths) */ max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) * PL080_CONTROL_TRANSFER_SIZE_MASK; + dev_vdbg(&pl08x->adev->dev, + "%s max bytes per lli = %zu\n", + __func__, max_bytes_per_lli); /* We need to count this down to zero */ bd.remainder = txd->len; + dev_vdbg(&pl08x->adev->dev, + "%s remainder = %zu\n", + __func__, bd.remainder); /* * Choose bus to align to @@ -634,16 +649,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, */ pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); - dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu llimax=%zu\n", - bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "", - bd.srcbus.buswidth, - bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "", - bd.dstbus.buswidth, - bd.remainder, max_bytes_per_lli); - dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n", - mbus == &bd.srcbus ? "src" : "dst", - sbus == &bd.srcbus ? "src" : "dst"); - if (txd->len < mbus->buswidth) { /* Less than a bus width available - send as single bytes */ while (bd.remainder) { @@ -835,14 +840,15 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, { int i; - dev_vdbg(&pl08x->adev->dev, - "%-3s %-9s %-10s %-10s %-10s %s\n", - "lli", "", "csrc", "cdst", "clli", "cctl"); for (i = 0; i < num_llis; i++) { dev_vdbg(&pl08x->adev->dev, - "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n", - i, &llis_va[i], llis_va[i].src, - llis_va[i].dst, llis_va[i].lli, llis_va[i].cctl + "lli %d @%p: csrc=0x%08x, cdst=0x%08x, cctl=0x%08x, clli=0x%08x\n", + i, + &llis_va[i], + llis_va[i].src, + llis_va[i].dst, + llis_va[i].cctl, + llis_va[i].lli ); } } @@ -1048,105 +1054,64 @@ pl08x_dma_tx_status(struct dma_chan *chan, /* PrimeCell DMA extension */ struct burst_table { - u32 burstwords; + int burstwords; u32 reg; }; static const struct burst_table burst_sizes[] = { { .burstwords = 256, - .reg = PL080_BSIZE_256, + .reg = (PL080_BSIZE_256 << PL080_CONTROL_SB_SIZE_SHIFT) | + (PL080_BSIZE_256 << PL080_CONTROL_DB_SIZE_SHIFT), }, { .burstwords = 128, - .reg = PL080_BSIZE_128, + .reg = (PL080_BSIZE_128 << PL080_CONTROL_SB_SIZE_SHIFT) | + (PL080_BSIZE_128 << PL080_CONTROL_DB_SIZE_SHIFT), }, { .burstwords = 64, - .reg = PL080_BSIZE_64, + .reg = (PL080_BSIZE_64 << PL080_CONTROL_SB_SIZE_SHIFT) | + (PL080_BSIZE_64 << PL080_CONTROL_DB_SIZE_SHIFT), }, { .burstwords = 32, - .reg = PL080_BSIZE_32, + .reg = (PL080_BSIZE_32 << PL080_CONTROL_SB_SIZE_SHIFT) | + (PL080_BSIZE_32 << PL080_CONTROL_DB_SIZE_SHIFT), }, { .burstwords = 16, - .reg = PL080_BSIZE_16, + .reg = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT) | + (PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT), }, { .burstwords = 8, - .reg = PL080_BSIZE_8, + .reg = (PL080_BSIZE_8 << PL080_CONTROL_SB_SIZE_SHIFT) | + (PL080_BSIZE_8 << PL080_CONTROL_DB_SIZE_SHIFT), }, { .burstwords = 4, - .reg = PL080_BSIZE_4, + .reg = (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT) | + (PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT), }, { - .burstwords = 0, - .reg = PL080_BSIZE_1, + .burstwords = 1, + .reg = (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) | + (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT), }, }; -/* - * Given the source and destination available bus masks, select which - * will be routed to each port. We try to have source and destination - * on separate ports, but always respect the allowable settings. - */ -static u32 pl08x_select_bus(u8 src, u8 dst) -{ - u32 cctl = 0; - - if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1))) - cctl |= PL080_CONTROL_DST_AHB2; - if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2))) - cctl |= PL080_CONTROL_SRC_AHB2; - - return cctl; -} - -static u32 pl08x_cctl(u32 cctl) -{ - cctl &= ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 | - PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR | - PL080_CONTROL_PROT_MASK); - - /* Access the cell in privileged mode, non-bufferable, non-cacheable */ - return cctl | PL080_CONTROL_PROT_SYS; -} - -static u32 pl08x_width(enum dma_slave_buswidth width) -{ - switch (width) { - case DMA_SLAVE_BUSWIDTH_1_BYTE: - return PL080_WIDTH_8BIT; - case DMA_SLAVE_BUSWIDTH_2_BYTES: - return PL080_WIDTH_16BIT; - case DMA_SLAVE_BUSWIDTH_4_BYTES: - return PL080_WIDTH_32BIT; - default: - return ~0; - } -} - -static u32 pl08x_burst(u32 maxburst) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(burst_sizes); i++) - if (burst_sizes[i].burstwords <= maxburst) - break; - - return burst_sizes[i].reg; -} - static int dma_set_runtime_config(struct dma_chan *chan, struct dma_slave_config *config) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; + struct pl08x_channel_data *cd = plchan->cd; enum dma_slave_buswidth addr_width; - u32 width, burst, maxburst; + dma_addr_t addr; + u32 maxburst; u32 cctl = 0; + int i; if (!plchan->slave) return -EINVAL; @@ -1154,9 +1119,11 @@ static int dma_set_runtime_config(struct dma_chan *chan, /* Transfer direction */ plchan->runtime_direction = config->direction; if (config->direction == DMA_TO_DEVICE) { + addr = config->dst_addr; addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; } else if (config->direction == DMA_FROM_DEVICE) { + addr = config->src_addr; addr_width = config->src_addr_width; maxburst = config->src_maxburst; } else { @@ -1165,40 +1132,46 @@ static int dma_set_runtime_config(struct dma_chan *chan, return -EINVAL; } - width = pl08x_width(addr_width); - if (width == ~0) { + switch (addr_width) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + cctl |= (PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT) | + (PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT); + break; + case DMA_SLAVE_BUSWIDTH_2_BYTES: + cctl |= (PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT) | + (PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT); + break; + case DMA_SLAVE_BUSWIDTH_4_BYTES: + cctl |= (PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT) | + (PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT); + break; + default: dev_err(&pl08x->adev->dev, "bad runtime_config: alien address width\n"); return -EINVAL; } - cctl |= width << PL080_CONTROL_SWIDTH_SHIFT; - cctl |= width << PL080_CONTROL_DWIDTH_SHIFT; - /* + * Now decide on a maxburst: * If this channel will only request single transfers, set this * down to ONE element. Also select one element if no maxburst * is specified. */ - if (plchan->cd->single) - maxburst = 1; - - burst = pl08x_burst(maxburst); - cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT; - cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT; - - if (plchan->runtime_direction == DMA_FROM_DEVICE) { - plchan->src_addr = config->src_addr; - plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR | - pl08x_select_bus(plchan->cd->periph_buses, - pl08x->mem_buses); + if (plchan->cd->single || maxburst == 0) { + cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) | + (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT); } else { - plchan->dst_addr = config->dst_addr; - plchan->dst_cctl = pl08x_cctl(cctl) | PL080_CONTROL_SRC_INCR | - pl08x_select_bus(pl08x->mem_buses, - plchan->cd->periph_buses); + for (i = 0; i < ARRAY_SIZE(burst_sizes); i++) + if (burst_sizes[i].burstwords <= maxburst) + break; + cctl |= burst_sizes[i].reg; } + plchan->runtime_addr = addr; + + /* Modify the default channel data to fit PrimeCell request */ + cd->cctl = cctl; + dev_dbg(&pl08x->adev->dev, "configured channel %s (%s) for %s, data width %d, " "maxburst %d words, LE, CCTL=0x%08x\n", @@ -1297,6 +1270,23 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, return 0; } +/* + * Given the source and destination available bus masks, select which + * will be routed to each port. We try to have source and destination + * on separate ports, but always respect the allowable settings. + */ +static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst) +{ + u32 cctl = 0; + + if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1))) + cctl |= PL080_CONTROL_DST_AHB2; + if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2))) + cctl |= PL080_CONTROL_SRC_AHB2; + + return cctl; +} + static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, unsigned long flags) { @@ -1348,8 +1338,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; if (pl08x->vd->dualmaster) - txd->cctl |= pl08x_select_bus(pl08x->mem_buses, - pl08x->mem_buses); + txd->cctl |= pl08x_select_bus(pl08x, + pl08x->mem_buses, pl08x->mem_buses); ret = pl08x_prep_channel_resources(plchan, txd); if (ret) @@ -1366,6 +1356,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; + u8 src_buses, dst_buses; int ret; /* @@ -1399,22 +1390,42 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( txd->direction = direction; txd->len = sgl->length; + txd->cctl = plchan->cd->cctl & + ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 | + PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR | + PL080_CONTROL_PROT_MASK); + + /* Access the cell in privileged mode, non-bufferable, non-cacheable */ + txd->cctl |= PL080_CONTROL_PROT_SYS; + if (direction == DMA_TO_DEVICE) { txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; - txd->cctl = plchan->dst_cctl; + txd->cctl |= PL080_CONTROL_SRC_INCR; txd->src_addr = sgl->dma_address; - txd->dst_addr = plchan->dst_addr; + if (plchan->runtime_addr) + txd->dst_addr = plchan->runtime_addr; + else + txd->dst_addr = plchan->cd->addr; + src_buses = pl08x->mem_buses; + dst_buses = plchan->cd->periph_buses; } else if (direction == DMA_FROM_DEVICE) { txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; - txd->cctl = plchan->src_cctl; - txd->src_addr = plchan->src_addr; + txd->cctl |= PL080_CONTROL_DST_INCR; + if (plchan->runtime_addr) + txd->src_addr = plchan->runtime_addr; + else + txd->src_addr = plchan->cd->addr; txd->dst_addr = sgl->dma_address; + src_buses = plchan->cd->periph_buses; + dst_buses = pl08x->mem_buses; } else { dev_err(&pl08x->adev->dev, "%s direction unsupported\n", __func__); return NULL; } + txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses); + ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; @@ -1665,20 +1676,6 @@ static irqreturn_t pl08x_irq(int irq, void *dev) return mask ? IRQ_HANDLED : IRQ_NONE; } -static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan) -{ - u32 cctl = pl08x_cctl(chan->cd->cctl); - - chan->slave = true; - chan->name = chan->cd->bus_id; - chan->src_addr = chan->cd->addr; - chan->dst_addr = chan->cd->addr; - chan->src_cctl = cctl | PL080_CONTROL_DST_INCR | - pl08x_select_bus(chan->cd->periph_buses, chan->host->mem_buses); - chan->dst_cctl = cctl | PL080_CONTROL_SRC_INCR | - pl08x_select_bus(chan->host->mem_buses, chan->cd->periph_buses); -} - /* * Initialise the DMAC memcpy/slave channels. * Make a local wrapper to hold required data @@ -1710,8 +1707,9 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, chan->state = PL08X_CHAN_IDLE; if (slave) { + chan->slave = true; + chan->name = pl08x->pd->slave_channels[i].bus_id; chan->cd = &pl08x->pd->slave_channels[i]; - pl08x_dma_slave_init(chan); } else { chan->cd = &pl08x->pd->memcpy_channel; chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i); diff --git a/trunk/drivers/dma/at_hdmac.c b/trunk/drivers/dma/at_hdmac.c index 6a483eac7b3f..36144f88d718 100644 --- a/trunk/drivers/dma/at_hdmac.c +++ b/trunk/drivers/dma/at_hdmac.c @@ -1216,7 +1216,7 @@ static int __init at_dma_probe(struct platform_device *pdev) atdma->dma_common.cap_mask = pdata->cap_mask; atdma->all_chan_mask = (1 << pdata->nr_channels) - 1; - size = resource_size(io); + size = io->end - io->start + 1; if (!request_mem_region(io->start, size, pdev->dev.driver->name)) { err = -EBUSY; goto err_kfree; @@ -1362,7 +1362,7 @@ static int __exit at_dma_remove(struct platform_device *pdev) atdma->regs = NULL; io = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(io->start, resource_size(io)); + release_mem_region(io->start, io->end - io->start + 1); kfree(atdma); diff --git a/trunk/drivers/dma/coh901318.c b/trunk/drivers/dma/coh901318.c index 4234f416ef11..a92d95eac86b 100644 --- a/trunk/drivers/dma/coh901318.c +++ b/trunk/drivers/dma/coh901318.c @@ -41,8 +41,6 @@ struct coh901318_desc { struct coh901318_lli *lli; enum dma_data_direction dir; unsigned long flags; - u32 head_config; - u32 head_ctrl; }; struct coh901318_base { @@ -663,9 +661,6 @@ static struct coh901318_desc *coh901318_queue_start(struct coh901318_chan *cohc) coh901318_desc_submit(cohc, cohd); - /* Program the transaction head */ - coh901318_set_conf(cohc, cohd->head_config); - coh901318_set_ctrl(cohc, cohd->head_ctrl); coh901318_prep_linked_list(cohc, cohd->lli); /* start dma job on this channel */ @@ -1096,6 +1091,8 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, } else goto err_direction; + coh901318_set_conf(cohc, config); + /* The dma only supports transmitting packages up to * MAX_DMA_PACKET_SIZE. Calculate to total number of * dma elemts required to send the entire sg list @@ -1132,18 +1129,16 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (ret) goto err_lli_fill; + /* + * Set the default ctrl for the channel to the one from the lli, + * things may have changed due to odd buffer alignment etc. + */ + coh901318_set_ctrl(cohc, lli->control); COH_DBG(coh901318_list_print(cohc, lli)); /* Pick a descriptor to handle this transfer */ cohd = coh901318_desc_get(cohc); - cohd->head_config = config; - /* - * Set the default head ctrl for the channel to the one from the - * lli, things may have changed due to odd buffer alignment - * etc. - */ - cohd->head_ctrl = lli->control; cohd->dir = direction; cohd->flags = flags; cohd->desc.tx_submit = coh901318_tx_submit; diff --git a/trunk/drivers/dma/dmaengine.c b/trunk/drivers/dma/dmaengine.c index b48967b499da..48694c34d96b 100644 --- a/trunk/drivers/dma/dmaengine.c +++ b/trunk/drivers/dma/dmaengine.c @@ -62,9 +62,9 @@ #include static DEFINE_MUTEX(dma_list_mutex); -static DEFINE_IDR(dma_idr); static LIST_HEAD(dma_device_list); static long dmaengine_ref_count; +static struct idr dma_idr; /* --- sysfs implementation --- */ @@ -510,8 +510,8 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v dma_chan_name(chan)); list_del_rcu(&device->global_node); } else if (err) - pr_debug("dmaengine: failed to get %s: (%d)\n", - dma_chan_name(chan), err); + pr_err("dmaengine: failed to get %s: (%d)\n", + dma_chan_name(chan), err); else break; if (--device->privatecnt == 0) @@ -1050,6 +1050,8 @@ EXPORT_SYMBOL_GPL(dma_run_dependencies); static int __init dma_bus_init(void) { + idr_init(&dma_idr); + mutex_init(&dma_list_mutex); return class_register(&dma_devclass); } arch_initcall(dma_bus_init); diff --git a/trunk/drivers/dma/ep93xx_dma.c b/trunk/drivers/dma/ep93xx_dma.c index 5d7a49bd7c26..0766c1e53b1d 100644 --- a/trunk/drivers/dma/ep93xx_dma.c +++ b/trunk/drivers/dma/ep93xx_dma.c @@ -902,7 +902,7 @@ static void ep93xx_dma_free_chan_resources(struct dma_chan *chan) * * Returns a valid DMA descriptor or %NULL in case of failure. */ -static struct dma_async_tx_descriptor * +struct dma_async_tx_descriptor * ep93xx_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, size_t len, unsigned long flags) { diff --git a/trunk/drivers/dma/imx-sdma.c b/trunk/drivers/dma/imx-sdma.c index 7bd7e98548cd..1eb60ded2f0d 100644 --- a/trunk/drivers/dma/imx-sdma.c +++ b/trunk/drivers/dma/imx-sdma.c @@ -1305,10 +1305,8 @@ static int __init sdma_probe(struct platform_device *pdev) goto err_request_irq; sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL); - if (!sdma->script_addrs) { - ret = -ENOMEM; + if (!sdma->script_addrs) goto err_alloc; - } if (of_id) pdev->id_entry = of_id->data; diff --git a/trunk/drivers/dma/intel_mid_dma.c b/trunk/drivers/dma/intel_mid_dma.c index 8a3fdd87db97..f653517ef744 100644 --- a/trunk/drivers/dma/intel_mid_dma.c +++ b/trunk/drivers/dma/intel_mid_dma.c @@ -1351,6 +1351,7 @@ int dma_suspend(struct pci_dev *pci, pm_message_t state) return -EAGAIN; } device->state = SUSPENDED; + pci_set_drvdata(pci, device); pci_save_state(pci); pci_disable_device(pci); pci_set_power_state(pci, PCI_D3hot); @@ -1379,6 +1380,7 @@ int dma_resume(struct pci_dev *pci) } device->state = RUNNING; iowrite32(REG_BIT0, device->dma_base + DMA_CFG); + pci_set_drvdata(pci, device); return 0; } diff --git a/trunk/drivers/dma/ioat/dma_v3.c b/trunk/drivers/dma/ioat/dma_v3.c index f519c93a61e7..d845dc4b7103 100644 --- a/trunk/drivers/dma/ioat/dma_v3.c +++ b/trunk/drivers/dma/ioat/dma_v3.c @@ -73,10 +73,10 @@ /* provide a lookup table for setting the source address in the base or * extended descriptor of an xor or pq descriptor */ -static const u8 xor_idx_to_desc = 0xe0; -static const u8 xor_idx_to_field[] = { 1, 4, 5, 6, 7, 0, 1, 2 }; -static const u8 pq_idx_to_desc = 0xf8; -static const u8 pq_idx_to_field[] = { 1, 4, 5, 0, 1, 2, 4, 5 }; +static const u8 xor_idx_to_desc __read_mostly = 0xd0; +static const u8 xor_idx_to_field[] __read_mostly = { 1, 4, 5, 6, 7, 0, 1, 2 }; +static const u8 pq_idx_to_desc __read_mostly = 0xf8; +static const u8 pq_idx_to_field[] __read_mostly = { 1, 4, 5, 0, 1, 2, 4, 5 }; static dma_addr_t xor_get_src(struct ioat_raw_descriptor *descs[2], int idx) { diff --git a/trunk/drivers/dma/ioat/pci.c b/trunk/drivers/dma/ioat/pci.c index 5e3a40f79945..fab37d1cf48d 100644 --- a/trunk/drivers/dma/ioat/pci.c +++ b/trunk/drivers/dma/ioat/pci.c @@ -72,17 +72,6 @@ static struct pci_device_id ioat_pci_tbl[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF8) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF9) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB0) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB1) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB2) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB3) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB4) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB5) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB6) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB7) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB8) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB9) }, - { 0, } }; MODULE_DEVICE_TABLE(pci, ioat_pci_tbl); diff --git a/trunk/drivers/dma/ipu/ipu_idmac.c b/trunk/drivers/dma/ipu/ipu_idmac.c index 6815905a772f..fd7d2b308cf2 100644 --- a/trunk/drivers/dma/ipu/ipu_idmac.c +++ b/trunk/drivers/dma/ipu/ipu_idmac.c @@ -1706,14 +1706,16 @@ static int __init ipu_probe(struct platform_device *pdev) ipu_data.irq_fn, ipu_data.irq_err, ipu_data.irq_base); /* Remap IPU common registers */ - ipu_data.reg_ipu = ioremap(mem_ipu->start, resource_size(mem_ipu)); + ipu_data.reg_ipu = ioremap(mem_ipu->start, + mem_ipu->end - mem_ipu->start + 1); if (!ipu_data.reg_ipu) { ret = -ENOMEM; goto err_ioremap_ipu; } /* Remap Image Converter and Image DMA Controller registers */ - ipu_data.reg_ic = ioremap(mem_ic->start, resource_size(mem_ic)); + ipu_data.reg_ic = ioremap(mem_ic->start, + mem_ic->end - mem_ic->start + 1); if (!ipu_data.reg_ic) { ret = -ENOMEM; goto err_ioremap_ic; diff --git a/trunk/drivers/dma/mv_xor.c b/trunk/drivers/dma/mv_xor.c index 9a353c2216d0..06f9f27dbe7c 100644 --- a/trunk/drivers/dma/mv_xor.c +++ b/trunk/drivers/dma/mv_xor.c @@ -1304,8 +1304,7 @@ static int mv_xor_shared_probe(struct platform_device *pdev) if (!res) return -ENODEV; - msp->xor_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); + msp->xor_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!msp->xor_base) return -EBUSY; diff --git a/trunk/drivers/dma/mxs-dma.c b/trunk/drivers/dma/mxs-dma.c index be641cbd36fc..88aad4f54002 100644 --- a/trunk/drivers/dma/mxs-dma.c +++ b/trunk/drivers/dma/mxs-dma.c @@ -327,12 +327,10 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan) memset(mxs_chan->ccw, 0, PAGE_SIZE); - if (mxs_chan->chan_irq != NO_IRQ) { - ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler, - 0, "mxs-dma", mxs_dma); - if (ret) - goto err_irq; - } + ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler, + 0, "mxs-dma", mxs_dma); + if (ret) + goto err_irq; ret = clk_enable(mxs_dma->clk); if (ret) @@ -537,7 +535,6 @@ static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, switch (cmd) { case DMA_TERMINATE_ALL: mxs_dma_disable_chan(mxs_chan); - mxs_dma_reset_chan(mxs_chan); break; case DMA_PAUSE: mxs_dma_pause_chan(mxs_chan); @@ -710,8 +707,6 @@ static struct platform_device_id mxs_dma_type[] = { }, { .name = "mxs-dma-apbx", .driver_data = MXS_DMA_APBX, - }, { - /* end of list */ } }; diff --git a/trunk/drivers/dma/pch_dma.c b/trunk/drivers/dma/pch_dma.c index 1ac8d4b580b7..ff5b38f9d45b 100644 --- a/trunk/drivers/dma/pch_dma.c +++ b/trunk/drivers/dma/pch_dma.c @@ -45,8 +45,7 @@ #define DMA_STATUS_MASK_BITS 0x3 #define DMA_STATUS_SHIFT_BITS 16 #define DMA_STATUS_IRQ(x) (0x1 << (x)) -#define DMA_STATUS0_ERR(x) (0x1 << ((x) + 8)) -#define DMA_STATUS2_ERR(x) (0x1 << (x)) +#define DMA_STATUS_ERR(x) (0x1 << ((x) + 8)) #define DMA_DESC_WIDTH_SHIFT_BITS 12 #define DMA_DESC_WIDTH_1_BYTE (0x3 << DMA_DESC_WIDTH_SHIFT_BITS) @@ -62,9 +61,6 @@ #define MAX_CHAN_NR 8 -#define DMA_MASK_CTL0_MODE 0x33333333 -#define DMA_MASK_CTL2_MODE 0x00003333 - static unsigned int init_nr_desc_per_channel = 64; module_param(init_nr_desc_per_channel, uint, 0644); MODULE_PARM_DESC(init_nr_desc_per_channel, @@ -137,7 +133,6 @@ struct pch_dma { #define PCH_DMA_CTL3 0x0C #define PCH_DMA_STS0 0x10 #define PCH_DMA_STS1 0x14 -#define PCH_DMA_STS2 0x18 #define dma_readl(pd, name) \ readl((pd)->membase + PCH_DMA_##name) @@ -188,19 +183,13 @@ static void pdc_enable_irq(struct dma_chan *chan, int enable) { struct pch_dma *pd = to_pd(chan->device); u32 val; - int pos; - - if (chan->chan_id < 8) - pos = chan->chan_id; - else - pos = chan->chan_id + 8; val = dma_readl(pd, CTL2); if (enable) - val |= 0x1 << pos; + val |= 0x1 << chan->chan_id; else - val &= ~(0x1 << pos); + val &= ~(0x1 << chan->chan_id); dma_writel(pd, CTL2, val); @@ -213,17 +202,10 @@ static void pdc_set_dir(struct dma_chan *chan) struct pch_dma_chan *pd_chan = to_pd_chan(chan); struct pch_dma *pd = to_pd(chan->device); u32 val; - u32 mask_mode; - u32 mask_ctl; if (chan->chan_id < 8) { val = dma_readl(pd, CTL0); - mask_mode = DMA_CTL0_MODE_MASK_BITS << - (DMA_CTL0_BITS_PER_CH * chan->chan_id); - mask_ctl = DMA_MASK_CTL0_MODE & ~(DMA_CTL0_MODE_MASK_BITS << - (DMA_CTL0_BITS_PER_CH * chan->chan_id)); - val &= mask_mode; if (pd_chan->dir == DMA_TO_DEVICE) val |= 0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id + DMA_CTL0_DIR_SHIFT_BITS); @@ -231,24 +213,18 @@ static void pdc_set_dir(struct dma_chan *chan) val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id + DMA_CTL0_DIR_SHIFT_BITS)); - val |= mask_ctl; dma_writel(pd, CTL0, val); } else { int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */ val = dma_readl(pd, CTL3); - mask_mode = DMA_CTL0_MODE_MASK_BITS << - (DMA_CTL0_BITS_PER_CH * ch); - mask_ctl = DMA_MASK_CTL2_MODE & ~(DMA_CTL0_MODE_MASK_BITS << - (DMA_CTL0_BITS_PER_CH * ch)); - val &= mask_mode; if (pd_chan->dir == DMA_TO_DEVICE) val |= 0x1 << (DMA_CTL0_BITS_PER_CH * ch + DMA_CTL0_DIR_SHIFT_BITS); else val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * ch + DMA_CTL0_DIR_SHIFT_BITS)); - val |= mask_ctl; + dma_writel(pd, CTL3, val); } @@ -260,37 +236,33 @@ static void pdc_set_mode(struct dma_chan *chan, u32 mode) { struct pch_dma *pd = to_pd(chan->device); u32 val; - u32 mask_ctl; - u32 mask_dir; if (chan->chan_id < 8) { - mask_ctl = DMA_MASK_CTL0_MODE & ~(DMA_CTL0_MODE_MASK_BITS << - (DMA_CTL0_BITS_PER_CH * chan->chan_id)); - mask_dir = 1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +\ - DMA_CTL0_DIR_SHIFT_BITS); val = dma_readl(pd, CTL0); - val &= mask_dir; + + val &= ~(DMA_CTL0_MODE_MASK_BITS << + (DMA_CTL0_BITS_PER_CH * chan->chan_id)); val |= mode << (DMA_CTL0_BITS_PER_CH * chan->chan_id); - val |= mask_ctl; + dma_writel(pd, CTL0, val); } else { int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */ - mask_ctl = DMA_MASK_CTL2_MODE & ~(DMA_CTL0_MODE_MASK_BITS << - (DMA_CTL0_BITS_PER_CH * ch)); - mask_dir = 1 << (DMA_CTL0_BITS_PER_CH * ch +\ - DMA_CTL0_DIR_SHIFT_BITS); + val = dma_readl(pd, CTL3); - val &= mask_dir; + + val &= ~(DMA_CTL0_MODE_MASK_BITS << + (DMA_CTL0_BITS_PER_CH * ch)); val |= mode << (DMA_CTL0_BITS_PER_CH * ch); - val |= mask_ctl; + dma_writel(pd, CTL3, val); + } dev_dbg(chan2dev(chan), "pdc_set_mode: chan %d -> %x\n", chan->chan_id, val); } -static u32 pdc_get_status0(struct pch_dma_chan *pd_chan) +static u32 pdc_get_status(struct pch_dma_chan *pd_chan) { struct pch_dma *pd = to_pd(pd_chan->chan.device); u32 val; @@ -300,27 +272,9 @@ static u32 pdc_get_status0(struct pch_dma_chan *pd_chan) DMA_STATUS_BITS_PER_CH * pd_chan->chan.chan_id)); } -static u32 pdc_get_status2(struct pch_dma_chan *pd_chan) -{ - struct pch_dma *pd = to_pd(pd_chan->chan.device); - u32 val; - - val = dma_readl(pd, STS2); - return DMA_STATUS_MASK_BITS & (val >> (DMA_STATUS_SHIFT_BITS + - DMA_STATUS_BITS_PER_CH * (pd_chan->chan.chan_id - 8))); -} - static bool pdc_is_idle(struct pch_dma_chan *pd_chan) { - u32 sts; - - if (pd_chan->chan.chan_id < 8) - sts = pdc_get_status0(pd_chan); - else - sts = pdc_get_status2(pd_chan); - - - if (sts == DMA_STATUS_IDLE) + if (pdc_get_status(pd_chan) == DMA_STATUS_IDLE) return true; else return false; @@ -541,11 +495,11 @@ static int pd_alloc_chan_resources(struct dma_chan *chan) list_add_tail(&desc->desc_node, &tmp_list); } - spin_lock_irq(&pd_chan->lock); + spin_lock_bh(&pd_chan->lock); list_splice(&tmp_list, &pd_chan->free_list); pd_chan->descs_allocated = i; pd_chan->completed_cookie = chan->cookie = 1; - spin_unlock_irq(&pd_chan->lock); + spin_unlock_bh(&pd_chan->lock); pdc_enable_irq(chan, 1); @@ -563,10 +517,10 @@ static void pd_free_chan_resources(struct dma_chan *chan) BUG_ON(!list_empty(&pd_chan->active_list)); BUG_ON(!list_empty(&pd_chan->queue)); - spin_lock_irq(&pd_chan->lock); + spin_lock_bh(&pd_chan->lock); list_splice_init(&pd_chan->free_list, &tmp_list); pd_chan->descs_allocated = 0; - spin_unlock_irq(&pd_chan->lock); + spin_unlock_bh(&pd_chan->lock); list_for_each_entry_safe(desc, _d, &tmp_list, desc_node) pci_pool_free(pd->pool, desc, desc->txd.phys); @@ -582,10 +536,10 @@ static enum dma_status pd_tx_status(struct dma_chan *chan, dma_cookie_t cookie, dma_cookie_t last_completed; int ret; - spin_lock_irq(&pd_chan->lock); + spin_lock_bh(&pd_chan->lock); last_completed = pd_chan->completed_cookie; last_used = chan->cookie; - spin_unlock_irq(&pd_chan->lock); + spin_unlock_bh(&pd_chan->lock); ret = dma_async_is_complete(cookie, last_completed, last_used); @@ -700,7 +654,7 @@ static int pd_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, if (cmd != DMA_TERMINATE_ALL) return -ENXIO; - spin_lock_irq(&pd_chan->lock); + spin_lock_bh(&pd_chan->lock); pdc_set_mode(&pd_chan->chan, DMA_CTL0_DISABLE); @@ -710,7 +664,7 @@ static int pd_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, list_for_each_entry_safe(desc, _d, &list, desc_node) pdc_chain_complete(pd_chan, desc); - spin_unlock_irq(&pd_chan->lock); + spin_unlock_bh(&pd_chan->lock); return 0; } @@ -739,45 +693,30 @@ static irqreturn_t pd_irq(int irq, void *devid) struct pch_dma *pd = (struct pch_dma *)devid; struct pch_dma_chan *pd_chan; u32 sts0; - u32 sts2; int i; - int ret0 = IRQ_NONE; - int ret2 = IRQ_NONE; + int ret = IRQ_NONE; sts0 = dma_readl(pd, STS0); - sts2 = dma_readl(pd, STS2); dev_dbg(pd->dma.dev, "pd_irq sts0: %x\n", sts0); for (i = 0; i < pd->dma.chancnt; i++) { pd_chan = &pd->channels[i]; - if (i < 8) { - if (sts0 & DMA_STATUS_IRQ(i)) { - if (sts0 & DMA_STATUS0_ERR(i)) - set_bit(0, &pd_chan->err_status); - - tasklet_schedule(&pd_chan->tasklet); - ret0 = IRQ_HANDLED; - } - } else { - if (sts2 & DMA_STATUS_IRQ(i - 8)) { - if (sts2 & DMA_STATUS2_ERR(i)) - set_bit(0, &pd_chan->err_status); + if (sts0 & DMA_STATUS_IRQ(i)) { + if (sts0 & DMA_STATUS_ERR(i)) + set_bit(0, &pd_chan->err_status); - tasklet_schedule(&pd_chan->tasklet); - ret2 = IRQ_HANDLED; - } + tasklet_schedule(&pd_chan->tasklet); + ret = IRQ_HANDLED; } + } /* clear interrupt bits in status register */ - if (ret0) - dma_writel(pd, STS0, sts0); - if (ret2) - dma_writel(pd, STS2, sts2); + dma_writel(pd, STS0, sts0); - return ret0 | ret2; + return ret; } #ifdef CONFIG_PM diff --git a/trunk/drivers/dma/pl330.c b/trunk/drivers/dma/pl330.c index 00eee59e8b33..6abe1ec1f2ce 100644 --- a/trunk/drivers/dma/pl330.c +++ b/trunk/drivers/dma/pl330.c @@ -82,7 +82,7 @@ struct dma_pl330_dmac { spinlock_t pool_lock; /* Peripheral channels connected to this DMAC */ - struct dma_pl330_chan *peripherals; /* keep at end */ + struct dma_pl330_chan peripherals[0]; /* keep at end */ }; struct dma_pl330_desc { @@ -451,13 +451,8 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) desc->txd.cookie = 0; async_tx_ack(&desc->txd); - if (peri) { - desc->req.rqtype = peri->rqtype; - desc->req.peri = peri->peri_id; - } else { - desc->req.rqtype = MEMTOMEM; - desc->req.peri = 0; - } + desc->req.rqtype = peri->rqtype; + desc->req.peri = peri->peri_id; dma_async_tx_descriptor_init(&desc->txd, &pch->chan); @@ -534,10 +529,10 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, struct pl330_info *pi; int burst; - if (unlikely(!pch || !len)) + if (unlikely(!pch || !len || !peri)) return NULL; - if (peri && peri->rqtype != MEMTOMEM) + if (peri->rqtype != MEMTOMEM) return NULL; pi = &pch->dmac->pif; @@ -582,7 +577,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, int i, burst_size; dma_addr_t addr; - if (unlikely(!pch || !sgl || !sg_len || !peri)) + if (unlikely(!pch || !sgl || !sg_len)) return NULL; /* Make sure the direction is consistent */ @@ -671,12 +666,17 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) struct dma_device *pd; struct resource *res; int i, ret, irq; - int num_chan; pdat = adev->dev.platform_data; + if (!pdat || !pdat->nr_valid_peri) { + dev_err(&adev->dev, "platform data missing\n"); + return -ENODEV; + } + /* Allocate a new DMAC and its Channels */ - pdmac = kzalloc(sizeof(*pdmac), GFP_KERNEL); + pdmac = kzalloc(pdat->nr_valid_peri * sizeof(*pch) + + sizeof(*pdmac), GFP_KERNEL); if (!pdmac) { dev_err(&adev->dev, "unable to allocate mem\n"); return -ENOMEM; @@ -685,7 +685,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pi = &pdmac->pif; pi->dev = &adev->dev; pi->pl330_data = NULL; - pi->mcbufsz = pdat ? pdat->mcbuf_sz : 0; + pi->mcbufsz = pdat->mcbuf_sz; res = &adev->res; request_mem_region(res->start, resource_size(res), "dma-pl330"); @@ -717,35 +717,27 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) INIT_LIST_HEAD(&pd->channels); /* Initialize channel parameters */ - num_chan = max(pdat ? pdat->nr_valid_peri : 0, (u8)pi->pcfg.num_chan); - pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); - - for (i = 0; i < num_chan; i++) { + for (i = 0; i < pdat->nr_valid_peri; i++) { + struct dma_pl330_peri *peri = &pdat->peri[i]; pch = &pdmac->peripherals[i]; - if (pdat) { - struct dma_pl330_peri *peri = &pdat->peri[i]; - - switch (peri->rqtype) { - case MEMTOMEM: - dma_cap_set(DMA_MEMCPY, pd->cap_mask); - break; - case MEMTODEV: - case DEVTOMEM: - dma_cap_set(DMA_SLAVE, pd->cap_mask); - break; - default: - dev_err(&adev->dev, "DEVTODEV Not Supported\n"); - continue; - } - pch->chan.private = peri; - } else { + + switch (peri->rqtype) { + case MEMTOMEM: dma_cap_set(DMA_MEMCPY, pd->cap_mask); - pch->chan.private = NULL; + break; + case MEMTODEV: + case DEVTOMEM: + dma_cap_set(DMA_SLAVE, pd->cap_mask); + break; + default: + dev_err(&adev->dev, "DEVTODEV Not Supported\n"); + continue; } INIT_LIST_HEAD(&pch->work_list); spin_lock_init(&pch->lock); pch->pl330_chid = NULL; + pch->chan.private = peri; pch->chan.device = pd; pch->chan.chan_id = i; pch->dmac = pdmac; diff --git a/trunk/drivers/dma/ste_dma40.c b/trunk/drivers/dma/ste_dma40.c index cd3a7c726bf8..29d1addbe0cf 100644 --- a/trunk/drivers/dma/ste_dma40.c +++ b/trunk/drivers/dma/ste_dma40.c @@ -14,7 +14,6 @@ #include #include #include -#include #include @@ -46,6 +45,9 @@ #define D40_ALLOC_PHY (1 << 30) #define D40_ALLOC_LOG_FREE 0 +/* Hardware designer of the block */ +#define D40_HW_DESIGNER 0x8 + /** * enum 40_command - The different commands and/or statuses. * @@ -184,8 +186,6 @@ struct d40_base; * @log_def: Default logical channel settings. * @lcla: Space for one dst src pair for logical channel transfers. * @lcpa: Pointer to dst and src lcpa settings. - * @runtime_addr: runtime configured address. - * @runtime_direction: runtime configured direction. * * This struct can either "be" a logical or a physical channel. */ @@ -200,7 +200,6 @@ struct d40_chan { struct dma_chan chan; struct tasklet_struct tasklet; struct list_head client; - struct list_head pending_queue; struct list_head active; struct list_head queue; struct stedma40_chan_cfg dma_cfg; @@ -646,20 +645,7 @@ static struct d40_desc *d40_first_active_get(struct d40_chan *d40c) static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc) { - list_add_tail(&desc->node, &d40c->pending_queue); -} - -static struct d40_desc *d40_first_pending(struct d40_chan *d40c) -{ - struct d40_desc *d; - - if (list_empty(&d40c->pending_queue)) - return NULL; - - d = list_first_entry(&d40c->pending_queue, - struct d40_desc, - node); - return d; + list_add_tail(&desc->node, &d40c->queue); } static struct d40_desc *d40_first_queued(struct d40_chan *d40c) @@ -816,11 +802,6 @@ static void d40_term_all(struct d40_chan *d40c) d40_desc_free(d40c, d40d); } - /* Release pending descriptors */ - while ((d40d = d40_first_pending(d40c))) { - d40_desc_remove(d40d); - d40_desc_free(d40c, d40d); - } d40c->pending_tx = 0; d40c->busy = false; @@ -2111,7 +2092,7 @@ dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, struct scatterlist *sg; int i; - sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_NOWAIT); + sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_KERNEL); for (i = 0; i < periods; i++) { sg_dma_address(&sg[i]) = dma_addr; sg_dma_len(&sg[i]) = period_len; @@ -2171,87 +2152,24 @@ static void d40_issue_pending(struct dma_chan *chan) spin_lock_irqsave(&d40c->lock, flags); - list_splice_tail_init(&d40c->pending_queue, &d40c->queue); - - /* Busy means that queued jobs are already being processed */ + /* Busy means that pending jobs are already being processed */ if (!d40c->busy) (void) d40_queue_start(d40c); spin_unlock_irqrestore(&d40c->lock, flags); } -static int -dma40_config_to_halfchannel(struct d40_chan *d40c, - struct stedma40_half_channel_info *info, - enum dma_slave_buswidth width, - u32 maxburst) -{ - enum stedma40_periph_data_width addr_width; - int psize; - - switch (width) { - case DMA_SLAVE_BUSWIDTH_1_BYTE: - addr_width = STEDMA40_BYTE_WIDTH; - break; - case DMA_SLAVE_BUSWIDTH_2_BYTES: - addr_width = STEDMA40_HALFWORD_WIDTH; - break; - case DMA_SLAVE_BUSWIDTH_4_BYTES: - addr_width = STEDMA40_WORD_WIDTH; - break; - case DMA_SLAVE_BUSWIDTH_8_BYTES: - addr_width = STEDMA40_DOUBLEWORD_WIDTH; - break; - default: - dev_err(d40c->base->dev, - "illegal peripheral address width " - "requested (%d)\n", - width); - return -EINVAL; - } - - if (chan_is_logical(d40c)) { - if (maxburst >= 16) - psize = STEDMA40_PSIZE_LOG_16; - else if (maxburst >= 8) - psize = STEDMA40_PSIZE_LOG_8; - else if (maxburst >= 4) - psize = STEDMA40_PSIZE_LOG_4; - else - psize = STEDMA40_PSIZE_LOG_1; - } else { - if (maxburst >= 16) - psize = STEDMA40_PSIZE_PHY_16; - else if (maxburst >= 8) - psize = STEDMA40_PSIZE_PHY_8; - else if (maxburst >= 4) - psize = STEDMA40_PSIZE_PHY_4; - else - psize = STEDMA40_PSIZE_PHY_1; - } - - info->data_width = addr_width; - info->psize = psize; - info->flow_ctrl = STEDMA40_NO_FLOW_CTRL; - - return 0; -} - /* Runtime reconfiguration extension */ -static int d40_set_runtime_config(struct dma_chan *chan, - struct dma_slave_config *config) +static void d40_set_runtime_config(struct dma_chan *chan, + struct dma_slave_config *config) { struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); struct stedma40_chan_cfg *cfg = &d40c->dma_cfg; - enum dma_slave_buswidth src_addr_width, dst_addr_width; + enum dma_slave_buswidth config_addr_width; dma_addr_t config_addr; - u32 src_maxburst, dst_maxburst; - int ret; - - src_addr_width = config->src_addr_width; - src_maxburst = config->src_maxburst; - dst_addr_width = config->dst_addr_width; - dst_maxburst = config->dst_maxburst; + u32 config_maxburst; + enum stedma40_periph_data_width addr_width; + int psize; if (config->direction == DMA_FROM_DEVICE) { dma_addr_t dev_addr_rx = @@ -2270,11 +2188,8 @@ static int d40_set_runtime_config(struct dma_chan *chan, cfg->dir); cfg->dir = STEDMA40_PERIPH_TO_MEM; - /* Configure the memory side */ - if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) - dst_addr_width = src_addr_width; - if (dst_maxburst == 0) - dst_maxburst = src_maxburst; + config_addr_width = config->src_addr_width; + config_maxburst = config->src_maxburst; } else if (config->direction == DMA_TO_DEVICE) { dma_addr_t dev_addr_tx = @@ -2293,39 +2208,68 @@ static int d40_set_runtime_config(struct dma_chan *chan, cfg->dir); cfg->dir = STEDMA40_MEM_TO_PERIPH; - /* Configure the memory side */ - if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) - src_addr_width = dst_addr_width; - if (src_maxburst == 0) - src_maxburst = dst_maxburst; + config_addr_width = config->dst_addr_width; + config_maxburst = config->dst_maxburst; + } else { dev_err(d40c->base->dev, "unrecognized channel direction %d\n", config->direction); - return -EINVAL; + return; } - if (src_maxburst * src_addr_width != dst_maxburst * dst_addr_width) { + switch (config_addr_width) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + addr_width = STEDMA40_BYTE_WIDTH; + break; + case DMA_SLAVE_BUSWIDTH_2_BYTES: + addr_width = STEDMA40_HALFWORD_WIDTH; + break; + case DMA_SLAVE_BUSWIDTH_4_BYTES: + addr_width = STEDMA40_WORD_WIDTH; + break; + case DMA_SLAVE_BUSWIDTH_8_BYTES: + addr_width = STEDMA40_DOUBLEWORD_WIDTH; + break; + default: dev_err(d40c->base->dev, - "src/dst width/maxburst mismatch: %d*%d != %d*%d\n", - src_maxburst, - src_addr_width, - dst_maxburst, - dst_addr_width); - return -EINVAL; + "illegal peripheral address width " + "requested (%d)\n", + config->src_addr_width); + return; } - ret = dma40_config_to_halfchannel(d40c, &cfg->src_info, - src_addr_width, - src_maxburst); - if (ret) - return ret; + if (chan_is_logical(d40c)) { + if (config_maxburst >= 16) + psize = STEDMA40_PSIZE_LOG_16; + else if (config_maxburst >= 8) + psize = STEDMA40_PSIZE_LOG_8; + else if (config_maxburst >= 4) + psize = STEDMA40_PSIZE_LOG_4; + else + psize = STEDMA40_PSIZE_LOG_1; + } else { + if (config_maxburst >= 16) + psize = STEDMA40_PSIZE_PHY_16; + else if (config_maxburst >= 8) + psize = STEDMA40_PSIZE_PHY_8; + else if (config_maxburst >= 4) + psize = STEDMA40_PSIZE_PHY_4; + else if (config_maxburst >= 2) + psize = STEDMA40_PSIZE_PHY_2; + else + psize = STEDMA40_PSIZE_PHY_1; + } - ret = dma40_config_to_halfchannel(d40c, &cfg->dst_info, - dst_addr_width, - dst_maxburst); - if (ret) - return ret; + /* Set up all the endpoint configs */ + cfg->src_info.data_width = addr_width; + cfg->src_info.psize = psize; + cfg->src_info.big_endian = false; + cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL; + cfg->dst_info.data_width = addr_width; + cfg->dst_info.psize = psize; + cfg->dst_info.big_endian = false; + cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL; /* Fill in register values */ if (chan_is_logical(d40c)) @@ -2338,14 +2282,12 @@ static int d40_set_runtime_config(struct dma_chan *chan, d40c->runtime_addr = config_addr; d40c->runtime_direction = config->direction; dev_dbg(d40c->base->dev, - "configured channel %s for %s, data width %d/%d, " - "maxburst %d/%d elements, LE, no flow control\n", + "configured channel %s for %s, data width %d, " + "maxburst %d bytes, LE, no flow control\n", dma_chan_name(chan), (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", - src_addr_width, dst_addr_width, - src_maxburst, dst_maxburst); - - return 0; + config_addr_width, + config_maxburst); } static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, @@ -2366,8 +2308,9 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, case DMA_RESUME: return d40_resume(d40c); case DMA_SLAVE_CONFIG: - return d40_set_runtime_config(chan, + d40_set_runtime_config(chan, (struct dma_slave_config *) arg); + return 0; default: break; } @@ -2398,7 +2341,6 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma, INIT_LIST_HEAD(&d40c->active); INIT_LIST_HEAD(&d40c->queue); - INIT_LIST_HEAD(&d40c->pending_queue); INIT_LIST_HEAD(&d40c->client); tasklet_init(&d40c->tasklet, dma_tasklet, @@ -2560,6 +2502,25 @@ static int __init d40_phy_res_init(struct d40_base *base) static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) { + static const struct d40_reg_val dma_id_regs[] = { + /* Peripheral Id */ + { .reg = D40_DREG_PERIPHID0, .val = 0x0040}, + { .reg = D40_DREG_PERIPHID1, .val = 0x0000}, + /* + * D40_DREG_PERIPHID2 Depends on HW revision: + * DB8500ed has 0x0008, + * ? has 0x0018, + * DB8500v1 has 0x0028 + * DB8500v2 has 0x0038 + */ + { .reg = D40_DREG_PERIPHID3, .val = 0x0000}, + + /* PCell Id */ + { .reg = D40_DREG_CELLID0, .val = 0x000d}, + { .reg = D40_DREG_CELLID1, .val = 0x00f0}, + { .reg = D40_DREG_CELLID2, .val = 0x0005}, + { .reg = D40_DREG_CELLID3, .val = 0x00b1} + }; struct stedma40_platform_data *plat_data; struct clk *clk = NULL; void __iomem *virtbase = NULL; @@ -2568,9 +2529,8 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) int num_log_chans = 0; int num_phy_chans; int i; - u32 pid; - u32 cid; - u8 rev; + u32 val; + u32 rev; clk = clk_get(&pdev->dev, NULL); @@ -2594,32 +2554,32 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) if (!virtbase) goto failure; - /* This is just a regular AMBA PrimeCell ID actually */ - for (pid = 0, i = 0; i < 4; i++) - pid |= (readl(virtbase + resource_size(res) - 0x20 + 4 * i) - & 255) << (i * 8); - for (cid = 0, i = 0; i < 4; i++) - cid |= (readl(virtbase + resource_size(res) - 0x10 + 4 * i) - & 255) << (i * 8); - - if (cid != AMBA_CID) { - d40_err(&pdev->dev, "Unknown hardware! No PrimeCell ID\n"); - goto failure; + /* HW version check */ + for (i = 0; i < ARRAY_SIZE(dma_id_regs); i++) { + if (dma_id_regs[i].val != + readl(virtbase + dma_id_regs[i].reg)) { + d40_err(&pdev->dev, + "Unknown hardware! Expected 0x%x at 0x%x but got 0x%x\n", + dma_id_regs[i].val, + dma_id_regs[i].reg, + readl(virtbase + dma_id_regs[i].reg)); + goto failure; + } } - if (AMBA_MANF_BITS(pid) != AMBA_VENDOR_ST) { + + /* Get silicon revision and designer */ + val = readl(virtbase + D40_DREG_PERIPHID2); + + if ((val & D40_DREG_PERIPHID2_DESIGNER_MASK) != + D40_HW_DESIGNER) { d40_err(&pdev->dev, "Unknown designer! Got %x wanted %x\n", - AMBA_MANF_BITS(pid), - AMBA_VENDOR_ST); + val & D40_DREG_PERIPHID2_DESIGNER_MASK, + D40_HW_DESIGNER); goto failure; } - /* - * HW revision: - * DB8500ed has revision 0 - * ? has revision 1 - * DB8500v1 has revision 2 - * DB8500v2 has revision 3 - */ - rev = AMBA_REV_BITS(pid); + + rev = (val & D40_DREG_PERIPHID2_REV_MASK) >> + D40_DREG_PERIPHID2_REV_POS; /* The number of physical channels on this HW */ num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4; diff --git a/trunk/drivers/dma/ste_dma40_ll.h b/trunk/drivers/dma/ste_dma40_ll.h index b44c455158de..195ee65ee7f3 100644 --- a/trunk/drivers/dma/ste_dma40_ll.h +++ b/trunk/drivers/dma/ste_dma40_ll.h @@ -184,6 +184,9 @@ #define D40_DREG_PERIPHID0 0xFE0 #define D40_DREG_PERIPHID1 0xFE4 #define D40_DREG_PERIPHID2 0xFE8 +#define D40_DREG_PERIPHID2_REV_POS 4 +#define D40_DREG_PERIPHID2_REV_MASK (0xf << D40_DREG_PERIPHID2_REV_POS) +#define D40_DREG_PERIPHID2_DESIGNER_MASK 0xf #define D40_DREG_PERIPHID3 0xFEC #define D40_DREG_CELLID0 0xFF0 #define D40_DREG_CELLID1 0xFF4 diff --git a/trunk/drivers/eisa/pci_eisa.c b/trunk/drivers/eisa/pci_eisa.c index cdae207028a7..30da70d06a6d 100644 --- a/trunk/drivers/eisa/pci_eisa.c +++ b/trunk/drivers/eisa/pci_eisa.c @@ -45,13 +45,13 @@ static int __init pci_eisa_init(struct pci_dev *pdev, return 0; } -static struct pci_device_id pci_eisa_pci_tbl[] = { +static struct pci_device_id __initdata pci_eisa_pci_tbl[] = { { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_EISA << 8, 0xffff00, 0 }, { 0, } }; -static struct pci_driver __refdata pci_eisa_driver = { +static struct pci_driver __initdata pci_eisa_driver = { .name = "pci_eisa", .id_table = pci_eisa_pci_tbl, .probe = pci_eisa_init, diff --git a/trunk/drivers/firmware/efivars.c b/trunk/drivers/firmware/efivars.c index eb80b549ed8d..5f29aafd4462 100644 --- a/trunk/drivers/firmware/efivars.c +++ b/trunk/drivers/firmware/efivars.c @@ -78,7 +78,6 @@ #include #include #include -#include #include @@ -90,8 +89,6 @@ MODULE_DESCRIPTION("sysfs interface to EFI Variables"); MODULE_LICENSE("GPL"); MODULE_VERSION(EFIVARS_VERSION); -#define DUMP_NAME_LEN 52 - /* * The maximum size of VariableName + Data = 1024 * Therefore, it's reasonable to save that much @@ -122,10 +119,6 @@ struct efivar_attribute { ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); }; -#define PSTORE_EFI_ATTRIBUTES \ - (EFI_VARIABLE_NON_VOLATILE | \ - EFI_VARIABLE_BOOTSERVICE_ACCESS | \ - EFI_VARIABLE_RUNTIME_ACCESS) #define EFIVAR_ATTR(_name, _mode, _show, _store) \ struct efivar_attribute efivar_attr_##_name = { \ @@ -148,72 +141,38 @@ efivar_create_sysfs_entry(struct efivars *efivars, /* Return the number of unicode characters in data */ static unsigned long -utf16_strnlen(efi_char16_t *s, size_t maxlength) +utf8_strlen(efi_char16_t *data, unsigned long maxlength) { unsigned long length = 0; - while (*s++ != 0 && length < maxlength) + while (*data++ != 0 && length < maxlength) length++; return length; } -static inline unsigned long -utf16_strlen(efi_char16_t *s) -{ - return utf16_strnlen(s, ~0UL); -} - /* * Return the number of bytes is the length of this string * Note: this is NOT the same as the number of unicode characters */ static inline unsigned long -utf16_strsize(efi_char16_t *data, unsigned long maxlength) +utf8_strsize(efi_char16_t *data, unsigned long maxlength) { - return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); -} - -static inline int -utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len) -{ - while (1) { - if (len == 0) - return 0; - if (*a < *b) - return -1; - if (*a > *b) - return 1; - if (*a == 0) /* implies *b == 0 */ - return 0; - a++; - b++; - len--; - } + return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); } static efi_status_t -get_var_data_locked(struct efivars *efivars, struct efi_variable *var) +get_var_data(struct efivars *efivars, struct efi_variable *var) { efi_status_t status; + spin_lock(&efivars->lock); var->DataSize = 1024; status = efivars->ops->get_variable(var->VariableName, &var->VendorGuid, &var->Attributes, &var->DataSize, var->Data); - return status; -} - -static efi_status_t -get_var_data(struct efivars *efivars, struct efi_variable *var) -{ - efi_status_t status; - - spin_lock(&efivars->lock); - status = get_var_data_locked(efivars, var); spin_unlock(&efivars->lock); - if (status != EFI_SUCCESS) { printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n", status); @@ -428,180 +387,12 @@ static struct kobj_type efivar_ktype = { .default_attrs = def_attrs, }; -static struct pstore_info efi_pstore_info; - static inline void efivar_unregister(struct efivar_entry *var) { kobject_put(&var->kobj); } -#ifdef CONFIG_PSTORE - -static int efi_pstore_open(struct pstore_info *psi) -{ - struct efivars *efivars = psi->data; - - spin_lock(&efivars->lock); - efivars->walk_entry = list_first_entry(&efivars->list, - struct efivar_entry, list); - return 0; -} - -static int efi_pstore_close(struct pstore_info *psi) -{ - struct efivars *efivars = psi->data; - - spin_unlock(&efivars->lock); - return 0; -} - -static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, - struct timespec *timespec, struct pstore_info *psi) -{ - efi_guid_t vendor = LINUX_EFI_CRASH_GUID; - struct efivars *efivars = psi->data; - char name[DUMP_NAME_LEN]; - int i; - unsigned int part, size; - unsigned long time; - - while (&efivars->walk_entry->list != &efivars->list) { - if (!efi_guidcmp(efivars->walk_entry->var.VendorGuid, - vendor)) { - for (i = 0; i < DUMP_NAME_LEN; i++) { - name[i] = efivars->walk_entry->var.VariableName[i]; - } - if (sscanf(name, "dump-type%u-%u-%lu", type, &part, &time) == 3) { - *id = part; - timespec->tv_sec = time; - timespec->tv_nsec = 0; - get_var_data_locked(efivars, &efivars->walk_entry->var); - size = efivars->walk_entry->var.DataSize; - memcpy(psi->buf, efivars->walk_entry->var.Data, size); - efivars->walk_entry = list_entry(efivars->walk_entry->list.next, - struct efivar_entry, list); - return size; - } - } - efivars->walk_entry = list_entry(efivars->walk_entry->list.next, - struct efivar_entry, list); - } - return 0; -} - -static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, - size_t size, struct pstore_info *psi) -{ - char name[DUMP_NAME_LEN]; - char stub_name[DUMP_NAME_LEN]; - efi_char16_t efi_name[DUMP_NAME_LEN]; - efi_guid_t vendor = LINUX_EFI_CRASH_GUID; - struct efivars *efivars = psi->data; - struct efivar_entry *entry, *found = NULL; - int i; - - sprintf(stub_name, "dump-type%u-%u-", type, part); - sprintf(name, "%s%lu", stub_name, get_seconds()); - - spin_lock(&efivars->lock); - - for (i = 0; i < DUMP_NAME_LEN; i++) - efi_name[i] = stub_name[i]; - - /* - * Clean up any entries with the same name - */ - - list_for_each_entry(entry, &efivars->list, list) { - get_var_data_locked(efivars, &entry->var); - - if (efi_guidcmp(entry->var.VendorGuid, vendor)) - continue; - if (utf16_strncmp(entry->var.VariableName, efi_name, - utf16_strlen(efi_name))) - continue; - /* Needs to be a prefix */ - if (entry->var.VariableName[utf16_strlen(efi_name)] == 0) - continue; - - /* found */ - found = entry; - efivars->ops->set_variable(entry->var.VariableName, - &entry->var.VendorGuid, - PSTORE_EFI_ATTRIBUTES, - 0, NULL); - } - - if (found) - list_del(&found->list); - - for (i = 0; i < DUMP_NAME_LEN; i++) - efi_name[i] = name[i]; - - efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES, - size, psi->buf); - - spin_unlock(&efivars->lock); - - if (found) - efivar_unregister(found); - - if (size) - efivar_create_sysfs_entry(efivars, - utf16_strsize(efi_name, - DUMP_NAME_LEN * 2), - efi_name, &vendor); - - return part; -}; - -static int efi_pstore_erase(enum pstore_type_id type, u64 id, - struct pstore_info *psi) -{ - efi_pstore_write(type, id, 0, psi); - - return 0; -} -#else -static int efi_pstore_open(struct pstore_info *psi) -{ - return 0; -} - -static int efi_pstore_close(struct pstore_info *psi) -{ - return 0; -} - -static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, - struct timespec *time, struct pstore_info *psi) -{ - return -1; -} - -static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, - size_t size, struct pstore_info *psi) -{ - return 0; -} - -static int efi_pstore_erase(enum pstore_type_id type, u64 id, - struct pstore_info *psi) -{ - return 0; -} -#endif - -static struct pstore_info efi_pstore_info = { - .owner = THIS_MODULE, - .name = "efi", - .open = efi_pstore_open, - .close = efi_pstore_close, - .read = efi_pstore_read, - .write = efi_pstore_write, - .erase = efi_pstore_erase, -}; static ssize_t efivar_create(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, @@ -623,8 +414,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, * Does this variable already exist? */ list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { - strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); - strsize2 = utf16_strsize(new_var->VariableName, 1024); + strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); + strsize2 = utf8_strsize(new_var->VariableName, 1024); if (strsize1 == strsize2 && !memcmp(&(search_efivar->var.VariableName), new_var->VariableName, strsize1) && @@ -656,8 +447,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, /* Create the entry in sysfs. Locking is not required here */ status = efivar_create_sysfs_entry(efivars, - utf16_strsize(new_var->VariableName, - 1024), + utf8_strsize(new_var->VariableName, + 1024), new_var->VariableName, &new_var->VendorGuid); if (status) { @@ -686,8 +477,8 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, * Does this variable already exist? */ list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { - strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); - strsize2 = utf16_strsize(del_var->VariableName, 1024); + strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); + strsize2 = utf8_strsize(del_var->VariableName, 1024); if (strsize1 == strsize2 && !memcmp(&(search_efivar->var.VariableName), del_var->VariableName, strsize1) && @@ -972,16 +763,6 @@ int register_efivars(struct efivars *efivars, if (error) unregister_efivars(efivars); - efivars->efi_pstore_info = efi_pstore_info; - - efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); - if (efivars->efi_pstore_info.buf) { - efivars->efi_pstore_info.bufsize = 1024; - efivars->efi_pstore_info.data = efivars; - mutex_init(&efivars->efi_pstore_info.buf_mutex); - pstore_register(&efivars->efi_pstore_info); - } - out: kfree(variable_name); diff --git a/trunk/drivers/gpu/drm/drm_debugfs.c b/trunk/drivers/gpu/drm/drm_debugfs.c index 9d2668a50872..9d8c892d07c9 100644 --- a/trunk/drivers/gpu/drm/drm_debugfs.c +++ b/trunk/drivers/gpu/drm/drm_debugfs.c @@ -90,6 +90,7 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count, struct drm_device *dev = minor->dev; struct dentry *ent; struct drm_info_node *tmp; + char name[64]; int i, ret; for (i = 0; i < count; i++) { @@ -107,9 +108,6 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count, ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO, root, tmp, &drm_debugfs_fops); if (!ent) { - char name[64]; - strncpy(name, root->d_name.name, - min(root->d_name.len, 64U)); DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n", name, files[i].name); kfree(tmp); diff --git a/trunk/drivers/gpu/drm/drm_edid.c b/trunk/drivers/gpu/drm/drm_edid.c index 7425e5c9bd75..756af4d7ec74 100644 --- a/trunk/drivers/gpu/drm/drm_edid.c +++ b/trunk/drivers/gpu/drm/drm_edid.c @@ -127,23 +127,6 @@ static const u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; - /* - * Sanity check the header of the base EDID block. Return 8 if the header - * is perfect, down to 0 if it's totally wrong. - */ -int drm_edid_header_is_valid(const u8 *raw_edid) -{ - int i, score = 0; - - for (i = 0; i < sizeof(edid_header); i++) - if (raw_edid[i] == edid_header[i]) - score++; - - return score; -} -EXPORT_SYMBOL(drm_edid_header_is_valid); - - /* * Sanity check the EDID block (base or extension). Return 0 if the block * doesn't check out, or 1 if it's valid. @@ -156,7 +139,12 @@ drm_edid_block_valid(u8 *raw_edid) struct edid *edid = (struct edid *)raw_edid; if (raw_edid[0] == 0x00) { - int score = drm_edid_header_is_valid(raw_edid); + int score = 0; + + for (i = 0; i < sizeof(edid_header); i++) + if (raw_edid[i] == edid_header[i]) + score++; + if (score == 8) ; else if (score >= 6) { DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); @@ -1451,8 +1439,6 @@ EXPORT_SYMBOL(drm_detect_monitor_audio); static void drm_add_display_info(struct edid *edid, struct drm_display_info *info) { - u8 *edid_ext; - info->width_mm = edid->width_cm * 10; info->height_mm = edid->height_cm * 10; @@ -1497,13 +1483,6 @@ static void drm_add_display_info(struct edid *edid, info->color_formats = DRM_COLOR_FORMAT_YCRCB444; if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422) info->color_formats = DRM_COLOR_FORMAT_YCRCB422; - - /* Get data from CEA blocks if present */ - edid_ext = drm_find_cea_extension(edid); - if (!edid_ext) - return; - - info->cea_rev = edid_ext[1]; } /** diff --git a/trunk/drivers/gpu/drm/drm_irq.c b/trunk/drivers/gpu/drm/drm_irq.c index 3830e9e478c0..2022a5c966bb 100644 --- a/trunk/drivers/gpu/drm/drm_irq.c +++ b/trunk/drivers/gpu/drm/drm_irq.c @@ -291,14 +291,11 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state) if (!dev->irq_enabled) return; - if (state) { - if (dev->driver->irq_uninstall) - dev->driver->irq_uninstall(dev); - } else { - if (dev->driver->irq_preinstall) - dev->driver->irq_preinstall(dev); - if (dev->driver->irq_postinstall) - dev->driver->irq_postinstall(dev); + if (state) + dev->driver->irq_uninstall(dev); + else { + dev->driver->irq_preinstall(dev); + dev->driver->irq_postinstall(dev); } } @@ -341,8 +338,7 @@ int drm_irq_install(struct drm_device *dev) DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); /* Before installing handler */ - if (dev->driver->irq_preinstall) - dev->driver->irq_preinstall(dev); + dev->driver->irq_preinstall(dev); /* Install handler */ if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED)) @@ -367,16 +363,11 @@ int drm_irq_install(struct drm_device *dev) vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL); /* After installing handler */ - if (dev->driver->irq_postinstall) - ret = dev->driver->irq_postinstall(dev); - + ret = dev->driver->irq_postinstall(dev); if (ret < 0) { mutex_lock(&dev->struct_mutex); dev->irq_enabled = 0; mutex_unlock(&dev->struct_mutex); - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - vga_client_register(dev->pdev, NULL, NULL, NULL); - free_irq(drm_dev_to_irq(dev), dev); } return ret; @@ -422,8 +413,7 @@ int drm_irq_uninstall(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) vga_client_register(dev->pdev, NULL, NULL, NULL); - if (dev->driver->irq_uninstall) - dev->driver->irq_uninstall(dev); + dev->driver->irq_uninstall(dev); free_irq(drm_dev_to_irq(dev), dev); diff --git a/trunk/drivers/gpu/drm/i915/i915_debugfs.c b/trunk/drivers/gpu/drm/i915/i915_debugfs.c index a8ab6263e0d7..e2662497d50f 100644 --- a/trunk/drivers/gpu/drm/i915/i915_debugfs.c +++ b/trunk/drivers/gpu/drm/i915/i915_debugfs.c @@ -1338,155 +1338,6 @@ static const struct file_operations i915_wedged_fops = { .llseek = default_llseek, }; -static int -i915_max_freq_open(struct inode *inode, - struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - -static ssize_t -i915_max_freq_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) -{ - struct drm_device *dev = filp->private_data; - drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - int len; - - len = snprintf(buf, sizeof (buf), - "max freq: %d\n", dev_priv->max_delay * 50); - - if (len > sizeof (buf)) - len = sizeof (buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); -} - -static ssize_t -i915_max_freq_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) -{ - struct drm_device *dev = filp->private_data; - struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; - int val = 1; - - if (cnt > 0) { - if (cnt > sizeof (buf) - 1) - return -EINVAL; - - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - val = simple_strtoul(buf, NULL, 0); - } - - DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val); - - /* - * Turbo will still be enabled, but won't go above the set value. - */ - dev_priv->max_delay = val / 50; - - gen6_set_rps(dev, val / 50); - - return cnt; -} - -static const struct file_operations i915_max_freq_fops = { - .owner = THIS_MODULE, - .open = i915_max_freq_open, - .read = i915_max_freq_read, - .write = i915_max_freq_write, - .llseek = default_llseek, -}; - -static int -i915_cache_sharing_open(struct inode *inode, - struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - -static ssize_t -i915_cache_sharing_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) -{ - struct drm_device *dev = filp->private_data; - drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - u32 snpcr; - int len; - - mutex_lock(&dev_priv->dev->struct_mutex); - snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); - mutex_unlock(&dev_priv->dev->struct_mutex); - - len = snprintf(buf, sizeof (buf), - "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >> - GEN6_MBC_SNPCR_SHIFT); - - if (len > sizeof (buf)) - len = sizeof (buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); -} - -static ssize_t -i915_cache_sharing_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) -{ - struct drm_device *dev = filp->private_data; - struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; - u32 snpcr; - int val = 1; - - if (cnt > 0) { - if (cnt > sizeof (buf) - 1) - return -EINVAL; - - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - val = simple_strtoul(buf, NULL, 0); - } - - if (val < 0 || val > 3) - return -EINVAL; - - DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val); - - /* Update the cache sharing policy here as well */ - snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); - snpcr &= ~GEN6_MBC_SNPCR_MASK; - snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); - I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); - - return cnt; -} - -static const struct file_operations i915_cache_sharing_fops = { - .owner = THIS_MODULE, - .open = i915_cache_sharing_open, - .read = i915_cache_sharing_read, - .write = i915_cache_sharing_write, - .llseek = default_llseek, -}; - /* As the drm_debugfs_init() routines are called before dev->dev_private is * allocated we need to hook into the minor for release. */ static int @@ -1586,36 +1437,6 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor) return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops); } -static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor) -{ - struct drm_device *dev = minor->dev; - struct dentry *ent; - - ent = debugfs_create_file("i915_max_freq", - S_IRUGO | S_IWUSR, - root, dev, - &i915_max_freq_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); - - return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops); -} - -static int i915_cache_sharing_create(struct dentry *root, struct drm_minor *minor) -{ - struct drm_device *dev = minor->dev; - struct dentry *ent; - - ent = debugfs_create_file("i915_cache_sharing", - S_IRUGO | S_IWUSR, - root, dev, - &i915_cache_sharing_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); - - return drm_add_fake_info_node(minor, ent, &i915_cache_sharing_fops); -} - static struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, @@ -1667,12 +1488,6 @@ int i915_debugfs_init(struct drm_minor *minor) return ret; ret = i915_forcewake_create(minor->debugfs_root, minor); - if (ret) - return ret; - ret = i915_max_freq_create(minor->debugfs_root, minor); - if (ret) - return ret; - ret = i915_cache_sharing_create(minor->debugfs_root, minor); if (ret) return ret; @@ -1689,10 +1504,6 @@ void i915_debugfs_cleanup(struct drm_minor *minor) 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops, 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops, - 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops, - 1, minor); } #endif /* CONFIG_DEBUG_FS */ diff --git a/trunk/drivers/gpu/drm/i915/i915_dma.c b/trunk/drivers/gpu/drm/i915/i915_dma.c index 8a3942c4f099..12712824a6d2 100644 --- a/trunk/drivers/gpu/drm/i915/i915_dma.c +++ b/trunk/drivers/gpu/drm/i915/i915_dma.c @@ -61,6 +61,7 @@ static void i915_write_hws_pga(struct drm_device *dev) static int i915_init_phys_hws(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = LP_RING(dev_priv); /* Program Hardware Status Page */ dev_priv->status_page_dmah = @@ -70,9 +71,10 @@ static int i915_init_phys_hws(struct drm_device *dev) DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } + ring->status_page.page_addr = + (void __force __iomem *)dev_priv->status_page_dmah->vaddr; - memset_io((void __force __iomem *)dev_priv->status_page_dmah->vaddr, - 0, PAGE_SIZE); + memset_io(ring->status_page.page_addr, 0, PAGE_SIZE); i915_write_hws_pga(dev); diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.h b/trunk/drivers/gpu/drm/i915/i915_drv.h index feb4f164fd1b..6867e193d85e 100644 --- a/trunk/drivers/gpu/drm/i915/i915_drv.h +++ b/trunk/drivers/gpu/drm/i915/i915_drv.h @@ -544,7 +544,6 @@ typedef struct drm_i915_private { u32 savePIPEB_LINK_M1; u32 savePIPEB_LINK_N1; u32 saveMCHBAR_RENDER_STANDBY; - u32 savePCH_PORT_HOTPLUG; struct { /** Bridge to intel-gtt-ko */ diff --git a/trunk/drivers/gpu/drm/i915/i915_gem.c b/trunk/drivers/gpu/drm/i915/i915_gem.c index a546a71fb060..d1cd8b89f47d 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem.c @@ -3112,7 +3112,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, if (pipelined != obj->ring) { ret = i915_gem_object_wait_rendering(obj); - if (ret == -ERESTARTSYS) + if (ret) return ret; } diff --git a/trunk/drivers/gpu/drm/i915/i915_irq.c b/trunk/drivers/gpu/drm/i915/i915_irq.c index 02f96fd0d52d..23d1ae67d279 100644 --- a/trunk/drivers/gpu/drm/i915/i915_irq.c +++ b/trunk/drivers/gpu/drm/i915/i915_irq.c @@ -306,15 +306,12 @@ static void i915_hotplug_work_func(struct work_struct *work) struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; - mutex_lock(&mode_config->mutex); DRM_DEBUG_KMS("running encoder hotplug functions\n"); list_for_each_entry(encoder, &mode_config->encoder_list, base.head) if (encoder->hot_plug) encoder->hot_plug(encoder); - mutex_unlock(&mode_config->mutex); - /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); } diff --git a/trunk/drivers/gpu/drm/i915/i915_reg.h b/trunk/drivers/gpu/drm/i915/i915_reg.h index d1331f771e2f..02db299f621a 100644 --- a/trunk/drivers/gpu/drm/i915/i915_reg.h +++ b/trunk/drivers/gpu/drm/i915/i915_reg.h @@ -78,14 +78,6 @@ #define GRDOM_RENDER (1<<2) #define GRDOM_MEDIA (3<<2) -#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */ -#define GEN6_MBC_SNPCR_SHIFT 21 -#define GEN6_MBC_SNPCR_MASK (3<<21) -#define GEN6_MBC_SNPCR_MAX (0<<21) -#define GEN6_MBC_SNPCR_MED (1<<21) -#define GEN6_MBC_SNPCR_LOW (2<<21) -#define GEN6_MBC_SNPCR_MIN (3<<21) /* only 1/16th of the cache is shared */ - #define GEN6_GDRST 0x941c #define GEN6_GRDOM_FULL (1 << 0) #define GEN6_GRDOM_RENDER (1 << 1) @@ -1514,7 +1506,6 @@ #define VIDEO_DIP_SELECT_AVI (0 << 19) #define VIDEO_DIP_SELECT_VENDOR (1 << 19) #define VIDEO_DIP_SELECT_SPD (3 << 19) -#define VIDEO_DIP_SELECT_MASK (3 << 19) #define VIDEO_DIP_FREQ_ONCE (0 << 16) #define VIDEO_DIP_FREQ_VSYNC (1 << 16) #define VIDEO_DIP_FREQ_2VSYNC (2 << 16) @@ -2093,6 +2084,9 @@ #define DP_PIPEB_SELECT (1 << 30) #define DP_PIPE_MASK (1 << 30) +#define DP_PIPE_ENABLED(V, P) \ + (((V) & (DP_PIPE_MASK | DP_PORT_EN)) == ((P) << 30 | DP_PORT_EN)) + /* Link training mode - select a suitable mode for each stage */ #define DP_LINK_TRAIN_PAT_1 (0 << 28) #define DP_LINK_TRAIN_PAT_2 (1 << 28) @@ -3030,20 +3024,6 @@ #define _TRANSA_DP_LINK_M2 0xe0048 #define _TRANSA_DP_LINK_N2 0xe004c -/* Per-transcoder DIP controls */ - -#define _VIDEO_DIP_CTL_A 0xe0200 -#define _VIDEO_DIP_DATA_A 0xe0208 -#define _VIDEO_DIP_GCP_A 0xe0210 - -#define _VIDEO_DIP_CTL_B 0xe1200 -#define _VIDEO_DIP_DATA_B 0xe1208 -#define _VIDEO_DIP_GCP_B 0xe1210 - -#define TVIDEO_DIP_CTL(pipe) _PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B) -#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) -#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) - #define _TRANS_HTOTAL_B 0xe1000 #define _TRANS_HBLANK_B 0xe1004 #define _TRANS_HSYNC_B 0xe1008 @@ -3096,16 +3076,6 @@ #define TRANS_6BPC (2<<5) #define TRANS_12BPC (3<<5) -#define _TRANSA_CHICKEN2 0xf0064 -#define _TRANSB_CHICKEN2 0xf1064 -#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) -#define TRANS_AUTOTRAIN_GEN_STALL_DIS (1<<31) - -#define SOUTH_CHICKEN1 0xc2000 -#define FDIA_PHASE_SYNC_SHIFT_OVR 19 -#define FDIA_PHASE_SYNC_SHIFT_EN 18 -#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) -#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) #define SOUTH_CHICKEN2 0xc2004 #define DPLS_EDP_PPS_FIX_DIS (1<<0) diff --git a/trunk/drivers/gpu/drm/i915/i915_suspend.c b/trunk/drivers/gpu/drm/i915/i915_suspend.c index 87677d60d0df..285758603ac8 100644 --- a/trunk/drivers/gpu/drm/i915/i915_suspend.c +++ b/trunk/drivers/gpu/drm/i915/i915_suspend.c @@ -812,7 +812,6 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR); dev_priv->saveMCHBAR_RENDER_STANDBY = I915_READ(RSTDBYCTL); - dev_priv->savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG); } else { dev_priv->saveIER = I915_READ(IER); dev_priv->saveIMR = I915_READ(IMR); @@ -864,7 +863,6 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(GTIMR, dev_priv->saveGTIMR); I915_WRITE(_FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR); I915_WRITE(_FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR); - I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->savePCH_PORT_HOTPLUG); } else { I915_WRITE(IER, dev_priv->saveIER); I915_WRITE(IMR, dev_priv->saveIMR); diff --git a/trunk/drivers/gpu/drm/i915/intel_display.c b/trunk/drivers/gpu/drm/i915/intel_display.c index 35364e68a091..393a39922e53 100644 --- a/trunk/drivers/gpu/drm/i915/intel_display.c +++ b/trunk/drivers/gpu/drm/i915/intel_display.c @@ -980,29 +980,11 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv, pipe_name(pipe)); } -static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe, - int reg, u32 port_sel, u32 val) -{ - if ((val & DP_PORT_EN) == 0) - return false; - - if (HAS_PCH_CPT(dev_priv->dev)) { - u32 trans_dp_ctl_reg = TRANS_DP_CTL(pipe); - u32 trans_dp_ctl = I915_READ(trans_dp_ctl_reg); - if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel) - return false; - } else { - if ((val & DP_PIPE_MASK) != (pipe << 30)) - return false; - } - return true; -} - static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, - enum pipe pipe, int reg, u32 port_sel) + enum pipe pipe, int reg) { u32 val = I915_READ(reg); - WARN(dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val), + WARN(DP_PIPE_ENABLED(val, pipe), "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); } @@ -1022,9 +1004,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, int reg; u32 val; - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D); reg = PCH_ADPA; val = I915_READ(reg); @@ -1294,17 +1276,6 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, intel_wait_for_pipe_off(dev_priv->dev, pipe); } -/* - * Plane regs are double buffered, going from enabled->disabled needs a - * trigger in order to latch. The display address reg provides this. - */ -static void intel_flush_display_plane(struct drm_i915_private *dev_priv, - enum plane plane) -{ - I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); - I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane))); -} - /** * intel_enable_plane - enable a display plane on a given pipe * @dev_priv: i915 private structure @@ -1328,10 +1299,20 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, return; I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); - intel_flush_display_plane(dev_priv, plane); intel_wait_for_vblank(dev_priv->dev, pipe); } +/* + * Plane regs are double buffered, going from enabled->disabled needs a + * trigger in order to latch. The display address reg provides this. + */ +static void intel_flush_display_plane(struct drm_i915_private *dev_priv, + enum plane plane) +{ + u32 reg = DSPADDR(plane); + I915_WRITE(reg, I915_READ(reg)); +} + /** * intel_disable_plane - disable a display plane * @dev_priv: i915 private structure @@ -1357,24 +1338,19 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, } static void disable_pch_dp(struct drm_i915_private *dev_priv, - enum pipe pipe, int reg, u32 port_sel) + enum pipe pipe, int reg) { u32 val = I915_READ(reg); - if (dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val)) { - DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe); + if (DP_PIPE_ENABLED(val, pipe)) I915_WRITE(reg, val & ~DP_PORT_EN); - } } static void disable_pch_hdmi(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = I915_READ(reg); - if (HDMI_PIPE_ENABLED(val, pipe)) { - DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n", - reg, pipe); + if (HDMI_PIPE_ENABLED(val, pipe)) I915_WRITE(reg, val & ~PORT_ENABLE); - } } /* Disable any ports connected to this transcoder */ @@ -1386,9 +1362,9 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, val = I915_READ(PCH_PP_CONTROL); I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS); - disable_pch_dp(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); - disable_pch_dp(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); - disable_pch_dp(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); + disable_pch_dp(dev_priv, pipe, PCH_DP_B); + disable_pch_dp(dev_priv, pipe, PCH_DP_C); + disable_pch_dp(dev_priv, pipe, PCH_DP_D); reg = PCH_ADPA; val = I915_READ(reg); @@ -2120,7 +2096,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, /* no fb bound */ if (!crtc->fb) { - DRM_ERROR("No FB bound\n"); + DRM_DEBUG_KMS("No FB bound\n"); return 0; } @@ -2129,7 +2105,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, case 1: break; default: - DRM_ERROR("no plane for crtc\n"); return -EINVAL; } @@ -2139,7 +2114,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, NULL); if (ret != 0) { mutex_unlock(&dev->struct_mutex); - DRM_ERROR("pin & fence failed\n"); return ret; } @@ -2168,7 +2142,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (ret) { i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); - DRM_ERROR("failed to update base address\n"); return ret; } @@ -2275,18 +2248,6 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) FDI_FE_ERRC_ENABLE); } -static void cpt_phase_pointer_enable(struct drm_device *dev, int pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 flags = I915_READ(SOUTH_CHICKEN1); - - flags |= FDI_PHASE_SYNC_OVR(pipe); - I915_WRITE(SOUTH_CHICKEN1, flags); /* once to unlock... */ - flags |= FDI_PHASE_SYNC_EN(pipe); - I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to enable */ - POSTING_READ(SOUTH_CHICKEN1); -} - /* The FDI link training functions for ILK/Ibexpeak. */ static void ironlake_fdi_link_train(struct drm_crtc *crtc) { @@ -2437,9 +2398,6 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); - if (HAS_PCH_CPT(dev)) - cpt_phase_pointer_enable(dev, pipe); - for (i = 0; i < 4; i++ ) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2556,9 +2514,6 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); - if (HAS_PCH_CPT(dev)) - cpt_phase_pointer_enable(dev, pipe); - for (i = 0; i < 4; i++ ) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2668,17 +2623,6 @@ static void ironlake_fdi_pll_enable(struct drm_crtc *crtc) } } -static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 flags = I915_READ(SOUTH_CHICKEN1); - - flags &= ~(FDI_PHASE_SYNC_EN(pipe)); - I915_WRITE(SOUTH_CHICKEN1, flags); /* once to disable... */ - flags &= ~(FDI_PHASE_SYNC_OVR(pipe)); - I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to lock */ - POSTING_READ(SOUTH_CHICKEN1); -} static void ironlake_fdi_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2708,8 +2652,6 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) I915_WRITE(FDI_RX_CHICKEN(pipe), I915_READ(FDI_RX_CHICKEN(pipe) & ~FDI_RX_PHASE_SYNC_POINTER_EN)); - } else if (HAS_PCH_CPT(dev)) { - cpt_phase_pointer_disable(dev, pipe); } /* still set train pattern 1 */ @@ -2920,18 +2862,14 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); } - /* - * On ILK+ LUT must be loaded before the pipe is running but with - * clocks enabled - */ - intel_crtc_load_lut(crtc); - intel_enable_pipe(dev_priv, pipe, is_pch_port); intel_enable_plane(dev_priv, plane, pipe); if (is_pch_port) ironlake_pch_enable(crtc); + intel_crtc_load_lut(crtc); + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); @@ -4600,9 +4538,7 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, if (connector->encoder != encoder) continue; - /* Don't use an invalid EDID bpc value */ - if (connector->display_info.bpc && - connector->display_info.bpc < display_bpc) { + if (connector->display_info.bpc < display_bpc) { DRM_DEBUG_DRIVER("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc); display_bpc = connector->display_info.bpc; } @@ -5217,8 +5153,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, temp |= PIPE_12BPC; break; default: - WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n", - pipe_bpp); + WARN(1, "intel_choose_pipe_bpp returned invalid value\n"); temp |= PIPE_8BPC; pipe_bpp = 24; break; @@ -5303,7 +5238,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } else if (is_sdvo && is_tv) factor = 20; - if (clock.m < factor * clock.n) + if (clock.m1 < factor * clock.n) fp |= FP_CB_TUNE; dpll = 0; @@ -5581,8 +5516,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, drm_vblank_post_modeset(dev, pipe); - intel_crtc->dpms_mode = DRM_MODE_DPMS_ON; - return ret; } @@ -7781,12 +7714,10 @@ static void gen6_init_clock_gating(struct drm_device *dev) ILK_DPARB_CLK_GATE | ILK_DPFD_CLK_GATE); - for_each_pipe(pipe) { + for_each_pipe(pipe) I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } } static void ivybridge_init_clock_gating(struct drm_device *dev) @@ -7803,12 +7734,10 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); - for_each_pipe(pipe) { + for_each_pipe(pipe) I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } } static void g4x_init_clock_gating(struct drm_device *dev) @@ -7891,7 +7820,6 @@ static void ibx_init_clock_gating(struct drm_device *dev) static void cpt_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; /* * On Ibex Peak and Cougar Point, we need to disable clock @@ -7901,9 +7829,6 @@ static void cpt_init_clock_gating(struct drm_device *dev) I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | DPLS_EDP_PPS_FIX_DIS); - /* Without this, mode sets may fail silently on FDI */ - for_each_pipe(pipe) - I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); } static void ironlake_teardown_rc6(struct drm_device *dev) @@ -8253,9 +8178,6 @@ struct intel_quirk intel_quirks[] = { /* Lenovo U160 cannot use SSC on LVDS */ { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable }, - - /* Sony Vaio Y cannot use SSC on LVDS */ - { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable }, }; static void intel_init_quirks(struct drm_device *dev) diff --git a/trunk/drivers/gpu/drm/i915/intel_dp.c b/trunk/drivers/gpu/drm/i915/intel_dp.c index 0feae908bb37..f797fb58ba9c 100644 --- a/trunk/drivers/gpu/drm/i915/intel_dp.c +++ b/trunk/drivers/gpu/drm/i915/intel_dp.c @@ -50,10 +50,9 @@ struct intel_dp { bool has_audio; int force_audio; uint32_t color_range; - int dpms_mode; uint8_t link_bw; uint8_t lane_count; - uint8_t dpcd[8]; + uint8_t dpcd[4]; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; bool is_pch_edp; @@ -317,17 +316,9 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, else precharge = 5; - /* Try to wait for any previous AUX channel activity */ - for (try = 0; try < 3; try++) { - status = I915_READ(ch_ctl); - if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) - break; - msleep(1); - } - - if (try == 3) { - WARN(1, "dp_aux_ch not started status 0x%08x\n", - I915_READ(ch_ctl)); + if (I915_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) { + DRM_ERROR("dp_aux_ch not started status 0x%08x\n", + I915_READ(ch_ctl)); return -EBUSY; } @@ -779,7 +770,6 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); intel_dp->link_configuration[0] = intel_dp->link_bw; intel_dp->link_configuration[1] = intel_dp->lane_count; - intel_dp->link_configuration[8] = DP_SET_ANSI_8B10B; /* * Check for DPCD version > 1.1 and enhanced framing support @@ -1021,8 +1011,6 @@ static void intel_dp_commit(struct drm_encoder *encoder) if (is_edp(intel_dp)) ironlake_edp_backlight_on(dev); - - intel_dp->dpms_mode = DRM_MODE_DPMS_ON; } static void @@ -1057,7 +1045,6 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) if (is_edp(intel_dp)) ironlake_edp_backlight_on(dev); } - intel_dp->dpms_mode = mode; } /* @@ -1347,16 +1334,10 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) u32 reg; uint32_t DP = intel_dp->DP; - /* - * On CPT we have to enable the port in training pattern 1, which - * will happen below in intel_dp_set_link_train. Otherwise, enable - * the port and wait for it to become active. - */ - if (!HAS_PCH_CPT(dev)) { - I915_WRITE(intel_dp->output_reg, intel_dp->DP); - POSTING_READ(intel_dp->output_reg); - intel_wait_for_vblank(dev, intel_crtc->pipe); - } + /* Enable output, wait for it to become active */ + I915_WRITE(intel_dp->output_reg, intel_dp->DP); + POSTING_READ(intel_dp->output_reg); + intel_wait_for_vblank(dev, intel_crtc->pipe); /* Write the link configuration data */ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, @@ -1389,8 +1370,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) reg = DP | DP_LINK_TRAIN_PAT_1; if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_1 | - DP_LINK_SCRAMBLING_DISABLE)) + DP_TRAINING_PATTERN_1)) break; /* Set training pattern 1 */ @@ -1465,8 +1445,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) /* channel eq pattern */ if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_2 | - DP_LINK_SCRAMBLING_DISABLE)) + DP_TRAINING_PATTERN_2)) break; udelay(400); @@ -1580,18 +1559,6 @@ intel_dp_link_down(struct intel_dp *intel_dp) POSTING_READ(intel_dp->output_reg); } -static bool -intel_dp_get_dpcd(struct intel_dp *intel_dp) -{ - if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, - sizeof (intel_dp->dpcd)) && - (intel_dp->dpcd[DP_DPCD_REV] != 0)) { - return true; - } - - return false; -} - /* * According to DP spec * 5.1.2: @@ -1604,44 +1571,36 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { - if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON) - return; + int ret; if (!intel_dp->base.base.crtc) return; - /* Try to read receiver status if the link appears to be up */ if (!intel_dp_get_link_status(intel_dp)) { intel_dp_link_down(intel_dp); return; } - /* Now read the DPCD to see if it's actually running */ - if (!intel_dp_get_dpcd(intel_dp)) { + /* Try to read receiver status if the link appears to be up */ + ret = intel_dp_aux_native_read(intel_dp, + 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)); + if (ret != sizeof(intel_dp->dpcd)) { intel_dp_link_down(intel_dp); return; } if (!intel_channel_eq_ok(intel_dp)) { - DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n", - drm_get_encoder_name(&intel_dp->base.base)); intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); } } -static enum drm_connector_status -intel_dp_detect_dpcd(struct intel_dp *intel_dp) -{ - if (intel_dp_get_dpcd(intel_dp)) - return connector_status_connected; - return connector_status_disconnected; -} - static enum drm_connector_status ironlake_dp_detect(struct intel_dp *intel_dp) { enum drm_connector_status status; + bool ret; /* Can't disconnect eDP, but you can close the lid... */ if (is_edp(intel_dp)) { @@ -1651,7 +1610,15 @@ ironlake_dp_detect(struct intel_dp *intel_dp) return status; } - return intel_dp_detect_dpcd(intel_dp); + status = connector_status_disconnected; + ret = intel_dp_aux_native_read_retry(intel_dp, + 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)); + if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0) + status = connector_status_connected; + DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], + intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); + return status; } static enum drm_connector_status @@ -1659,6 +1626,7 @@ g4x_dp_detect(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + enum drm_connector_status status; uint32_t temp, bit; switch (intel_dp->output_reg) { @@ -1680,7 +1648,15 @@ g4x_dp_detect(struct intel_dp *intel_dp) if ((temp & bit) == 0) return connector_status_disconnected; - return intel_dp_detect_dpcd(intel_dp); + status = connector_status_disconnected; + if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) + { + if (intel_dp->dpcd[DP_DPCD_REV] != 0) + status = connector_status_connected; + } + + return status; } /** @@ -1703,12 +1679,6 @@ intel_dp_detect(struct drm_connector *connector, bool force) status = ironlake_dp_detect(intel_dp); else status = g4x_dp_detect(intel_dp); - - DRM_DEBUG_KMS("DPCD: %02hx%02hx%02hx%02hx%02hx%02hx%02hx%02hx\n", - intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], - intel_dp->dpcd[3], intel_dp->dpcd[4], intel_dp->dpcd[5], - intel_dp->dpcd[6], intel_dp->dpcd[7]); - if (status != connector_status_connected) return status; @@ -1954,7 +1924,6 @@ intel_dp_init(struct drm_device *dev, int output_reg) return; intel_dp->output_reg = output_reg; - intel_dp->dpms_mode = -1; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { @@ -2031,7 +2000,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) /* Cache some DPCD data in the eDP case */ if (is_edp(intel_dp)) { - bool ret; + int ret; u32 pp_on, pp_div; pp_on = I915_READ(PCH_PP_ON_DELAYS); @@ -2044,9 +2013,11 @@ intel_dp_init(struct drm_device *dev, int output_reg) dev_priv->panel_t12 *= 100; /* t12 in 100ms units */ ironlake_edp_panel_vdd_on(intel_dp); - ret = intel_dp_get_dpcd(intel_dp); + ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV, + intel_dp->dpcd, + sizeof(intel_dp->dpcd)); ironlake_edp_panel_vdd_off(intel_dp); - if (ret) { + if (ret == sizeof(intel_dp->dpcd)) { if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] & diff --git a/trunk/drivers/gpu/drm/i915/intel_drv.h b/trunk/drivers/gpu/drm/i915/intel_drv.h index 7b330e76a435..6e990f9760ef 100644 --- a/trunk/drivers/gpu/drm/i915/intel_drv.h +++ b/trunk/drivers/gpu/drm/i915/intel_drv.h @@ -178,28 +178,10 @@ struct intel_crtc { #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) -#define DIP_HEADER_SIZE 5 - #define DIP_TYPE_AVI 0x82 #define DIP_VERSION_AVI 0x2 #define DIP_LEN_AVI 13 -#define DIP_TYPE_SPD 0x3 -#define DIP_VERSION_SPD 0x1 -#define DIP_LEN_SPD 25 -#define DIP_SPD_UNKNOWN 0 -#define DIP_SPD_DSTB 0x1 -#define DIP_SPD_DVDP 0x2 -#define DIP_SPD_DVHS 0x3 -#define DIP_SPD_HDDVR 0x4 -#define DIP_SPD_DVC 0x5 -#define DIP_SPD_DSC 0x6 -#define DIP_SPD_VCD 0x7 -#define DIP_SPD_GAME 0x8 -#define DIP_SPD_PC 0x9 -#define DIP_SPD_BD 0xa -#define DIP_SPD_SCD 0xb - struct dip_infoframe { uint8_t type; /* HB0 */ uint8_t ver; /* HB1 */ @@ -224,11 +206,6 @@ struct dip_infoframe { uint16_t left_bar_end; uint16_t right_bar_start; } avi; - struct { - uint8_t vn[8]; - uint8_t pd[16]; - uint8_t sdi; - } spd; uint8_t payload[27]; } __attribute__ ((packed)) body; } __attribute__((packed)); diff --git a/trunk/drivers/gpu/drm/i915/intel_hdmi.c b/trunk/drivers/gpu/drm/i915/intel_hdmi.c index 226ba830f383..1ed8e6903915 100644 --- a/trunk/drivers/gpu/drm/i915/intel_hdmi.c +++ b/trunk/drivers/gpu/drm/i915/intel_hdmi.c @@ -45,8 +45,6 @@ struct intel_hdmi { bool has_hdmi_sink; bool has_audio; int force_audio; - void (*write_infoframe)(struct drm_encoder *encoder, - struct dip_infoframe *frame); }; static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) @@ -60,70 +58,37 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) struct intel_hdmi, base); } -void intel_dip_infoframe_csum(struct dip_infoframe *frame) +void intel_dip_infoframe_csum(struct dip_infoframe *avi_if) { - uint8_t *data = (uint8_t *)frame; + uint8_t *data = (uint8_t *)avi_if; uint8_t sum = 0; unsigned i; - frame->checksum = 0; - frame->ecc = 0; + avi_if->checksum = 0; + avi_if->ecc = 0; - /* Header isn't part of the checksum */ - for (i = 5; i < frame->len; i++) + for (i = 0; i < sizeof(*avi_if); i++) sum += data[i]; - frame->checksum = 0x100 - sum; + avi_if->checksum = 0x100 - sum; } -static u32 intel_infoframe_index(struct dip_infoframe *frame) -{ - u32 flags = 0; - - switch (frame->type) { - case DIP_TYPE_AVI: - flags |= VIDEO_DIP_SELECT_AVI; - break; - case DIP_TYPE_SPD: - flags |= VIDEO_DIP_SELECT_SPD; - break; - default: - DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); - break; - } - - return flags; -} - -static u32 intel_infoframe_flags(struct dip_infoframe *frame) -{ - u32 flags = 0; - - switch (frame->type) { - case DIP_TYPE_AVI: - flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC; - break; - case DIP_TYPE_SPD: - flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_2VSYNC; - break; - default: - DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); - break; - } - - return flags; -} - -static void i9xx_write_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) +static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) { - uint32_t *data = (uint32_t *)frame; + struct dip_infoframe avi_if = { + .type = DIP_TYPE_AVI, + .ver = DIP_VERSION_AVI, + .len = DIP_LEN_AVI, + }; + uint32_t *data = (uint32_t *)&avi_if; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 port, flags, val = I915_READ(VIDEO_DIP_CTL); - unsigned i, len = DIP_HEADER_SIZE + frame->len; + u32 port; + unsigned i; + if (!intel_hdmi->has_hdmi_sink) + return; /* XXX first guess at handling video port, is this corrent? */ if (intel_hdmi->sdvox_reg == SDVOB) @@ -133,87 +98,18 @@ static void i9xx_write_infoframe(struct drm_encoder *encoder, else return; - flags = intel_infoframe_index(frame); - - val &= ~VIDEO_DIP_SELECT_MASK; + I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | + VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC); - I915_WRITE(VIDEO_DIP_CTL, val | port | flags); - - for (i = 0; i < len; i += 4) { + intel_dip_infoframe_csum(&avi_if); + for (i = 0; i < sizeof(avi_if); i += 4) { I915_WRITE(VIDEO_DIP_DATA, *data); data++; } - flags |= intel_infoframe_flags(frame); - - I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); -} - -static void ironlake_write_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) -{ - uint32_t *data = (uint32_t *)frame; - struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = encoder->crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); - unsigned i, len = DIP_HEADER_SIZE + frame->len; - u32 flags, val = I915_READ(reg); - - intel_wait_for_vblank(dev, intel_crtc->pipe); - - flags = intel_infoframe_index(frame); - - val &= ~VIDEO_DIP_SELECT_MASK; - - I915_WRITE(reg, val | flags); - - for (i = 0; i < len; i += 4) { - I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); - data++; - } - - flags |= intel_infoframe_flags(frame); - - I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); -} -static void intel_set_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) -{ - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - - if (!intel_hdmi->has_hdmi_sink) - return; - - intel_dip_infoframe_csum(frame); - intel_hdmi->write_infoframe(encoder, frame); -} - -static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) -{ - struct dip_infoframe avi_if = { - .type = DIP_TYPE_AVI, - .ver = DIP_VERSION_AVI, - .len = DIP_LEN_AVI, - }; - - intel_set_infoframe(encoder, &avi_if); -} - -static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) -{ - struct dip_infoframe spd_if; - - memset(&spd_if, 0, sizeof(spd_if)); - spd_if.type = DIP_TYPE_SPD; - spd_if.ver = DIP_VERSION_SPD; - spd_if.len = DIP_LEN_SPD; - strcpy(spd_if.body.spd.vn, "Intel"); - strcpy(spd_if.body.spd.pd, "Integrated gfx"); - spd_if.body.spd.sdi = DIP_SPD_PC; - - intel_set_infoframe(encoder, &spd_if); + I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | + VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC | + VIDEO_DIP_ENABLE_AVI); } static void intel_hdmi_mode_set(struct drm_encoder *encoder, @@ -260,7 +156,6 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, POSTING_READ(intel_hdmi->sdvox_reg); intel_hdmi_set_avi_infoframe(encoder); - intel_hdmi_set_spd_infoframe(encoder); } static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) @@ -538,11 +433,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_hdmi->sdvox_reg = sdvox_reg; - if (!HAS_PCH_SPLIT(dev)) - intel_hdmi->write_infoframe = i9xx_write_infoframe; - else - intel_hdmi->write_infoframe = ironlake_write_infoframe; - drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); intel_hdmi_add_properties(intel_hdmi, connector); diff --git a/trunk/drivers/gpu/drm/i915/intel_lvds.c b/trunk/drivers/gpu/drm/i915/intel_lvds.c index 2e8ddfcba40c..b28f7bd9f88a 100644 --- a/trunk/drivers/gpu/drm/i915/intel_lvds.c +++ b/trunk/drivers/gpu/drm/i915/intel_lvds.c @@ -688,14 +688,6 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"), }, }, - { - .callback = intel_no_lvds_dmi_callback, - .ident = "Dell OptiPlex FX170", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex FX170"), - }, - }, { .callback = intel_no_lvds_dmi_callback, .ident = "AOpen Mini PC", diff --git a/trunk/drivers/gpu/drm/i915/intel_panel.c b/trunk/drivers/gpu/drm/i915/intel_panel.c index 05f500cd9c24..a06ff07a4d3b 100644 --- a/trunk/drivers/gpu/drm/i915/intel_panel.c +++ b/trunk/drivers/gpu/drm/i915/intel_panel.c @@ -83,15 +83,11 @@ intel_pch_panel_fitting(struct drm_device *dev, u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; if (scaled_width > scaled_height) { /* pillar */ width = scaled_height / mode->vdisplay; - if (width & 1) - width++; x = (adjusted_mode->hdisplay - width + 1) / 2; y = 0; height = adjusted_mode->vdisplay; } else if (scaled_width < scaled_height) { /* letter */ height = scaled_width / mode->hdisplay; - if (height & 1) - height++; y = (adjusted_mode->vdisplay - height + 1) / 2; x = 0; width = adjusted_mode->hdisplay; diff --git a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c index 47b9b2777038..e9615685a39c 100644 --- a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1321,9 +1321,6 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->get_seqno = pc_render_get_seqno; } - if (!I915_NEED_GFX_HWS(dev)) - ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; - ring->dev = dev; INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); diff --git a/trunk/drivers/gpu/drm/radeon/Makefile b/trunk/drivers/gpu/drm/radeon/Makefile index 9f363e0c4b60..3896ef811102 100644 --- a/trunk/drivers/gpu/drm/radeon/Makefile +++ b/trunk/drivers/gpu/drm/radeon/Makefile @@ -5,7 +5,6 @@ ccflags-y := -Iinclude/drm hostprogs-y := mkregtable -clean-files := rn50_reg_safe.h r100_reg_safe.h r200_reg_safe.h rv515_reg_safe.h r300_reg_safe.h r420_reg_safe.h rs600_reg_safe.h r600_reg_safe.h evergreen_reg_safe.h cayman_reg_safe.h quiet_cmd_mkregtable = MKREGTABLE $@ cmd_mkregtable = $(obj)/mkregtable $< > $@ diff --git a/trunk/drivers/gpu/drm/radeon/atom.c b/trunk/drivers/gpu/drm/radeon/atom.c index e88c64417a8a..ebdb0fdb8348 100644 --- a/trunk/drivers/gpu/drm/radeon/atom.c +++ b/trunk/drivers/gpu/drm/radeon/atom.c @@ -1245,9 +1245,6 @@ struct atom_context *atom_parse(struct card_info *card, void *bios) char name[512]; int i; - if (!ctx) - return NULL; - ctx->card = card; ctx->bios = bios; diff --git a/trunk/drivers/gpu/drm/radeon/evergreen_cs.c b/trunk/drivers/gpu/drm/radeon/evergreen_cs.c index a134790903d3..189e86522b5b 100644 --- a/trunk/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/trunk/drivers/gpu/drm/radeon/evergreen_cs.c @@ -428,7 +428,7 @@ static inline int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u3 last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); i = (reg >> 7); - if (i >= last_reg) { + if (i > last_reg) { dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); return -EINVAL; } diff --git a/trunk/drivers/gpu/drm/radeon/r600_cs.c b/trunk/drivers/gpu/drm/radeon/r600_cs.c index cf83aa05a684..db8ef1905d5f 100644 --- a/trunk/drivers/gpu/drm/radeon/r600_cs.c +++ b/trunk/drivers/gpu/drm/radeon/r600_cs.c @@ -915,11 +915,12 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx { struct r600_cs_track *track = (struct r600_cs_track *)p->track; struct radeon_cs_reloc *reloc; + u32 last_reg = ARRAY_SIZE(r600_reg_safe_bm); u32 m, i, tmp, *ib; int r; i = (reg >> 7); - if (i >= ARRAY_SIZE(r600_reg_safe_bm)) { + if (i > last_reg) { dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); return -EINVAL; } diff --git a/trunk/drivers/gpu/drm/radeon/radeon_combios.c b/trunk/drivers/gpu/drm/radeon/radeon_combios.c index e0138b674aca..a74217cd192f 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_combios.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_combios.c @@ -2557,7 +2557,6 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) u16 offset, misc, misc2 = 0; u8 rev, blocks, tmp; int state_index = 0; - struct radeon_i2c_bus_rec i2c_bus; rdev->pm.default_power_state_index = -1; @@ -2576,6 +2575,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) offset = combios_get_table_offset(dev, COMBIOS_OVERDRIVE_INFO_TABLE); if (offset) { u8 thermal_controller = 0, gpio = 0, i2c_addr = 0, clk_bit = 0, data_bit = 0; + struct radeon_i2c_bus_rec i2c_bus; rev = RBIOS8(offset); @@ -2617,25 +2617,6 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); } } - } else { - /* boards with a thermal chip, but no overdrive table */ - - /* Asus 9600xt has an f75375 on the monid bus */ - if ((dev->pdev->device == 0x4152) && - (dev->pdev->subsystem_vendor == 0x1043) && - (dev->pdev->subsystem_device == 0xc002)) { - i2c_bus = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0); - rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); - if (rdev->pm.i2c_bus) { - struct i2c_board_info info = { }; - const char *name = "f75375"; - info.addr = 0x28; - strlcpy(info.type, name, sizeof(info.type)); - i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); - DRM_INFO("Possible %s thermal controller at 0x%02x\n", - name, info.addr); - } - } } if (rdev->flags & RADEON_IS_MOBILITY) { diff --git a/trunk/drivers/gpu/drm/radeon/radeon_connectors.c b/trunk/drivers/gpu/drm/radeon/radeon_connectors.c index 6d6b5f16bc09..9792d4ffdc86 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_connectors.c @@ -430,45 +430,6 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr return 0; } -/* - * Some integrated ATI Radeon chipset implementations (e. g. - * Asus M2A-VM HDMI) may indicate the availability of a DDC, - * even when there's no monitor connected. For these connectors - * following DDC probe extension will be applied: check also for the - * availability of EDID with at least a correct EDID header. Only then, - * DDC is assumed to be available. This prevents drm_get_edid() and - * drm_edid_block_valid() from periodically dumping data and kernel - * errors into the logs and onto the terminal. - */ -static bool radeon_connector_needs_extended_probe(struct radeon_device *dev, - uint32_t supported_device, - int connector_type) -{ - /* Asus M2A-VM HDMI board sends data to i2c bus even, - * if HDMI add-on card is not plugged in or HDMI is disabled in - * BIOS. Valid DDC can only be assumed, if also a valid EDID header - * can be retrieved via i2c bus during DDC probe */ - if ((dev->pdev->device == 0x791e) && - (dev->pdev->subsystem_vendor == 0x1043) && - (dev->pdev->subsystem_device == 0x826d)) { - if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) && - (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) - return true; - } - /* ECS A740GM-M with ATI RADEON 2100 sends data to i2c bus - * for a DVI connector that is not implemented */ - if ((dev->pdev->device == 0x796e) && - (dev->pdev->subsystem_vendor == 0x1019) && - (dev->pdev->subsystem_device == 0x2615)) { - if ((connector_type == DRM_MODE_CONNECTOR_DVID) && - (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) - return true; - } - - /* Default: no EDID header probe required for DDC probing */ - return false; -} - static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, struct drm_connector *connector) { @@ -700,8 +661,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) ret = connector_status_disconnected; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe); + dret = radeon_ddc_probe(radeon_connector); if (dret) { if (radeon_connector->edid) { kfree(radeon_connector->edid); @@ -873,8 +833,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) bool dret = false; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe); + dret = radeon_ddc_probe(radeon_connector); if (dret) { if (radeon_connector->edid) { kfree(radeon_connector->edid); @@ -1292,8 +1251,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; } else { - if (radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe)) + if (radeon_ddc_probe(radeon_connector)) ret = connector_status_connected; } } @@ -1448,9 +1406,6 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_connector->shared_ddc = shared_ddc; radeon_connector->connector_object_id = connector_object_id; radeon_connector->hpd = *hpd; - radeon_connector->requires_extended_probe = - radeon_connector_needs_extended_probe(rdev, supported_device, - connector_type); radeon_connector->router = *router; if (router->ddc_valid || router->cd_valid) { radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); @@ -1797,9 +1752,6 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_connector->devices = supported_device; radeon_connector->connector_object_id = connector_object_id; radeon_connector->hpd = *hpd; - radeon_connector->requires_extended_probe = - radeon_connector_needs_extended_probe(rdev, supported_device, - connector_type); switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); diff --git a/trunk/drivers/gpu/drm/radeon/radeon_device.c b/trunk/drivers/gpu/drm/radeon/radeon_device.c index 440e6ecccc40..7cfaa7e2f3b5 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_device.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_device.c @@ -704,9 +704,8 @@ int radeon_device_init(struct radeon_device *rdev, rdev->gpu_lockup = false; rdev->accel_working = false; - DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", - radeon_family_name[rdev->family], pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); + DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X).\n", + radeon_family_name[rdev->family], pdev->vendor, pdev->device); /* mutex initialization are all done here so we * can recall function without having locking issues */ diff --git a/trunk/drivers/gpu/drm/radeon/radeon_display.c b/trunk/drivers/gpu/drm/radeon/radeon_display.c index 1a858944e4f3..28f4655905bc 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_display.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_display.c @@ -751,17 +751,8 @@ static int radeon_ddc_dump(struct drm_connector *connector) if (!radeon_connector->ddc_bus) return -1; edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); - /* Log EDID retrieval status here. In particular with regard to - * connectors with requires_extended_probe flag set, that will prevent - * function radeon_dvi_detect() to fetch EDID on this connector, - * as long as there is no valid EDID header found */ if (edid) { - DRM_INFO("Radeon display connector %s: Found valid EDID", - drm_get_connector_name(connector)); kfree(edid); - } else { - DRM_INFO("Radeon display connector %s: No monitor connected or invalid EDID", - drm_get_connector_name(connector)); } return ret; } diff --git a/trunk/drivers/gpu/drm/radeon/radeon_drv.c b/trunk/drivers/gpu/drm/radeon/radeon_drv.c index e71d2ed7fa11..85f033f19a8a 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_drv.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_drv.c @@ -50,8 +50,8 @@ * 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK, clock crystal query * 2.9.0 - r600 tiling (s3tc,rgtc) working, SET_PREDICATION packet 3 on r600 + eg, backend query - * 2.10.0 - fusion 2D tiling - * 2.11.0 - backend map, initial compute support for the CS checker + * 2.10.0 - fusion 2D tiling, initial compute support for the CS checker + * 2.11.0 - backend map */ #define KMS_DRIVER_MAJOR 2 #define KMS_DRIVER_MINOR 11 diff --git a/trunk/drivers/gpu/drm/radeon/radeon_i2c.c b/trunk/drivers/gpu/drm/radeon/radeon_i2c.c index 6c111c1fa3f9..781196db792f 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_i2c.c @@ -32,17 +32,17 @@ * radeon_ddc_probe * */ -bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_extended_probe) +bool radeon_ddc_probe(struct radeon_connector *radeon_connector) { - u8 out = 0x0; - u8 buf[8]; + u8 out_buf[] = { 0x0, 0x0}; + u8 buf[2]; int ret; struct i2c_msg msgs[] = { { .addr = 0x50, .flags = 0, .len = 1, - .buf = &out, + .buf = out_buf, }, { .addr = 0x50, @@ -52,31 +52,15 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_e } }; - /* Read 8 bytes from i2c for extended probe of EDID header */ - if (requires_extended_probe) - msgs[1].len = 8; - /* on hw with routers, select right port */ if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); - if (ret != 2) - /* Couldn't find an accessible DDC on this connector */ - return false; - if (requires_extended_probe) { - /* Probe also for valid EDID header - * EDID header starts with: - * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00. - * Only the first 6 bytes must be valid as - * drm_edid_block_valid() can fix the last 2 bytes */ - if (drm_edid_header_is_valid(buf) < 6) { - /* Couldn't find an accessible EDID on this - * connector */ - return false; - } - } - return true; + if (ret == 2) + return true; + + return false; } /* bit banging i2c */ diff --git a/trunk/drivers/gpu/drm/radeon/radeon_mode.h b/trunk/drivers/gpu/drm/radeon/radeon_mode.h index d09031c03e26..6df4e3cec0c2 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_mode.h +++ b/trunk/drivers/gpu/drm/radeon/radeon_mode.h @@ -438,9 +438,6 @@ struct radeon_connector { struct radeon_i2c_chan *ddc_bus; /* some systems have an hdmi and vga port with a shared ddc line */ bool shared_ddc; - /* for some Radeon chip families we apply an additional EDID header - check as part of the DDC probe */ - bool requires_extended_probe; bool use_digital; /* we need to mind the EDID between detect and get modes due to analog/digital/tvencoder */ @@ -517,8 +514,7 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c, u8 val); extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); -extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, - bool requires_extended_probe); +extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); diff --git a/trunk/drivers/ide/cy82c693.c b/trunk/drivers/ide/cy82c693.c index 67cbcfa35122..3be60da52123 100644 --- a/trunk/drivers/ide/cy82c693.c +++ b/trunk/drivers/ide/cy82c693.c @@ -141,8 +141,6 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16); pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8); } - if (hwif->index > 0) - pci_dev_put(dev); } static void __devinit init_iops_cy82c693(ide_hwif_t *hwif) diff --git a/trunk/drivers/ide/ide_platform.c b/trunk/drivers/ide/ide_platform.c index 962693b10a1c..542603b394e4 100644 --- a/trunk/drivers/ide/ide_platform.c +++ b/trunk/drivers/ide/ide_platform.c @@ -19,7 +19,6 @@ #include #include #include -#include #include static void __devinit plat_ide_setup_ports(struct ide_hw *hw, @@ -96,10 +95,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start); hw.dev = &pdev->dev; - d.irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; - if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) - d.irq_flags |= IRQF_SHARED; - + d.irq_flags = res_irq->flags; if (mmio) d.host_flags |= IDE_HFLAG_MMIO; diff --git a/trunk/drivers/input/keyboard/gpio_keys.c b/trunk/drivers/input/keyboard/gpio_keys.c index 67df91af8424..ce281d152275 100644 --- a/trunk/drivers/input/keyboard/gpio_keys.c +++ b/trunk/drivers/input/keyboard/gpio_keys.c @@ -483,7 +483,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev, buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL); if (!buttons) - return -ENOMEM; + return -ENODEV; pp = NULL; i = 0; diff --git a/trunk/drivers/input/keyboard/lm8323.c b/trunk/drivers/input/keyboard/lm8323.c index 756348a7f93a..ab0acaf7fe8f 100644 --- a/trunk/drivers/input/keyboard/lm8323.c +++ b/trunk/drivers/input/keyboard/lm8323.c @@ -754,11 +754,8 @@ static int __devinit lm8323_probe(struct i2c_client *client, device_remove_file(&client->dev, &dev_attr_disable_kp); fail2: while (--pwm >= 0) - if (lm->pwm[pwm].enabled) { - device_remove_file(lm->pwm[pwm].cdev.dev, - &dev_attr_time); + if (lm->pwm[pwm].enabled) led_classdev_unregister(&lm->pwm[pwm].cdev); - } fail1: input_free_device(idev); kfree(lm); @@ -778,10 +775,8 @@ static int __devexit lm8323_remove(struct i2c_client *client) device_remove_file(&lm->client->dev, &dev_attr_disable_kp); for (i = 0; i < 3; i++) - if (lm->pwm[i].enabled) { - device_remove_file(lm->pwm[i].cdev.dev, &dev_attr_time); + if (lm->pwm[i].enabled) led_classdev_unregister(&lm->pwm[i].cdev); - } kfree(lm); diff --git a/trunk/drivers/input/keyboard/tegra-kbc.c b/trunk/drivers/input/keyboard/tegra-kbc.c index f270447ba951..da3828fc2c09 100644 --- a/trunk/drivers/input/keyboard/tegra-kbc.c +++ b/trunk/drivers/input/keyboard/tegra-kbc.c @@ -19,7 +19,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include #include #include #include @@ -38,7 +37,7 @@ #define KBC_ROW_SCAN_DLY 5 /* KBC uses a 32KHz clock so a cycle = 1/32Khz */ -#define KBC_CYCLE_MS 32 +#define KBC_CYCLE_USEC 32 /* KBC Registers */ @@ -648,7 +647,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows; kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt; - kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS); + kbc->repoll_dly = ((kbc->repoll_dly * KBC_CYCLE_USEC) + 999) / 1000; input_dev->name = pdev->name; input_dev->id.bustype = BUS_HOST; diff --git a/trunk/drivers/input/misc/kxtj9.c b/trunk/drivers/input/misc/kxtj9.c index 783597a9a64a..c456f63b6bae 100644 --- a/trunk/drivers/input/misc/kxtj9.c +++ b/trunk/drivers/input/misc/kxtj9.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/input/misc/mma8450.c b/trunk/drivers/input/misc/mma8450.c index 6c76cf792991..20f8f9284f02 100644 --- a/trunk/drivers/input/misc/mma8450.c +++ b/trunk/drivers/input/misc/mma8450.c @@ -24,7 +24,6 @@ #include #include #include -#include #define MMA8450_DRV_NAME "mma8450" @@ -230,17 +229,10 @@ static const struct i2c_device_id mma8450_id[] = { }; MODULE_DEVICE_TABLE(i2c, mma8450_id); -static const struct of_device_id mma8450_dt_ids[] = { - { .compatible = "fsl,mma8450", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(i2c, mma8450_dt_ids); - static struct i2c_driver mma8450_driver = { .driver = { .name = MMA8450_DRV_NAME, .owner = THIS_MODULE, - .of_match_table = mma8450_dt_ids, }, .probe = mma8450_probe, .remove = __devexit_p(mma8450_remove), diff --git a/trunk/drivers/input/mouse/hgpk.c b/trunk/drivers/input/mouse/hgpk.c index 4d17d9f3320b..95577c15ae56 100644 --- a/trunk/drivers/input/mouse/hgpk.c +++ b/trunk/drivers/input/mouse/hgpk.c @@ -32,7 +32,6 @@ #define DEBUG #include #include -#include #include #include #include diff --git a/trunk/drivers/input/serio/xilinx_ps2.c b/trunk/drivers/input/serio/xilinx_ps2.c index d64c5a43aaad..80baa53da5b1 100644 --- a/trunk/drivers/input/serio/xilinx_ps2.c +++ b/trunk/drivers/input/serio/xilinx_ps2.c @@ -23,7 +23,7 @@ #include #include #include -#include + #include #include diff --git a/trunk/drivers/input/touchscreen/ad7879.c b/trunk/drivers/input/touchscreen/ad7879.c index 131f9d1c921b..bc3b5187f3a3 100644 --- a/trunk/drivers/input/touchscreen/ad7879.c +++ b/trunk/drivers/input/touchscreen/ad7879.c @@ -249,14 +249,12 @@ static void __ad7879_enable(struct ad7879 *ts) static void __ad7879_disable(struct ad7879 *ts) { - u16 reg = (ts->cmd_crtl2 & ~AD7879_PM(-1)) | - AD7879_PM(AD7879_PM_SHUTDOWN); disable_irq(ts->irq); if (del_timer_sync(&ts->timer)) ad7879_ts_event_release(ts); - ad7879_write(ts, AD7879_REG_CTRL2, reg); + ad7879_write(ts, AD7879_REG_CTRL2, AD7879_PM(AD7879_PM_SHUTDOWN)); } diff --git a/trunk/drivers/md/Kconfig b/trunk/drivers/md/Kconfig index f75a66e7d312..8420129fc5ee 100644 --- a/trunk/drivers/md/Kconfig +++ b/trunk/drivers/md/Kconfig @@ -241,13 +241,12 @@ config DM_MIRROR needed for live data migration tools such as 'pvmove'. config DM_RAID - tristate "RAID 1/4/5/6 target (EXPERIMENTAL)" + tristate "RAID 4/5/6 target (EXPERIMENTAL)" depends on BLK_DEV_DM && EXPERIMENTAL - select MD_RAID1 select MD_RAID456 select BLK_DEV_MD ---help--- - A dm target that supports RAID1, RAID4, RAID5 and RAID6 mappings + A dm target that supports RAID4, RAID5 and RAID6 mappings A RAID-5 set of N drives with a capacity of C MB per drive provides the capacity of C * (N - 1) MB, and protects against a failure diff --git a/trunk/drivers/md/dm-crypt.c b/trunk/drivers/md/dm-crypt.c index 49da55c1528a..bae6c4e23d3f 100644 --- a/trunk/drivers/md/dm-crypt.c +++ b/trunk/drivers/md/dm-crypt.c @@ -30,6 +30,7 @@ #include #define DM_MSG_PREFIX "crypt" +#define MESG_STR(x) x, sizeof(x) /* * context holding the current state of a multi-part conversion @@ -238,7 +239,7 @@ static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, struct dm_crypt_request *dmreq) { memset(iv, 0, cc->iv_size); - *(__le32 *)iv = cpu_to_le32(dmreq->iv_sector & 0xffffffff); + *(u32 *)iv = cpu_to_le32(dmreq->iv_sector & 0xffffffff); return 0; } @@ -247,7 +248,7 @@ static int crypt_iv_plain64_gen(struct crypt_config *cc, u8 *iv, struct dm_crypt_request *dmreq) { memset(iv, 0, cc->iv_size); - *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector); + *(u64 *)iv = cpu_to_le64(dmreq->iv_sector); return 0; } @@ -414,7 +415,7 @@ static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, struct crypto_cipher *essiv_tfm = this_crypt_config(cc)->iv_private; memset(iv, 0, cc->iv_size); - *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector); + *(u64 *)iv = cpu_to_le64(dmreq->iv_sector); crypto_cipher_encrypt_one(essiv_tfm, iv, iv); return 0; @@ -1574,17 +1575,11 @@ static int crypt_ctr_cipher(struct dm_target *ti, static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct crypt_config *cc; - unsigned int key_size, opt_params; + unsigned int key_size; unsigned long long tmpll; int ret; - struct dm_arg_set as; - const char *opt_string; - - static struct dm_arg _args[] = { - {0, 1, "Invalid number of feature args"}, - }; - if (argc < 5) { + if (argc != 5) { ti->error = "Not enough arguments"; return -EINVAL; } @@ -1653,30 +1648,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) } cc->start = tmpll; - argv += 5; - argc -= 5; - - /* Optional parameters */ - if (argc) { - as.argc = argc; - as.argv = argv; - - ret = dm_read_arg_group(_args, &as, &opt_params, &ti->error); - if (ret) - goto bad; - - opt_string = dm_shift_arg(&as); - - if (opt_params == 1 && opt_string && - !strcasecmp(opt_string, "allow_discards")) - ti->num_discard_requests = 1; - else if (opt_params) { - ret = -EINVAL; - ti->error = "Invalid feature arguments"; - goto bad; - } - } - ret = -ENOMEM; cc->io_queue = alloc_workqueue("kcryptd_io", WQ_NON_REENTRANT| @@ -1711,16 +1682,9 @@ static int crypt_map(struct dm_target *ti, struct bio *bio, struct dm_crypt_io *io; struct crypt_config *cc; - /* - * If bio is REQ_FLUSH or REQ_DISCARD, just bypass crypt queues. - * - for REQ_FLUSH device-mapper core ensures that no IO is in-flight - * - for REQ_DISCARD caller must use flush if IO ordering matters - */ - if (unlikely(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) { + if (bio->bi_rw & REQ_FLUSH) { cc = ti->private; bio->bi_bdev = cc->dev->bdev; - if (bio_sectors(bio)) - bio->bi_sector = cc->start + dm_target_offset(ti, bio->bi_sector); return DM_MAPIO_REMAPPED; } @@ -1763,10 +1727,6 @@ static int crypt_status(struct dm_target *ti, status_type_t type, DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset, cc->dev->name, (unsigned long long)cc->start); - - if (ti->num_discard_requests) - DMEMIT(" 1 allow_discards"); - break; } return 0; @@ -1810,12 +1770,12 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv) if (argc < 2) goto error; - if (!strcasecmp(argv[0], "key")) { + if (!strnicmp(argv[0], MESG_STR("key"))) { if (!test_bit(DM_CRYPT_SUSPENDED, &cc->flags)) { DMWARN("not suspended during key manipulation."); return -EINVAL; } - if (argc == 3 && !strcasecmp(argv[1], "set")) { + if (argc == 3 && !strnicmp(argv[1], MESG_STR("set"))) { ret = crypt_set_key(cc, argv[2]); if (ret) return ret; @@ -1823,7 +1783,7 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv) ret = cc->iv_gen_ops->init(cc); return ret; } - if (argc == 2 && !strcasecmp(argv[1], "wipe")) { + if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe"))) { if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) { ret = cc->iv_gen_ops->wipe(cc); if (ret) @@ -1863,7 +1823,7 @@ static int crypt_iterate_devices(struct dm_target *ti, static struct target_type crypt_target = { .name = "crypt", - .version = {1, 11, 0}, + .version = {1, 10, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, diff --git a/trunk/drivers/md/dm-flakey.c b/trunk/drivers/md/dm-flakey.c index 89f73ca22cfa..ea790623c30b 100644 --- a/trunk/drivers/md/dm-flakey.c +++ b/trunk/drivers/md/dm-flakey.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2003 Sistina Software (UK) Limited. - * Copyright (C) 2004, 2010-2011 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved. * * This file is released under the GPL. */ @@ -15,9 +15,6 @@ #define DM_MSG_PREFIX "flakey" -#define all_corrupt_bio_flags_match(bio, fc) \ - (((bio)->bi_rw & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags) - /* * Flakey: Used for testing only, simulates intermittent, * catastrophic device failure. @@ -28,189 +25,60 @@ struct flakey_c { sector_t start; unsigned up_interval; unsigned down_interval; - unsigned long flags; - unsigned corrupt_bio_byte; - unsigned corrupt_bio_rw; - unsigned corrupt_bio_value; - unsigned corrupt_bio_flags; -}; - -enum feature_flag_bits { - DROP_WRITES }; -static int parse_features(struct dm_arg_set *as, struct flakey_c *fc, - struct dm_target *ti) -{ - int r; - unsigned argc; - const char *arg_name; - - static struct dm_arg _args[] = { - {0, 6, "Invalid number of feature args"}, - {1, UINT_MAX, "Invalid corrupt bio byte"}, - {0, 255, "Invalid corrupt value to write into bio byte (0-255)"}, - {0, UINT_MAX, "Invalid corrupt bio flags mask"}, - }; - - /* No feature arguments supplied. */ - if (!as->argc) - return 0; - - r = dm_read_arg_group(_args, as, &argc, &ti->error); - if (r) - return r; - - while (argc) { - arg_name = dm_shift_arg(as); - argc--; - - /* - * drop_writes - */ - if (!strcasecmp(arg_name, "drop_writes")) { - if (test_and_set_bit(DROP_WRITES, &fc->flags)) { - ti->error = "Feature drop_writes duplicated"; - return -EINVAL; - } - - continue; - } - - /* - * corrupt_bio_byte - */ - if (!strcasecmp(arg_name, "corrupt_bio_byte")) { - if (!argc) - ti->error = "Feature corrupt_bio_byte requires parameters"; - - r = dm_read_arg(_args + 1, as, &fc->corrupt_bio_byte, &ti->error); - if (r) - return r; - argc--; - - /* - * Direction r or w? - */ - arg_name = dm_shift_arg(as); - if (!strcasecmp(arg_name, "w")) - fc->corrupt_bio_rw = WRITE; - else if (!strcasecmp(arg_name, "r")) - fc->corrupt_bio_rw = READ; - else { - ti->error = "Invalid corrupt bio direction (r or w)"; - return -EINVAL; - } - argc--; - - /* - * Value of byte (0-255) to write in place of correct one. - */ - r = dm_read_arg(_args + 2, as, &fc->corrupt_bio_value, &ti->error); - if (r) - return r; - argc--; - - /* - * Only corrupt bios with these flags set. - */ - r = dm_read_arg(_args + 3, as, &fc->corrupt_bio_flags, &ti->error); - if (r) - return r; - argc--; - - continue; - } - - ti->error = "Unrecognised flakey feature requested"; - return -EINVAL; - } - - if (test_bit(DROP_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) { - ti->error = "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set"; - return -EINVAL; - } - - return 0; -} - /* - * Construct a flakey mapping: - * [<#feature args> []*] - * - * Feature args: - * [drop_writes] - * [corrupt_bio_byte ] - * - * Nth_byte starts from 1 for the first byte. - * Direction is r for READ or w for WRITE. - * bio_flags is ignored if 0. + * Construct a flakey mapping: */ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) { - static struct dm_arg _args[] = { - {0, UINT_MAX, "Invalid up interval"}, - {0, UINT_MAX, "Invalid down interval"}, - }; - - int r; struct flakey_c *fc; - unsigned long long tmpll; - struct dm_arg_set as; - const char *devname; + unsigned long long tmp; - as.argc = argc; - as.argv = argv; - - if (argc < 4) { - ti->error = "Invalid argument count"; + if (argc != 4) { + ti->error = "dm-flakey: Invalid argument count"; return -EINVAL; } - fc = kzalloc(sizeof(*fc), GFP_KERNEL); + fc = kmalloc(sizeof(*fc), GFP_KERNEL); if (!fc) { - ti->error = "Cannot allocate linear context"; + ti->error = "dm-flakey: Cannot allocate linear context"; return -ENOMEM; } fc->start_time = jiffies; - devname = dm_shift_arg(&as); - - if (sscanf(dm_shift_arg(&as), "%llu", &tmpll) != 1) { - ti->error = "Invalid device sector"; + if (sscanf(argv[1], "%llu", &tmp) != 1) { + ti->error = "dm-flakey: Invalid device sector"; goto bad; } - fc->start = tmpll; + fc->start = tmp; - r = dm_read_arg(_args, &as, &fc->up_interval, &ti->error); - if (r) + if (sscanf(argv[2], "%u", &fc->up_interval) != 1) { + ti->error = "dm-flakey: Invalid up interval"; goto bad; + } - r = dm_read_arg(_args, &as, &fc->down_interval, &ti->error); - if (r) + if (sscanf(argv[3], "%u", &fc->down_interval) != 1) { + ti->error = "dm-flakey: Invalid down interval"; goto bad; + } if (!(fc->up_interval + fc->down_interval)) { - ti->error = "Total (up + down) interval is zero"; + ti->error = "dm-flakey: Total (up + down) interval is zero"; goto bad; } if (fc->up_interval + fc->down_interval < fc->up_interval) { - ti->error = "Interval overflow"; + ti->error = "dm-flakey: Interval overflow"; goto bad; } - r = parse_features(&as, fc, ti); - if (r) - goto bad; - - if (dm_get_device(ti, devname, dm_table_get_mode(ti->table), &fc->dev)) { - ti->error = "Device lookup failed"; + if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &fc->dev)) { + ti->error = "dm-flakey: Device lookup failed"; goto bad; } ti->num_flush_requests = 1; - ti->num_discard_requests = 1; ti->private = fc; return 0; @@ -231,7 +99,7 @@ static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector) { struct flakey_c *fc = ti->private; - return fc->start + dm_target_offset(ti, bi_sector); + return fc->start + (bi_sector - ti->begin); } static void flakey_map_bio(struct dm_target *ti, struct bio *bio) @@ -243,25 +111,6 @@ static void flakey_map_bio(struct dm_target *ti, struct bio *bio) bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); } -static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) -{ - unsigned bio_bytes = bio_cur_bytes(bio); - char *data = bio_data(bio); - - /* - * Overwrite the Nth byte of the data returned. - */ - if (data && bio_bytes >= fc->corrupt_bio_byte) { - data[fc->corrupt_bio_byte - 1] = fc->corrupt_bio_value; - - DMDEBUG("Corrupting data bio=%p by writing %u to byte %u " - "(rw=%c bi_rw=%lu bi_sector=%llu cur_bytes=%u)\n", - bio, fc->corrupt_bio_value, fc->corrupt_bio_byte, - (bio_data_dir(bio) == WRITE) ? 'w' : 'r', - bio->bi_rw, (unsigned long long)bio->bi_sector, bio_bytes); - } -} - static int flakey_map(struct dm_target *ti, struct bio *bio, union map_info *map_context) { @@ -270,71 +119,18 @@ static int flakey_map(struct dm_target *ti, struct bio *bio, /* Are we alive ? */ elapsed = (jiffies - fc->start_time) / HZ; - if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) { - /* - * Flag this bio as submitted while down. - */ - map_context->ll = 1; - - /* - * Map reads as normal. - */ - if (bio_data_dir(bio) == READ) - goto map_bio; - - /* - * Drop writes? - */ - if (test_bit(DROP_WRITES, &fc->flags)) { - bio_endio(bio, 0); - return DM_MAPIO_SUBMITTED; - } - - /* - * Corrupt matching writes. - */ - if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == WRITE)) { - if (all_corrupt_bio_flags_match(bio, fc)) - corrupt_bio_data(bio, fc); - goto map_bio; - } - - /* - * By default, error all I/O. - */ + if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) return -EIO; - } -map_bio: flakey_map_bio(ti, bio); return DM_MAPIO_REMAPPED; } -static int flakey_end_io(struct dm_target *ti, struct bio *bio, - int error, union map_info *map_context) -{ - struct flakey_c *fc = ti->private; - unsigned bio_submitted_while_down = map_context->ll; - - /* - * Corrupt successful READs while in down state. - * If flags were specified, only corrupt those that match. - */ - if (!error && bio_submitted_while_down && - (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) && - all_corrupt_bio_flags_match(bio, fc)) - corrupt_bio_data(bio, fc); - - return error; -} - static int flakey_status(struct dm_target *ti, status_type_t type, char *result, unsigned int maxlen) { - unsigned sz = 0; struct flakey_c *fc = ti->private; - unsigned drop_writes; switch (type) { case STATUSTYPE_INFO: @@ -342,22 +138,9 @@ static int flakey_status(struct dm_target *ti, status_type_t type, break; case STATUSTYPE_TABLE: - DMEMIT("%s %llu %u %u ", fc->dev->name, - (unsigned long long)fc->start, fc->up_interval, - fc->down_interval); - - drop_writes = test_bit(DROP_WRITES, &fc->flags); - DMEMIT("%u ", drop_writes + (fc->corrupt_bio_byte > 0) * 5); - - if (drop_writes) - DMEMIT("drop_writes "); - - if (fc->corrupt_bio_byte) - DMEMIT("corrupt_bio_byte %u %c %u %u ", - fc->corrupt_bio_byte, - (fc->corrupt_bio_rw == WRITE) ? 'w' : 'r', - fc->corrupt_bio_value, fc->corrupt_bio_flags); - + snprintf(result, maxlen, "%s %llu %u %u", fc->dev->name, + (unsigned long long)fc->start, fc->up_interval, + fc->down_interval); break; } return 0; @@ -394,12 +177,11 @@ static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_ static struct target_type flakey_target = { .name = "flakey", - .version = {1, 2, 0}, + .version = {1, 1, 0}, .module = THIS_MODULE, .ctr = flakey_ctr, .dtr = flakey_dtr, .map = flakey_map, - .end_io = flakey_end_io, .status = flakey_status, .ioctl = flakey_ioctl, .merge = flakey_merge, diff --git a/trunk/drivers/md/dm-io.c b/trunk/drivers/md/dm-io.c index ad2eba40e319..2067288f61f9 100644 --- a/trunk/drivers/md/dm-io.c +++ b/trunk/drivers/md/dm-io.c @@ -38,8 +38,6 @@ struct io { struct dm_io_client *client; io_notify_fn callback; void *context; - void *vma_invalidate_address; - unsigned long vma_invalidate_size; } __attribute__((aligned(DM_IO_MAX_REGIONS))); static struct kmem_cache *_dm_io_cache; @@ -118,10 +116,6 @@ static void dec_count(struct io *io, unsigned int region, int error) set_bit(region, &io->error_bits); if (atomic_dec_and_test(&io->count)) { - if (io->vma_invalidate_size) - invalidate_kernel_vmap_range(io->vma_invalidate_address, - io->vma_invalidate_size); - if (io->sleeper) wake_up_process(io->sleeper); @@ -165,9 +159,6 @@ struct dpages { unsigned context_u; void *context_ptr; - - void *vma_invalidate_address; - unsigned long vma_invalidate_size; }; /* @@ -386,9 +377,6 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, io->sleeper = current; io->client = client; - io->vma_invalidate_address = dp->vma_invalidate_address; - io->vma_invalidate_size = dp->vma_invalidate_size; - dispatch_io(rw, num_regions, where, dp, io, 1); while (1) { @@ -427,21 +415,13 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, io->callback = fn; io->context = context; - io->vma_invalidate_address = dp->vma_invalidate_address; - io->vma_invalidate_size = dp->vma_invalidate_size; - dispatch_io(rw, num_regions, where, dp, io, 0); return 0; } -static int dp_init(struct dm_io_request *io_req, struct dpages *dp, - unsigned long size) +static int dp_init(struct dm_io_request *io_req, struct dpages *dp) { /* Set up dpages based on memory type */ - - dp->vma_invalidate_address = NULL; - dp->vma_invalidate_size = 0; - switch (io_req->mem.type) { case DM_IO_PAGE_LIST: list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset); @@ -452,11 +432,6 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp, break; case DM_IO_VMA: - flush_kernel_vmap_range(io_req->mem.ptr.vma, size); - if ((io_req->bi_rw & RW_MASK) == READ) { - dp->vma_invalidate_address = io_req->mem.ptr.vma; - dp->vma_invalidate_size = size; - } vm_dp_init(dp, io_req->mem.ptr.vma); break; @@ -485,7 +460,7 @@ int dm_io(struct dm_io_request *io_req, unsigned num_regions, int r; struct dpages dp; - r = dp_init(io_req, &dp, (unsigned long)where->count << SECTOR_SHIFT); + r = dp_init(io_req, &dp); if (r) return r; diff --git a/trunk/drivers/md/dm-ioctl.c b/trunk/drivers/md/dm-ioctl.c index 2e9a3ca37bdd..4cacdad2270a 100644 --- a/trunk/drivers/md/dm-ioctl.c +++ b/trunk/drivers/md/dm-ioctl.c @@ -128,24 +128,6 @@ static struct hash_cell *__get_uuid_cell(const char *str) return NULL; } -static struct hash_cell *__get_dev_cell(uint64_t dev) -{ - struct mapped_device *md; - struct hash_cell *hc; - - md = dm_get_md(huge_decode_dev(dev)); - if (!md) - return NULL; - - hc = dm_get_mdptr(md); - if (!hc) { - dm_put(md); - return NULL; - } - - return hc; -} - /*----------------------------------------------------------------- * Inserting, removing and renaming a device. *---------------------------------------------------------------*/ @@ -736,45 +718,25 @@ static int dev_create(struct dm_ioctl *param, size_t param_size) */ static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) { - struct hash_cell *hc = NULL; + struct mapped_device *md; + void *mdptr = NULL; - if (*param->uuid) { - if (*param->name || param->dev) - return NULL; + if (*param->uuid) + return __get_uuid_cell(param->uuid); - hc = __get_uuid_cell(param->uuid); - if (!hc) - return NULL; - } else if (*param->name) { - if (param->dev) - return NULL; + if (*param->name) + return __get_name_cell(param->name); - hc = __get_name_cell(param->name); - if (!hc) - return NULL; - } else if (param->dev) { - hc = __get_dev_cell(param->dev); - if (!hc) - return NULL; - } else - return NULL; - - /* - * Sneakily write in both the name and the uuid - * while we have the cell. - */ - strlcpy(param->name, hc->name, sizeof(param->name)); - if (hc->uuid) - strlcpy(param->uuid, hc->uuid, sizeof(param->uuid)); - else - param->uuid[0] = '\0'; + md = dm_get_md(huge_decode_dev(param->dev)); + if (!md) + goto out; - if (hc->new_map) - param->flags |= DM_INACTIVE_PRESENT_FLAG; - else - param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + mdptr = dm_get_mdptr(md); + if (!mdptr) + dm_put(md); - return hc; +out: + return mdptr; } static struct mapped_device *find_device(struct dm_ioctl *param) @@ -784,8 +746,24 @@ static struct mapped_device *find_device(struct dm_ioctl *param) down_read(&_hash_lock); hc = __find_device_hash_cell(param); - if (hc) + if (hc) { md = hc->md; + + /* + * Sneakily write in both the name and the uuid + * while we have the cell. + */ + strlcpy(param->name, hc->name, sizeof(param->name)); + if (hc->uuid) + strlcpy(param->uuid, hc->uuid, sizeof(param->uuid)); + else + param->uuid[0] = '\0'; + + if (hc->new_map) + param->flags |= DM_INACTIVE_PRESENT_FLAG; + else + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + } up_read(&_hash_lock); return md; @@ -1424,11 +1402,6 @@ static int target_message(struct dm_ioctl *param, size_t param_size) goto out; } - if (!argc) { - DMWARN("Empty message received."); - goto out; - } - table = dm_get_live_table(md); if (!table) goto out_argv; diff --git a/trunk/drivers/md/dm-kcopyd.c b/trunk/drivers/md/dm-kcopyd.c index f82147029636..320401dec104 100644 --- a/trunk/drivers/md/dm-kcopyd.c +++ b/trunk/drivers/md/dm-kcopyd.c @@ -224,6 +224,8 @@ struct kcopyd_job { unsigned int num_dests; struct dm_io_region dests[DM_KCOPYD_MAX_REGIONS]; + sector_t offset; + unsigned int nr_pages; struct page_list *pages; /* @@ -378,7 +380,7 @@ static int run_io_job(struct kcopyd_job *job) .bi_rw = job->rw, .mem.type = DM_IO_PAGE_LIST, .mem.ptr.pl = job->pages, - .mem.offset = 0, + .mem.offset = job->offset, .notify.fn = complete_io, .notify.context = job, .client = job->kc->io_client, @@ -395,9 +397,10 @@ static int run_io_job(struct kcopyd_job *job) static int run_pages_job(struct kcopyd_job *job) { int r; - unsigned nr_pages = dm_div_up(job->dests[0].count, PAGE_SIZE >> 9); - r = kcopyd_get_pages(job->kc, nr_pages, &job->pages); + job->nr_pages = dm_div_up(job->dests[0].count + job->offset, + PAGE_SIZE >> 9); + r = kcopyd_get_pages(job->kc, job->nr_pages, &job->pages); if (!r) { /* this job is ready for io */ push(&job->kc->io_jobs, job); @@ -599,6 +602,8 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, job->num_dests = num_dests; memcpy(&job->dests, dests, sizeof(*dests) * num_dests); + job->offset = 0; + job->nr_pages = 0; job->pages = NULL; job->fn = fn; @@ -617,37 +622,6 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, } EXPORT_SYMBOL(dm_kcopyd_copy); -void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, - dm_kcopyd_notify_fn fn, void *context) -{ - struct kcopyd_job *job; - - job = mempool_alloc(kc->job_pool, GFP_NOIO); - - memset(job, 0, sizeof(struct kcopyd_job)); - job->kc = kc; - job->fn = fn; - job->context = context; - - atomic_inc(&kc->nr_jobs); - - return job; -} -EXPORT_SYMBOL(dm_kcopyd_prepare_callback); - -void dm_kcopyd_do_callback(void *j, int read_err, unsigned long write_err) -{ - struct kcopyd_job *job = j; - struct dm_kcopyd_client *kc = job->kc; - - job->read_err = read_err; - job->write_err = write_err; - - push(&kc->complete_jobs, job); - wake(kc); -} -EXPORT_SYMBOL(dm_kcopyd_do_callback); - /* * Cancels a kcopyd job, eg. someone might be deactivating a * mirror. diff --git a/trunk/drivers/md/dm-log-userspace-base.c b/trunk/drivers/md/dm-log-userspace-base.c index 1021c8986011..aa2e0c374ab3 100644 --- a/trunk/drivers/md/dm-log-userspace-base.c +++ b/trunk/drivers/md/dm-log-userspace-base.c @@ -394,7 +394,8 @@ static int flush_by_group(struct log_c *lc, struct list_head *flush_list) group[count] = fe->region; count++; - list_move(&fe->list, &tmp_list); + list_del(&fe->list); + list_add(&fe->list, &tmp_list); type = fe->type; if (count >= MAX_FLUSH_GROUP_COUNT) diff --git a/trunk/drivers/md/dm-log.c b/trunk/drivers/md/dm-log.c index 3b52bb72bd1f..948e3f4925bf 100644 --- a/trunk/drivers/md/dm-log.c +++ b/trunk/drivers/md/dm-log.c @@ -197,21 +197,15 @@ EXPORT_SYMBOL(dm_dirty_log_destroy); #define MIRROR_DISK_VERSION 2 #define LOG_OFFSET 2 -struct log_header_disk { - __le32 magic; +struct log_header { + uint32_t magic; /* * Simple, incrementing version. no backward * compatibility. */ - __le32 version; - __le64 nr_regions; -} __packed; - -struct log_header_core { - uint32_t magic; uint32_t version; - uint64_t nr_regions; + sector_t nr_regions; }; struct log_c { @@ -245,10 +239,10 @@ struct log_c { int log_dev_failed; int log_dev_flush_failed; struct dm_dev *log_dev; - struct log_header_core header; + struct log_header header; struct dm_io_region header_location; - struct log_header_disk *disk_header; + struct log_header *disk_header; }; /* @@ -257,34 +251,34 @@ struct log_c { */ static inline int log_test_bit(uint32_t *bs, unsigned bit) { - return test_bit_le(bit, bs) ? 1 : 0; + return test_bit_le(bit, (unsigned long *) bs) ? 1 : 0; } static inline void log_set_bit(struct log_c *l, uint32_t *bs, unsigned bit) { - __set_bit_le(bit, bs); + __test_and_set_bit_le(bit, (unsigned long *) bs); l->touched_cleaned = 1; } static inline void log_clear_bit(struct log_c *l, uint32_t *bs, unsigned bit) { - __clear_bit_le(bit, bs); + __test_and_clear_bit_le(bit, (unsigned long *) bs); l->touched_dirtied = 1; } /*---------------------------------------------------------------- * Header IO *--------------------------------------------------------------*/ -static void header_to_disk(struct log_header_core *core, struct log_header_disk *disk) +static void header_to_disk(struct log_header *core, struct log_header *disk) { disk->magic = cpu_to_le32(core->magic); disk->version = cpu_to_le32(core->version); disk->nr_regions = cpu_to_le64(core->nr_regions); } -static void header_from_disk(struct log_header_core *core, struct log_header_disk *disk) +static void header_from_disk(struct log_header *core, struct log_header *disk) { core->magic = le32_to_cpu(disk->magic); core->version = le32_to_cpu(disk->version); @@ -492,7 +486,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size); lc->sync_count = (sync == NOSYNC) ? region_count : 0; - lc->recovering_bits = vzalloc(bitset_size); + lc->recovering_bits = vmalloc(bitset_size); if (!lc->recovering_bits) { DMWARN("couldn't allocate sync bitset"); vfree(lc->sync_bits); @@ -504,6 +498,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, kfree(lc); return -ENOMEM; } + memset(lc->recovering_bits, 0, bitset_size); lc->sync_search = 0; log->context = lc; @@ -744,7 +739,8 @@ static int core_get_resync_work(struct dm_dirty_log *log, region_t *region) return 0; do { - *region = find_next_zero_bit_le(lc->sync_bits, + *region = find_next_zero_bit_le( + (unsigned long *) lc->sync_bits, lc->region_count, lc->sync_search); lc->sync_search = *region + 1; diff --git a/trunk/drivers/md/dm-mpath.c b/trunk/drivers/md/dm-mpath.c index 5e0090ef4182..c3547016f0f1 100644 --- a/trunk/drivers/md/dm-mpath.c +++ b/trunk/drivers/md/dm-mpath.c @@ -22,6 +22,7 @@ #include #define DM_MSG_PREFIX "multipath" +#define MESG_STR(x) x, sizeof(x) #define DM_PG_INIT_DELAY_MSECS 2000 #define DM_PG_INIT_DELAY_DEFAULT ((unsigned) -1) @@ -504,29 +505,80 @@ static void trigger_event(struct work_struct *work) * <#paths> <#per-path selector args> * [ []* ]+ ]+ *---------------------------------------------------------------*/ -static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg, +struct param { + unsigned min; + unsigned max; + char *error; +}; + +static int read_param(struct param *param, char *str, unsigned *v, char **error) +{ + if (!str || + (sscanf(str, "%u", v) != 1) || + (*v < param->min) || + (*v > param->max)) { + *error = param->error; + return -EINVAL; + } + + return 0; +} + +struct arg_set { + unsigned argc; + char **argv; +}; + +static char *shift(struct arg_set *as) +{ + char *r; + + if (as->argc) { + as->argc--; + r = *as->argv; + as->argv++; + return r; + } + + return NULL; +} + +static void consume(struct arg_set *as, unsigned n) +{ + BUG_ON (as->argc < n); + as->argc -= n; + as->argv += n; +} + +static int parse_path_selector(struct arg_set *as, struct priority_group *pg, struct dm_target *ti) { int r; struct path_selector_type *pst; unsigned ps_argc; - static struct dm_arg _args[] = { + static struct param _params[] = { {0, 1024, "invalid number of path selector args"}, }; - pst = dm_get_path_selector(dm_shift_arg(as)); + pst = dm_get_path_selector(shift(as)); if (!pst) { ti->error = "unknown path selector type"; return -EINVAL; } - r = dm_read_arg_group(_args, as, &ps_argc, &ti->error); + r = read_param(_params, shift(as), &ps_argc, &ti->error); if (r) { dm_put_path_selector(pst); return -EINVAL; } + if (ps_argc > as->argc) { + dm_put_path_selector(pst); + ti->error = "not enough arguments for path selector"; + return -EINVAL; + } + r = pst->create(&pg->ps, ps_argc, as->argv); if (r) { dm_put_path_selector(pst); @@ -535,12 +587,12 @@ static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg, } pg->ps.type = pst; - dm_consume_args(as, ps_argc); + consume(as, ps_argc); return 0; } -static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps, +static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, struct dm_target *ti) { int r; @@ -557,7 +609,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps if (!p) return ERR_PTR(-ENOMEM); - r = dm_get_device(ti, dm_shift_arg(as), dm_table_get_mode(ti->table), + r = dm_get_device(ti, shift(as), dm_table_get_mode(ti->table), &p->path.dev); if (r) { ti->error = "error getting device"; @@ -608,16 +660,16 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps return ERR_PTR(r); } -static struct priority_group *parse_priority_group(struct dm_arg_set *as, +static struct priority_group *parse_priority_group(struct arg_set *as, struct multipath *m) { - static struct dm_arg _args[] = { + static struct param _params[] = { {1, 1024, "invalid number of paths"}, {0, 1024, "invalid number of selector args"} }; int r; - unsigned i, nr_selector_args, nr_args; + unsigned i, nr_selector_args, nr_params; struct priority_group *pg; struct dm_target *ti = m->ti; @@ -641,26 +693,26 @@ static struct priority_group *parse_priority_group(struct dm_arg_set *as, /* * read the paths */ - r = dm_read_arg(_args, as, &pg->nr_pgpaths, &ti->error); + r = read_param(_params, shift(as), &pg->nr_pgpaths, &ti->error); if (r) goto bad; - r = dm_read_arg(_args + 1, as, &nr_selector_args, &ti->error); + r = read_param(_params + 1, shift(as), &nr_selector_args, &ti->error); if (r) goto bad; - nr_args = 1 + nr_selector_args; + nr_params = 1 + nr_selector_args; for (i = 0; i < pg->nr_pgpaths; i++) { struct pgpath *pgpath; - struct dm_arg_set path_args; + struct arg_set path_args; - if (as->argc < nr_args) { + if (as->argc < nr_params) { ti->error = "not enough path parameters"; r = -EINVAL; goto bad; } - path_args.argc = nr_args; + path_args.argc = nr_params; path_args.argv = as->argv; pgpath = parse_path(&path_args, &pg->ps, ti); @@ -671,7 +723,7 @@ static struct priority_group *parse_priority_group(struct dm_arg_set *as, pgpath->pg = pg; list_add_tail(&pgpath->list, &pg->pgpaths); - dm_consume_args(as, nr_args); + consume(as, nr_params); } return pg; @@ -681,23 +733,28 @@ static struct priority_group *parse_priority_group(struct dm_arg_set *as, return ERR_PTR(r); } -static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) +static int parse_hw_handler(struct arg_set *as, struct multipath *m) { unsigned hw_argc; int ret; struct dm_target *ti = m->ti; - static struct dm_arg _args[] = { + static struct param _params[] = { {0, 1024, "invalid number of hardware handler args"}, }; - if (dm_read_arg_group(_args, as, &hw_argc, &ti->error)) + if (read_param(_params, shift(as), &hw_argc, &ti->error)) return -EINVAL; if (!hw_argc) return 0; - m->hw_handler_name = kstrdup(dm_shift_arg(as), GFP_KERNEL); + if (hw_argc > as->argc) { + ti->error = "not enough arguments for hardware handler"; + return -EINVAL; + } + + m->hw_handler_name = kstrdup(shift(as), GFP_KERNEL); request_module("scsi_dh_%s", m->hw_handler_name); if (scsi_dh_handler_exist(m->hw_handler_name) == 0) { ti->error = "unknown hardware handler type"; @@ -721,7 +778,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) for (i = 0, p+=j+1; i <= hw_argc - 2; i++, p+=j+1) j = sprintf(p, "%s", as->argv[i]); } - dm_consume_args(as, hw_argc - 1); + consume(as, hw_argc - 1); return 0; fail: @@ -730,20 +787,20 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) return ret; } -static int parse_features(struct dm_arg_set *as, struct multipath *m) +static int parse_features(struct arg_set *as, struct multipath *m) { int r; unsigned argc; struct dm_target *ti = m->ti; - const char *arg_name; + const char *param_name; - static struct dm_arg _args[] = { + static struct param _params[] = { {0, 5, "invalid number of feature args"}, {1, 50, "pg_init_retries must be between 1 and 50"}, {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, }; - r = dm_read_arg_group(_args, as, &argc, &ti->error); + r = read_param(_params, shift(as), &argc, &ti->error); if (r) return -EINVAL; @@ -751,24 +808,26 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) return 0; do { - arg_name = dm_shift_arg(as); + param_name = shift(as); argc--; - if (!strcasecmp(arg_name, "queue_if_no_path")) { + if (!strnicmp(param_name, MESG_STR("queue_if_no_path"))) { r = queue_if_no_path(m, 1, 0); continue; } - if (!strcasecmp(arg_name, "pg_init_retries") && + if (!strnicmp(param_name, MESG_STR("pg_init_retries")) && (argc >= 1)) { - r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error); + r = read_param(_params + 1, shift(as), + &m->pg_init_retries, &ti->error); argc--; continue; } - if (!strcasecmp(arg_name, "pg_init_delay_msecs") && + if (!strnicmp(param_name, MESG_STR("pg_init_delay_msecs")) && (argc >= 1)) { - r = dm_read_arg(_args + 2, as, &m->pg_init_delay_msecs, &ti->error); + r = read_param(_params + 2, shift(as), + &m->pg_init_delay_msecs, &ti->error); argc--; continue; } @@ -783,15 +842,15 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) static int multipath_ctr(struct dm_target *ti, unsigned int argc, char **argv) { - /* target arguments */ - static struct dm_arg _args[] = { + /* target parameters */ + static struct param _params[] = { {0, 1024, "invalid number of priority groups"}, {0, 1024, "invalid initial priority group number"}, }; int r; struct multipath *m; - struct dm_arg_set as; + struct arg_set as; unsigned pg_count = 0; unsigned next_pg_num; @@ -812,11 +871,11 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, if (r) goto bad; - r = dm_read_arg(_args, &as, &m->nr_priority_groups, &ti->error); + r = read_param(_params, shift(&as), &m->nr_priority_groups, &ti->error); if (r) goto bad; - r = dm_read_arg(_args + 1, &as, &next_pg_num, &ti->error); + r = read_param(_params + 1, shift(&as), &next_pg_num, &ti->error); if (r) goto bad; @@ -1446,10 +1505,10 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv) } if (argc == 1) { - if (!strcasecmp(argv[0], "queue_if_no_path")) { + if (!strnicmp(argv[0], MESG_STR("queue_if_no_path"))) { r = queue_if_no_path(m, 1, 0); goto out; - } else if (!strcasecmp(argv[0], "fail_if_no_path")) { + } else if (!strnicmp(argv[0], MESG_STR("fail_if_no_path"))) { r = queue_if_no_path(m, 0, 0); goto out; } @@ -1460,18 +1519,18 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv) goto out; } - if (!strcasecmp(argv[0], "disable_group")) { + if (!strnicmp(argv[0], MESG_STR("disable_group"))) { r = bypass_pg_num(m, argv[1], 1); goto out; - } else if (!strcasecmp(argv[0], "enable_group")) { + } else if (!strnicmp(argv[0], MESG_STR("enable_group"))) { r = bypass_pg_num(m, argv[1], 0); goto out; - } else if (!strcasecmp(argv[0], "switch_group")) { + } else if (!strnicmp(argv[0], MESG_STR("switch_group"))) { r = switch_pg_num(m, argv[1]); goto out; - } else if (!strcasecmp(argv[0], "reinstate_path")) + } else if (!strnicmp(argv[0], MESG_STR("reinstate_path"))) action = reinstate_path; - else if (!strcasecmp(argv[0], "fail_path")) + else if (!strnicmp(argv[0], MESG_STR("fail_path"))) action = fail_path; else { DMWARN("Unrecognised multipath message received."); diff --git a/trunk/drivers/md/dm-raid.c b/trunk/drivers/md/dm-raid.c index a002dd85db1e..e5d8904fc8f6 100644 --- a/trunk/drivers/md/dm-raid.c +++ b/trunk/drivers/md/dm-raid.c @@ -8,19 +8,19 @@ #include #include "md.h" -#include "raid1.h" #include "raid5.h" +#include "dm.h" #include "bitmap.h" -#include - #define DM_MSG_PREFIX "raid" /* - * The following flags are used by dm-raid.c to set up the array state. - * They must be cleared before md_run is called. + * If the MD doesn't support MD_SYNC_STATE_FORCED yet, then + * make it so the flag doesn't set anything. */ -#define FirstUse 10 /* rdev flag */ +#ifndef MD_SYNC_STATE_FORCED +#define MD_SYNC_STATE_FORCED 0 +#endif struct raid_dev { /* @@ -43,15 +43,14 @@ struct raid_dev { /* * Flags for rs->print_flags field. */ -#define DMPF_SYNC 0x1 -#define DMPF_NOSYNC 0x2 -#define DMPF_REBUILD 0x4 -#define DMPF_DAEMON_SLEEP 0x8 -#define DMPF_MIN_RECOVERY_RATE 0x10 -#define DMPF_MAX_RECOVERY_RATE 0x20 -#define DMPF_MAX_WRITE_BEHIND 0x40 -#define DMPF_STRIPE_CACHE 0x80 -#define DMPF_REGION_SIZE 0X100 +#define DMPF_DAEMON_SLEEP 0x1 +#define DMPF_MAX_WRITE_BEHIND 0x2 +#define DMPF_SYNC 0x4 +#define DMPF_NOSYNC 0x8 +#define DMPF_STRIPE_CACHE 0x10 +#define DMPF_MIN_RECOVERY_RATE 0x20 +#define DMPF_MAX_RECOVERY_RATE 0x40 + struct raid_set { struct dm_target *ti; @@ -73,7 +72,6 @@ static struct raid_type { const unsigned level; /* RAID level. */ const unsigned algorithm; /* RAID algorithm. */ } raid_types[] = { - {"raid1", "RAID1 (mirroring)", 0, 2, 1, 0 /* NONE */}, {"raid4", "RAID4 (dedicated parity disk)", 1, 2, 5, ALGORITHM_PARITY_0}, {"raid5_la", "RAID5 (left asymmetric)", 1, 2, 5, ALGORITHM_LEFT_ASYMMETRIC}, {"raid5_ra", "RAID5 (right asymmetric)", 1, 2, 5, ALGORITHM_RIGHT_ASYMMETRIC}, @@ -107,8 +105,7 @@ static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *ra } sectors_per_dev = ti->len; - if ((raid_type->level > 1) && - sector_div(sectors_per_dev, (raid_devs - raid_type->parity_devs))) { + if (sector_div(sectors_per_dev, (raid_devs - raid_type->parity_devs))) { ti->error = "Target length not divisible by number of data devices"; return ERR_PTR(-EINVAL); } @@ -150,16 +147,9 @@ static void context_free(struct raid_set *rs) { int i; - for (i = 0; i < rs->md.raid_disks; i++) { - if (rs->dev[i].meta_dev) - dm_put_device(rs->ti, rs->dev[i].meta_dev); - if (rs->dev[i].rdev.sb_page) - put_page(rs->dev[i].rdev.sb_page); - rs->dev[i].rdev.sb_page = NULL; - rs->dev[i].rdev.sb_loaded = 0; + for (i = 0; i < rs->md.raid_disks; i++) if (rs->dev[i].data_dev) dm_put_device(rs->ti, rs->dev[i].data_dev); - } kfree(rs); } @@ -169,16 +159,7 @@ static void context_free(struct raid_set *rs) * : meta device name or '-' if missing * : data device name or '-' if missing * - * The following are permitted: - * - - - * - - * - * - * The following is not allowed: - * - - * - * This code parses those words. If there is a failure, - * the caller must use context_free to unwind the operations. + * This code parses those words. */ static int dev_parms(struct raid_set *rs, char **argv) { @@ -201,16 +182,8 @@ static int dev_parms(struct raid_set *rs, char **argv) rs->dev[i].rdev.mddev = &rs->md; if (strcmp(argv[0], "-")) { - ret = dm_get_device(rs->ti, argv[0], - dm_table_get_mode(rs->ti->table), - &rs->dev[i].meta_dev); - rs->ti->error = "RAID metadata device lookup failure"; - if (ret) - return ret; - - rs->dev[i].rdev.sb_page = alloc_page(GFP_KERNEL); - if (!rs->dev[i].rdev.sb_page) - return -ENOMEM; + rs->ti->error = "Metadata devices not supported"; + return -EINVAL; } if (!strcmp(argv[1], "-")) { @@ -220,10 +193,6 @@ static int dev_parms(struct raid_set *rs, char **argv) return -EINVAL; } - rs->ti->error = "No data device supplied with metadata device"; - if (rs->dev[i].meta_dev) - return -EINVAL; - continue; } @@ -235,10 +204,6 @@ static int dev_parms(struct raid_set *rs, char **argv) return ret; } - if (rs->dev[i].meta_dev) { - metadata_available = 1; - rs->dev[i].rdev.meta_bdev = rs->dev[i].meta_dev->bdev; - } rs->dev[i].rdev.bdev = rs->dev[i].data_dev->bdev; list_add(&rs->dev[i].rdev.same_set, &rs->md.disks); if (!test_bit(In_sync, &rs->dev[i].rdev.flags)) @@ -269,110 +234,34 @@ static int dev_parms(struct raid_set *rs, char **argv) return 0; } -/* - * validate_region_size - * @rs - * @region_size: region size in sectors. If 0, pick a size (4MiB default). - * - * Set rs->md.bitmap_info.chunksize (which really refers to 'region size'). - * Ensure that (ti->len/region_size < 2^21) - required by MD bitmap. - * - * Returns: 0 on success, -EINVAL on failure. - */ -static int validate_region_size(struct raid_set *rs, unsigned long region_size) -{ - unsigned long min_region_size = rs->ti->len / (1 << 21); - - if (!region_size) { - /* - * Choose a reasonable default. All figures in sectors. - */ - if (min_region_size > (1 << 13)) { - DMINFO("Choosing default region size of %lu sectors", - region_size); - region_size = min_region_size; - } else { - DMINFO("Choosing default region size of 4MiB"); - region_size = 1 << 13; /* sectors */ - } - } else { - /* - * Validate user-supplied value. - */ - if (region_size > rs->ti->len) { - rs->ti->error = "Supplied region size is too large"; - return -EINVAL; - } - - if (region_size < min_region_size) { - DMERR("Supplied region_size (%lu sectors) below minimum (%lu)", - region_size, min_region_size); - rs->ti->error = "Supplied region size is too small"; - return -EINVAL; - } - - if (!is_power_of_2(region_size)) { - rs->ti->error = "Region size is not a power of 2"; - return -EINVAL; - } - - if (region_size < rs->md.chunk_sectors) { - rs->ti->error = "Region size is smaller than the chunk size"; - return -EINVAL; - } - } - - /* - * Convert sectors to bytes. - */ - rs->md.bitmap_info.chunksize = (region_size << 9); - - return 0; -} - /* * Possible arguments are... + * RAID456: * [optional_args] * - * Argument definitions - * The number of sectors per disk that - * will form the "stripe" - * [[no]sync] Force or prevent recovery of the - * entire array + * Optional args: + * [[no]sync] Force or prevent recovery of the entire array * [rebuild ] Rebuild the drive indicated by the index - * [daemon_sleep ] Time between bitmap daemon work to - * clear bits + * [daemon_sleep ] Time between bitmap daemon work to clear bits * [min_recovery_rate ] Throttle RAID initialization * [max_recovery_rate ] Throttle RAID initialization - * [write_mostly ] Indicate a write mostly drive via index * [max_write_behind ] See '-write-behind=' (man mdadm) * [stripe_cache ] Stripe cache size for higher RAIDs - * [region_size ] Defines granularity of bitmap */ static int parse_raid_params(struct raid_set *rs, char **argv, unsigned num_raid_params) { unsigned i, rebuild_cnt = 0; - unsigned long value, region_size = 0; + unsigned long value; char *key; /* * First, parse the in-order required arguments - * "chunk_size" is the only argument of this type. */ - if ((strict_strtoul(argv[0], 10, &value) < 0)) { + if ((strict_strtoul(argv[0], 10, &value) < 0) || + !is_power_of_2(value) || (value < 8)) { rs->ti->error = "Bad chunk size"; return -EINVAL; - } else if (rs->raid_type->level == 1) { - if (value) - DMERR("Ignoring chunk size parameter for RAID 1"); - value = 0; - } else if (!is_power_of_2(value)) { - rs->ti->error = "Chunk size must be a power of 2"; - return -EINVAL; - } else if (value < 8) { - rs->ti->error = "Chunk size value is too small"; - return -EINVAL; } rs->md.new_chunk_sectors = rs->md.chunk_sectors = value; @@ -380,39 +269,22 @@ static int parse_raid_params(struct raid_set *rs, char **argv, num_raid_params--; /* - * We set each individual device as In_sync with a completed - * 'recovery_offset'. If there has been a device failure or - * replacement then one of the following cases applies: - * - * 1) User specifies 'rebuild'. - * - Device is reset when param is read. - * 2) A new device is supplied. - * - No matching superblock found, resets device. - * 3) Device failure was transient and returns on reload. - * - Failure noticed, resets device for bitmap replay. - * 4) Device hadn't completed recovery after previous failure. - * - Superblock is read and overrides recovery_offset. - * - * What is found in the superblocks of the devices is always - * authoritative, unless 'rebuild' or '[no]sync' was specified. + * Second, parse the unordered optional arguments */ - for (i = 0; i < rs->md.raid_disks; i++) { + for (i = 0; i < rs->md.raid_disks; i++) set_bit(In_sync, &rs->dev[i].rdev.flags); - rs->dev[i].rdev.recovery_offset = MaxSector; - } - /* - * Second, parse the unordered optional arguments - */ for (i = 0; i < num_raid_params; i++) { - if (!strcasecmp(argv[i], "nosync")) { + if (!strcmp(argv[i], "nosync")) { rs->md.recovery_cp = MaxSector; rs->print_flags |= DMPF_NOSYNC; + rs->md.flags |= MD_SYNC_STATE_FORCED; continue; } - if (!strcasecmp(argv[i], "sync")) { + if (!strcmp(argv[i], "sync")) { rs->md.recovery_cp = 0; rs->print_flags |= DMPF_SYNC; + rs->md.flags |= MD_SYNC_STATE_FORCED; continue; } @@ -428,13 +300,9 @@ static int parse_raid_params(struct raid_set *rs, char **argv, return -EINVAL; } - if (!strcasecmp(key, "rebuild")) { - rebuild_cnt++; - if (((rs->raid_type->level != 1) && - (rebuild_cnt > rs->raid_type->parity_devs)) || - ((rs->raid_type->level == 1) && - (rebuild_cnt > (rs->md.raid_disks - 1)))) { - rs->ti->error = "Too many rebuild devices specified for given RAID type"; + if (!strcmp(key, "rebuild")) { + if (++rebuild_cnt > rs->raid_type->parity_devs) { + rs->ti->error = "Too many rebuild drives given"; return -EINVAL; } if (value > rs->md.raid_disks) { @@ -443,22 +311,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv, } clear_bit(In_sync, &rs->dev[value].rdev.flags); rs->dev[value].rdev.recovery_offset = 0; - rs->print_flags |= DMPF_REBUILD; - } else if (!strcasecmp(key, "write_mostly")) { - if (rs->raid_type->level != 1) { - rs->ti->error = "write_mostly option is only valid for RAID1"; - return -EINVAL; - } - if (value > rs->md.raid_disks) { - rs->ti->error = "Invalid write_mostly drive index given"; - return -EINVAL; - } - set_bit(WriteMostly, &rs->dev[value].rdev.flags); - } else if (!strcasecmp(key, "max_write_behind")) { - if (rs->raid_type->level != 1) { - rs->ti->error = "max_write_behind option is only valid for RAID1"; - return -EINVAL; - } + } else if (!strcmp(key, "max_write_behind")) { rs->print_flags |= DMPF_MAX_WRITE_BEHIND; /* @@ -471,14 +324,14 @@ static int parse_raid_params(struct raid_set *rs, char **argv, return -EINVAL; } rs->md.bitmap_info.max_write_behind = value; - } else if (!strcasecmp(key, "daemon_sleep")) { + } else if (!strcmp(key, "daemon_sleep")) { rs->print_flags |= DMPF_DAEMON_SLEEP; if (!value || (value > MAX_SCHEDULE_TIMEOUT)) { rs->ti->error = "daemon sleep period out of range"; return -EINVAL; } rs->md.bitmap_info.daemon_sleep = value; - } else if (!strcasecmp(key, "stripe_cache")) { + } else if (!strcmp(key, "stripe_cache")) { rs->print_flags |= DMPF_STRIPE_CACHE; /* @@ -495,23 +348,20 @@ static int parse_raid_params(struct raid_set *rs, char **argv, rs->ti->error = "Bad stripe_cache size"; return -EINVAL; } - } else if (!strcasecmp(key, "min_recovery_rate")) { + } else if (!strcmp(key, "min_recovery_rate")) { rs->print_flags |= DMPF_MIN_RECOVERY_RATE; if (value > INT_MAX) { rs->ti->error = "min_recovery_rate out of range"; return -EINVAL; } rs->md.sync_speed_min = (int)value; - } else if (!strcasecmp(key, "max_recovery_rate")) { + } else if (!strcmp(key, "max_recovery_rate")) { rs->print_flags |= DMPF_MAX_RECOVERY_RATE; if (value > INT_MAX) { rs->ti->error = "max_recovery_rate out of range"; return -EINVAL; } rs->md.sync_speed_max = (int)value; - } else if (!strcasecmp(key, "region_size")) { - rs->print_flags |= DMPF_REGION_SIZE; - region_size = value; } else { DMERR("Unable to parse RAID parameter: %s", key); rs->ti->error = "Unable to parse RAID parameters"; @@ -519,19 +369,6 @@ static int parse_raid_params(struct raid_set *rs, char **argv, } } - if (validate_region_size(rs, region_size)) - return -EINVAL; - - if (rs->md.chunk_sectors) - rs->ti->split_io = rs->md.chunk_sectors; - else - rs->ti->split_io = region_size; - - if (rs->md.chunk_sectors) - rs->ti->split_io = rs->md.chunk_sectors; - else - rs->ti->split_io = region_size; - /* Assume there are no metadata devices until the drives are parsed */ rs->md.persistent = 0; rs->md.external = 1; @@ -550,351 +387,17 @@ static int raid_is_congested(struct dm_target_callbacks *cb, int bits) { struct raid_set *rs = container_of(cb, struct raid_set, callbacks); - if (rs->raid_type->level == 1) - return md_raid1_congested(&rs->md, bits); - return md_raid5_congested(&rs->md, bits); } -/* - * This structure is never routinely used by userspace, unlike md superblocks. - * Devices with this superblock should only ever be accessed via device-mapper. - */ -#define DM_RAID_MAGIC 0x64526D44 -struct dm_raid_superblock { - __le32 magic; /* "DmRd" */ - __le32 features; /* Used to indicate possible future changes */ - - __le32 num_devices; /* Number of devices in this array. (Max 64) */ - __le32 array_position; /* The position of this drive in the array */ - - __le64 events; /* Incremented by md when superblock updated */ - __le64 failed_devices; /* Bit field of devices to indicate failures */ - - /* - * This offset tracks the progress of the repair or replacement of - * an individual drive. - */ - __le64 disk_recovery_offset; - - /* - * This offset tracks the progress of the initial array - * synchronisation/parity calculation. - */ - __le64 array_resync_offset; - - /* - * RAID characteristics - */ - __le32 level; - __le32 layout; - __le32 stripe_sectors; - - __u8 pad[452]; /* Round struct to 512 bytes. */ - /* Always set to 0 when writing. */ -} __packed; - -static int read_disk_sb(mdk_rdev_t *rdev, int size) -{ - BUG_ON(!rdev->sb_page); - - if (rdev->sb_loaded) - return 0; - - if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) { - DMERR("Failed to read device superblock"); - return -EINVAL; - } - - rdev->sb_loaded = 1; - - return 0; -} - -static void super_sync(mddev_t *mddev, mdk_rdev_t *rdev) -{ - mdk_rdev_t *r, *t; - uint64_t failed_devices; - struct dm_raid_superblock *sb; - - sb = page_address(rdev->sb_page); - failed_devices = le64_to_cpu(sb->failed_devices); - - rdev_for_each(r, t, mddev) - if ((r->raid_disk >= 0) && test_bit(Faulty, &r->flags)) - failed_devices |= (1ULL << r->raid_disk); - - memset(sb, 0, sizeof(*sb)); - - sb->magic = cpu_to_le32(DM_RAID_MAGIC); - sb->features = cpu_to_le32(0); /* No features yet */ - - sb->num_devices = cpu_to_le32(mddev->raid_disks); - sb->array_position = cpu_to_le32(rdev->raid_disk); - - sb->events = cpu_to_le64(mddev->events); - sb->failed_devices = cpu_to_le64(failed_devices); - - sb->disk_recovery_offset = cpu_to_le64(rdev->recovery_offset); - sb->array_resync_offset = cpu_to_le64(mddev->recovery_cp); - - sb->level = cpu_to_le32(mddev->level); - sb->layout = cpu_to_le32(mddev->layout); - sb->stripe_sectors = cpu_to_le32(mddev->chunk_sectors); -} - -/* - * super_load - * - * This function creates a superblock if one is not found on the device - * and will decide which superblock to use if there's a choice. - * - * Return: 1 if use rdev, 0 if use refdev, -Exxx otherwise - */ -static int super_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev) -{ - int ret; - struct dm_raid_superblock *sb; - struct dm_raid_superblock *refsb; - uint64_t events_sb, events_refsb; - - rdev->sb_start = 0; - rdev->sb_size = sizeof(*sb); - - ret = read_disk_sb(rdev, rdev->sb_size); - if (ret) - return ret; - - sb = page_address(rdev->sb_page); - if (sb->magic != cpu_to_le32(DM_RAID_MAGIC)) { - super_sync(rdev->mddev, rdev); - - set_bit(FirstUse, &rdev->flags); - - /* Force writing of superblocks to disk */ - set_bit(MD_CHANGE_DEVS, &rdev->mddev->flags); - - /* Any superblock is better than none, choose that if given */ - return refdev ? 0 : 1; - } - - if (!refdev) - return 1; - - events_sb = le64_to_cpu(sb->events); - - refsb = page_address(refdev->sb_page); - events_refsb = le64_to_cpu(refsb->events); - - return (events_sb > events_refsb) ? 1 : 0; -} - -static int super_init_validation(mddev_t *mddev, mdk_rdev_t *rdev) -{ - int role; - struct raid_set *rs = container_of(mddev, struct raid_set, md); - uint64_t events_sb; - uint64_t failed_devices; - struct dm_raid_superblock *sb; - uint32_t new_devs = 0; - uint32_t rebuilds = 0; - mdk_rdev_t *r, *t; - struct dm_raid_superblock *sb2; - - sb = page_address(rdev->sb_page); - events_sb = le64_to_cpu(sb->events); - failed_devices = le64_to_cpu(sb->failed_devices); - - /* - * Initialise to 1 if this is a new superblock. - */ - mddev->events = events_sb ? : 1; - - /* - * Reshaping is not currently allowed - */ - if ((le32_to_cpu(sb->level) != mddev->level) || - (le32_to_cpu(sb->layout) != mddev->layout) || - (le32_to_cpu(sb->stripe_sectors) != mddev->chunk_sectors)) { - DMERR("Reshaping arrays not yet supported."); - return -EINVAL; - } - - /* We can only change the number of devices in RAID1 right now */ - if ((rs->raid_type->level != 1) && - (le32_to_cpu(sb->num_devices) != mddev->raid_disks)) { - DMERR("Reshaping arrays not yet supported."); - return -EINVAL; - } - - if (!(rs->print_flags & (DMPF_SYNC | DMPF_NOSYNC))) - mddev->recovery_cp = le64_to_cpu(sb->array_resync_offset); - - /* - * During load, we set FirstUse if a new superblock was written. - * There are two reasons we might not have a superblock: - * 1) The array is brand new - in which case, all of the - * devices must have their In_sync bit set. Also, - * recovery_cp must be 0, unless forced. - * 2) This is a new device being added to an old array - * and the new device needs to be rebuilt - in which - * case the In_sync bit will /not/ be set and - * recovery_cp must be MaxSector. - */ - rdev_for_each(r, t, mddev) { - if (!test_bit(In_sync, &r->flags)) { - if (!test_bit(FirstUse, &r->flags)) - DMERR("Superblock area of " - "rebuild device %d should have been " - "cleared.", r->raid_disk); - set_bit(FirstUse, &r->flags); - rebuilds++; - } else if (test_bit(FirstUse, &r->flags)) - new_devs++; - } - - if (!rebuilds) { - if (new_devs == mddev->raid_disks) { - DMINFO("Superblocks created for new array"); - set_bit(MD_ARRAY_FIRST_USE, &mddev->flags); - } else if (new_devs) { - DMERR("New device injected " - "into existing array without 'rebuild' " - "parameter specified"); - return -EINVAL; - } - } else if (new_devs) { - DMERR("'rebuild' devices cannot be " - "injected into an array with other first-time devices"); - return -EINVAL; - } else if (mddev->recovery_cp != MaxSector) { - DMERR("'rebuild' specified while array is not in-sync"); - return -EINVAL; - } - - /* - * Now we set the Faulty bit for those devices that are - * recorded in the superblock as failed. - */ - rdev_for_each(r, t, mddev) { - if (!r->sb_page) - continue; - sb2 = page_address(r->sb_page); - sb2->failed_devices = 0; - - /* - * Check for any device re-ordering. - */ - if (!test_bit(FirstUse, &r->flags) && (r->raid_disk >= 0)) { - role = le32_to_cpu(sb2->array_position); - if (role != r->raid_disk) { - if (rs->raid_type->level != 1) { - rs->ti->error = "Cannot change device " - "positions in RAID array"; - return -EINVAL; - } - DMINFO("RAID1 device #%d now at position #%d", - role, r->raid_disk); - } - - /* - * Partial recovery is performed on - * returning failed devices. - */ - if (failed_devices & (1 << role)) - set_bit(Faulty, &r->flags); - } - } - - return 0; -} - -static int super_validate(mddev_t *mddev, mdk_rdev_t *rdev) -{ - struct dm_raid_superblock *sb = page_address(rdev->sb_page); - - /* - * If mddev->events is not set, we know we have not yet initialized - * the array. - */ - if (!mddev->events && super_init_validation(mddev, rdev)) - return -EINVAL; - - mddev->bitmap_info.offset = 4096 >> 9; /* Enable bitmap creation */ - rdev->mddev->bitmap_info.default_offset = 4096 >> 9; - if (!test_bit(FirstUse, &rdev->flags)) { - rdev->recovery_offset = le64_to_cpu(sb->disk_recovery_offset); - if (rdev->recovery_offset != MaxSector) - clear_bit(In_sync, &rdev->flags); - } - - /* - * If a device comes back, set it as not In_sync and no longer faulty. - */ - if (test_bit(Faulty, &rdev->flags)) { - clear_bit(Faulty, &rdev->flags); - clear_bit(In_sync, &rdev->flags); - rdev->saved_raid_disk = rdev->raid_disk; - rdev->recovery_offset = 0; - } - - clear_bit(FirstUse, &rdev->flags); - - return 0; -} - -/* - * Analyse superblocks and select the freshest. - */ -static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs) -{ - int ret; - mdk_rdev_t *rdev, *freshest, *tmp; - mddev_t *mddev = &rs->md; - - freshest = NULL; - rdev_for_each(rdev, tmp, mddev) { - if (!rdev->meta_bdev) - continue; - - ret = super_load(rdev, freshest); - - switch (ret) { - case 1: - freshest = rdev; - break; - case 0: - break; - default: - ti->error = "Failed to load superblock"; - return ret; - } - } - - if (!freshest) - return 0; - - /* - * Validation of the freshest device provides the source of - * validation for the remaining devices. - */ - ti->error = "Unable to assemble array: Invalid superblocks"; - if (super_validate(mddev, freshest)) - return -EINVAL; - - rdev_for_each(rdev, tmp, mddev) - if ((rdev != freshest) && super_validate(mddev, rdev)) - return -EINVAL; - - return 0; -} - /* * Construct a RAID4/5/6 mapping: * Args: * <#raid_params> \ * <#raid_devs> { .. } * + * ** metadata devices are not supported yet, use '-' instead ** + * * varies by . See 'parse_raid_params' for * details on possible . */ @@ -962,12 +465,8 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) if (ret) goto bad; - rs->md.sync_super = super_sync; - ret = analyse_superblocks(ti, rs); - if (ret) - goto bad; - INIT_WORK(&rs->md.event_work, do_table_event); + ti->split_io = rs->md.chunk_sectors; ti->private = rs; mutex_lock(&rs->md.reconfig_mutex); @@ -983,7 +482,6 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) rs->callbacks.congested_fn = raid_is_congested; dm_table_add_target_callbacks(ti->table, &rs->callbacks); - mddev_suspend(&rs->md); return 0; bad: @@ -1048,17 +546,12 @@ static int raid_status(struct dm_target *ti, status_type_t type, break; case STATUSTYPE_TABLE: /* The string you would use to construct this array */ - for (i = 0; i < rs->md.raid_disks; i++) { - if ((rs->print_flags & DMPF_REBUILD) && - rs->dev[i].data_dev && - !test_bit(In_sync, &rs->dev[i].rdev.flags)) - raid_param_cnt += 2; /* for rebuilds */ + for (i = 0; i < rs->md.raid_disks; i++) if (rs->dev[i].data_dev && - test_bit(WriteMostly, &rs->dev[i].rdev.flags)) - raid_param_cnt += 2; - } + !test_bit(In_sync, &rs->dev[i].rdev.flags)) + raid_param_cnt++; /* for rebuilds */ - raid_param_cnt += (hweight64(rs->print_flags & ~DMPF_REBUILD) * 2); + raid_param_cnt += (hweight64(rs->print_flags) * 2); if (rs->print_flags & (DMPF_SYNC | DMPF_NOSYNC)) raid_param_cnt--; @@ -1072,8 +565,7 @@ static int raid_status(struct dm_target *ti, status_type_t type, DMEMIT(" nosync"); for (i = 0; i < rs->md.raid_disks; i++) - if ((rs->print_flags & DMPF_REBUILD) && - rs->dev[i].data_dev && + if (rs->dev[i].data_dev && !test_bit(In_sync, &rs->dev[i].rdev.flags)) DMEMIT(" rebuild %u", i); @@ -1087,11 +579,6 @@ static int raid_status(struct dm_target *ti, status_type_t type, if (rs->print_flags & DMPF_MAX_RECOVERY_RATE) DMEMIT(" max_recovery_rate %d", rs->md.sync_speed_max); - for (i = 0; i < rs->md.raid_disks; i++) - if (rs->dev[i].data_dev && - test_bit(WriteMostly, &rs->dev[i].rdev.flags)) - DMEMIT(" write_mostly %u", i); - if (rs->print_flags & DMPF_MAX_WRITE_BEHIND) DMEMIT(" max_write_behind %lu", rs->md.bitmap_info.max_write_behind); @@ -1104,16 +591,9 @@ static int raid_status(struct dm_target *ti, status_type_t type, conf ? conf->max_nr_stripes * 2 : 0); } - if (rs->print_flags & DMPF_REGION_SIZE) - DMEMIT(" region_size %lu", - rs->md.bitmap_info.chunksize >> 9); - DMEMIT(" %d", rs->md.raid_disks); for (i = 0; i < rs->md.raid_disks; i++) { - if (rs->dev[i].meta_dev) - DMEMIT(" %s", rs->dev[i].meta_dev->name); - else - DMEMIT(" -"); + DMEMIT(" -"); /* metadata device */ if (rs->dev[i].data_dev) DMEMIT(" %s", rs->dev[i].data_dev->name); @@ -1170,13 +650,12 @@ static void raid_resume(struct dm_target *ti) { struct raid_set *rs = ti->private; - bitmap_load(&rs->md); mddev_resume(&rs->md); } static struct target_type raid_target = { .name = "raid", - .version = {1, 1, 0}, + .version = {1, 0, 0}, .module = THIS_MODULE, .ctr = raid_ctr, .dtr = raid_dtr, diff --git a/trunk/drivers/md/dm-snap-persistent.c b/trunk/drivers/md/dm-snap-persistent.c index d1f1d7017103..135c2f1fdbfc 100644 --- a/trunk/drivers/md/dm-snap-persistent.c +++ b/trunk/drivers/md/dm-snap-persistent.c @@ -58,30 +58,25 @@ #define NUM_SNAPSHOT_HDR_CHUNKS 1 struct disk_header { - __le32 magic; + uint32_t magic; /* * Is this snapshot valid. There is no way of recovering * an invalid snapshot. */ - __le32 valid; + uint32_t valid; /* * Simple, incrementing version. no backward * compatibility. */ - __le32 version; + uint32_t version; /* In sectors */ - __le32 chunk_size; -} __packed; + uint32_t chunk_size; +}; struct disk_exception { - __le64 old_chunk; - __le64 new_chunk; -} __packed; - -struct core_exception { uint64_t old_chunk; uint64_t new_chunk; }; @@ -174,9 +169,10 @@ static int alloc_area(struct pstore *ps) if (!ps->area) goto err_area; - ps->zero_area = vzalloc(len); + ps->zero_area = vmalloc(len); if (!ps->zero_area) goto err_zero_area; + memset(ps->zero_area, 0, len); ps->header_area = vmalloc(len); if (!ps->header_area) @@ -400,32 +396,32 @@ static struct disk_exception *get_exception(struct pstore *ps, uint32_t index) } static void read_exception(struct pstore *ps, - uint32_t index, struct core_exception *result) + uint32_t index, struct disk_exception *result) { - struct disk_exception *de = get_exception(ps, index); + struct disk_exception *e = get_exception(ps, index); /* copy it */ - result->old_chunk = le64_to_cpu(de->old_chunk); - result->new_chunk = le64_to_cpu(de->new_chunk); + result->old_chunk = le64_to_cpu(e->old_chunk); + result->new_chunk = le64_to_cpu(e->new_chunk); } static void write_exception(struct pstore *ps, - uint32_t index, struct core_exception *e) + uint32_t index, struct disk_exception *de) { - struct disk_exception *de = get_exception(ps, index); + struct disk_exception *e = get_exception(ps, index); /* copy it */ - de->old_chunk = cpu_to_le64(e->old_chunk); - de->new_chunk = cpu_to_le64(e->new_chunk); + e->old_chunk = cpu_to_le64(de->old_chunk); + e->new_chunk = cpu_to_le64(de->new_chunk); } static void clear_exception(struct pstore *ps, uint32_t index) { - struct disk_exception *de = get_exception(ps, index); + struct disk_exception *e = get_exception(ps, index); /* clear it */ - de->old_chunk = 0; - de->new_chunk = 0; + e->old_chunk = 0; + e->new_chunk = 0; } /* @@ -441,13 +437,13 @@ static int insert_exceptions(struct pstore *ps, { int r; unsigned int i; - struct core_exception e; + struct disk_exception de; /* presume the area is full */ *full = 1; for (i = 0; i < ps->exceptions_per_area; i++) { - read_exception(ps, i, &e); + read_exception(ps, i, &de); /* * If the new_chunk is pointing at the start of @@ -455,7 +451,7 @@ static int insert_exceptions(struct pstore *ps, * is we know that we've hit the end of the * exceptions. Therefore the area is not full. */ - if (e.new_chunk == 0LL) { + if (de.new_chunk == 0LL) { ps->current_committed = i; *full = 0; break; @@ -464,13 +460,13 @@ static int insert_exceptions(struct pstore *ps, /* * Keep track of the start of the free chunks. */ - if (ps->next_free <= e.new_chunk) - ps->next_free = e.new_chunk + 1; + if (ps->next_free <= de.new_chunk) + ps->next_free = de.new_chunk + 1; /* * Otherwise we add the exception to the snapshot. */ - r = callback(callback_context, e.old_chunk, e.new_chunk); + r = callback(callback_context, de.old_chunk, de.new_chunk); if (r) return r; } @@ -567,7 +563,7 @@ static int persistent_read_metadata(struct dm_exception_store *store, ps->exceptions_per_area = (ps->store->chunk_size << SECTOR_SHIFT) / sizeof(struct disk_exception); ps->callbacks = dm_vcalloc(ps->exceptions_per_area, - sizeof(*ps->callbacks)); + sizeof(*ps->callbacks)); if (!ps->callbacks) return -ENOMEM; @@ -645,12 +641,12 @@ static void persistent_commit_exception(struct dm_exception_store *store, { unsigned int i; struct pstore *ps = get_info(store); - struct core_exception ce; + struct disk_exception de; struct commit_callback *cb; - ce.old_chunk = e->old_chunk; - ce.new_chunk = e->new_chunk; - write_exception(ps, ps->current_committed++, &ce); + de.old_chunk = e->old_chunk; + de.new_chunk = e->new_chunk; + write_exception(ps, ps->current_committed++, &de); /* * Add the callback to the back of the array. This code @@ -674,7 +670,7 @@ static void persistent_commit_exception(struct dm_exception_store *store, * If we completely filled the current area, then wipe the next one. */ if ((ps->current_committed == ps->exceptions_per_area) && - zero_disk_area(ps, ps->current_area + 1)) + zero_disk_area(ps, ps->current_area + 1)) ps->valid = 0; /* @@ -705,7 +701,7 @@ static int persistent_prepare_merge(struct dm_exception_store *store, chunk_t *last_new_chunk) { struct pstore *ps = get_info(store); - struct core_exception ce; + struct disk_exception de; int nr_consecutive; int r; @@ -726,9 +722,9 @@ static int persistent_prepare_merge(struct dm_exception_store *store, ps->current_committed = ps->exceptions_per_area; } - read_exception(ps, ps->current_committed - 1, &ce); - *last_old_chunk = ce.old_chunk; - *last_new_chunk = ce.new_chunk; + read_exception(ps, ps->current_committed - 1, &de); + *last_old_chunk = de.old_chunk; + *last_new_chunk = de.new_chunk; /* * Find number of consecutive chunks within the current area, @@ -737,9 +733,9 @@ static int persistent_prepare_merge(struct dm_exception_store *store, for (nr_consecutive = 1; nr_consecutive < ps->current_committed; nr_consecutive++) { read_exception(ps, ps->current_committed - 1 - nr_consecutive, - &ce); - if (ce.old_chunk != *last_old_chunk - nr_consecutive || - ce.new_chunk != *last_new_chunk - nr_consecutive) + &de); + if (de.old_chunk != *last_old_chunk - nr_consecutive || + de.new_chunk != *last_new_chunk - nr_consecutive) break; } @@ -757,7 +753,7 @@ static int persistent_commit_merge(struct dm_exception_store *store, for (i = 0; i < nr_merged; i++) clear_exception(ps, ps->current_committed - 1 - i); - r = area_io(ps, WRITE_FLUSH_FUA); + r = area_io(ps, WRITE); if (r < 0) return r; diff --git a/trunk/drivers/md/dm-snap.c b/trunk/drivers/md/dm-snap.c index 6f758870fc19..9ecff5f3023a 100644 --- a/trunk/drivers/md/dm-snap.c +++ b/trunk/drivers/md/dm-snap.c @@ -29,6 +29,16 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge"; #define dm_target_is_snapshot_merge(ti) \ ((ti)->type->name == dm_snapshot_merge_target_name) +/* + * The percentage increment we will wake up users at + */ +#define WAKE_UP_PERCENT 5 + +/* + * kcopyd priority of snapshot operations + */ +#define SNAPSHOT_COPY_PRIORITY 2 + /* * The size of the mempool used to track chunks in use. */ @@ -170,13 +180,6 @@ struct dm_snap_pending_exception { * kcopyd. */ int started; - - /* - * For writing a complete chunk, bypassing the copy. - */ - struct bio *full_bio; - bio_end_io_t *full_bio_end_io; - void *full_bio_private; }; /* @@ -1052,7 +1055,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) { - ti->error = "Cannot allocate private snapshot structure"; + ti->error = "Cannot allocate snapshot context private " + "structure"; r = -ENOMEM; goto bad; } @@ -1376,7 +1380,6 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) struct dm_snapshot *s = pe->snap; struct bio *origin_bios = NULL; struct bio *snapshot_bios = NULL; - struct bio *full_bio = NULL; int error = 0; if (!success) { @@ -1412,15 +1415,10 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) */ dm_insert_exception(&s->complete, e); -out: + out: dm_remove_exception(&pe->e); snapshot_bios = bio_list_get(&pe->snapshot_bios); origin_bios = bio_list_get(&pe->origin_bios); - full_bio = pe->full_bio; - if (full_bio) { - full_bio->bi_end_io = pe->full_bio_end_io; - full_bio->bi_private = pe->full_bio_private; - } free_pending_exception(pe); increment_pending_exceptions_done_count(); @@ -1428,15 +1426,10 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) up_write(&s->lock); /* Submit any pending write bios */ - if (error) { - if (full_bio) - bio_io_error(full_bio); + if (error) error_bios(snapshot_bios); - } else { - if (full_bio) - bio_endio(full_bio, 0); + else flush_bios(snapshot_bios); - } retry_origin_bios(s, origin_bios); } @@ -1487,33 +1480,8 @@ static void start_copy(struct dm_snap_pending_exception *pe) dest.count = src.count; /* Hand over to kcopyd */ - dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe); -} - -static void full_bio_end_io(struct bio *bio, int error) -{ - void *callback_data = bio->bi_private; - - dm_kcopyd_do_callback(callback_data, 0, error ? 1 : 0); -} - -static void start_full_bio(struct dm_snap_pending_exception *pe, - struct bio *bio) -{ - struct dm_snapshot *s = pe->snap; - void *callback_data; - - pe->full_bio = bio; - pe->full_bio_end_io = bio->bi_end_io; - pe->full_bio_private = bio->bi_private; - - callback_data = dm_kcopyd_prepare_callback(s->kcopyd_client, - copy_callback, pe); - - bio->bi_end_io = full_bio_end_io; - bio->bi_private = callback_data; - - generic_make_request(bio); + dm_kcopyd_copy(s->kcopyd_client, + &src, 1, &dest, 0, copy_callback, pe); } static struct dm_snap_pending_exception * @@ -1551,7 +1519,6 @@ __find_pending_exception(struct dm_snapshot *s, bio_list_init(&pe->origin_bios); bio_list_init(&pe->snapshot_bios); pe->started = 0; - pe->full_bio = NULL; if (s->store->type->prepare_exception(s->store, &pe->e)) { free_pending_exception(pe); @@ -1645,19 +1612,10 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, } remap_exception(s, &pe->e, bio, chunk); + bio_list_add(&pe->snapshot_bios, bio); r = DM_MAPIO_SUBMITTED; - if (!pe->started && - bio->bi_size == (s->store->chunk_size << SECTOR_SHIFT)) { - pe->started = 1; - up_write(&s->lock); - start_full_bio(pe, bio); - goto out; - } - - bio_list_add(&pe->snapshot_bios, bio); - if (!pe->started) { /* this is protected by snap->lock */ pe->started = 1; @@ -1670,9 +1628,9 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, map_context->ptr = track_chunk(s, chunk); } -out_unlock: + out_unlock: up_write(&s->lock); -out: + out: return r; } @@ -2016,7 +1974,7 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, pe_to_start_now = pe; } -next_snapshot: + next_snapshot: up_write(&snap->lock); if (pe_to_start_now) { diff --git a/trunk/drivers/md/dm-table.c b/trunk/drivers/md/dm-table.c index 986b8754bb08..bfe9c2333cea 100644 --- a/trunk/drivers/md/dm-table.c +++ b/trunk/drivers/md/dm-table.c @@ -54,6 +54,7 @@ struct dm_table { sector_t *highs; struct dm_target *targets; + unsigned discards_supported:1; unsigned integrity_supported:1; /* @@ -153,11 +154,12 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size) return NULL; size = nmemb * elem_size; - addr = vzalloc(size); + addr = vmalloc(size); + if (addr) + memset(addr, 0, size); return addr; } -EXPORT_SYMBOL(dm_vcalloc); /* * highs, and targets are managed as dynamic arrays during a @@ -207,6 +209,7 @@ int dm_table_create(struct dm_table **result, fmode_t mode, INIT_LIST_HEAD(&t->devices); INIT_LIST_HEAD(&t->target_callbacks); atomic_set(&t->holders, 0); + t->discards_supported = 1; if (!num_targets) num_targets = KEYS_PER_NODE; @@ -278,7 +281,6 @@ void dm_table_get(struct dm_table *t) { atomic_inc(&t->holders); } -EXPORT_SYMBOL(dm_table_get); void dm_table_put(struct dm_table *t) { @@ -288,7 +290,6 @@ void dm_table_put(struct dm_table *t) smp_mb__before_atomic_dec(); atomic_dec(&t->holders); } -EXPORT_SYMBOL(dm_table_put); /* * Checks to see if we need to extend highs or targets. @@ -454,14 +455,13 @@ static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode, * Add a device to the list, or just increment the usage count if * it's already present. */ -int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode, - struct dm_dev **result) +static int __table_get_device(struct dm_table *t, struct dm_target *ti, + const char *path, fmode_t mode, struct dm_dev **result) { int r; dev_t uninitialized_var(dev); struct dm_dev_internal *dd; unsigned int major, minor; - struct dm_table *t = ti->table; BUG_ON(!t); @@ -509,7 +509,6 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode, *result = &dd->dm_dev; return 0; } -EXPORT_SYMBOL(dm_get_device); int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, sector_t start, sector_t len, void *data) @@ -540,15 +539,23 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, * If not we'll force DM to use PAGE_SIZE or * smaller I/O, just to be safe. */ - if (dm_queue_merge_is_compulsory(q) && !ti->type->merge) + + if (q->merge_bvec_fn && !ti->type->merge) blk_limits_max_hw_sectors(limits, (unsigned int) (PAGE_SIZE >> 9)); return 0; } EXPORT_SYMBOL_GPL(dm_set_device_limits); +int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode, + struct dm_dev **result) +{ + return __table_get_device(ti->table, ti, path, mode, result); +} + + /* - * Decrement a device's use count and remove it if necessary. + * Decrement a devices use count and remove it if necessary. */ void dm_put_device(struct dm_target *ti, struct dm_dev *d) { @@ -561,7 +568,6 @@ void dm_put_device(struct dm_target *ti, struct dm_dev *d) kfree(dd); } } -EXPORT_SYMBOL(dm_put_device); /* * Checks to see if the target joins onto the end of the table. @@ -785,9 +791,8 @@ int dm_table_add_target(struct dm_table *t, const char *type, t->highs[t->num_targets++] = tgt->begin + tgt->len - 1; - if (!tgt->num_discard_requests && tgt->discards_supported) - DMWARN("%s: %s: ignoring discards_supported because num_discard_requests is zero.", - dm_device_name(t->md), type); + if (!tgt->num_discard_requests) + t->discards_supported = 0; return 0; @@ -797,63 +802,6 @@ int dm_table_add_target(struct dm_table *t, const char *type, return r; } -/* - * Target argument parsing helpers. - */ -static int validate_next_arg(struct dm_arg *arg, struct dm_arg_set *arg_set, - unsigned *value, char **error, unsigned grouped) -{ - const char *arg_str = dm_shift_arg(arg_set); - - if (!arg_str || - (sscanf(arg_str, "%u", value) != 1) || - (*value < arg->min) || - (*value > arg->max) || - (grouped && arg_set->argc < *value)) { - *error = arg->error; - return -EINVAL; - } - - return 0; -} - -int dm_read_arg(struct dm_arg *arg, struct dm_arg_set *arg_set, - unsigned *value, char **error) -{ - return validate_next_arg(arg, arg_set, value, error, 0); -} -EXPORT_SYMBOL(dm_read_arg); - -int dm_read_arg_group(struct dm_arg *arg, struct dm_arg_set *arg_set, - unsigned *value, char **error) -{ - return validate_next_arg(arg, arg_set, value, error, 1); -} -EXPORT_SYMBOL(dm_read_arg_group); - -const char *dm_shift_arg(struct dm_arg_set *as) -{ - char *r; - - if (as->argc) { - as->argc--; - r = *as->argv; - as->argv++; - return r; - } - - return NULL; -} -EXPORT_SYMBOL(dm_shift_arg); - -void dm_consume_args(struct dm_arg_set *as, unsigned num_args) -{ - BUG_ON(as->argc < num_args); - as->argc -= num_args; - as->argv += num_args; -} -EXPORT_SYMBOL(dm_consume_args); - static int dm_table_set_type(struct dm_table *t) { unsigned i; @@ -1129,13 +1077,11 @@ void dm_table_event(struct dm_table *t) t->event_fn(t->event_context); mutex_unlock(&_event_lock); } -EXPORT_SYMBOL(dm_table_event); sector_t dm_table_get_size(struct dm_table *t) { return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0; } -EXPORT_SYMBOL(dm_table_get_size); struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index) { @@ -1248,45 +1194,9 @@ static void dm_table_set_integrity(struct dm_table *t) blk_get_integrity(template_disk)); } -static int device_flush_capable(struct dm_target *ti, struct dm_dev *dev, - sector_t start, sector_t len, void *data) -{ - unsigned flush = (*(unsigned *)data); - struct request_queue *q = bdev_get_queue(dev->bdev); - - return q && (q->flush_flags & flush); -} - -static bool dm_table_supports_flush(struct dm_table *t, unsigned flush) -{ - struct dm_target *ti; - unsigned i = 0; - - /* - * Require at least one underlying device to support flushes. - * t->devices includes internal dm devices such as mirror logs - * so we need to use iterate_devices here, which targets - * supporting flushes must provide. - */ - while (i < dm_table_get_num_targets(t)) { - ti = dm_table_get_target(t, i++); - - if (!ti->num_flush_requests) - continue; - - if (ti->type->iterate_devices && - ti->type->iterate_devices(ti, device_flush_capable, &flush)) - return 1; - } - - return 0; -} - void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, struct queue_limits *limits) { - unsigned flush = 0; - /* * Copy table's limits to the DM device's request_queue */ @@ -1297,13 +1207,6 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, else queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); - if (dm_table_supports_flush(t, REQ_FLUSH)) { - flush |= REQ_FLUSH; - if (dm_table_supports_flush(t, REQ_FUA)) - flush |= REQ_FUA; - } - blk_queue_flush(q, flush); - dm_table_set_integrity(t); /* @@ -1334,7 +1237,6 @@ fmode_t dm_table_get_mode(struct dm_table *t) { return t->mode; } -EXPORT_SYMBOL(dm_table_get_mode); static void suspend_targets(struct dm_table *t, unsigned postsuspend) { @@ -1443,7 +1345,6 @@ struct mapped_device *dm_table_get_md(struct dm_table *t) { return t->md; } -EXPORT_SYMBOL(dm_table_get_md); static int device_discard_capable(struct dm_target *ti, struct dm_dev *dev, sector_t start, sector_t len, void *data) @@ -1458,19 +1359,19 @@ bool dm_table_supports_discards(struct dm_table *t) struct dm_target *ti; unsigned i = 0; + if (!t->discards_supported) + return 0; + /* * Unless any target used by the table set discards_supported, * require at least one underlying device to support discards. * t->devices includes internal dm devices such as mirror logs * so we need to use iterate_devices here, which targets - * supporting discard selectively must provide. + * supporting discard must provide. */ while (i < dm_table_get_num_targets(t)) { ti = dm_table_get_target(t, i++); - if (!ti->num_discard_requests) - continue; - if (ti->discards_supported) return 1; @@ -1481,3 +1382,13 @@ bool dm_table_supports_discards(struct dm_table *t) return 0; } + +EXPORT_SYMBOL(dm_vcalloc); +EXPORT_SYMBOL(dm_get_device); +EXPORT_SYMBOL(dm_put_device); +EXPORT_SYMBOL(dm_table_event); +EXPORT_SYMBOL(dm_table_get_size); +EXPORT_SYMBOL(dm_table_get_mode); +EXPORT_SYMBOL(dm_table_get_md); +EXPORT_SYMBOL(dm_table_put); +EXPORT_SYMBOL(dm_table_get); diff --git a/trunk/drivers/md/dm.c b/trunk/drivers/md/dm.c index 52b39f335bb3..0cf68b478878 100644 --- a/trunk/drivers/md/dm.c +++ b/trunk/drivers/md/dm.c @@ -37,8 +37,6 @@ static const char *_name = DM_NAME; static unsigned int major = 0; static unsigned int _major = 0; -static DEFINE_IDR(_minor_idr); - static DEFINE_SPINLOCK(_minor_lock); /* * For bio-based dm. @@ -111,7 +109,6 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo); #define DMF_FREEING 3 #define DMF_DELETING 4 #define DMF_NOFLUSH_SUSPENDING 5 -#define DMF_MERGE_IS_OPTIONAL 6 /* * Work processed by per-device workqueue. @@ -316,12 +313,6 @@ static void __exit dm_exit(void) while (i--) _exits[i](); - - /* - * Should be empty by this point. - */ - idr_remove_all(&_minor_idr); - idr_destroy(&_minor_idr); } /* @@ -1180,8 +1171,7 @@ static int __clone_and_map_discard(struct clone_info *ci) /* * Even though the device advertised discard support, - * that does not mean every target supports it, and - * reconfiguration might also have changed that since the + * reconfiguration might have changed that since the * check was performed. */ if (!ti->num_discard_requests) @@ -1715,6 +1705,8 @@ static int dm_any_congested(void *congested_data, int bdi_bits) /*----------------------------------------------------------------- * An IDR is used to keep track of allocated minor numbers. *---------------------------------------------------------------*/ +static DEFINE_IDR(_minor_idr); + static void free_minor(int minor) { spin_lock(&_minor_lock); @@ -1808,6 +1800,7 @@ static void dm_init_md_queue(struct mapped_device *md) blk_queue_make_request(md->queue, dm_request); blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); blk_queue_merge_bvec(md->queue, dm_merge_bvec); + blk_queue_flush(md->queue, REQ_FLUSH | REQ_FUA); } /* @@ -1992,59 +1985,6 @@ static void __set_size(struct mapped_device *md, sector_t size) i_size_write(md->bdev->bd_inode, (loff_t)size << SECTOR_SHIFT); } -/* - * Return 1 if the queue has a compulsory merge_bvec_fn function. - * - * If this function returns 0, then the device is either a non-dm - * device without a merge_bvec_fn, or it is a dm device that is - * able to split any bios it receives that are too big. - */ -int dm_queue_merge_is_compulsory(struct request_queue *q) -{ - struct mapped_device *dev_md; - - if (!q->merge_bvec_fn) - return 0; - - if (q->make_request_fn == dm_request) { - dev_md = q->queuedata; - if (test_bit(DMF_MERGE_IS_OPTIONAL, &dev_md->flags)) - return 0; - } - - return 1; -} - -static int dm_device_merge_is_compulsory(struct dm_target *ti, - struct dm_dev *dev, sector_t start, - sector_t len, void *data) -{ - struct block_device *bdev = dev->bdev; - struct request_queue *q = bdev_get_queue(bdev); - - return dm_queue_merge_is_compulsory(q); -} - -/* - * Return 1 if it is acceptable to ignore merge_bvec_fn based - * on the properties of the underlying devices. - */ -static int dm_table_merge_is_optional(struct dm_table *table) -{ - unsigned i = 0; - struct dm_target *ti; - - while (i < dm_table_get_num_targets(table)) { - ti = dm_table_get_target(table, i++); - - if (ti->type->iterate_devices && - ti->type->iterate_devices(ti, dm_device_merge_is_compulsory, NULL)) - return 0; - } - - return 1; -} - /* * Returns old map, which caller must destroy. */ @@ -2055,7 +1995,6 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t, struct request_queue *q = md->queue; sector_t size; unsigned long flags; - int merge_is_optional; size = dm_table_get_size(t); @@ -2081,16 +2020,10 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t, __bind_mempools(md, t); - merge_is_optional = dm_table_merge_is_optional(t); - write_lock_irqsave(&md->map_lock, flags); old_map = md->map; md->map = t; dm_table_set_restrictions(t, q, limits); - if (merge_is_optional) - set_bit(DMF_MERGE_IS_OPTIONAL, &md->flags); - else - clear_bit(DMF_MERGE_IS_OPTIONAL, &md->flags); write_unlock_irqrestore(&md->map_lock, flags); return old_map; diff --git a/trunk/drivers/md/dm.h b/trunk/drivers/md/dm.h index 6745dbd278a4..1aaf16746da8 100644 --- a/trunk/drivers/md/dm.h +++ b/trunk/drivers/md/dm.h @@ -66,8 +66,6 @@ int dm_table_alloc_md_mempools(struct dm_table *t); void dm_table_free_md_mempools(struct dm_table *t); struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); -int dm_queue_merge_is_compulsory(struct request_queue *q); - void dm_lock_md_type(struct mapped_device *md); void dm_unlock_md_type(struct mapped_device *md); void dm_set_md_type(struct mapped_device *md, unsigned type); diff --git a/trunk/drivers/net/bnx2x/bnx2x_cmn.c b/trunk/drivers/net/bnx2x/bnx2x_cmn.c index d724a18b5285..5b0dba6d4efa 100644 --- a/trunk/drivers/net/bnx2x/bnx2x_cmn.c +++ b/trunk/drivers/net/bnx2x/bnx2x_cmn.c @@ -1989,20 +1989,14 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) return -EINVAL; } - /* - * It's important to set the bp->state to the value different from - * BNX2X_STATE_OPEN and only then stop the Tx. Otherwise bnx2x_tx_int() - * may restart the Tx from the NAPI context (see bnx2x_tx_int()). - */ - bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; - smp_mb(); - /* Stop Tx */ bnx2x_tx_disable(bp); #ifdef BCM_CNIC bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD); #endif + bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; + smp_mb(); bp->rx_mode = BNX2X_RX_MODE_NONE; diff --git a/trunk/drivers/net/bnx2x/bnx2x_hsi.h b/trunk/drivers/net/bnx2x/bnx2x_hsi.h index dc24de40e336..06727f32e505 100644 --- a/trunk/drivers/net/bnx2x/bnx2x_hsi.h +++ b/trunk/drivers/net/bnx2x/bnx2x_hsi.h @@ -1204,8 +1204,6 @@ struct drv_port_mb { #define LINK_STATUS_PFC_ENABLED 0x20000000 - #define LINK_STATUS_PHYSICAL_LINK_FLAG 0x40000000 - u32 port_stx; u32 stat_nig_timer; diff --git a/trunk/drivers/net/bnx2x/bnx2x_link.c b/trunk/drivers/net/bnx2x/bnx2x_link.c index d45b1555a602..bcd8f0038628 100644 --- a/trunk/drivers/net/bnx2x/bnx2x_link.c +++ b/trunk/drivers/net/bnx2x/bnx2x_link.c @@ -1546,12 +1546,6 @@ static void bnx2x_umac_enable(struct link_params *params, vars->line_speed); break; } - if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) - val |= UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE; - - if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)) - val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE; - REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val); udelay(50); @@ -1667,20 +1661,10 @@ static void bnx2x_xmac_disable(struct link_params *params) { u8 port = params->port; struct bnx2x *bp = params->bp; - u32 pfc_ctrl, xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + u32 xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; if (REG_RD(bp, MISC_REG_RESET_REG_2) & MISC_REGISTERS_RESET_REG_2_XMAC) { - /* - * Send an indication to change the state in the NIG back to XON - * Clearing this bit enables the next set of this bit to get - * rising edge - */ - pfc_ctrl = REG_RD(bp, xmac_base + XMAC_REG_PFC_CTRL_HI); - REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, - (pfc_ctrl & ~(1<<1))); - REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, - (pfc_ctrl | (1<<1))); DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port); REG_WR(bp, xmac_base + XMAC_REG_CTRL, 0); usleep_range(1000, 1000); @@ -1745,10 +1729,6 @@ static int bnx2x_emac_enable(struct link_params *params, DP(NETIF_MSG_LINK, "enabling EMAC\n"); - /* Disable BMAC */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); - /* enable emac and not bmac */ REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1); @@ -2603,6 +2583,12 @@ static int bnx2x_bmac1_enable(struct link_params *params, REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS, wb_data, 2); + if (vars->phy_flags & PHY_TX_ERROR_CHECK_FLAG) { + REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LSS_STATUS, + wb_data, 2); + if (wb_data[0] > 0) + return -ESRCH; + } return 0; } @@ -2668,6 +2654,16 @@ static int bnx2x_bmac2_enable(struct link_params *params, udelay(30); bnx2x_update_pfc_bmac2(params, vars, is_lb); + if (vars->phy_flags & PHY_TX_ERROR_CHECK_FLAG) { + REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LSS_STAT, + wb_data, 2); + if (wb_data[0] > 0) { + DP(NETIF_MSG_LINK, "Got bad LSS status 0x%x\n", + wb_data[0]); + return -ESRCH; + } + } + return 0; } @@ -2953,9 +2949,7 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, u32 val; u16 i; int rc = 0; - if (phy->flags & FLAGS_MDC_MDIO_WA_B0) - bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, - EMAC_MDIO_STATUS_10MB); + /* address */ val = ((phy->addr << 21) | (devad << 16) | reg | EMAC_MDIO_COMM_COMMAND_ADDRESS | @@ -3009,9 +3003,6 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, } } - if (phy->flags & FLAGS_MDC_MDIO_WA_B0) - bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, - EMAC_MDIO_STATUS_10MB); return rc; } @@ -3021,9 +3012,6 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, u32 tmp; u8 i; int rc = 0; - if (phy->flags & FLAGS_MDC_MDIO_WA_B0) - bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, - EMAC_MDIO_STATUS_10MB); /* address */ @@ -3077,9 +3065,7 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val); } } - if (phy->flags & FLAGS_MDC_MDIO_WA_B0) - bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, - EMAC_MDIO_STATUS_10MB); + return rc; } @@ -4367,9 +4353,6 @@ void bnx2x_link_status_update(struct link_params *params, vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP); vars->phy_flags = PHY_XGXS_FLAG; - if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG) - vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG; - if (vars->link_up) { DP(NETIF_MSG_LINK, "phy link up\n"); @@ -4461,8 +4444,6 @@ void bnx2x_link_status_update(struct link_params *params, /* indicate no mac active */ vars->mac_type = MAC_TYPE_NONE; - if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG) - vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; } /* Sync media type */ @@ -5922,30 +5903,20 @@ int bnx2x_set_led(struct link_params *params, tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE)); - /* - * return here without enabling traffic - * LED blink andsetting rate in ON mode. - * In oper mode, enabling LED blink - * and setting rate is needed. - */ - if (mode == LED_MODE_ON) - return rc; + return rc; } - } else if (SINGLE_MEDIA_DIRECT(params)) { + } else if (SINGLE_MEDIA_DIRECT(params) && + (CHIP_IS_E1x(bp) || + CHIP_IS_E2(bp))) { /* * This is a work-around for HW issue found when link * is up in CL73 */ + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1); - if (CHIP_IS_E1x(bp) || - CHIP_IS_E2(bp) || - (mode == LED_MODE_ON)) - REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); - else - REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, - hw_led_mode); - } else + } else { REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode); + } REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0); /* Set blinking rate to ~15.9Hz */ @@ -6189,7 +6160,6 @@ static int bnx2x_update_link_down(struct link_params *params, /* update shared memory */ vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK | LINK_STATUS_LINK_UP | - LINK_STATUS_PHYSICAL_LINK_FLAG | LINK_STATUS_AUTO_NEGOTIATE_COMPLETE | LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK | LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK | @@ -6227,8 +6197,7 @@ static int bnx2x_update_link_up(struct link_params *params, u8 port = params->port; int rc = 0; - vars->link_status |= (LINK_STATUS_LINK_UP | - LINK_STATUS_PHYSICAL_LINK_FLAG); + vars->link_status |= LINK_STATUS_LINK_UP; vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG; if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) @@ -8029,9 +7998,6 @@ static void bnx2x_warpcore_set_limiting_mode(struct link_params *params, bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val); - /* Restart microcode to re-read the new mode */ - bnx2x_warpcore_reset_lane(bp, phy, 1); - bnx2x_warpcore_reset_lane(bp, phy, 0); } @@ -8150,6 +8116,7 @@ void bnx2x_handle_module_detect_int(struct link_params *params) offsetof(struct shmem_region, dev_info. port_feature_config[params->port]. config)); + bnx2x_set_gpio_int(bp, gpio_num, MISC_REGISTERS_GPIO_INT_OUTPUT_SET, gpio_port); @@ -8158,9 +8125,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params) * Disable transmit for this module */ phy->media_type = ETH_PHY_NOT_PRESENT; - if (((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == - PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) || - CHIP_IS_E3(bp)) + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) bnx2x_sfp_set_transmitter(params, phy, 0); } } @@ -8262,6 +8228,9 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, u16 cnt, val, tmp1; struct bnx2x *bp = params->bp; + /* SPF+ PHY: Set flag to check for Tx error */ + vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG; + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); /* HW reset */ @@ -8445,6 +8414,9 @@ static int bnx2x_8726_config_init(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; DP(NETIF_MSG_LINK, "Initializing BCM8726\n"); + /* SPF+ PHY: Set flag to check for Tx error */ + vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG; + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); bnx2x_wait_reset_complete(bp, phy, params); @@ -8613,6 +8585,9 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */ + /* SPF+ PHY: Set flag to check for Tx error */ + vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG; + bnx2x_wait_reset_complete(bp, phy, params); rx_alarm_ctrl_val = (1<<2) | (1<<5) ; /* Should be 0x6 to enable XS on Tx side. */ @@ -9268,13 +9243,7 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, if (phy->req_duplex == DUPLEX_FULL) autoneg_val |= (1<<8); - /* - * Always write this if this is not 84833. - * For 84833, write it only when it's a forced speed. - */ - if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - ((autoneg_val & (1<<12)) == 0)) - bnx2x_cl45_write(bp, phy, + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val); @@ -9288,12 +9257,13 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x3200); - } else + } else if (phy->req_line_speed != SPEED_10 && + phy->req_line_speed != SPEED_100) { bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8481_10GBASE_T_AN_CTRL, 1); - + } /* Save spirom version */ bnx2x_save_848xx_spirom_version(phy, params); @@ -9786,9 +9756,11 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &val16); - bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_CTRL, 0x800); + /* Put to low power mode on newer FW */ + if ((val16 & 0x303f) > 0x1009) + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x800); } } @@ -10219,15 +10191,8 @@ static void bnx2x_54618se_link_reset(struct bnx2x_phy *phy, u32 cfg_pin; u8 port; - /* - * In case of no EPIO routed to reset the GPHY, put it - * in low power mode. - */ - bnx2x_cl22_write(bp, phy, MDIO_PMA_REG_CTRL, 0x800); - /* - * This works with E3 only, no need to check the chip - * before determining the port. - */ + /* This works with E3 only, no need to check the chip + before determining the port. */ port = params->port; cfg_pin = (REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, @@ -10638,8 +10603,7 @@ static struct bnx2x_phy phy_warpcore = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT, .addr = 0xff, .def_md_devad = 0, - .flags = (FLAGS_HW_LOCK_REQUIRED | - FLAGS_TX_ERROR_CHECK), + .flags = FLAGS_HW_LOCK_REQUIRED, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10765,8 +10729,7 @@ static struct bnx2x_phy phy_8706 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706, .addr = 0xff, .def_md_devad = 0, - .flags = (FLAGS_INIT_XGXS_FIRST | - FLAGS_TX_ERROR_CHECK), + .flags = FLAGS_INIT_XGXS_FIRST, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10797,8 +10760,7 @@ static struct bnx2x_phy phy_8726 = { .addr = 0xff, .def_md_devad = 0, .flags = (FLAGS_HW_LOCK_REQUIRED | - FLAGS_INIT_XGXS_FIRST | - FLAGS_TX_ERROR_CHECK), + FLAGS_INIT_XGXS_FIRST), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10829,8 +10791,7 @@ static struct bnx2x_phy phy_8727 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, .addr = 0xff, .def_md_devad = 0, - .flags = (FLAGS_FAN_FAILURE_DET_REQ | - FLAGS_TX_ERROR_CHECK), + .flags = FLAGS_FAN_FAILURE_DET_REQ, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -11151,8 +11112,6 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, */ if (CHIP_REV(bp) == CHIP_REV_Ax) phy->flags |= FLAGS_MDC_MDIO_WA; - else - phy->flags |= FLAGS_MDC_MDIO_WA_B0; } else { switch (switch_cfg) { case SWITCH_CFG_1G: @@ -11541,12 +11500,13 @@ void bnx2x_init_xmac_loopback(struct link_params *params, * Set WC to loopback mode since link is required to provide clock * to the XMAC in 20G mode */ - bnx2x_set_aer_mmd(params, ¶ms->phy[0]); - bnx2x_warpcore_reset_lane(bp, ¶ms->phy[0], 0); - params->phy[INT_PHY].config_loopback( + if (vars->line_speed == SPEED_20000) { + bnx2x_set_aer_mmd(params, ¶ms->phy[0]); + bnx2x_warpcore_reset_lane(bp, ¶ms->phy[0], 0); + params->phy[INT_PHY].config_loopback( ¶ms->phy[INT_PHY], params); - + } bnx2x_xmac_enable(params, vars, 1); REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); } @@ -11724,16 +11684,12 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars, bnx2x_set_led(params, vars, LED_MODE_OFF, 0); if (reset_ext_phy) { - bnx2x_set_mdio_clk(bp, params->chip_id, port); for (phy_index = EXT_PHY1; phy_index < params->num_phys; phy_index++) { - if (params->phy[phy_index].link_reset) { - bnx2x_set_aer_mmd(params, - ¶ms->phy[phy_index]); + if (params->phy[phy_index].link_reset) params->phy[phy_index].link_reset( ¶ms->phy[phy_index], params); - } if (params->phy[phy_index].flags & FLAGS_REARM_LATCH_SIGNAL) clear_latch_ind = 1; @@ -12222,6 +12178,10 @@ static void bnx2x_analyze_link_error(struct link_params *params, u8 led_mode; u32 half_open_conn = (vars->phy_flags & PHY_HALF_OPEN_CONN_FLAG) > 0; + /*DP(NETIF_MSG_LINK, "CHECK LINK: %x half_open:%x-> lss:%x\n", + vars->link_up, + half_open_conn, lss_status);*/ + if ((lss_status ^ half_open_conn) == 0) return; @@ -12234,7 +12194,6 @@ static void bnx2x_analyze_link_error(struct link_params *params, * b. Update link_vars->link_up */ if (lss_status) { - DP(NETIF_MSG_LINK, "Remote Fault detected !!!\n"); vars->link_status &= ~LINK_STATUS_LINK_UP; vars->link_up = 0; vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; @@ -12244,7 +12203,6 @@ static void bnx2x_analyze_link_error(struct link_params *params, */ led_mode = LED_MODE_OFF; } else { - DP(NETIF_MSG_LINK, "Remote Fault cleared\n"); vars->link_status |= LINK_STATUS_LINK_UP; vars->link_up = 1; vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG; @@ -12261,15 +12219,6 @@ static void bnx2x_analyze_link_error(struct link_params *params, bnx2x_notify_link_changed(bp); } -/****************************************************************************** -* Description: -* This function checks for half opened connection change indication. -* When such change occurs, it calls the bnx2x_analyze_link_error -* to check if Remote Fault is set or cleared. Reception of remote fault -* status message in the MAC indicates that the peer's MAC has detected -* a fault, for example, due to break in the TX side of fiber. -* -******************************************************************************/ static void bnx2x_check_half_open_conn(struct link_params *params, struct link_vars *vars) { @@ -12280,28 +12229,9 @@ static void bnx2x_check_half_open_conn(struct link_params *params, if ((vars->phy_flags & PHY_PHYSICAL_LINK_FLAG) == 0) return; - if (CHIP_IS_E3(bp) && + if (!CHIP_IS_E3(bp) && (REG_RD(bp, MISC_REG_RESET_REG_2) & - (MISC_REGISTERS_RESET_REG_2_XMAC))) { - /* Check E3 XMAC */ - /* - * Note that link speed cannot be queried here, since it may be - * zero while link is down. In case UMAC is active, LSS will - * simply not be set - */ - mac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; - - /* Clear stick bits (Requires rising edge) */ - REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, 0); - REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, - XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS | - XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS); - if (REG_RD(bp, mac_base + XMAC_REG_RX_LSS_STATUS)) - lss_status = 1; - - bnx2x_analyze_link_error(params, vars, lss_status); - } else if (REG_RD(bp, MISC_REG_RESET_REG_2) & - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) { + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))) { /* Check E1X / E2 BMAC */ u32 lss_status_reg; u32 wb_data[2]; @@ -12323,20 +12253,14 @@ static void bnx2x_check_half_open_conn(struct link_params *params, void bnx2x_period_func(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; - u16 phy_idx; if (!params) { - DP(NETIF_MSG_LINK, "Uninitialized params !\n"); + DP(NETIF_MSG_LINK, "Ininitliazed params !\n"); return; } - - for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) { - if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) { - bnx2x_set_aer_mmd(params, ¶ms->phy[phy_idx]); - bnx2x_check_half_open_conn(params, vars); - break; - } - } - + /* DP(NETIF_MSG_LINK, "Periodic called vars->phy_flags 0x%x speed 0x%x + RESET_REG_2 0x%x\n", vars->phy_flags, vars->line_speed, + REG_RD(bp, MISC_REG_RESET_REG_2)); */ + bnx2x_check_half_open_conn(params, vars); if (CHIP_IS_E3(bp)) bnx2x_check_over_curr(params, vars); } diff --git a/trunk/drivers/net/bnx2x/bnx2x_link.h b/trunk/drivers/net/bnx2x/bnx2x_link.h index c12db6da213e..6a7708d5da37 100644 --- a/trunk/drivers/net/bnx2x/bnx2x_link.h +++ b/trunk/drivers/net/bnx2x/bnx2x_link.h @@ -145,8 +145,6 @@ struct bnx2x_phy { #define FLAGS_SFP_NOT_APPROVED (1<<7) #define FLAGS_MDC_MDIO_WA (1<<8) #define FLAGS_DUMMY_READ (1<<9) -#define FLAGS_MDC_MDIO_WA_B0 (1<<10) -#define FLAGS_TX_ERROR_CHECK (1<<12) /* preemphasis values for the rx side */ u16 rx_preemphasis[4]; @@ -278,6 +276,7 @@ struct link_vars { #define PHY_PHYSICAL_LINK_FLAG (1<<2) #define PHY_HALF_OPEN_CONN_FLAG (1<<3) #define PHY_OVER_CURRENT_FLAG (1<<4) +#define PHY_TX_ERROR_CHECK_FLAG (1<<5) u8 mac_type; #define MAC_TYPE_NONE 0 diff --git a/trunk/drivers/net/bnx2x/bnx2x_reg.h b/trunk/drivers/net/bnx2x/bnx2x_reg.h index 27b5ecb11830..02461fef8751 100644 --- a/trunk/drivers/net/bnx2x/bnx2x_reg.h +++ b/trunk/drivers/net/bnx2x/bnx2x_reg.h @@ -4771,11 +4771,9 @@ The fields are: [4:0] - tail pointer; 10:5] - Link List size; 15:11] - header pointer. */ #define UCM_REG_XX_TABLE 0xe0300 -#define UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE (0x1<<28) #define UMAC_COMMAND_CONFIG_REG_LOOP_ENA (0x1<<15) #define UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK (0x1<<24) #define UMAC_COMMAND_CONFIG_REG_PAD_EN (0x1<<5) -#define UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE (0x1<<8) #define UMAC_COMMAND_CONFIG_REG_PROMIS_EN (0x1<<4) #define UMAC_COMMAND_CONFIG_REG_RX_ENA (0x1<<1) #define UMAC_COMMAND_CONFIG_REG_SW_RESET (0x1<<13) @@ -5624,9 +5622,8 @@ #define EMAC_MDIO_COMM_START_BUSY (1L<<29) #define EMAC_MDIO_MODE_AUTO_POLL (1L<<4) #define EMAC_MDIO_MODE_CLAUSE_45 (1L<<31) -#define EMAC_MDIO_MODE_CLOCK_CNT (0x3ffL<<16) +#define EMAC_MDIO_MODE_CLOCK_CNT (0x3fL<<16) #define EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT 16 -#define EMAC_MDIO_STATUS_10MB (1L<<1) #define EMAC_MODE_25G_MODE (1L<<5) #define EMAC_MODE_HALF_DUPLEX (1L<<1) #define EMAC_MODE_PORT_GMII (2L<<2) @@ -5637,7 +5634,6 @@ #define EMAC_REG_EMAC_MAC_MATCH 0x10 #define EMAC_REG_EMAC_MDIO_COMM 0xac #define EMAC_REG_EMAC_MDIO_MODE 0xb4 -#define EMAC_REG_EMAC_MDIO_STATUS 0xb0 #define EMAC_REG_EMAC_MODE 0x0 #define EMAC_REG_EMAC_RX_MODE 0xc8 #define EMAC_REG_EMAC_RX_MTU_SIZE 0x9c diff --git a/trunk/drivers/net/e1000/e1000_ethtool.c b/trunk/drivers/net/e1000/e1000_ethtool.c index 5548d464261a..c5f0f04219f3 100644 --- a/trunk/drivers/net/e1000/e1000_ethtool.c +++ b/trunk/drivers/net/e1000/e1000_ethtool.c @@ -838,7 +838,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - E1000_WRITE_FLUSH(); msleep(10); /* Test each interrupt */ @@ -857,7 +856,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, mask); ew32(ICS, mask); - E1000_WRITE_FLUSH(); msleep(10); if (adapter->test_icr & mask) { @@ -875,7 +873,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMS, mask); ew32(ICS, mask); - E1000_WRITE_FLUSH(); msleep(10); if (!(adapter->test_icr & mask)) { @@ -893,7 +890,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, ~mask & 0x00007FFF); ew32(ICS, ~mask & 0x00007FFF); - E1000_WRITE_FLUSH(); msleep(10); if (adapter->test_icr) { @@ -905,7 +901,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - E1000_WRITE_FLUSH(); msleep(10); /* Unhook test interrupt handler */ @@ -1399,7 +1394,6 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter) if (unlikely(++k == txdr->count)) k = 0; } ew32(TDT, k); - E1000_WRITE_FLUSH(); msleep(200); time = jiffies; /* set the start time for the receive */ good_cnt = 0; diff --git a/trunk/drivers/net/e1000/e1000_hw.c b/trunk/drivers/net/e1000/e1000_hw.c index 8545c7aa93eb..1698622af434 100644 --- a/trunk/drivers/net/e1000/e1000_hw.c +++ b/trunk/drivers/net/e1000/e1000_hw.c @@ -446,7 +446,6 @@ s32 e1000_reset_hw(struct e1000_hw *hw) /* Must reset the PHY before resetting the MAC */ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { ew32(CTRL, (ctrl | E1000_CTRL_PHY_RST)); - E1000_WRITE_FLUSH(); msleep(5); } @@ -3753,7 +3752,6 @@ static s32 e1000_acquire_eeprom(struct e1000_hw *hw) /* Clear SK and CS */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); ew32(EECD, eecd); - E1000_WRITE_FLUSH(); udelay(1); } @@ -3826,7 +3824,6 @@ static void e1000_release_eeprom(struct e1000_hw *hw) eecd &= ~E1000_EECD_SK; /* Lower SCK */ ew32(EECD, eecd); - E1000_WRITE_FLUSH(); udelay(hw->eeprom.delay_usec); } else if (hw->eeprom.type == e1000_eeprom_microwire) { diff --git a/trunk/drivers/net/e1000e/es2lan.c b/trunk/drivers/net/e1000e/es2lan.c index e4f42257c24c..c0ecb2d9fdb7 100644 --- a/trunk/drivers/net/e1000e/es2lan.c +++ b/trunk/drivers/net/e1000e/es2lan.c @@ -1313,7 +1313,6 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; ew32(KMRNCTRLSTA, kmrnctrlsta); - e1e_flush(); udelay(2); @@ -1348,7 +1347,6 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | data; ew32(KMRNCTRLSTA, kmrnctrlsta); - e1e_flush(); udelay(2); diff --git a/trunk/drivers/net/e1000e/ethtool.c b/trunk/drivers/net/e1000e/ethtool.c index 06d88f316dce..cb1a3623253e 100644 --- a/trunk/drivers/net/e1000e/ethtool.c +++ b/trunk/drivers/net/e1000e/ethtool.c @@ -28,8 +28,8 @@ /* ethtool support for e1000 */ -#include #include +#include #include #include #include @@ -964,7 +964,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - e1e_flush(); usleep_range(10000, 20000); /* Test each interrupt */ @@ -997,7 +996,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, mask); ew32(ICS, mask); - e1e_flush(); usleep_range(10000, 20000); if (adapter->test_icr & mask) { @@ -1016,7 +1014,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMS, mask); ew32(ICS, mask); - e1e_flush(); usleep_range(10000, 20000); if (!(adapter->test_icr & mask)) { @@ -1035,7 +1032,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, ~mask & 0x00007FFF); ew32(ICS, ~mask & 0x00007FFF); - e1e_flush(); usleep_range(10000, 20000); if (adapter->test_icr) { @@ -1047,7 +1043,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - e1e_flush(); usleep_range(10000, 20000); /* Unhook test interrupt handler */ @@ -1281,7 +1276,6 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter) E1000_CTRL_FD); /* Force Duplex to FULL */ ew32(CTRL, ctrl_reg); - e1e_flush(); udelay(500); return 0; @@ -1424,7 +1418,6 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) */ #define E1000_SERDES_LB_ON 0x410 ew32(SCTL, E1000_SERDES_LB_ON); - e1e_flush(); usleep_range(10000, 20000); return 0; @@ -1520,7 +1513,6 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter) hw->phy.media_type == e1000_media_type_internal_serdes) { #define E1000_SERDES_LB_OFF 0x400 ew32(SCTL, E1000_SERDES_LB_OFF); - e1e_flush(); usleep_range(10000, 20000); break; } @@ -1600,7 +1592,6 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter) k = 0; } ew32(TDT, k); - e1e_flush(); msleep(200); time = jiffies; /* set the start time for the receive */ good_cnt = 0; diff --git a/trunk/drivers/net/e1000e/ich8lan.c b/trunk/drivers/net/e1000e/ich8lan.c index 4e36978b8fd8..c1752124f3cd 100644 --- a/trunk/drivers/net/e1000e/ich8lan.c +++ b/trunk/drivers/net/e1000e/ich8lan.c @@ -283,7 +283,6 @@ static void e1000_toggle_lanphypc_value_ich8lan(struct e1000_hw *hw) ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE; ctrl &= ~E1000_CTRL_LANPHYPC_VALUE; ew32(CTRL, ctrl); - e1e_flush(); udelay(10); ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE; ew32(CTRL, ctrl); @@ -1231,11 +1230,9 @@ s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) ew32(CTRL, reg); ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); - e1e_flush(); udelay(20); ew32(CTRL, ctrl_reg); ew32(CTRL_EXT, ctrl_ext); - e1e_flush(); udelay(20); out: @@ -2137,7 +2134,8 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, ret_val = 0; for (i = 0; i < words; i++) { - if (dev_spec->shadow_ram[offset+i].modified) { + if ((dev_spec->shadow_ram) && + (dev_spec->shadow_ram[offset+i].modified)) { data[i] = dev_spec->shadow_ram[offset+i].value; } else { ret_val = e1000_read_flash_word_ich8lan(hw, @@ -3092,7 +3090,6 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ret_val = e1000_acquire_swflag_ich8lan(hw); e_dbg("Issuing a global reset to ich8lan\n"); ew32(CTRL, (ctrl | E1000_CTRL_RST)); - /* cannot issue a flush here because it hangs the hardware */ msleep(20); if (!ret_val) diff --git a/trunk/drivers/net/e1000e/lib.c b/trunk/drivers/net/e1000e/lib.c index 7898a67d6505..65580b405942 100644 --- a/trunk/drivers/net/e1000e/lib.c +++ b/trunk/drivers/net/e1000e/lib.c @@ -1986,7 +1986,6 @@ static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw) /* Clear SK and CS */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); ew32(EECD, eecd); - e1e_flush(); udelay(1); /* diff --git a/trunk/drivers/net/e1000e/netdev.c b/trunk/drivers/net/e1000e/netdev.c index ab4be80f7ab5..4353ad56cf16 100644 --- a/trunk/drivers/net/e1000e/netdev.c +++ b/trunk/drivers/net/e1000e/netdev.c @@ -31,12 +31,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include diff --git a/trunk/drivers/net/e1000e/phy.c b/trunk/drivers/net/e1000e/phy.c index 8666476cb9be..2a6ee13285b1 100644 --- a/trunk/drivers/net/e1000e/phy.c +++ b/trunk/drivers/net/e1000e/phy.c @@ -537,7 +537,6 @@ static s32 __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data, kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; ew32(KMRNCTRLSTA, kmrnctrlsta); - e1e_flush(); udelay(2); @@ -610,7 +609,6 @@ static s32 __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data, kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | data; ew32(KMRNCTRLSTA, kmrnctrlsta); - e1e_flush(); udelay(2); diff --git a/trunk/drivers/net/igb/e1000_nvm.c b/trunk/drivers/net/igb/e1000_nvm.c index 40407124e722..7dcd65cede56 100644 --- a/trunk/drivers/net/igb/e1000_nvm.c +++ b/trunk/drivers/net/igb/e1000_nvm.c @@ -285,7 +285,6 @@ static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw) /* Clear SK and CS */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); wr32(E1000_EECD, eecd); - wrfl(); udelay(1); timeout = NVM_MAX_RETRY_SPI; diff --git a/trunk/drivers/net/igb/igb_ethtool.c b/trunk/drivers/net/igb/igb_ethtool.c index 414b0225be89..ff244ce803ce 100644 --- a/trunk/drivers/net/igb/igb_ethtool.c +++ b/trunk/drivers/net/igb/igb_ethtool.c @@ -1225,7 +1225,6 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) /* Disable all the interrupts */ wr32(E1000_IMC, ~0); - wrfl(); msleep(10); /* Define all writable bits for ICS */ @@ -1269,7 +1268,6 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_IMC, mask); wr32(E1000_ICS, mask); - wrfl(); msleep(10); if (adapter->test_icr & mask) { @@ -1291,7 +1289,6 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_IMS, mask); wr32(E1000_ICS, mask); - wrfl(); msleep(10); if (!(adapter->test_icr & mask)) { @@ -1313,7 +1310,6 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_IMC, ~mask); wr32(E1000_ICS, ~mask); - wrfl(); msleep(10); if (adapter->test_icr & mask) { @@ -1325,7 +1321,6 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) /* Disable all the interrupts */ wr32(E1000_IMC, ~0); - wrfl(); msleep(10); /* Unhook test interrupt handler */ diff --git a/trunk/drivers/net/igb/igb_main.c b/trunk/drivers/net/igb/igb_main.c index 40d4c405fd7e..dc599059512a 100644 --- a/trunk/drivers/net/igb/igb_main.c +++ b/trunk/drivers/net/igb/igb_main.c @@ -1052,7 +1052,6 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter) kfree(adapter->vf_data); adapter->vf_data = NULL; wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ); - wrfl(); msleep(100); dev_info(&adapter->pdev->dev, "IOV Disabled\n"); } @@ -2023,7 +2022,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (hw->bus.func == 0) hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); - else if (hw->mac.type >= e1000_82580) + else if (hw->mac.type == e1000_82580) hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A + NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1, &eeprom_data); @@ -2199,7 +2198,6 @@ static void __devexit igb_remove(struct pci_dev *pdev) kfree(adapter->vf_data); adapter->vf_data = NULL; wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ); - wrfl(); msleep(100); dev_info(&pdev->dev, "IOV Disabled\n"); } diff --git a/trunk/drivers/net/igbvf/netdev.c b/trunk/drivers/net/igbvf/netdev.c index 40ed066e3ef4..1330c8e932da 100644 --- a/trunk/drivers/net/igbvf/netdev.c +++ b/trunk/drivers/net/igbvf/netdev.c @@ -1226,7 +1226,6 @@ static void igbvf_configure_tx(struct igbvf_adapter *adapter) /* disable transmits */ txdctl = er32(TXDCTL(0)); ew32(TXDCTL(0), txdctl & ~E1000_TXDCTL_QUEUE_ENABLE); - e1e_flush(); msleep(10); /* Setup the HW Tx Head and Tail descriptor pointers */ @@ -1307,7 +1306,6 @@ static void igbvf_configure_rx(struct igbvf_adapter *adapter) /* disable receives */ rxdctl = er32(RXDCTL(0)); ew32(RXDCTL(0), rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE); - e1e_flush(); msleep(10); rdlen = rx_ring->count * sizeof(union e1000_adv_rx_desc); diff --git a/trunk/drivers/net/irda/smsc-ircc2.c b/trunk/drivers/net/irda/smsc-ircc2.c index 8b1c3484d271..954f6e938fb7 100644 --- a/trunk/drivers/net/irda/smsc-ircc2.c +++ b/trunk/drivers/net/irda/smsc-ircc2.c @@ -2405,6 +2405,8 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) * addresses making a subsystem device table necessary. */ #ifdef CONFIG_PCI +#define PCIID_VENDOR_INTEL 0x8086 +#define PCIID_VENDOR_ALI 0x10b9 static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = { /* * Subsystems needing entries: @@ -2414,7 +2416,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini */ { /* Guessed entry */ - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ .device = 0x24cc, .subvendor = 0x103c, .subdevice = 0x08bc, @@ -2427,7 +2429,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini .name = "HP nx5000 family", }, { - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ .device = 0x24cc, .subvendor = 0x103c, .subdevice = 0x088c, @@ -2441,7 +2443,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini .name = "HP nc8000 family", }, { - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ .device = 0x24cc, .subvendor = 0x103c, .subdevice = 0x0890, @@ -2454,7 +2456,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini .name = "HP nc6000 family", }, { - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ .device = 0x24cc, .subvendor = 0x0e11, .subdevice = 0x0860, @@ -2469,7 +2471,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini }, { /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ - .vendor = PCI_VENDOR_ID_INTEL, + .vendor = PCIID_VENDOR_INTEL, .device = 0x24c0, .subvendor = 0x1179, .subdevice = 0xffff, /* 0xffff is "any" */ @@ -2482,7 +2484,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", }, { - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801CAM ISA bridge */ + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ .device = 0x248c, .subvendor = 0x1179, .subdevice = 0xffff, /* 0xffff is "any" */ @@ -2496,7 +2498,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini }, { /* 82801DBM (ICH4-M) LPC Interface Bridge */ - .vendor = PCI_VENDOR_ID_INTEL, + .vendor = PCIID_VENDOR_INTEL, .device = 0x24cc, .subvendor = 0x1179, .subdevice = 0xffff, /* 0xffff is "any" */ @@ -2510,7 +2512,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini }, { /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ - .vendor = PCI_VENDOR_ID_AL, + .vendor = PCIID_VENDOR_ALI, .device = 0x1533, .subvendor = 0x1179, .subdevice = 0xffff, /* 0xffff is "any" */ diff --git a/trunk/drivers/net/ixgb/ixgb_ee.c b/trunk/drivers/net/ixgb/ixgb_ee.c index 38b362b67857..c982ab9f9005 100644 --- a/trunk/drivers/net/ixgb/ixgb_ee.c +++ b/trunk/drivers/net/ixgb/ixgb_ee.c @@ -57,7 +57,6 @@ ixgb_raise_clock(struct ixgb_hw *hw, */ *eecd_reg = *eecd_reg | IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, *eecd_reg); - IXGB_WRITE_FLUSH(hw); udelay(50); } @@ -76,7 +75,6 @@ ixgb_lower_clock(struct ixgb_hw *hw, */ *eecd_reg = *eecd_reg & ~IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, *eecd_reg); - IXGB_WRITE_FLUSH(hw); udelay(50); } @@ -114,7 +112,6 @@ ixgb_shift_out_bits(struct ixgb_hw *hw, eecd_reg |= IXGB_EECD_DI; IXGB_WRITE_REG(hw, EECD, eecd_reg); - IXGB_WRITE_FLUSH(hw); udelay(50); @@ -209,25 +206,21 @@ ixgb_standby_eeprom(struct ixgb_hw *hw) /* Deselect EEPROM */ eecd_reg &= ~(IXGB_EECD_CS | IXGB_EECD_SK); IXGB_WRITE_REG(hw, EECD, eecd_reg); - IXGB_WRITE_FLUSH(hw); udelay(50); /* Clock high */ eecd_reg |= IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); - IXGB_WRITE_FLUSH(hw); udelay(50); /* Select EEPROM */ eecd_reg |= IXGB_EECD_CS; IXGB_WRITE_REG(hw, EECD, eecd_reg); - IXGB_WRITE_FLUSH(hw); udelay(50); /* Clock low */ eecd_reg &= ~IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); - IXGB_WRITE_FLUSH(hw); udelay(50); } @@ -246,13 +239,11 @@ ixgb_clock_eeprom(struct ixgb_hw *hw) /* Rising edge of clock */ eecd_reg |= IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); - IXGB_WRITE_FLUSH(hw); udelay(50); /* Falling edge of clock */ eecd_reg &= ~IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); - IXGB_WRITE_FLUSH(hw); udelay(50); } diff --git a/trunk/drivers/net/ixgb/ixgb_hw.c b/trunk/drivers/net/ixgb/ixgb_hw.c index 3d61a9e4faf7..6cb2e42ff4c1 100644 --- a/trunk/drivers/net/ixgb/ixgb_hw.c +++ b/trunk/drivers/net/ixgb/ixgb_hw.c @@ -149,7 +149,6 @@ ixgb_adapter_stop(struct ixgb_hw *hw) */ IXGB_WRITE_REG(hw, RCTL, IXGB_READ_REG(hw, RCTL) & ~IXGB_RCTL_RXEN); IXGB_WRITE_REG(hw, TCTL, IXGB_READ_REG(hw, TCTL) & ~IXGB_TCTL_TXEN); - IXGB_WRITE_FLUSH(hw); msleep(IXGB_DELAY_BEFORE_RESET); /* Issue a global reset to the MAC. This will reset the chip's @@ -1221,7 +1220,6 @@ ixgb_optics_reset_bcm(struct ixgb_hw *hw) ctrl &= ~IXGB_CTRL0_SDP2; ctrl |= IXGB_CTRL0_SDP3; IXGB_WRITE_REG(hw, CTRL0, ctrl); - IXGB_WRITE_FLUSH(hw); /* SerDes needs extra delay */ msleep(IXGB_SUN_PHY_RESET_DELAY); diff --git a/trunk/drivers/net/ixgbe/ixgbe_82599.c b/trunk/drivers/net/ixgbe/ixgbe_82599.c index 34f30ec79c2e..3b3dd4df4c5c 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_82599.c +++ b/trunk/drivers/net/ixgbe/ixgbe_82599.c @@ -213,7 +213,6 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) switch (hw->phy.type) { case ixgbe_phy_tn: phy->ops.check_link = &ixgbe_check_phy_link_tnx; - phy->ops.setup_link = &ixgbe_setup_phy_link_tnx; phy->ops.get_firmware_version = &ixgbe_get_phy_firmware_version_tnx; break; diff --git a/trunk/drivers/net/ixgbe/ixgbe_common.c b/trunk/drivers/net/ixgbe/ixgbe_common.c index fc1375f26fe5..777051f54e53 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_common.c +++ b/trunk/drivers/net/ixgbe/ixgbe_common.c @@ -2632,7 +2632,6 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); - IXGBE_WRITE_FLUSH(hw); usleep_range(10000, 20000); } diff --git a/trunk/drivers/net/ixgbe/ixgbe_ethtool.c b/trunk/drivers/net/ixgbe/ixgbe_ethtool.c index 82d4244c6e10..dc649553a0a6 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/trunk/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1378,7 +1378,6 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); - IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); /* Test each interrupt */ @@ -1399,7 +1398,6 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); - IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); if (adapter->test_icr & mask) { @@ -1417,7 +1415,6 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) adapter->test_icr = 0; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); - IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); if (!(adapter->test_icr &mask)) { @@ -1438,7 +1435,6 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); - IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); if (adapter->test_icr) { @@ -1450,7 +1446,6 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); - IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); /* Unhook test interrupt handler */ diff --git a/trunk/drivers/net/ixgbe/ixgbe_main.c b/trunk/drivers/net/ixgbe/ixgbe_main.c index e86297b32733..1be617545dc9 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_main.c +++ b/trunk/drivers/net/ixgbe/ixgbe_main.c @@ -184,7 +184,6 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter) vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL); vmdctl &= ~IXGBE_VT_CTL_POOL_MASK; IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl); - IXGBE_WRITE_FLUSH(hw); /* take a breather then clean up driver data */ msleep(100); @@ -1006,7 +1005,7 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) struct ixgbe_adapter *adapter = dev_get_drvdata(dev); unsigned long event = *(unsigned long *)data; - if (!(adapter->flags & IXGBE_FLAG_DCA_CAPABLE)) + if (!(adapter->flags & IXGBE_FLAG_DCA_ENABLED)) return 0; switch (event) { diff --git a/trunk/drivers/net/ixgbe/ixgbe_phy.c b/trunk/drivers/net/ixgbe/ixgbe_phy.c index f7ca3511b9fe..735f686c3b36 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_phy.c +++ b/trunk/drivers/net/ixgbe/ixgbe_phy.c @@ -1585,7 +1585,6 @@ static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) *i2cctl |= IXGBE_I2C_CLK_OUT; IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); - IXGBE_WRITE_FLUSH(hw); /* SCL rise time (1000ns) */ udelay(IXGBE_I2C_T_RISE); @@ -1606,7 +1605,6 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) *i2cctl &= ~IXGBE_I2C_CLK_OUT; IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); - IXGBE_WRITE_FLUSH(hw); /* SCL fall time (300ns) */ udelay(IXGBE_I2C_T_FALL); @@ -1630,7 +1628,6 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) *i2cctl &= ~IXGBE_I2C_DATA_OUT; IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); - IXGBE_WRITE_FLUSH(hw); /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */ udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA); diff --git a/trunk/drivers/net/ixgbe/ixgbe_x540.c b/trunk/drivers/net/ixgbe/ixgbe_x540.c index 2696c78e9f46..bec30ed91adc 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_x540.c +++ b/trunk/drivers/net/ixgbe/ixgbe_x540.c @@ -162,7 +162,6 @@ static s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw) ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD; IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); - IXGBE_WRITE_FLUSH(hw); msleep(50); diff --git a/trunk/drivers/net/macb.c b/trunk/drivers/net/macb.c index dc4e305a1087..0fcdc25699d8 100644 --- a/trunk/drivers/net/macb.c +++ b/trunk/drivers/net/macb.c @@ -322,9 +322,6 @@ static void macb_tx(struct macb *bp) for (i = 0; i < TX_RING_SIZE; i++) bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); - /* Add wrap bit */ - bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); - /* free transmit buffer in upper layer*/ for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { struct ring_info *rp = &bp->tx_skb[tail]; diff --git a/trunk/drivers/net/mlx4/en_port.c b/trunk/drivers/net/mlx4/en_port.c index 5ada5b469112..5e7109178061 100644 --- a/trunk/drivers/net/mlx4/en_port.c +++ b/trunk/drivers/net/mlx4/en_port.c @@ -128,7 +128,7 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, memset(context, 0, sizeof *context); context->base_qpn = cpu_to_be32(base_qpn); - context->n_mac = 0x2; + context->n_mac = 0x7; context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | base_qpn); context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | diff --git a/trunk/drivers/net/mlx4/main.c b/trunk/drivers/net/mlx4/main.c index f0ee35df4dd7..c94b3426d355 100644 --- a/trunk/drivers/net/mlx4/main.c +++ b/trunk/drivers/net/mlx4/main.c @@ -1117,8 +1117,6 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) info->port = port; mlx4_init_mac_table(dev, &info->mac_table); mlx4_init_vlan_table(dev, &info->vlan_table); - info->base_qpn = dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + - (port - 1) * (1 << log_num_mac); sprintf(info->dev_name, "mlx4_port%d", port); info->port_attr.attr.name = info->dev_name; diff --git a/trunk/drivers/net/mlx4/port.c b/trunk/drivers/net/mlx4/port.c index 609e0ec14cee..1f95afda6841 100644 --- a/trunk/drivers/net/mlx4/port.c +++ b/trunk/drivers/net/mlx4/port.c @@ -258,12 +258,9 @@ void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn) if (validate_index(dev, table, index)) goto out; - /* Check whether this address has reference count */ - if (!(--table->refs[index])) { - table->entries[index] = 0; - mlx4_set_port_mac_table(dev, port, table->entries); - --table->total; - } + table->entries[index] = 0; + mlx4_set_port_mac_table(dev, port, table->entries); + --table->total; out: mutex_unlock(&table->mutex); } diff --git a/trunk/drivers/net/niu.c b/trunk/drivers/net/niu.c index ed47585a6862..cd6c2317e29e 100644 --- a/trunk/drivers/net/niu.c +++ b/trunk/drivers/net/niu.c @@ -9201,7 +9201,7 @@ static int __devinit niu_ldg_init(struct niu *np) first_chan = 0; for (i = 0; i < port; i++) - first_chan += parent->rxchan_per_port[i]; + first_chan += parent->rxchan_per_port[port]; num_chan = parent->rxchan_per_port[port]; for (i = first_chan; i < (first_chan + num_chan); i++) { @@ -9217,7 +9217,7 @@ static int __devinit niu_ldg_init(struct niu *np) first_chan = 0; for (i = 0; i < port; i++) - first_chan += parent->txchan_per_port[i]; + first_chan += parent->txchan_per_port[port]; num_chan = parent->txchan_per_port[port]; for (i = first_chan; i < (first_chan + num_chan); i++) { err = niu_ldg_assign_ldn(np, parent, diff --git a/trunk/drivers/net/r8169.c b/trunk/drivers/net/r8169.c index 02339b3352e7..7d9c650f395e 100644 --- a/trunk/drivers/net/r8169.c +++ b/trunk/drivers/net/r8169.c @@ -239,7 +239,6 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 }, { PCI_VENDOR_ID_LINKSYS, 0x1032, @@ -1092,21 +1091,6 @@ rtl_w1w0_eri(void __iomem *ioaddr, int addr, u32 mask, u32 p, u32 m, int type) rtl_eri_write(ioaddr, addr, mask, (val & ~m) | p, type); } -struct exgmac_reg { - u16 addr; - u16 mask; - u32 val; -}; - -static void rtl_write_exgmac_batch(void __iomem *ioaddr, - const struct exgmac_reg *r, int len) -{ - while (len-- > 0) { - rtl_eri_write(ioaddr, r->addr, r->mask, r->val, ERIAR_EXGMAC); - r++; - } -} - static u8 rtl8168d_efuse_read(void __iomem *ioaddr, int reg_addr) { u8 value = 0xff; @@ -3132,18 +3116,6 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) RTL_W32(MAC0, low); RTL_R32(MAC0); - if (tp->mac_version == RTL_GIGA_MAC_VER_34) { - const struct exgmac_reg e[] = { - { .addr = 0xe0, ERIAR_MASK_1111, .val = low }, - { .addr = 0xe4, ERIAR_MASK_1111, .val = high }, - { .addr = 0xf0, ERIAR_MASK_1111, .val = low << 16 }, - { .addr = 0xf4, ERIAR_MASK_1111, .val = high << 16 | - low >> 16 }, - }; - - rtl_write_exgmac_batch(ioaddr, e, ARRAY_SIZE(e)); - } - RTL_W8(Cfg9346, Cfg9346_Lock); spin_unlock_irq(&tp->lock); diff --git a/trunk/drivers/net/sis190.c b/trunk/drivers/net/sis190.c index 3c0f1312b391..8ad7bfbaa3af 100644 --- a/trunk/drivers/net/sis190.c +++ b/trunk/drivers/net/sis190.c @@ -1825,16 +1825,6 @@ static int sis190_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL); } -static int sis190_mac_addr(struct net_device *dev, void *p) -{ - int rc; - - rc = eth_mac_addr(dev, p); - if (!rc) - sis190_init_rxfilter(dev); - return rc; -} - static const struct net_device_ops sis190_netdev_ops = { .ndo_open = sis190_open, .ndo_stop = sis190_close, @@ -1843,7 +1833,7 @@ static const struct net_device_ops sis190_netdev_ops = { .ndo_tx_timeout = sis190_tx_timeout, .ndo_set_multicast_list = sis190_set_rx_mode, .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = sis190_mac_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = sis190_netpoll, diff --git a/trunk/drivers/net/usb/cdc_ncm.c b/trunk/drivers/net/usb/cdc_ncm.c index a03336e086d5..fd622a66ebbf 100644 --- a/trunk/drivers/net/usb/cdc_ncm.c +++ b/trunk/drivers/net/usb/cdc_ncm.c @@ -53,7 +53,7 @@ #include #include -#define DRIVER_VERSION "04-Aug-2011" +#define DRIVER_VERSION "01-June-2011" /* CDC NCM subclass 3.2.1 */ #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 @@ -163,8 +163,35 @@ cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); } +static int +cdc_ncm_do_request(struct cdc_ncm_ctx *ctx, struct usb_cdc_notification *req, + void *data, u16 flags, u16 *actlen, u16 timeout) +{ + int err; + + err = usb_control_msg(ctx->udev, (req->bmRequestType & USB_DIR_IN) ? + usb_rcvctrlpipe(ctx->udev, 0) : + usb_sndctrlpipe(ctx->udev, 0), + req->bNotificationType, req->bmRequestType, + req->wValue, + req->wIndex, data, + req->wLength, timeout); + + if (err < 0) { + if (actlen) + *actlen = 0; + return err; + } + + if (actlen) + *actlen = err; + + return 0; +} + static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) { + struct usb_cdc_notification req; u32 val; u8 flags; u8 iface_no; @@ -173,14 +200,14 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; - err = usb_control_msg(ctx->udev, - usb_rcvctrlpipe(ctx->udev, 0), - USB_CDC_GET_NTB_PARAMETERS, - USB_TYPE_CLASS | USB_DIR_IN - | USB_RECIP_INTERFACE, - 0, iface_no, &ctx->ncm_parm, - sizeof(ctx->ncm_parm), 10000); - if (err < 0) { + req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE; + req.bNotificationType = USB_CDC_GET_NTB_PARAMETERS; + req.wValue = 0; + req.wIndex = cpu_to_le16(iface_no); + req.wLength = cpu_to_le16(sizeof(ctx->ncm_parm)); + + err = cdc_ncm_do_request(ctx, &req, &ctx->ncm_parm, 0, NULL, 1000); + if (err) { pr_debug("failed GET_NTB_PARAMETERS\n"); return 1; } @@ -226,26 +253,31 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) /* inform device about NTB input size changes */ if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) { + req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | + USB_RECIP_INTERFACE; + req.bNotificationType = USB_CDC_SET_NTB_INPUT_SIZE; + req.wValue = 0; + req.wIndex = cpu_to_le16(iface_no); if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) { struct usb_cdc_ncm_ndp_input_size ndp_in_sz; - err = usb_control_msg(ctx->udev, - usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_NTB_INPUT_SIZE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - 0, iface_no, &ndp_in_sz, 8, 1000); + + req.wLength = 8; + ndp_in_sz.dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); + ndp_in_sz.wNtbInMaxDatagrams = + cpu_to_le16(CDC_NCM_DPT_DATAGRAMS_MAX); + ndp_in_sz.wReserved = 0; + err = cdc_ncm_do_request(ctx, &req, &ndp_in_sz, 0, NULL, + 1000); } else { __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); - err = usb_control_msg(ctx->udev, - usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_NTB_INPUT_SIZE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - 0, iface_no, &dwNtbInMaxSize, 4, 1000); + + req.wLength = 4; + err = cdc_ncm_do_request(ctx, &req, &dwNtbInMaxSize, 0, + NULL, 1000); } - if (err < 0) + if (err) pr_debug("Setting NTB Input Size failed\n"); } @@ -300,24 +332,29 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) /* set CRC Mode */ if (flags & USB_CDC_NCM_NCAP_CRC_MODE) { - err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_CRC_MODE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - USB_CDC_NCM_CRC_NOT_APPENDED, - iface_no, NULL, 0, 1000); - if (err < 0) + req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | + USB_RECIP_INTERFACE; + req.bNotificationType = USB_CDC_SET_CRC_MODE; + req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED); + req.wIndex = cpu_to_le16(iface_no); + req.wLength = 0; + + err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000); + if (err) pr_debug("Setting CRC mode off failed\n"); } /* set NTB format, if both formats are supported */ if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) { - err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_NTB_FORMAT, USB_TYPE_CLASS - | USB_DIR_OUT | USB_RECIP_INTERFACE, - USB_CDC_NCM_NTB16_FORMAT, - iface_no, NULL, 0, 1000); - if (err < 0) + req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | + USB_RECIP_INTERFACE; + req.bNotificationType = USB_CDC_SET_NTB_FORMAT; + req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT); + req.wIndex = cpu_to_le16(iface_no); + req.wLength = 0; + + err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000); + if (err) pr_debug("Setting NTB format to 16-bit failed\n"); } @@ -327,13 +364,17 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) { __le16 max_datagram_size; u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); - err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0), - USB_CDC_GET_MAX_DATAGRAM_SIZE, - USB_TYPE_CLASS | USB_DIR_IN - | USB_RECIP_INTERFACE, - 0, iface_no, &max_datagram_size, - 2, 1000); - if (err < 0) { + + req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | + USB_RECIP_INTERFACE; + req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE; + req.wValue = 0; + req.wIndex = cpu_to_le16(iface_no); + req.wLength = cpu_to_le16(2); + + err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL, + 1000); + if (err) { pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", CDC_NCM_MIN_DATAGRAM_SIZE); } else { @@ -354,15 +395,17 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) CDC_NCM_MIN_DATAGRAM_SIZE; /* if value changed, update device */ - err = usb_control_msg(ctx->udev, - usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_MAX_DATAGRAM_SIZE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - 0, - iface_no, &max_datagram_size, - 2, 1000); - if (err < 0) + req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | + USB_RECIP_INTERFACE; + req.bNotificationType = USB_CDC_SET_MAX_DATAGRAM_SIZE; + req.wValue = 0; + req.wIndex = cpu_to_le16(iface_no); + req.wLength = 2; + max_datagram_size = cpu_to_le16(ctx->max_datagram_size); + + err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, + 0, NULL, 1000); + if (err) pr_debug("SET_MAX_DATAGRAM_SIZE failed\n"); } @@ -628,7 +671,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) u32 rem; u32 offset; u32 last_offset; - u16 n = 0, index; + u16 n = 0; u8 ready2send = 0; /* if there is a remaining skb, it gets priority */ @@ -816,8 +859,8 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) cpu_to_le16(sizeof(ctx->tx_ncm.nth16)); ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq); ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset); - index = ALIGN(sizeof(struct usb_cdc_ncm_nth16), ctx->tx_ndp_modulus); - ctx->tx_ncm.nth16.wNdpIndex = cpu_to_le16(index); + ctx->tx_ncm.nth16.wNdpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16), + ctx->tx_ndp_modulus); memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16)); ctx->tx_seq++; @@ -830,11 +873,12 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem); ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */ - memcpy(((u8 *)skb_out->data) + index, + memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex, &(ctx->tx_ncm.ndp16), sizeof(ctx->tx_ncm.ndp16)); - memcpy(((u8 *)skb_out->data) + index + sizeof(ctx->tx_ncm.ndp16), + memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex + + sizeof(ctx->tx_ncm.ndp16), &(ctx->tx_ncm.dpe16), (ctx->tx_curr_frame_num + 1) * sizeof(struct usb_cdc_ncm_dpe16)); diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/trunk/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 44d9d8d56490..9ff7c30573b8 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -309,7 +309,11 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, u8 i; u32 val; - if (ah->is_pciexpress != true || ah->aspm_enabled != true) + if (ah->is_pciexpress != true) + return; + + /* Do not touch SerDes registers */ + if (ah->config.pcie_powersave_enable == 2) return; /* Nothing to do on restore for 11N */ diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/trunk/drivers/net/wireless/ath/ath9k/ar9003_hw.c index ad2bb2bf4e8a..8efdec247c02 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -519,7 +519,11 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off) { - if (ah->is_pciexpress != true || ah->aspm_enabled != true) + if (ah->is_pciexpress != true) + return; + + /* Do not touch SerDes registers */ + if (ah->config.pcie_powersave_enable == 2) return; /* Nothing to do on restore for 11N */ diff --git a/trunk/drivers/net/wireless/ath/ath9k/hw.c b/trunk/drivers/net/wireless/ath/ath9k/hw.c index 8dcefe74f4c3..8006ce0c7357 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/hw.c +++ b/trunk/drivers/net/wireless/ath/ath9k/hw.c @@ -318,14 +318,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah) REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); } -static void ath9k_hw_aspm_init(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - - if (common->bus_ops->aspm_init) - common->bus_ops->aspm_init(common); -} - /* This should work for all families including legacy */ static bool ath9k_hw_chip_test(struct ath_hw *ah) { @@ -386,6 +378,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.additional_swba_backoff = 0; ah->config.ack_6mb = 0x0; ah->config.cwm_ignore_extcca = 0; + ah->config.pcie_powersave_enable = 0; ah->config.pcie_clock_req = 0; ah->config.pcie_waen = 0; ah->config.analog_shiftreg = 1; @@ -605,7 +598,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (ah->is_pciexpress) - ath9k_hw_aspm_init(ah); + ath9k_hw_configpcipowersave(ah, 0, 0); else ath9k_hw_disablepcie(ah); diff --git a/trunk/drivers/net/wireless/ath/ath9k/hw.h b/trunk/drivers/net/wireless/ath/ath9k/hw.h index c79889036ec4..6acd0f975ae1 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/hw.h +++ b/trunk/drivers/net/wireless/ath/ath9k/hw.h @@ -219,6 +219,7 @@ struct ath9k_ops_config { int additional_swba_backoff; int ack_6mb; u32 cwm_ignore_extcca; + u8 pcie_powersave_enable; bool pcieSerDesWrite; u8 pcie_clock_req; u32 pcie_waen; @@ -672,7 +673,6 @@ struct ath_hw { bool sw_mgmt_crypto; bool is_pciexpress; - bool aspm_enabled; bool is_monitoring; bool need_an_top2_fixup; u16 tx_trig_level; @@ -874,7 +874,6 @@ struct ath_bus_ops { bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); void (*bt_coex_prep)(struct ath_common *common); void (*extn_synch_en)(struct ath_common *common); - void (*aspm_init)(struct ath_common *common); }; static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) diff --git a/trunk/drivers/net/wireless/ath/ath9k/init.c b/trunk/drivers/net/wireless/ath/ath9k/init.c index aa0ff7e2c922..ac5107172f94 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/init.c +++ b/trunk/drivers/net/wireless/ath/ath9k/init.c @@ -670,10 +670,8 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) static void ath9k_init_txpower_limits(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_channel *curchan = ah->curchan; - ah->txchainmask = common->tx_chainmask; if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ); if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) diff --git a/trunk/drivers/net/wireless/ath/ath9k/pci.c b/trunk/drivers/net/wireless/ath/ath9k/pci.c index be4ea1329813..3bad0b2cf9a3 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/pci.c +++ b/trunk/drivers/net/wireless/ath/ath9k/pci.c @@ -16,7 +16,6 @@ #include #include -#include #include #include "ath9k.h" @@ -116,38 +115,12 @@ static void ath_pci_extn_synch_enable(struct ath_common *common) pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl); } -static void ath_pci_aspm_init(struct ath_common *common) -{ - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct ath_hw *ah = sc->sc_ah; - struct pci_dev *pdev = to_pci_dev(sc->dev); - struct pci_dev *parent; - int pos; - u8 aspm; - - if (!pci_is_pcie(pdev)) - return; - - parent = pdev->bus->self; - if (WARN_ON(!parent)) - return; - - pos = pci_pcie_cap(parent); - pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm); - if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { - ah->aspm_enabled = true; - /* Initialize PCIe PM and SERDES registers. */ - ath9k_hw_configpcipowersave(ah, 0, 0); - } -} - static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath_pci_read_cachesize, .eeprom_read = ath_pci_eeprom_read, .bt_coex_prep = ath_pci_bt_coex_prep, .extn_synch_en = ath_pci_extn_synch_enable, - .aspm_init = ath_pci_aspm_init, }; static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/trunk/drivers/net/wireless/iwlegacy/iwl-3945.c b/trunk/drivers/net/wireless/iwlegacy/iwl-3945.c index 73fe3cdf796b..dab67a12d73b 100644 --- a/trunk/drivers/net/wireless/iwlegacy/iwl-3945.c +++ b/trunk/drivers/net/wireless/iwlegacy/iwl-3945.c @@ -1746,11 +1746,7 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) } memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - /* - * We do not commit tx power settings while channel changing, - * do it now if tx power changed. - */ - iwl_legacy_set_tx_power(priv, priv->tx_power_next, false); + return 0; } diff --git a/trunk/drivers/net/wireless/iwlegacy/iwl-4965.c b/trunk/drivers/net/wireless/iwlegacy/iwl-4965.c index ecdc6e557428..bd4b000733f7 100644 --- a/trunk/drivers/net/wireless/iwlegacy/iwl-4965.c +++ b/trunk/drivers/net/wireless/iwlegacy/iwl-4965.c @@ -1235,12 +1235,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); iwl_legacy_print_rx_config_cmd(priv, ctx); - /* - * We do not commit tx power settings while channel changing, - * do it now if tx power changed. - */ - iwl_legacy_set_tx_power(priv, priv->tx_power_next, false); - return 0; + goto set_tx_power; } /* If we are currently associated and the new config requires @@ -1320,6 +1315,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c iwl4965_init_sensitivity(priv); +set_tx_power: /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ ret = iwl_legacy_set_tx_power(priv, priv->tx_power_next, true); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c index c95cefd529dc..3eeb12ebe6e9 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -365,7 +365,6 @@ static struct iwl_base_params iwl5000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .no_idle_support = true, }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-core.h b/trunk/drivers/net/wireless/iwlwifi/iwl-core.h index 02817a438550..3e6bb734dcb7 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-core.h @@ -135,7 +135,6 @@ struct iwl_mod_params { * @temperature_kelvin: temperature report by uCode in kelvin * @max_event_log_size: size of event log buffer size for ucode event logging * @shadow_reg_enable: HW shadhow register bit - * @no_idle_support: do not support idle mode */ struct iwl_base_params { int eeprom_size; @@ -157,7 +156,6 @@ struct iwl_base_params { bool temperature_kelvin; u32 max_event_log_size; const bool shadow_reg_enable; - const bool no_idle_support; }; /* * @advanced_bt_coexist: support advanced bt coexist diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-pci.c b/trunk/drivers/net/wireless/iwlwifi/iwl-pci.c index 69d4ec467dca..fb7e436b40c7 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -134,7 +134,6 @@ static void iwl_pci_apm_config(struct iwl_bus *bus) static void iwl_pci_set_drv_data(struct iwl_bus *bus, void *drv_data) { bus->drv_data = drv_data; - pci_set_drvdata(IWL_BUS_GET_PCI_DEV(bus), drv_data); } static void iwl_pci_get_hw_id(struct iwl_bus *bus, char buf[], @@ -455,6 +454,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); } + pci_set_drvdata(pdev, bus); + bus->dev = &pdev->dev; bus->irq = pdev->irq; bus->ops = &pci_ops; @@ -493,12 +494,11 @@ static void iwl_pci_down(struct iwl_bus *bus) static void __devexit iwl_pci_remove(struct pci_dev *pdev) { - struct iwl_priv *priv = pci_get_drvdata(pdev); - void *bus_specific = priv->bus->bus_specific; + struct iwl_bus *bus = pci_get_drvdata(pdev); - iwl_remove(priv); + iwl_remove(bus->drv_data); - iwl_pci_down(bus_specific); + iwl_pci_down(bus); } #ifdef CONFIG_PM @@ -506,20 +506,20 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) static int iwl_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_priv *priv = pci_get_drvdata(pdev); + struct iwl_bus *bus = pci_get_drvdata(pdev); /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx. */ - return iwl_suspend(priv); + return iwl_suspend(bus->drv_data); } static int iwl_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_priv *priv = pci_get_drvdata(pdev); + struct iwl_bus *bus = pci_get_drvdata(pdev); /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if @@ -532,7 +532,7 @@ static int iwl_pci_resume(struct device *device) */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - return iwl_resume(priv); + return iwl_resume(bus->drv_data); } static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-power.c b/trunk/drivers/net/wireless/iwlwifi/iwl-power.c index cd64df05f9ed..3ec619c6881c 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-power.c @@ -349,8 +349,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, if (priv->wowlan) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper); - else if (!priv->cfg->base_params->no_idle_support && - priv->hw->conf.flags & IEEE80211_CONF_IDLE) + else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); else if (iwl_tt_is_low_power_state(priv)) { /* in thermal throttling low power state */ diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800lib.c b/trunk/drivers/net/wireless/rt2x00/rt2800lib.c index ef67f6786a84..84ab7d1acb6a 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800lib.c @@ -703,7 +703,8 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) /* * Add space for the TXWI in front of the skb. */ - memset(skb_push(entry->skb, TXWI_DESC_SIZE), 0, TXWI_DESC_SIZE); + skb_push(entry->skb, TXWI_DESC_SIZE); + memset(entry->skb, 0, TXWI_DESC_SIZE); /* * Register descriptor details in skb frame descriptor. diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00lib.h b/trunk/drivers/net/wireless/rt2x00/rt2x00lib.h index 4cdf247a870d..15cdc7e57fc4 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -355,8 +355,7 @@ static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf * return CIPHER_NONE; } -static inline void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, struct txentry_desc *txdesc) { } diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c b/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c index 4ccf23805973..8efab3983528 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -113,7 +113,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * due to possible race conditions in mac80211. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) - goto exit_free_skb; + goto exit_fail; /* * Use the ATIM queue if appropriate and present. @@ -127,7 +127,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ERROR(rt2x00dev, "Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", qid, DRV_PROJECT); - goto exit_free_skb; + goto exit_fail; } /* @@ -159,7 +159,6 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) exit_fail: rt2x00queue_pause_queue(queue); - exit_free_skb: dev_kfree_skb_any(skb); } EXPORT_SYMBOL_GPL(rt2x00mac_tx); diff --git a/trunk/drivers/net/wireless/rtlwifi/pci.c b/trunk/drivers/net/wireless/rtlwifi/pci.c index 56f12358389d..5efd57833489 100644 --- a/trunk/drivers/net/wireless/rtlwifi/pci.c +++ b/trunk/drivers/net/wireless/rtlwifi/pci.c @@ -1696,17 +1696,15 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn); pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn); - if (bridge_pdev) { - /*find bridge info if available */ - pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor; - for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { - if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { - pcipriv->ndis_adapter.pcibridge_vendor = tmp; - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - ("Pci Bridge Vendor is found index:" - " %d\n", tmp)); - break; - } + /*find bridge info */ + pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor; + for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { + if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { + pcipriv->ndis_adapter.pcibridge_vendor = tmp; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("Pci Bridge Vendor is found index: %d\n", + tmp)); + break; } } diff --git a/trunk/drivers/of/address.c b/trunk/drivers/of/address.c index 72c33fbe451d..da1f4b9605df 100644 --- a/trunk/drivers/of/address.c +++ b/trunk/drivers/of/address.c @@ -610,6 +610,6 @@ void __iomem *of_iomap(struct device_node *np, int index) if (of_address_to_resource(np, index, &res)) return NULL; - return ioremap(res.start, resource_size(&res)); + return ioremap(res.start, 1 + res.end - res.start); } EXPORT_SYMBOL(of_iomap); diff --git a/trunk/drivers/of/base.c b/trunk/drivers/of/base.c index 3ff22e32b602..02ed36719def 100644 --- a/trunk/drivers/of/base.c +++ b/trunk/drivers/of/base.c @@ -610,9 +610,8 @@ EXPORT_SYMBOL(of_find_node_by_phandle); * * The out_value is modified only if a valid u32 value can be decoded. */ -int of_property_read_u32_array(const struct device_node *np, - const char *propname, u32 *out_values, - size_t sz) +int of_property_read_u32_array(const struct device_node *np, char *propname, + u32 *out_values, size_t sz) { struct property *prop = of_find_property(np, propname, NULL); const __be32 *val; @@ -646,7 +645,7 @@ EXPORT_SYMBOL_GPL(of_property_read_u32_array); * * The out_string pointer is modified only if a valid string can be decoded. */ -int of_property_read_string(struct device_node *np, const char *propname, +int of_property_read_string(struct device_node *np, char *propname, const char **out_string) { struct property *prop = of_find_property(np, propname, NULL); diff --git a/trunk/drivers/pci/hotplug/acpiphp_glue.c b/trunk/drivers/pci/hotplug/acpiphp_glue.c index 220285760b68..a70fa89f76fd 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_glue.c +++ b/trunk/drivers/pci/hotplug/acpiphp_glue.c @@ -110,7 +110,7 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, } -static const struct acpi_dock_ops acpiphp_dock_ops = { +static struct acpi_dock_ops acpiphp_dock_ops = { .handler = handle_hotplug_event_func, }; diff --git a/trunk/drivers/platform/x86/Kconfig b/trunk/drivers/platform/x86/Kconfig index 1e88d4785321..45e0191c35dd 100644 --- a/trunk/drivers/platform/x86/Kconfig +++ b/trunk/drivers/platform/x86/Kconfig @@ -769,12 +769,4 @@ config INTEL_OAKTRAIL enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y here; it will only load on supported platforms. -config SAMSUNG_Q10 - tristate "Samsung Q10 Extras" - depends on SERIO_I8042 - select BACKLIGHT_CLASS_DEVICE - ---help--- - This driver provides support for backlight control on Samsung Q10 - and related laptops, including Dell Latitude X200. - endif # X86_PLATFORM_DEVICES diff --git a/trunk/drivers/platform/x86/Makefile b/trunk/drivers/platform/x86/Makefile index 293a320d9faa..afc1f832aa67 100644 --- a/trunk/drivers/platform/x86/Makefile +++ b/trunk/drivers/platform/x86/Makefile @@ -44,4 +44,3 @@ obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o obj-$(CONFIG_MXM_WMI) += mxm-wmi.o obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o -obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o diff --git a/trunk/drivers/platform/x86/acer-wmi.c b/trunk/drivers/platform/x86/acer-wmi.c index af2bb20cb2fb..e1c4938b301b 100644 --- a/trunk/drivers/platform/x86/acer-wmi.c +++ b/trunk/drivers/platform/x86/acer-wmi.c @@ -99,7 +99,6 @@ enum acer_wmi_event_ids { static const struct key_entry acer_wmi_keymap[] = { {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */ {KE_KEY, 0x03, {KEY_WLAN} }, /* WiFi */ - {KE_KEY, 0x04, {KEY_WLAN} }, /* WiFi */ {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */ {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */ {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */ @@ -305,10 +304,6 @@ static struct quirk_entry quirk_fujitsu_amilo_li_1718 = { .wireless = 2, }; -static struct quirk_entry quirk_lenovo_ideapad_s205 = { - .wireless = 3, -}; - /* The Aspire One has a dummy ACPI-WMI interface - disable it */ static struct dmi_system_id __devinitdata acer_blacklist[] = { { @@ -455,15 +450,6 @@ static struct dmi_system_id acer_quirks[] = { }, .driver_data = &quirk_medion_md_98300, }, - { - .callback = dmi_matched, - .ident = "Lenovo Ideapad S205", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"), - }, - .driver_data = &quirk_lenovo_ideapad_s205, - }, {} }; @@ -556,12 +542,6 @@ struct wmi_interface *iface) return AE_ERROR; *value = result & 0x1; return AE_OK; - case 3: - err = ec_read(0x78, &result); - if (err) - return AE_ERROR; - *value = result & 0x1; - return AE_OK; default: err = ec_read(0xA, &result); if (err) @@ -1286,13 +1266,8 @@ static void acer_rfkill_update(struct work_struct *ignored) acpi_status status; status = get_u32(&state, ACER_CAP_WIRELESS); - if (ACPI_SUCCESS(status)) { - if (quirks->wireless == 3) { - rfkill_set_hw_state(wireless_rfkill, !state); - } else { - rfkill_set_sw_state(wireless_rfkill, !state); - } - } + if (ACPI_SUCCESS(status)) + rfkill_set_sw_state(wireless_rfkill, !state); if (has_cap(ACER_CAP_BLUETOOTH)) { status = get_u32(&state, ACER_CAP_BLUETOOTH); @@ -1425,9 +1400,6 @@ static ssize_t show_bool_threeg(struct device *dev, { u32 result; \ acpi_status status; - - pr_info("This threeg sysfs will be removed in 2012" - " - used by: %s\n", current->comm); if (wmi_has_guid(WMID_GUID3)) status = wmid3_get_device_status(&result, ACER_WMID3_GDS_THREEG); @@ -1443,10 +1415,8 @@ static ssize_t set_bool_threeg(struct device *dev, { u32 tmp = simple_strtoul(buf, NULL, 10); acpi_status status = set_u32(tmp, ACER_CAP_THREEG); - pr_info("This threeg sysfs will be removed in 2012" - " - used by: %s\n", current->comm); - if (ACPI_FAILURE(status)) - return -EINVAL; + if (ACPI_FAILURE(status)) + return -EINVAL; return count; } static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg, @@ -1455,8 +1425,6 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg, static ssize_t show_interface(struct device *dev, struct device_attribute *attr, char *buf) { - pr_info("This interface sysfs will be removed in 2012" - " - used by: %s\n", current->comm); switch (interface->type) { case ACER_AMW0: return sprintf(buf, "AMW0\n"); diff --git a/trunk/drivers/platform/x86/acerhdf.c b/trunk/drivers/platform/x86/acerhdf.c index 760c6d7624fe..fca3489218b7 100644 --- a/trunk/drivers/platform/x86/acerhdf.c +++ b/trunk/drivers/platform/x86/acerhdf.c @@ -182,7 +182,6 @@ static const struct bios_settings_t bios_tbl[] = { {"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, - {"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00} }, /* Acer 531 */ {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} }, /* Gateway */ @@ -704,15 +703,15 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Peter Feuerer"); MODULE_DESCRIPTION("Aspire One temperature and fan driver"); MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:"); -MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:"); -MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:"); +MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:"); +MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:"); MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:"); MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:"); -MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:"); -MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOA*:"); -MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMU*:"); -MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:"); +MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:"); +MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:"); +MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:"); +MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMA*:"); module_init(acerhdf_init); module_exit(acerhdf_exit); diff --git a/trunk/drivers/platform/x86/asus-laptop.c b/trunk/drivers/platform/x86/asus-laptop.c index fa6d7ec68b26..d65df92e2acc 100644 --- a/trunk/drivers/platform/x86/asus-laptop.c +++ b/trunk/drivers/platform/x86/asus-laptop.c @@ -70,10 +70,11 @@ MODULE_LICENSE("GPL"); * WAPF defines the behavior of the Fn+Fx wlan key * The significance of values is yet to be found, but * most of the time: - * Bit | Bluetooth | WLAN - * 0 | Hardware | Hardware - * 1 | Hardware | Software - * 4 | Software | Software + * 0x0 will do nothing + * 0x1 will allow to control the device with Fn+Fx key. + * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key + * 0x5 like 0x1 or 0x4 + * So, if something doesn't work as you want, just try other values =) */ static uint wapf = 1; module_param(wapf, uint, 0444); diff --git a/trunk/drivers/platform/x86/asus-nb-wmi.c b/trunk/drivers/platform/x86/asus-nb-wmi.c index b0859d4183e8..0580d99b0798 100644 --- a/trunk/drivers/platform/x86/asus-nb-wmi.c +++ b/trunk/drivers/platform/x86/asus-nb-wmi.c @@ -38,24 +38,6 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); -/* - * WAPF defines the behavior of the Fn+Fx wlan key - * The significance of values is yet to be found, but - * most of the time: - * Bit | Bluetooth | WLAN - * 0 | Hardware | Hardware - * 1 | Hardware | Software - * 4 | Software | Software - */ -static uint wapf; -module_param(wapf, uint, 0444); -MODULE_PARM_DESC(wapf, "WAPF value"); - -static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) -{ - driver->wapf = wapf; -} - static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x30, { KEY_VOLUMEUP } }, { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, @@ -71,16 +53,16 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x51, { KEY_WWW } }, { KE_KEY, 0x55, { KEY_CALC } }, { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ - { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */ - { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */ - { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */ + { KE_KEY, 0x5D, { KEY_WLAN } }, + { KE_KEY, 0x5E, { KEY_WLAN } }, + { KE_KEY, 0x5F, { KEY_WLAN } }, { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, - { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, + { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, { KE_KEY, 0x82, { KEY_CAMERA } }, { KE_KEY, 0x88, { KEY_RFKILL } }, { KE_KEY, 0x8A, { KEY_PROG1 } }, @@ -99,7 +81,6 @@ static struct asus_wmi_driver asus_nb_wmi_driver = { .keymap = asus_nb_wmi_keymap, .input_name = "Asus WMI hotkeys", .input_phys = ASUS_NB_WMI_FILE "/input0", - .quirks = asus_nb_wmi_quirks, }; diff --git a/trunk/drivers/platform/x86/asus-wmi.c b/trunk/drivers/platform/x86/asus-wmi.c index 95cba9ebf6c0..65b66aa44c78 100644 --- a/trunk/drivers/platform/x86/asus-wmi.c +++ b/trunk/drivers/platform/x86/asus-wmi.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -67,8 +66,6 @@ MODULE_LICENSE("GPL"); #define NOTIFY_BRNUP_MAX 0x1f #define NOTIFY_BRNDOWN_MIN 0x20 #define NOTIFY_BRNDOWN_MAX 0x2e -#define NOTIFY_KBD_BRTUP 0xc4 -#define NOTIFY_KBD_BRTDWN 0xc5 /* WMI Methods */ #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ @@ -96,7 +93,6 @@ MODULE_LICENSE("GPL"); /* Wireless */ #define ASUS_WMI_DEVID_HW_SWITCH 0x00010001 #define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002 -#define ASUS_WMI_DEVID_CWAP 0x00010003 #define ASUS_WMI_DEVID_WLAN 0x00010011 #define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 #define ASUS_WMI_DEVID_GPS 0x00010015 @@ -106,12 +102,6 @@ MODULE_LICENSE("GPL"); /* Leds */ /* 0x000200XX and 0x000400XX */ -#define ASUS_WMI_DEVID_LED1 0x00020011 -#define ASUS_WMI_DEVID_LED2 0x00020012 -#define ASUS_WMI_DEVID_LED3 0x00020013 -#define ASUS_WMI_DEVID_LED4 0x00020014 -#define ASUS_WMI_DEVID_LED5 0x00020015 -#define ASUS_WMI_DEVID_LED6 0x00020016 /* Backlight and Brightness */ #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 @@ -184,18 +174,13 @@ struct asus_wmi { struct led_classdev tpd_led; int tpd_led_wk; - struct led_classdev kbd_led; - int kbd_led_wk; struct workqueue_struct *led_workqueue; struct work_struct tpd_led_work; - struct work_struct kbd_led_work; struct asus_rfkill wlan; struct asus_rfkill bluetooth; struct asus_rfkill wimax; struct asus_rfkill wwan3g; - struct asus_rfkill gps; - struct asus_rfkill uwb; struct hotplug_slot *hotplug_slot; struct mutex hotplug_lock; @@ -220,7 +205,6 @@ static int asus_wmi_input_init(struct asus_wmi *asus) asus->inputdev->phys = asus->driver->input_phys; asus->inputdev->id.bustype = BUS_HOST; asus->inputdev->dev.parent = &asus->platform_device->dev; - set_bit(EV_REP, asus->inputdev->evbit); err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL); if (err) @@ -375,80 +359,30 @@ static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) return read_tpd_led_state(asus); } -static void kbd_led_update(struct work_struct *work) +static int asus_wmi_led_init(struct asus_wmi *asus) { - int ctrl_param = 0; - struct asus_wmi *asus; - - asus = container_of(work, struct asus_wmi, kbd_led_work); + int rv; - /* - * bits 0-2: level - * bit 7: light on/off - */ - if (asus->kbd_led_wk > 0) - ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); + if (read_tpd_led_state(asus) < 0) + return 0; - asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); -} + asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); + if (!asus->led_workqueue) + return -ENOMEM; + INIT_WORK(&asus->tpd_led_work, tpd_led_update); -static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) -{ - int retval; + asus->tpd_led.name = "asus::touchpad"; + asus->tpd_led.brightness_set = tpd_led_set; + asus->tpd_led.brightness_get = tpd_led_get; + asus->tpd_led.max_brightness = 1; - /* - * bits 0-2: level - * bit 7: light on/off - * bit 8-10: environment (0: dark, 1: normal, 2: light) - * bit 17: status unknown - */ - retval = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_KBD_BACKLIGHT, - 0xFFFF); - - /* Unknown status is considered as off */ - if (retval == 0x8000) - retval = 0; - - if (retval >= 0) { - if (level) - *level = retval & 0x80 ? retval & 0x7F : 0; - if (env) - *env = (retval >> 8) & 0x7F; - retval = 0; + rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led); + if (rv) { + destroy_workqueue(asus->led_workqueue); + return rv; } - return retval; -} - -static void kbd_led_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - struct asus_wmi *asus; - - asus = container_of(led_cdev, struct asus_wmi, kbd_led); - - if (value > asus->kbd_led.max_brightness) - value = asus->kbd_led.max_brightness; - else if (value < 0) - value = 0; - - asus->kbd_led_wk = value; - queue_work(asus->led_workqueue, &asus->kbd_led_work); -} - -static enum led_brightness kbd_led_get(struct led_classdev *led_cdev) -{ - struct asus_wmi *asus; - int retval, value; - - asus = container_of(led_cdev, struct asus_wmi, kbd_led); - - retval = kbd_led_read(asus, &value, NULL); - - if (retval < 0) - return retval; - - return value; + return 0; } static void asus_wmi_led_exit(struct asus_wmi *asus) @@ -459,48 +393,6 @@ static void asus_wmi_led_exit(struct asus_wmi *asus) destroy_workqueue(asus->led_workqueue); } -static int asus_wmi_led_init(struct asus_wmi *asus) -{ - int rv = 0; - - asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); - if (!asus->led_workqueue) - return -ENOMEM; - - if (read_tpd_led_state(asus) >= 0) { - INIT_WORK(&asus->tpd_led_work, tpd_led_update); - - asus->tpd_led.name = "asus::touchpad"; - asus->tpd_led.brightness_set = tpd_led_set; - asus->tpd_led.brightness_get = tpd_led_get; - asus->tpd_led.max_brightness = 1; - - rv = led_classdev_register(&asus->platform_device->dev, - &asus->tpd_led); - if (rv) - goto error; - } - - if (kbd_led_read(asus, NULL, NULL) >= 0) { - INIT_WORK(&asus->kbd_led_work, kbd_led_update); - - asus->kbd_led.name = "asus::kbd_backlight"; - asus->kbd_led.brightness_set = kbd_led_set; - asus->kbd_led.brightness_get = kbd_led_get; - asus->kbd_led.max_brightness = 3; - - rv = led_classdev_register(&asus->platform_device->dev, - &asus->kbd_led); - } - -error: - if (rv) - asus_wmi_led_exit(asus); - - return rv; -} - - /* * PCI hotplug (for wlan rfkill) */ @@ -837,16 +729,6 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus) rfkill_destroy(asus->wwan3g.rfkill); asus->wwan3g.rfkill = NULL; } - if (asus->gps.rfkill) { - rfkill_unregister(asus->gps.rfkill); - rfkill_destroy(asus->gps.rfkill); - asus->gps.rfkill = NULL; - } - if (asus->uwb.rfkill) { - rfkill_unregister(asus->uwb.rfkill); - rfkill_destroy(asus->uwb.rfkill); - asus->uwb.rfkill = NULL; - } } static int asus_wmi_rfkill_init(struct asus_wmi *asus) @@ -881,18 +763,6 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus) if (result && result != -ENODEV) goto exit; - result = asus_new_rfkill(asus, &asus->gps, "asus-gps", - RFKILL_TYPE_GPS, ASUS_WMI_DEVID_GPS); - - if (result && result != -ENODEV) - goto exit; - - result = asus_new_rfkill(asus, &asus->uwb, "asus-uwb", - RFKILL_TYPE_UWB, ASUS_WMI_DEVID_UWB); - - if (result && result != -ENODEV) - goto exit; - if (!asus->driver->hotplug_wireless) goto exit; @@ -927,8 +797,8 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus) * Hwmon device */ static ssize_t asus_hwmon_pwm1(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct asus_wmi *asus = dev_get_drvdata(dev); u32 value; @@ -939,7 +809,7 @@ static ssize_t asus_hwmon_pwm1(struct device *dev, if (err < 0) return err; - value &= 0xFF; + value |= 0xFF; if (value == 1) /* Low Speed */ value = 85; @@ -955,26 +825,7 @@ static ssize_t asus_hwmon_pwm1(struct device *dev, return sprintf(buf, "%d\n", value); } -static ssize_t asus_hwmon_temp1(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct asus_wmi *asus = dev_get_drvdata(dev); - u32 value; - int err; - - err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, &value); - - if (err < 0) - return err; - - value = KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000; - - return sprintf(buf, "%d\n", value); -} - static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0); -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL, 0); static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -985,13 +836,12 @@ static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_pwm1.dev_attr.attr, - &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_name.dev_attr.attr, NULL }; static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, - struct attribute *attr, int idx) + struct attribute *attr, int idx) { struct device *dev = container_of(kobj, struct device, kobj); struct platform_device *pdev = to_platform_device(dev->parent); @@ -1002,8 +852,6 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, if (attr == &sensor_dev_attr_pwm1.dev_attr.attr) dev_id = ASUS_WMI_DEVID_FAN_CTRL; - else if (attr == &sensor_dev_attr_temp1_input.dev_attr.attr) - dev_id = ASUS_WMI_DEVID_THERMAL_CTRL; if (dev_id != -1) { int err = asus_wmi_get_devstate(asus, dev_id, &value); @@ -1021,13 +869,9 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, * - reverved bits are non-zero * - sfun and presence bit are not set */ - if (value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 + if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))) ok = false; - } else if (dev_id == ASUS_WMI_DEVID_THERMAL_CTRL) { - /* If value is zero, something is clearly wrong */ - if (value == 0) - ok = false; } return ok ? attr->mode : 0; @@ -1060,7 +904,6 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus) pr_err("Could not register asus hwmon device\n"); return PTR_ERR(hwmon); } - dev_set_drvdata(hwmon, asus); asus->hwmon_device = hwmon; result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group); if (result) @@ -1217,8 +1060,6 @@ static void asus_wmi_notify(u32 value, void *context) acpi_status status; int code; int orig_code; - unsigned int key_value = 1; - bool autorelease = 1; status = wmi_get_event_data(value, &response); if (status != AE_OK) { @@ -1234,13 +1075,6 @@ static void asus_wmi_notify(u32 value, void *context) code = obj->integer.value; orig_code = code; - if (asus->driver->key_filter) { - asus->driver->key_filter(asus->driver, &code, &key_value, - &autorelease); - if (code == ASUS_WMI_KEY_IGNORE) - goto exit; - } - if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) code = NOTIFY_BRNUP_MIN; else if (code >= NOTIFY_BRNDOWN_MIN && @@ -1250,8 +1084,7 @@ static void asus_wmi_notify(u32 value, void *context) if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { if (!acpi_video_backlight_support()) asus_wmi_backlight_notify(asus, orig_code); - } else if (!sparse_keymap_report_event(asus->inputdev, code, - key_value, autorelease)) + } else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true)) pr_info("Unknown key %x pressed\n", code); exit: @@ -1331,18 +1164,14 @@ ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int value, rv; + int value; if (!count || sscanf(buf, "%i", &value) != 1) return -EINVAL; if (value < 0 || value > 2) return -EINVAL; - rv = asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); - if (rv < 0) - return rv; - - return count; + return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); } static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); @@ -1405,7 +1234,7 @@ static int asus_wmi_platform_init(struct asus_wmi *asus) /* We don't know yet what to do with this version... */ if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) { - pr_info("BIOS WMI version: %d.%d", rv >> 16, rv & 0xFF); + pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF); asus->spec = rv; } @@ -1437,12 +1266,6 @@ static int asus_wmi_platform_init(struct asus_wmi *asus) return -ENODEV; } - /* CWAP allow to define the behavior of the Fn+F2 key, - * this method doesn't seems to be present on Eee PCs */ - if (asus->driver->wapf >= 0) - asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP, - asus->driver->wapf, NULL); - return asus_wmi_sysfs_init(asus->platform_device); } @@ -1745,14 +1568,6 @@ static int asus_hotk_restore(struct device *device) bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G); rfkill_set_sw_state(asus->wwan3g.rfkill, bl); } - if (asus->gps.rfkill) { - bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPS); - rfkill_set_sw_state(asus->gps.rfkill, bl); - } - if (asus->uwb.rfkill) { - bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB); - rfkill_set_sw_state(asus->uwb.rfkill, bl); - } return 0; } @@ -1789,7 +1604,7 @@ static int asus_wmi_probe(struct platform_device *pdev) static bool used; -int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver) +int asus_wmi_register_driver(struct asus_wmi_driver *driver) { struct platform_driver *platform_driver; struct platform_device *platform_device; diff --git a/trunk/drivers/platform/x86/asus-wmi.h b/trunk/drivers/platform/x86/asus-wmi.h index 8147c10161cc..c044522c8766 100644 --- a/trunk/drivers/platform/x86/asus-wmi.h +++ b/trunk/drivers/platform/x86/asus-wmi.h @@ -29,15 +29,12 @@ #include -#define ASUS_WMI_KEY_IGNORE (-1) - struct module; struct key_entry; struct asus_wmi; struct asus_wmi_driver { bool hotplug_wireless; - int wapf; const char *name; struct module *owner; @@ -47,10 +44,6 @@ struct asus_wmi_driver { const struct key_entry *keymap; const char *input_name; const char *input_phys; - /* Returns new code, value, and autorelease values in arguments. - * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */ - void (*key_filter) (struct asus_wmi_driver *driver, int *code, - unsigned int *value, bool *autorelease); int (*probe) (struct platform_device *device); void (*quirks) (struct asus_wmi_driver *driver); diff --git a/trunk/drivers/platform/x86/dell-laptop.c b/trunk/drivers/platform/x86/dell-laptop.c index f31fa4efa725..e39ab1d3ed87 100644 --- a/trunk/drivers/platform/x86/dell-laptop.c +++ b/trunk/drivers/platform/x86/dell-laptop.c @@ -612,6 +612,7 @@ static int __init dell_init(void) if (!bufferpage) goto fail_buffer; buffer = page_address(bufferpage); + mutex_init(&buffer_mutex); ret = dell_setup_rfkill(); diff --git a/trunk/drivers/platform/x86/dell-wmi.c b/trunk/drivers/platform/x86/dell-wmi.c index fa9a2171cc13..ce790827e199 100644 --- a/trunk/drivers/platform/x86/dell-wmi.c +++ b/trunk/drivers/platform/x86/dell-wmi.c @@ -54,8 +54,6 @@ MODULE_ALIAS("wmi:"DELL_EVENT_GUID); */ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { - { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } }, - { KE_KEY, 0xe045, { KEY_PROG1 } }, { KE_KEY, 0xe009, { KEY_EJECTCD } }, @@ -87,11 +85,6 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe013, { KEY_RESERVED } }, { KE_IGNORE, 0xe020, { KEY_MUTE } }, - - /* Shortcut and audio panel keys */ - { KE_IGNORE, 0xe025, { KEY_RESERVED } }, - { KE_IGNORE, 0xe026, { KEY_RESERVED } }, - { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } }, { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } }, @@ -99,9 +92,6 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } }, { KE_IGNORE, 0xe045, { KEY_NUMLOCK } }, { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } }, - { KE_IGNORE, 0xe0f7, { KEY_MUTE } }, - { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } }, - { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } }, { KE_END, 0 } }; diff --git a/trunk/drivers/platform/x86/eeepc-wmi.c b/trunk/drivers/platform/x86/eeepc-wmi.c index 9f6e64302b45..4aa867a9b88b 100644 --- a/trunk/drivers/platform/x86/eeepc-wmi.c +++ b/trunk/drivers/platform/x86/eeepc-wmi.c @@ -56,11 +56,6 @@ MODULE_PARM_DESC(hotplug_wireless, "If your laptop needs that, please report to " "acpi4asus-user@lists.sourceforge.net."); -/* Values for T101MT "Home" key */ -#define HOME_PRESS 0xe4 -#define HOME_HOLD 0xea -#define HOME_RELEASE 0xe5 - static const struct key_entry eeepc_wmi_keymap[] = { /* Sleep already handled via generic ACPI code */ { KE_KEY, 0x30, { KEY_VOLUMEUP } }, @@ -76,7 +71,6 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ - { KE_KEY, HOME_PRESS, { KEY_CONFIG } }, /* Home/Express gate key */ { KE_KEY, 0xe8, { KEY_SCREENLOCK } }, { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, @@ -87,25 +81,6 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_END, 0}, }; -static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, - unsigned int *value, bool *autorelease) -{ - switch (*code) { - case HOME_PRESS: - *value = 1; - *autorelease = 0; - break; - case HOME_HOLD: - *code = ASUS_WMI_KEY_IGNORE; - break; - case HOME_RELEASE: - *code = HOME_PRESS; - *value = 0; - *autorelease = 0; - break; - } -} - static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level, void *context, void **retval) { @@ -166,7 +141,6 @@ static void eeepc_dmi_check(struct asus_wmi_driver *driver) static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) { driver->hotplug_wireless = hotplug_wireless; - driver->wapf = -1; eeepc_dmi_check(driver); } @@ -177,7 +151,6 @@ static struct asus_wmi_driver asus_wmi_driver = { .keymap = eeepc_wmi_keymap, .input_name = "Eee PC WMI hotkeys", .input_phys = EEEPC_WMI_FILE "/input0", - .key_filter = eeepc_wmi_key_filter, .probe = eeepc_wmi_probe, .quirks = eeepc_wmi_quirks, }; diff --git a/trunk/drivers/platform/x86/ideapad-laptop.c b/trunk/drivers/platform/x86/ideapad-laptop.c index 0c595410e788..bfdda33feb26 100644 --- a/trunk/drivers/platform/x86/ideapad-laptop.c +++ b/trunk/drivers/platform/x86/ideapad-laptop.c @@ -32,22 +32,13 @@ #include #include #include -#include -#include #define IDEAPAD_RFKILL_DEV_NUM (3) -#define CFG_BT_BIT (16) -#define CFG_3G_BIT (17) -#define CFG_WIFI_BIT (18) -#define CFG_CAMERA_BIT (19) - struct ideapad_private { struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; struct platform_device *platform_device; struct input_dev *inputdev; - struct backlight_device *blightdev; - unsigned long cfg; }; static acpi_handle ideapad_handle; @@ -164,7 +155,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data) } /* - * sysfs + * camera power */ static ssize_t show_ideapad_cam(struct device *dev, struct device_attribute *attr, @@ -195,44 +186,6 @@ static ssize_t store_ideapad_cam(struct device *dev, static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); -static ssize_t show_ideapad_cfg(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ideapad_private *priv = dev_get_drvdata(dev); - - return sprintf(buf, "0x%.8lX\n", priv->cfg); -} - -static DEVICE_ATTR(cfg, 0444, show_ideapad_cfg, NULL); - -static struct attribute *ideapad_attributes[] = { - &dev_attr_camera_power.attr, - &dev_attr_cfg.attr, - NULL -}; - -static mode_t ideapad_is_visible(struct kobject *kobj, - struct attribute *attr, - int idx) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct ideapad_private *priv = dev_get_drvdata(dev); - bool supported; - - if (attr == &dev_attr_camera_power.attr) - supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg)); - else - supported = true; - - return supported ? attr->mode : 0; -} - -static struct attribute_group ideapad_attribute_group = { - .is_visible = ideapad_is_visible, - .attrs = ideapad_attributes -}; - /* * Rfkill */ @@ -244,9 +197,9 @@ struct ideapad_rfk_data { }; const struct ideapad_rfk_data ideapad_rfk_data[] = { - { "ideapad_wlan", CFG_WIFI_BIT, 0x15, RFKILL_TYPE_WLAN }, - { "ideapad_bluetooth", CFG_BT_BIT, 0x17, RFKILL_TYPE_BLUETOOTH }, - { "ideapad_3g", CFG_3G_BIT, 0x20, RFKILL_TYPE_WWAN }, + { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN }, + { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH }, + { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN }, }; static int ideapad_rfk_set(void *data, bool blocked) @@ -312,7 +265,8 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice, return 0; } -static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev) +static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice, + int dev) { struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); @@ -326,6 +280,15 @@ static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev) /* * Platform device */ +static struct attribute *ideapad_attributes[] = { + &dev_attr_camera_power.attr, + NULL +}; + +static struct attribute_group ideapad_attribute_group = { + .attrs = ideapad_attributes +}; + static int __devinit ideapad_platform_init(struct ideapad_private *priv) { int result; @@ -406,7 +369,7 @@ static int __devinit ideapad_input_init(struct ideapad_private *priv) return error; } -static void ideapad_input_exit(struct ideapad_private *priv) +static void __devexit ideapad_input_exit(struct ideapad_private *priv) { sparse_keymap_free(priv->inputdev); input_unregister_device(priv->inputdev); @@ -419,98 +382,6 @@ static void ideapad_input_report(struct ideapad_private *priv, sparse_keymap_report_event(priv->inputdev, scancode, 1, true); } -/* - * backlight - */ -static int ideapad_backlight_get_brightness(struct backlight_device *blightdev) -{ - unsigned long now; - - if (read_ec_data(ideapad_handle, 0x12, &now)) - return -EIO; - return now; -} - -static int ideapad_backlight_update_status(struct backlight_device *blightdev) -{ - if (write_ec_cmd(ideapad_handle, 0x13, blightdev->props.brightness)) - return -EIO; - if (write_ec_cmd(ideapad_handle, 0x33, - blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1)) - return -EIO; - - return 0; -} - -static const struct backlight_ops ideapad_backlight_ops = { - .get_brightness = ideapad_backlight_get_brightness, - .update_status = ideapad_backlight_update_status, -}; - -static int ideapad_backlight_init(struct ideapad_private *priv) -{ - struct backlight_device *blightdev; - struct backlight_properties props; - unsigned long max, now, power; - - if (read_ec_data(ideapad_handle, 0x11, &max)) - return -EIO; - if (read_ec_data(ideapad_handle, 0x12, &now)) - return -EIO; - if (read_ec_data(ideapad_handle, 0x18, &power)) - return -EIO; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = max; - props.type = BACKLIGHT_PLATFORM; - blightdev = backlight_device_register("ideapad", - &priv->platform_device->dev, - priv, - &ideapad_backlight_ops, - &props); - if (IS_ERR(blightdev)) { - pr_err("Could not register backlight device\n"); - return PTR_ERR(blightdev); - } - - priv->blightdev = blightdev; - blightdev->props.brightness = now; - blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; - backlight_update_status(blightdev); - - return 0; -} - -static void ideapad_backlight_exit(struct ideapad_private *priv) -{ - if (priv->blightdev) - backlight_device_unregister(priv->blightdev); - priv->blightdev = NULL; -} - -static void ideapad_backlight_notify_power(struct ideapad_private *priv) -{ - unsigned long power; - struct backlight_device *blightdev = priv->blightdev; - - if (read_ec_data(ideapad_handle, 0x18, &power)) - return; - blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; -} - -static void ideapad_backlight_notify_brightness(struct ideapad_private *priv) -{ - unsigned long now; - - /* if we control brightness via acpi video driver */ - if (priv->blightdev == NULL) { - read_ec_data(ideapad_handle, 0x12, &now); - return; - } - - backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY); -} - /* * module init/exit */ @@ -522,11 +393,10 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); static int __devinit ideapad_acpi_add(struct acpi_device *adevice) { - int ret, i; - unsigned long cfg; + int ret, i, cfg; struct ideapad_private *priv; - if (read_method_int(adevice->handle, "_CFG", (int *)&cfg)) + if (read_method_int(adevice->handle, "_CFG", &cfg)) return -ENODEV; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -534,7 +404,6 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) return -ENOMEM; dev_set_drvdata(&adevice->dev, priv); ideapad_handle = adevice->handle; - priv->cfg = cfg; ret = ideapad_platform_init(priv); if (ret) @@ -545,25 +414,15 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) goto input_failed; for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) { - if (test_bit(ideapad_rfk_data[i].cfgbit, &cfg)) + if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) ideapad_register_rfkill(adevice, i); else priv->rfk[i] = NULL; } ideapad_sync_rfk_state(adevice); - if (!acpi_video_backlight_support()) { - ret = ideapad_backlight_init(priv); - if (ret && ret != -ENODEV) - goto backlight_failed; - } - return 0; -backlight_failed: - for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) - ideapad_unregister_rfkill(adevice, i); - ideapad_input_exit(priv); input_failed: ideapad_platform_exit(priv); platform_failed: @@ -576,7 +435,6 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type) struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); int i; - ideapad_backlight_exit(priv); for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) ideapad_unregister_rfkill(adevice, i); ideapad_input_exit(priv); @@ -601,19 +459,12 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) vpc1 = (vpc2 << 8) | vpc1; for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) { if (test_bit(vpc_bit, &vpc1)) { - switch (vpc_bit) { - case 9: + if (vpc_bit == 9) ideapad_sync_rfk_state(adevice); - break; - case 4: - ideapad_backlight_notify_brightness(priv); - break; - case 2: - ideapad_backlight_notify_power(priv); - break; - default: + else if (vpc_bit == 4) + read_ec_data(handle, 0x12, &vpc2); + else ideapad_input_report(priv, vpc_bit); - } } } } diff --git a/trunk/drivers/platform/x86/intel_ips.c b/trunk/drivers/platform/x86/intel_ips.c index 809a3ae943c6..5ffe7c398148 100644 --- a/trunk/drivers/platform/x86/intel_ips.c +++ b/trunk/drivers/platform/x86/intel_ips.c @@ -403,7 +403,7 @@ static void ips_cpu_raise(struct ips_driver *ips) thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8); - turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN; + turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN; wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); turbo_override &= ~TURBO_TDP_MASK; @@ -438,7 +438,7 @@ static void ips_cpu_lower(struct ips_driver *ips) thm_writew(THM_MPCPC, (new_limit * 10) / 8); - turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN; + turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN; wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); turbo_override &= ~TURBO_TDP_MASK; diff --git a/trunk/drivers/platform/x86/intel_menlow.c b/trunk/drivers/platform/x86/intel_menlow.c index abddc83e9fd7..809adea4965f 100644 --- a/trunk/drivers/platform/x86/intel_menlow.c +++ b/trunk/drivers/platform/x86/intel_menlow.c @@ -477,8 +477,6 @@ static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl, return AE_ERROR; } - return AE_OK; - aux1_not_found: if (status == AE_NOT_FOUND) return AE_OK; diff --git a/trunk/drivers/platform/x86/intel_mid_thermal.c b/trunk/drivers/platform/x86/intel_mid_thermal.c index ccd7b1f83519..3a578323122b 100644 --- a/trunk/drivers/platform/x86/intel_mid_thermal.c +++ b/trunk/drivers/platform/x86/intel_mid_thermal.c @@ -493,30 +493,20 @@ static int mid_thermal_probe(struct platform_device *pdev) /* Register each sensor with the generic thermal framework*/ for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { - struct thermal_device_info *td_info = initialize_sensor(i); - - if (!td_info) { - ret = -ENOMEM; - goto err; - } pinfo->tzd[i] = thermal_zone_device_register(name[i], - 0, td_info, &tzd_ops, 0, 0, 0, 0); - if (IS_ERR(pinfo->tzd[i])) { - kfree(td_info); - ret = PTR_ERR(pinfo->tzd[i]); - goto err; - } + 0, initialize_sensor(i), &tzd_ops, 0, 0, 0, 0); + if (IS_ERR(pinfo->tzd[i])) + goto reg_fail; } pinfo->pdev = pdev; platform_set_drvdata(pdev, pinfo); return 0; -err: - while (--i >= 0) { - kfree(pinfo->tzd[i]->devdata); +reg_fail: + ret = PTR_ERR(pinfo->tzd[i]); + while (--i >= 0) thermal_zone_device_unregister(pinfo->tzd[i]); - } configure_adc(0); kfree(pinfo); return ret; @@ -534,10 +524,8 @@ static int mid_thermal_remove(struct platform_device *pdev) int i; struct platform_info *pinfo = platform_get_drvdata(pdev); - for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { - kfree(pinfo->tzd[i]->devdata); + for (i = 0; i < MSIC_THERMAL_SENSORS; i++) thermal_zone_device_unregister(pinfo->tzd[i]); - } kfree(pinfo); platform_set_drvdata(pdev, NULL); diff --git a/trunk/drivers/platform/x86/intel_rar_register.c b/trunk/drivers/platform/x86/intel_rar_register.c index c8a6aed45277..bde47e9080cd 100644 --- a/trunk/drivers/platform/x86/intel_rar_register.c +++ b/trunk/drivers/platform/x86/intel_rar_register.c @@ -637,13 +637,15 @@ static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id) return error; } -static DEFINE_PCI_DEVICE_TABLE(rar_pci_id_tbl) = { +const struct pci_device_id rar_pci_id_tbl[] = { { PCI_VDEVICE(INTEL, 0x4110) }, { 0 } }; MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl); +const struct pci_device_id *my_id_table = rar_pci_id_tbl; + /* field for registering driver to PCI device */ static struct pci_driver rar_pci_driver = { .name = "rar_register_driver", diff --git a/trunk/drivers/platform/x86/intel_scu_ipc.c b/trunk/drivers/platform/x86/intel_scu_ipc.c index c86665369a22..940accbe28d3 100644 --- a/trunk/drivers/platform/x86/intel_scu_ipc.c +++ b/trunk/drivers/platform/x86/intel_scu_ipc.c @@ -725,7 +725,7 @@ static void ipc_remove(struct pci_dev *pdev) intel_scu_devices_destroy(); } -static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { +static const struct pci_device_id pci_ids[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, { 0,} diff --git a/trunk/drivers/platform/x86/msi-laptop.c b/trunk/drivers/platform/x86/msi-laptop.c index f204643c5052..3ff629df9f01 100644 --- a/trunk/drivers/platform/x86/msi-laptop.c +++ b/trunk/drivers/platform/x86/msi-laptop.c @@ -538,15 +538,6 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { }, .callback = dmi_check_cb }, - { - .ident = "MSI U270", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "Micro-Star International Co., Ltd."), - DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"), - }, - .callback = dmi_check_cb - }, { } }; @@ -1005,4 +996,3 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*"); MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*"); MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*"); MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*"); -MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*"); diff --git a/trunk/drivers/platform/x86/msi-wmi.c b/trunk/drivers/platform/x86/msi-wmi.c index 6f40bf202dc7..c832e3356cd6 100644 --- a/trunk/drivers/platform/x86/msi-wmi.c +++ b/trunk/drivers/platform/x86/msi-wmi.c @@ -272,7 +272,6 @@ static int __init msi_wmi_init(void) err_free_backlight: backlight_device_unregister(backlight); err_free_input: - sparse_keymap_free(msi_wmi_input_dev); input_unregister_device(msi_wmi_input_dev); err_uninstall_notifier: wmi_remove_notify_handler(MSIWMI_EVENT_GUID); diff --git a/trunk/drivers/platform/x86/samsung-laptop.c b/trunk/drivers/platform/x86/samsung-laptop.c index 359163011044..d347116d150e 100644 --- a/trunk/drivers/platform/x86/samsung-laptop.c +++ b/trunk/drivers/platform/x86/samsung-laptop.c @@ -520,16 +520,6 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { }, .callback = dmi_check_cb, }, - { - .ident = "N510", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N510"), - DMI_MATCH(DMI_BOARD_NAME, "N510"), - }, - .callback = dmi_check_cb, - }, { .ident = "X125", .matches = { @@ -610,16 +600,6 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { }, .callback = dmi_check_cb, }, - { - .ident = "N150/N210/N220", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), - DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), - }, - .callback = dmi_check_cb, - }, { .ident = "N150/N210/N220/N230", .matches = { diff --git a/trunk/drivers/platform/x86/samsung-q10.c b/trunk/drivers/platform/x86/samsung-q10.c deleted file mode 100644 index 1e54ae74274c..000000000000 --- a/trunk/drivers/platform/x86/samsung-q10.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Driver for Samsung Q10 and related laptops: controls the backlight - * - * Copyright (c) 2011 Frederick van der Wyck - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#define SAMSUNGQ10_BL_MAX_INTENSITY 255 -#define SAMSUNGQ10_BL_DEFAULT_INTENSITY 185 - -#define SAMSUNGQ10_BL_8042_CMD 0xbe -#define SAMSUNGQ10_BL_8042_DATA { 0x89, 0x91 } - -static int samsungq10_bl_brightness; - -static bool force; -module_param(force, bool, 0); -MODULE_PARM_DESC(force, - "Disable the DMI check and force the driver to be loaded"); - -static int samsungq10_bl_set_intensity(struct backlight_device *bd) -{ - - int brightness = bd->props.brightness; - unsigned char c[3] = SAMSUNGQ10_BL_8042_DATA; - - c[2] = (unsigned char)brightness; - i8042_lock_chip(); - i8042_command(c, (0x30 << 8) | SAMSUNGQ10_BL_8042_CMD); - i8042_unlock_chip(); - samsungq10_bl_brightness = brightness; - - return 0; -} - -static int samsungq10_bl_get_intensity(struct backlight_device *bd) -{ - return samsungq10_bl_brightness; -} - -static const struct backlight_ops samsungq10_bl_ops = { - .get_brightness = samsungq10_bl_get_intensity, - .update_status = samsungq10_bl_set_intensity, -}; - -#ifdef CONFIG_PM_SLEEP -static int samsungq10_suspend(struct device *dev) -{ - return 0; -} - -static int samsungq10_resume(struct device *dev) -{ - - struct backlight_device *bd = dev_get_drvdata(dev); - - samsungq10_bl_set_intensity(bd); - return 0; -} -#else -#define samsungq10_suspend NULL -#define samsungq10_resume NULL -#endif - -static SIMPLE_DEV_PM_OPS(samsungq10_pm_ops, - samsungq10_suspend, samsungq10_resume); - -static int __devinit samsungq10_probe(struct platform_device *pdev) -{ - - struct backlight_properties props; - struct backlight_device *bd; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_PLATFORM; - props.max_brightness = SAMSUNGQ10_BL_MAX_INTENSITY; - bd = backlight_device_register("samsung", &pdev->dev, NULL, - &samsungq10_bl_ops, &props); - if (IS_ERR(bd)) - return PTR_ERR(bd); - - platform_set_drvdata(pdev, bd); - - bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY; - samsungq10_bl_set_intensity(bd); - - return 0; -} - -static int __devexit samsungq10_remove(struct platform_device *pdev) -{ - - struct backlight_device *bd = platform_get_drvdata(pdev); - - bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY; - samsungq10_bl_set_intensity(bd); - - backlight_device_unregister(bd); - - return 0; -} - -static struct platform_driver samsungq10_driver = { - .driver = { - .name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .pm = &samsungq10_pm_ops, - }, - .probe = samsungq10_probe, - .remove = __devexit_p(samsungq10_remove), -}; - -static struct platform_device *samsungq10_device; - -static int __init dmi_check_callback(const struct dmi_system_id *id) -{ - printk(KERN_INFO KBUILD_MODNAME ": found model '%s'\n", id->ident); - return 1; -} - -static struct dmi_system_id __initdata samsungq10_dmi_table[] = { - { - .ident = "Samsung Q10", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Samsung"), - DMI_MATCH(DMI_PRODUCT_NAME, "SQ10"), - }, - .callback = dmi_check_callback, - }, - { - .ident = "Samsung Q20", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), - DMI_MATCH(DMI_PRODUCT_NAME, "SENS Q20"), - }, - .callback = dmi_check_callback, - }, - { - .ident = "Samsung Q25", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), - DMI_MATCH(DMI_PRODUCT_NAME, "NQ25"), - }, - .callback = dmi_check_callback, - }, - { - .ident = "Dell Latitude X200", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "X200"), - }, - .callback = dmi_check_callback, - }, - { }, -}; -MODULE_DEVICE_TABLE(dmi, samsungq10_dmi_table); - -static int __init samsungq10_init(void) -{ - if (!force && !dmi_check_system(samsungq10_dmi_table)) - return -ENODEV; - - samsungq10_device = platform_create_bundle(&samsungq10_driver, - samsungq10_probe, - NULL, 0, NULL, 0); - - if (IS_ERR(samsungq10_device)) - return PTR_ERR(samsungq10_device); - - return 0; -} - -static void __exit samsungq10_exit(void) -{ - platform_device_unregister(samsungq10_device); - platform_driver_unregister(&samsungq10_driver); -} - -module_init(samsungq10_init); -module_exit(samsungq10_exit); - -MODULE_AUTHOR("Frederick van der Wyck "); -MODULE_DESCRIPTION("Samsung Q10 Driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/platform/x86/thinkpad_acpi.c b/trunk/drivers/platform/x86/thinkpad_acpi.c index 7bd829f247eb..26c5b117df22 100644 --- a/trunk/drivers/platform/x86/thinkpad_acpi.c +++ b/trunk/drivers/platform/x86/thinkpad_acpi.c @@ -3186,17 +3186,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ /* (assignments unknown, please report if found) */ - KEY_UNKNOWN, KEY_UNKNOWN, - - /* - * The mic mute button only sends 0x1a. It does not - * automatically mute the mic or change the mute light. - */ - KEY_MICMUTE, /* 0x1a: Mic mute (since ?400 or so) */ - - /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, - KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, }, }; diff --git a/trunk/drivers/regulator/core.c b/trunk/drivers/regulator/core.c index d8e6a429e8ba..d3e38790906e 100644 --- a/trunk/drivers/regulator/core.c +++ b/trunk/drivers/regulator/core.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -34,8 +33,6 @@ #include "dummy.h" -#define rdev_crit(rdev, fmt, ...) \ - pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) #define rdev_err(rdev, fmt, ...) \ pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) #define rdev_warn(rdev, fmt, ...) \ @@ -81,13 +78,11 @@ struct regulator { char *supply_name; struct device_attribute dev_attr; struct regulator_dev *rdev; -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs; -#endif }; static int _regulator_is_enabled(struct regulator_dev *rdev); -static int _regulator_disable(struct regulator_dev *rdev); +static int _regulator_disable(struct regulator_dev *rdev, + struct regulator_dev **supply_rdev_ptr); static int _regulator_get_voltage(struct regulator_dev *rdev); static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); @@ -95,9 +90,6 @@ static void _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data); static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV); -static struct regulator *create_regulator(struct regulator_dev *rdev, - struct device *dev, - const char *supply_name); static const char *rdev_get_name(struct regulator_dev *rdev) { @@ -151,11 +143,8 @@ static int regulator_check_voltage(struct regulator_dev *rdev, if (*min_uV < rdev->constraints->min_uV) *min_uV = rdev->constraints->min_uV; - if (*min_uV > *max_uV) { - rdev_err(rdev, "unsupportable voltage range: %d-%duV\n", - *min_uV, *max_uV); + if (*min_uV > *max_uV) return -EINVAL; - } return 0; } @@ -208,11 +197,8 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, if (*min_uA < rdev->constraints->min_uA) *min_uA = rdev->constraints->min_uA; - if (*min_uA > *max_uA) { - rdev_err(rdev, "unsupportable current range: %d-%duA\n", - *min_uA, *max_uA); + if (*min_uA > *max_uA) return -EINVAL; - } return 0; } @@ -227,7 +213,6 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode) case REGULATOR_MODE_STANDBY: break; default: - rdev_err(rdev, "invalid mode %x specified\n", *mode); return -EINVAL; } @@ -794,6 +779,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, if (ret < 0) { rdev_err(rdev, "failed to apply %duV constraint\n", rdev->constraints->min_uV); + rdev->constraints = NULL; return ret; } } @@ -896,6 +882,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, ret = suspend_prepare(rdev, rdev->constraints->initial_state); if (ret < 0) { rdev_err(rdev, "failed to set suspend state\n"); + rdev->constraints = NULL; goto out; } } @@ -922,15 +909,13 @@ static int set_machine_constraints(struct regulator_dev *rdev, ret = ops->enable(rdev); if (ret < 0) { rdev_err(rdev, "failed to enable\n"); + rdev->constraints = NULL; goto out; } } print_constraints(rdev); - return 0; out: - kfree(rdev->constraints); - rdev->constraints = NULL; return ret; } @@ -944,20 +929,21 @@ static int set_machine_constraints(struct regulator_dev *rdev, * core if it's child is enabled. */ static int set_supply(struct regulator_dev *rdev, - struct regulator_dev *supply_rdev) + struct regulator_dev *supply_rdev) { int err; - rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev)); - - rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY"); - if (IS_ERR(rdev->supply)) { - err = PTR_ERR(rdev->supply); - rdev->supply = NULL; - return err; + err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, + "supply"); + if (err) { + rdev_err(rdev, "could not add device link %s err %d\n", + supply_rdev->dev.kobj.name, err); + goto out; } - - return 0; + rdev->supply = supply_rdev; + list_add(&rdev->slist, &supply_rdev->supply_list); +out: + return err; } /** @@ -1046,7 +1032,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev) } } -#define REG_STR_SIZE 64 +#define REG_STR_SIZE 32 static struct regulator *create_regulator(struct regulator_dev *rdev, struct device *dev, @@ -1066,9 +1052,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, if (dev) { /* create a 'requested_microamps_name' sysfs entry */ - size = scnprintf(buf, REG_STR_SIZE, - "microamps_requested_%s-%s", - dev_name(dev), supply_name); + size = scnprintf(buf, REG_STR_SIZE, "microamps_requested_%s", + supply_name); if (size >= REG_STR_SIZE) goto overflow_err; @@ -1103,28 +1088,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, dev->kobj.name, err); goto link_name_err; } - } else { - regulator->supply_name = kstrdup(supply_name, GFP_KERNEL); - if (regulator->supply_name == NULL) - goto attr_err; - } - -#ifdef CONFIG_DEBUG_FS - regulator->debugfs = debugfs_create_dir(regulator->supply_name, - rdev->debugfs); - if (IS_ERR_OR_NULL(regulator->debugfs)) { - rdev_warn(rdev, "Failed to create debugfs directory\n"); - regulator->debugfs = NULL; - } else { - debugfs_create_u32("uA_load", 0444, regulator->debugfs, - ®ulator->uA_load); - debugfs_create_u32("min_uV", 0444, regulator->debugfs, - ®ulator->min_uV); - debugfs_create_u32("max_uV", 0444, regulator->debugfs, - ®ulator->max_uV); } -#endif - mutex_unlock(&rdev->mutex); return regulator; link_name_err: @@ -1303,17 +1267,13 @@ void regulator_put(struct regulator *regulator) mutex_lock(®ulator_list_mutex); rdev = regulator->rdev; -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(regulator->debugfs); -#endif - /* remove any sysfs entries */ if (regulator->dev) { sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); + kfree(regulator->supply_name); device_remove_file(regulator->dev, ®ulator->dev_attr); kfree(regulator->dev_attr.attr.name); } - kfree(regulator->supply_name); list_del(®ulator->list); kfree(regulator); @@ -1341,6 +1301,19 @@ static int _regulator_enable(struct regulator_dev *rdev) { int ret, delay; + if (rdev->use_count == 0) { + /* do we need to enable the supply regulator first */ + if (rdev->supply) { + mutex_lock(&rdev->supply->mutex); + ret = _regulator_enable(rdev->supply); + mutex_unlock(&rdev->supply->mutex); + if (ret < 0) { + rdev_err(rdev, "failed to enable: %d\n", ret); + return ret; + } + } + } + /* check voltage and requested load before enabling */ if (rdev->constraints && (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) @@ -1415,27 +1388,19 @@ int regulator_enable(struct regulator *regulator) struct regulator_dev *rdev = regulator->rdev; int ret = 0; - if (rdev->supply) { - ret = regulator_enable(rdev->supply); - if (ret != 0) - return ret; - } - mutex_lock(&rdev->mutex); ret = _regulator_enable(rdev); mutex_unlock(&rdev->mutex); - - if (ret != 0) - regulator_disable(rdev->supply); - return ret; } EXPORT_SYMBOL_GPL(regulator_enable); /* locks held by regulator_disable() */ -static int _regulator_disable(struct regulator_dev *rdev) +static int _regulator_disable(struct regulator_dev *rdev, + struct regulator_dev **supply_rdev_ptr) { int ret = 0; + *supply_rdev_ptr = NULL; if (WARN(rdev->use_count <= 0, "unbalanced disables for %s\n", rdev_get_name(rdev))) @@ -1462,6 +1427,9 @@ static int _regulator_disable(struct regulator_dev *rdev) NULL); } + /* decrease our supplies ref count and disable if required */ + *supply_rdev_ptr = rdev->supply; + rdev->use_count = 0; } else if (rdev->use_count > 1) { @@ -1472,7 +1440,6 @@ static int _regulator_disable(struct regulator_dev *rdev) rdev->use_count--; } - return ret; } @@ -1491,21 +1458,29 @@ static int _regulator_disable(struct regulator_dev *rdev) int regulator_disable(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; + struct regulator_dev *supply_rdev = NULL; int ret = 0; mutex_lock(&rdev->mutex); - ret = _regulator_disable(rdev); + ret = _regulator_disable(rdev, &supply_rdev); mutex_unlock(&rdev->mutex); - if (ret == 0 && rdev->supply) - regulator_disable(rdev->supply); + /* decrease our supplies ref count and disable if required */ + while (supply_rdev != NULL) { + rdev = supply_rdev; + + mutex_lock(&rdev->mutex); + _regulator_disable(rdev, &supply_rdev); + mutex_unlock(&rdev->mutex); + } return ret; } EXPORT_SYMBOL_GPL(regulator_disable); /* locks held by regulator_force_disable() */ -static int _regulator_force_disable(struct regulator_dev *rdev) +static int _regulator_force_disable(struct regulator_dev *rdev, + struct regulator_dev **supply_rdev_ptr) { int ret = 0; @@ -1522,6 +1497,10 @@ static int _regulator_force_disable(struct regulator_dev *rdev) REGULATOR_EVENT_DISABLE, NULL); } + /* decrease our supplies ref count and disable if required */ + *supply_rdev_ptr = rdev->supply; + + rdev->use_count = 0; return ret; } @@ -1537,16 +1516,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev) int regulator_force_disable(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; + struct regulator_dev *supply_rdev = NULL; int ret; mutex_lock(&rdev->mutex); regulator->uA_load = 0; - ret = _regulator_force_disable(regulator->rdev); + ret = _regulator_force_disable(rdev, &supply_rdev); mutex_unlock(&rdev->mutex); - if (rdev->supply) - while (rdev->open_count--) - regulator_disable(rdev->supply); + if (supply_rdev) + regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev))); return ret; } @@ -2157,7 +2136,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) /* get input voltage */ input_uV = 0; if (rdev->supply) - input_uV = regulator_get_voltage(rdev->supply); + input_uV = _regulator_get_voltage(rdev->supply); if (input_uV <= 0) input_uV = rdev->constraints->input_uV; if (input_uV <= 0) { @@ -2227,8 +2206,17 @@ EXPORT_SYMBOL_GPL(regulator_unregister_notifier); static void _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data) { + struct regulator_dev *_rdev; + /* call rdev chain first */ blocking_notifier_call_chain(&rdev->notifier, event, NULL); + + /* now notify regulator we supply */ + list_for_each_entry(_rdev, &rdev->supply_list, slist) { + mutex_lock(&_rdev->mutex); + _notifier_call_chain(_rdev, event, data); + mutex_unlock(&_rdev->mutex); + } } /** @@ -2276,13 +2264,6 @@ int regulator_bulk_get(struct device *dev, int num_consumers, } EXPORT_SYMBOL_GPL(regulator_bulk_get); -static void regulator_bulk_enable_async(void *data, async_cookie_t cookie) -{ - struct regulator_bulk_data *bulk = data; - - bulk->ret = regulator_enable(bulk->consumer); -} - /** * regulator_bulk_enable - enable multiple regulator consumers * @@ -2298,33 +2279,21 @@ static void regulator_bulk_enable_async(void *data, async_cookie_t cookie) int regulator_bulk_enable(int num_consumers, struct regulator_bulk_data *consumers) { - LIST_HEAD(async_domain); int i; - int ret = 0; - - for (i = 0; i < num_consumers; i++) - async_schedule_domain(regulator_bulk_enable_async, - &consumers[i], &async_domain); - - async_synchronize_full_domain(&async_domain); + int ret; - /* If any consumer failed we need to unwind any that succeeded */ for (i = 0; i < num_consumers; i++) { - if (consumers[i].ret != 0) { - ret = consumers[i].ret; + ret = regulator_enable(consumers[i].consumer); + if (ret != 0) goto err; - } } return 0; err: - for (i = 0; i < num_consumers; i++) - if (consumers[i].ret == 0) - regulator_disable(consumers[i].consumer); - else - pr_err("Failed to enable %s: %d\n", - consumers[i].supply, consumers[i].ret); + pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret); + for (--i; i >= 0; --i) + regulator_disable(consumers[i].consumer); return ret; } @@ -2620,7 +2589,9 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, rdev->owner = regulator_desc->owner; rdev->desc = regulator_desc; INIT_LIST_HEAD(&rdev->consumer_list); + INIT_LIST_HEAD(&rdev->supply_list); INIT_LIST_HEAD(&rdev->list); + INIT_LIST_HEAD(&rdev->slist); BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); /* preform any regulator specific init */ @@ -2701,7 +2672,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, unset_regulator_supplies(rdev); scrub: - kfree(rdev->constraints); device_unregister(&rdev->dev); /* device core frees rdev */ rdev = ERR_PTR(ret); @@ -2733,7 +2703,7 @@ void regulator_unregister(struct regulator_dev *rdev) unset_regulator_supplies(rdev); list_del(&rdev->list); if (rdev->supply) - regulator_put(rdev->supply); + sysfs_remove_link(&rdev->dev.kobj, "supply"); device_unregister(&rdev->dev); kfree(rdev->constraints); mutex_unlock(®ulator_list_mutex); diff --git a/trunk/drivers/regulator/dummy.c b/trunk/drivers/regulator/dummy.c index f6ef6694ab98..c7410bde7b5d 100644 --- a/trunk/drivers/regulator/dummy.c +++ b/trunk/drivers/regulator/dummy.c @@ -36,29 +36,6 @@ static struct regulator_desc dummy_desc = { .ops = &dummy_ops, }; -static int __devinit dummy_regulator_probe(struct platform_device *pdev) -{ - int ret; - - dummy_regulator_rdev = regulator_register(&dummy_desc, NULL, - &dummy_initdata, NULL); - if (IS_ERR(dummy_regulator_rdev)) { - ret = PTR_ERR(dummy_regulator_rdev); - pr_err("Failed to register regulator: %d\n", ret); - return ret; - } - - return 0; -} - -static struct platform_driver dummy_regulator_driver = { - .probe = dummy_regulator_probe, - .driver = { - .name = "reg-dummy", - .owner = THIS_MODULE, - }, -}; - static struct platform_device *dummy_pdev; void __init regulator_dummy_init(void) @@ -78,9 +55,12 @@ void __init regulator_dummy_init(void) return; } - ret = platform_driver_register(&dummy_regulator_driver); - if (ret != 0) { - pr_err("Failed to register dummy regulator driver: %d\n", ret); + dummy_regulator_rdev = regulator_register(&dummy_desc, NULL, + &dummy_initdata, NULL); + if (IS_ERR(dummy_regulator_rdev)) { + ret = PTR_ERR(dummy_regulator_rdev); + pr_err("Failed to register regulator: %d\n", ret); platform_device_unregister(dummy_pdev); + return; } } diff --git a/trunk/drivers/regulator/tps65910-regulator.c b/trunk/drivers/regulator/tps65910-regulator.c index 66d2d60b436a..55dd4e6650db 100644 --- a/trunk/drivers/regulator/tps65910-regulator.c +++ b/trunk/drivers/regulator/tps65910-regulator.c @@ -49,6 +49,7 @@ #define TPS65911_REG_LDO7 11 #define TPS65911_REG_LDO8 12 +#define TPS65910_NUM_REGULATOR 13 #define TPS65910_SUPPLY_STATE_ENABLED 0x1 /* supported VIO voltages in milivolts */ @@ -263,12 +264,11 @@ static struct tps_info tps65911_regs[] = { }; struct tps65910_reg { - struct regulator_desc *desc; + struct regulator_desc desc[TPS65910_NUM_REGULATOR]; struct tps65910 *mfd; - struct regulator_dev **rdev; - struct tps_info **info; + struct regulator_dev *rdev[TPS65910_NUM_REGULATOR]; + struct tps_info *info[TPS65910_NUM_REGULATOR]; struct mutex mutex; - int num_regulators; int mode; int (*get_ctrl_reg)(int); }; @@ -759,13 +759,8 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev, mult = (selector / VDD1_2_NUM_VOLTS) + 1; volt = VDD1_2_MIN_VOLT + (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET; - break; case TPS65911_REG_VDDCTRL: volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET); - break; - default: - BUG(); - return -EINVAL; } return volt * 100 * mult; @@ -902,42 +897,16 @@ static __devinit int tps65910_probe(struct platform_device *pdev) switch(tps65910_chip_id(tps65910)) { case TPS65910: pmic->get_ctrl_reg = &tps65910_get_ctrl_register; - pmic->num_regulators = ARRAY_SIZE(tps65910_regs); info = tps65910_regs; - break; case TPS65911: pmic->get_ctrl_reg = &tps65911_get_ctrl_register; - pmic->num_regulators = ARRAY_SIZE(tps65911_regs); info = tps65911_regs; - break; default: pr_err("Invalid tps chip version\n"); - kfree(pmic); return -ENODEV; } - pmic->desc = kcalloc(pmic->num_regulators, - sizeof(struct regulator_desc), GFP_KERNEL); - if (!pmic->desc) { - err = -ENOMEM; - goto err_free_pmic; - } - - pmic->info = kcalloc(pmic->num_regulators, - sizeof(struct tps_info *), GFP_KERNEL); - if (!pmic->info) { - err = -ENOMEM; - goto err_free_desc; - } - - pmic->rdev = kcalloc(pmic->num_regulators, - sizeof(struct regulator_dev *), GFP_KERNEL); - if (!pmic->rdev) { - err = -ENOMEM; - goto err_free_info; - } - - for (i = 0; i < pmic->num_regulators; i++, info++, reg_data++) { + for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) { /* Register the regulators */ pmic->info[i] = info; @@ -969,7 +938,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev) "failed to register %s regulator\n", pdev->name); err = PTR_ERR(rdev); - goto err_unregister_regulator; + goto err; } /* Save regulator for cleanup */ @@ -977,31 +946,23 @@ static __devinit int tps65910_probe(struct platform_device *pdev) } return 0; -err_unregister_regulator: +err: while (--i >= 0) regulator_unregister(pmic->rdev[i]); - kfree(pmic->rdev); -err_free_info: - kfree(pmic->info); -err_free_desc: - kfree(pmic->desc); -err_free_pmic: + kfree(pmic); return err; } static int __devexit tps65910_remove(struct platform_device *pdev) { - struct tps65910_reg *pmic = platform_get_drvdata(pdev); + struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev); int i; - for (i = 0; i < pmic->num_regulators; i++) - regulator_unregister(pmic->rdev[i]); + for (i = 0; i < TPS65910_NUM_REGULATOR; i++) + regulator_unregister(tps65910_reg->rdev[i]); - kfree(pmic->rdev); - kfree(pmic->info); - kfree(pmic->desc); - kfree(pmic); + kfree(tps65910_reg); return 0; } diff --git a/trunk/drivers/regulator/twl-regulator.c b/trunk/drivers/regulator/twl-regulator.c index ee8747f4fa08..87fe0f75a56e 100644 --- a/trunk/drivers/regulator/twl-regulator.c +++ b/trunk/drivers/regulator/twl-regulator.c @@ -835,8 +835,8 @@ static struct regulator_ops twlsmps_ops = { remap_conf) \ TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ remap_conf, TWL4030, twl4030fixed_ops) -#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \ - TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \ +#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \ + TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ 0x0, TWL6030, twl6030fixed_ops) #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \ @@ -856,22 +856,24 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \ +#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \ .base = offset, \ + .id = num, \ .min_mV = min_mVolts, \ .max_mV = max_mVolts, \ .desc = { \ .name = #label, \ .id = TWL6030_REG_##label, \ - .n_voltages = (max_mVolts - min_mVolts)/100 + 1, \ + .n_voltages = (max_mVolts - min_mVolts)/100, \ .ops = &twl6030ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ }, \ } -#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \ +#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \ .base = offset, \ + .id = num, \ .min_mV = min_mVolts, \ .max_mV = max_mVolts, \ .desc = { \ @@ -901,8 +903,9 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) { \ +#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay) { \ .base = offset, \ + .id = num, \ .delay = turnon_delay, \ .desc = { \ .name = #label, \ @@ -913,8 +916,9 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6025_ADJUSTABLE_SMPS(label, offset) { \ +#define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \ .base = offset, \ + .id = num, \ .min_mV = 600, \ .max_mV = 2100, \ .desc = { \ @@ -957,32 +961,32 @@ static struct twlreg_info twl_regs[] = { /* 6030 REG with base as PMC Slave Misc : 0x0030 */ /* Turnon-delay and remap configuration values for 6030 are not verified since the specification is not public */ - TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300), - TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0), - TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0), - TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0), - TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0), - TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0), + TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1), + TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2), + TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3), + TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4), + TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5), + TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7), + TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0), + TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0), + TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0), + TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0), + TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0), /* 6025 are renamed compared to 6030 versions */ - TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300), - - TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34), - TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10), - TWL6025_ADJUSTABLE_SMPS(VIO, 0x16), + TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1), + TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2), + TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3), + TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4), + TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5), + TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7), + TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16), + TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17), + TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18), + + TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1), + TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2), + TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3), }; static u8 twl_get_smps_offset(void) diff --git a/trunk/drivers/regulator/wm831x-dcdc.c b/trunk/drivers/regulator/wm831x-dcdc.c index bd3531d8b2ac..a0982e809851 100644 --- a/trunk/drivers/regulator/wm831x-dcdc.c +++ b/trunk/drivers/regulator/wm831x-dcdc.c @@ -267,6 +267,23 @@ static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev, return vsel; } +static int wm831x_buckv_select_max_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + u16 vsel; + + if (max_uV < 600000 || max_uV > 1800000) + return -EINVAL; + + vsel = ((max_uV - 600000) / 12500) + 8; + + if (wm831x_buckv_list_voltage(rdev, vsel) < min_uV || + wm831x_buckv_list_voltage(rdev, vsel) < max_uV) + return -EINVAL; + + return vsel; +} + static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); @@ -321,23 +338,28 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, if (ret < 0) return ret; - /* - * If this VSEL is higher than the last one we've seen then - * remember it as the DVS VSEL. This is optimised for CPUfreq - * usage where we want to get to the highest voltage very - * quickly. - */ - if (vsel > dcdc->dvs_vsel) { - ret = wm831x_set_bits(wm831x, dvs_reg, - WM831X_DC1_DVS_VSEL_MASK, - dcdc->dvs_vsel); - if (ret == 0) - dcdc->dvs_vsel = vsel; - else - dev_warn(wm831x->dev, - "Failed to set DCDC DVS VSEL: %d\n", ret); + /* Set the high voltage as the DVS voltage. This is optimised + * for CPUfreq usage, most processors will keep the maximum + * voltage constant and lower the minimum with the frequency. */ + vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV); + if (vsel < 0) { + /* This should never happen - at worst the same vsel + * should be chosen */ + WARN_ON(vsel < 0); + return 0; } + /* Don't bother if it's the same VSEL we're already using */ + if (vsel == dcdc->on_vsel) + return 0; + + ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel); + if (ret == 0) + dcdc->dvs_vsel = vsel; + else + dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n", + ret); + return 0; } @@ -434,6 +456,27 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, if (!pdata || !pdata->dvs_gpio) return; + switch (pdata->dvs_control_src) { + case 1: + ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; + break; + case 2: + ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT; + break; + default: + dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n", + pdata->dvs_control_src, dcdc->name); + return; + } + + ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL, + WM831X_DC1_DVS_SRC_MASK, ctrl); + if (ret < 0) { + dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n", + dcdc->name, ret); + return; + } + ret = gpio_request(pdata->dvs_gpio, "DCDC DVS"); if (ret < 0) { dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", @@ -455,57 +498,17 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, } dcdc->dvs_gpio = pdata->dvs_gpio; - - switch (pdata->dvs_control_src) { - case 1: - ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; - break; - case 2: - ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT; - break; - default: - dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n", - pdata->dvs_control_src, dcdc->name); - return; - } - - /* If DVS_VSEL is set to the minimum value then raise it to ON_VSEL - * to make bootstrapping a bit smoother. - */ - if (!dcdc->dvs_vsel) { - ret = wm831x_set_bits(wm831x, - dcdc->base + WM831X_DCDC_DVS_CONTROL, - WM831X_DC1_DVS_VSEL_MASK, dcdc->on_vsel); - if (ret == 0) - dcdc->dvs_vsel = dcdc->on_vsel; - else - dev_warn(wm831x->dev, "Failed to set DVS_VSEL: %d\n", - ret); - } - - ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL, - WM831X_DC1_DVS_SRC_MASK, ctrl); - if (ret < 0) { - dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n", - dcdc->name, ret); - } } static __devinit int wm831x_buckv_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; - int id; + int id = pdev->id % ARRAY_SIZE(pdata->dcdc); struct wm831x_dcdc *dcdc; struct resource *res; int ret, irq; - if (pdata && pdata->wm831x_num) - id = (pdata->wm831x_num * 10) + 1; - else - id = 0; - id = pdev->id - id; - dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1); if (pdata == NULL || pdata->dcdc[id] == NULL) @@ -542,7 +545,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) } dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK; - ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL); + ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG); if (ret < 0) { dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret); goto err; @@ -706,17 +709,11 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; - int id; + int id = pdev->id % ARRAY_SIZE(pdata->dcdc); struct wm831x_dcdc *dcdc; struct resource *res; int ret, irq; - if (pdata && pdata->wm831x_num) - id = (pdata->wm831x_num * 10) + 1; - else - id = 0; - id = pdev->id - id; - dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1); if (pdata == NULL || pdata->dcdc[id] == NULL) @@ -1049,4 +1046,3 @@ MODULE_DESCRIPTION("WM831x DC-DC convertor driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:wm831x-buckv"); MODULE_ALIAS("platform:wm831x-buckp"); -MODULE_ALIAS("platform:wm831x-epe"); diff --git a/trunk/drivers/regulator/wm831x-ldo.c b/trunk/drivers/regulator/wm831x-ldo.c index 6709710a059e..2220cf8defb1 100644 --- a/trunk/drivers/regulator/wm831x-ldo.c +++ b/trunk/drivers/regulator/wm831x-ldo.c @@ -310,17 +310,11 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; - int id; + int id = pdev->id % ARRAY_SIZE(pdata->ldo); struct wm831x_ldo *ldo; struct resource *res; int ret, irq; - if (pdata && pdata->wm831x_num) - id = (pdata->wm831x_num * 10) + 1; - else - id = 0; - id = pdev->id - id; - dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); if (pdata == NULL || pdata->ldo[id] == NULL) @@ -580,17 +574,11 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; - int id; + int id = pdev->id % ARRAY_SIZE(pdata->ldo); struct wm831x_ldo *ldo; struct resource *res; int ret, irq; - if (pdata && pdata->wm831x_num) - id = (pdata->wm831x_num * 10) + 1; - else - id = 0; - id = pdev->id - id; - dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); if (pdata == NULL || pdata->ldo[id] == NULL) @@ -776,18 +764,11 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; - int id; + int id = pdev->id % ARRAY_SIZE(pdata->ldo); struct wm831x_ldo *ldo; struct resource *res; int ret; - if (pdata && pdata->wm831x_num) - id = (pdata->wm831x_num * 10) + 1; - else - id = 0; - id = pdev->id - id; - - dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); if (pdata == NULL || pdata->ldo[id] == NULL) diff --git a/trunk/drivers/regulator/wm8994-regulator.c b/trunk/drivers/regulator/wm8994-regulator.c index 1a6a690f24db..35b2958d5106 100644 --- a/trunk/drivers/regulator/wm8994-regulator.c +++ b/trunk/drivers/regulator/wm8994-regulator.c @@ -43,7 +43,7 @@ static int wm8994_ldo_enable(struct regulator_dev *rdev) if (!ldo->enable) return 0; - gpio_set_value_cansleep(ldo->enable, 1); + gpio_set_value(ldo->enable, 1); ldo->is_enabled = true; return 0; @@ -57,7 +57,7 @@ static int wm8994_ldo_disable(struct regulator_dev *rdev) if (!ldo->enable) return -EINVAL; - gpio_set_value_cansleep(ldo->enable, 0); + gpio_set_value(ldo->enable, 0); ldo->is_enabled = false; return 0; diff --git a/trunk/drivers/rtc/rtc-omap.c b/trunk/drivers/rtc/rtc-omap.c index 7789002bdd5c..bcae8dd41496 100644 --- a/trunk/drivers/rtc/rtc-omap.c +++ b/trunk/drivers/rtc/rtc-omap.c @@ -368,7 +368,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) pr_info("%s: already running\n", pdev->name); /* force to 24 hour mode */ - new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP); + new_ctrl = reg & ~(OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP); new_ctrl |= OMAP_RTC_CTRL_STOP; /* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE: diff --git a/trunk/drivers/s390/block/dasd.c b/trunk/drivers/s390/block/dasd.c index a1d3ddba99cc..432444af7ee4 100644 --- a/trunk/drivers/s390/block/dasd.c +++ b/trunk/drivers/s390/block/dasd.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -889,11 +888,11 @@ char *dasd_get_user_string(const char __user *user_buf, size_t user_len) { char *buffer; - buffer = vmalloc(user_len + 1); + buffer = kmalloc(user_len + 1, GFP_KERNEL); if (buffer == NULL) return ERR_PTR(-ENOMEM); if (copy_from_user(buffer, user_buf, user_len) != 0) { - vfree(buffer); + kfree(buffer); return ERR_PTR(-EFAULT); } /* got the string, now strip linefeed. */ @@ -931,7 +930,7 @@ static ssize_t dasd_stats_write(struct file *file, dasd_profile_off(prof); } else rc = -EINVAL; - vfree(buffer); + kfree(buffer); return rc; } @@ -1043,7 +1042,7 @@ static ssize_t dasd_stats_global_write(struct file *file, dasd_global_profile_level = DASD_PROFILE_OFF; } else rc = -EINVAL; - vfree(buffer); + kfree(buffer); return rc; } diff --git a/trunk/drivers/s390/block/dasd_eckd.c b/trunk/drivers/s390/block/dasd_eckd.c index 6e835c9fdfcb..30fb979d684d 100644 --- a/trunk/drivers/s390/block/dasd_eckd.c +++ b/trunk/drivers/s390/block/dasd_eckd.c @@ -1461,15 +1461,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device) "Read device characteristic failed, rc=%d", rc); goto out_err3; } - - if ((device->features & DASD_FEATURE_USERAW) && - !(private->rdc_data.facilities.RT_in_LR)) { - dev_err(&device->cdev->dev, "The storage server does not " - "support raw-track access\n"); - rc = -EINVAL; - goto out_err3; - } - /* find the valid cylinder size */ if (private->rdc_data.no_cyl == LV_COMPAT_CYL && private->rdc_data.long_no_cyl) diff --git a/trunk/drivers/s390/block/dasd_proc.c b/trunk/drivers/s390/block/dasd_proc.c index e12989fff4ff..6c3c5364d082 100644 --- a/trunk/drivers/s390/block/dasd_proc.c +++ b/trunk/drivers/s390/block/dasd_proc.c @@ -312,14 +312,14 @@ static ssize_t dasd_stats_proc_write(struct file *file, pr_info("The statistics have been reset\n"); } else goto out_parse_error; - vfree(buffer); + kfree(buffer); return user_len; out_parse_error: rc = -EINVAL; pr_warning("%s is not a supported value for /proc/dasd/statistics\n", str); out_error: - vfree(buffer); + kfree(buffer); return rc; #else pr_warning("/proc/dasd/statistics: is not activated in this kernel\n"); diff --git a/trunk/drivers/s390/char/sclp_async.c b/trunk/drivers/s390/char/sclp_async.c index 5f9f929e891c..7ad30e72f868 100644 --- a/trunk/drivers/s390/char/sclp_async.c +++ b/trunk/drivers/s390/char/sclp_async.c @@ -82,9 +82,12 @@ static int proc_handler_callhome(struct ctl_table *ctl, int write, return -EFAULT; } else { len = *count; - rc = kstrtoul_from_user(buffer, len, 0, &val); - if (rc) - return rc; + rc = copy_from_user(buf, buffer, sizeof(buf)); + if (rc != 0) + return -EFAULT; + buf[sizeof(buf) - 1] = '\0'; + if (strict_strtoul(buf, 0, &val) != 0) + return -EINVAL; if (val != 0 && val != 1) return -EINVAL; callhome_enabled = val; diff --git a/trunk/drivers/s390/cio/qdio.h b/trunk/drivers/s390/cio/qdio.h index e5c966462c5a..7bc643f3f5ab 100644 --- a/trunk/drivers/s390/cio/qdio.h +++ b/trunk/drivers/s390/cio/qdio.h @@ -14,8 +14,6 @@ #include "chsc.h" #define QDIO_BUSY_BIT_PATIENCE (100 << 12) /* 100 microseconds */ -#define QDIO_BUSY_BIT_RETRY_DELAY 10 /* 10 milliseconds */ -#define QDIO_BUSY_BIT_RETRIES 1000 /* = 10s retry time */ #define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */ /* diff --git a/trunk/drivers/s390/cio/qdio_debug.c b/trunk/drivers/s390/cio/qdio_debug.c index 0e615cb912d0..f8b03a636e49 100644 --- a/trunk/drivers/s390/cio/qdio_debug.c +++ b/trunk/drivers/s390/cio/qdio_debug.c @@ -188,13 +188,19 @@ static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf, struct qdio_irq *irq_ptr = seq->private; struct qdio_q *q; unsigned long val; + char buf[8]; int ret, i; if (!irq_ptr) return 0; - - ret = kstrtoul_from_user(ubuf, count, 10, &val); - if (ret) + if (count >= sizeof(buf)) + return -EINVAL; + if (copy_from_user(&buf, ubuf, count)) + return -EFAULT; + buf[count] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; switch (val) { diff --git a/trunk/drivers/s390/cio/qdio_main.c b/trunk/drivers/s390/cio/qdio_main.c index 288c9140290e..e58169c32474 100644 --- a/trunk/drivers/s390/cio/qdio_main.c +++ b/trunk/drivers/s390/cio/qdio_main.c @@ -313,7 +313,7 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) unsigned long schid = *((u32 *) &q->irq_ptr->schid); unsigned int fc = QDIO_SIGA_WRITE; u64 start_time = 0; - int retries = 0, cc; + int cc; if (is_qebsm(q)) { schid = q->irq_ptr->sch_token; @@ -325,7 +325,6 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) /* hipersocket busy condition */ if (unlikely(*busy_bit)) { WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); - retries++; if (!start_time) { start_time = get_clock(); @@ -334,11 +333,6 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE) goto again; } - if (retries) { - DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, - "%4x cc2 BB1:%1d", SCH_NO(q), q->nr); - DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "count:%u", retries); - } return cc; } @@ -734,14 +728,13 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) static int qdio_kick_outbound_q(struct qdio_q *q) { - int retries = 0, cc; unsigned int busy_bit; + int cc; if (!need_siga_out(q)) return 0; DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); -retry: qperf_inc(q, siga_write); cc = qdio_siga_output(q, &busy_bit); @@ -750,11 +743,7 @@ static int qdio_kick_outbound_q(struct qdio_q *q) break; case 2: if (busy_bit) { - while (++retries < QDIO_BUSY_BIT_RETRIES) { - mdelay(QDIO_BUSY_BIT_RETRY_DELAY); - goto retry; - } - DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr); + DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); cc |= QDIO_ERROR_SIGA_BUSY; } else DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); @@ -764,10 +753,6 @@ static int qdio_kick_outbound_q(struct qdio_q *q) DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); break; } - if (retries) { - DBF_ERROR("%4x cc2 BB2:%1d", SCH_NO(q), q->nr); - DBF_ERROR("count:%u", retries); - } return cc; } diff --git a/trunk/drivers/spi/spi-pl022.c b/trunk/drivers/spi/spi-pl022.c index 730b4a37b823..eba88c749fb1 100644 --- a/trunk/drivers/spi/spi-pl022.c +++ b/trunk/drivers/spi/spi-pl022.c @@ -2267,13 +2267,17 @@ static int __devexit pl022_remove(struct amba_device *adev) { struct pl022 *pl022 = amba_get_drvdata(adev); - + int status = 0; if (!pl022) return 0; /* Remove the queue */ - if (destroy_queue(pl022) != 0) - dev_err(&adev->dev, "queue remove failed\n"); + status = destroy_queue(pl022); + if (status != 0) { + dev_err(&adev->dev, + "queue remove failed (%d)\n", status); + return status; + } load_ssp_default_config(pl022); pl022_dma_remove(pl022); free_irq(adev->irq[0], pl022); @@ -2285,6 +2289,7 @@ pl022_remove(struct amba_device *adev) spi_unregister_master(pl022->master); spi_master_put(pl022->master); amba_set_drvdata(adev, NULL); + dev_dbg(&adev->dev, "remove succeeded\n"); return 0; } diff --git a/trunk/drivers/target/iscsi/Kconfig b/trunk/drivers/target/iscsi/Kconfig index 8345fb457a40..564ff4e0dbc4 100644 --- a/trunk/drivers/target/iscsi/Kconfig +++ b/trunk/drivers/target/iscsi/Kconfig @@ -1,6 +1,5 @@ config ISCSI_TARGET tristate "Linux-iSCSI.org iSCSI Target Mode Stack" - depends on NET select CRYPTO select CRYPTO_CRC32C select CRYPTO_CRC32C_INTEL if X86 diff --git a/trunk/drivers/target/iscsi/iscsi_target.c b/trunk/drivers/target/iscsi/iscsi_target.c index c24fb10de60b..14c81c4265bd 100644 --- a/trunk/drivers/target/iscsi/iscsi_target.c +++ b/trunk/drivers/target/iscsi/iscsi_target.c @@ -120,7 +120,7 @@ struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf) struct iscsi_tiqn *tiqn = NULL; int ret; - if (strlen(buf) >= ISCSI_IQN_LEN) { + if (strlen(buf) > ISCSI_IQN_LEN) { pr_err("Target IQN exceeds %d bytes\n", ISCSI_IQN_LEN); return ERR_PTR(-EINVAL); @@ -1857,7 +1857,7 @@ static int iscsit_handle_text_cmd( char *text_ptr, *text_in; int cmdsn_ret, niov = 0, rx_got, rx_size; u32 checksum = 0, data_crc = 0, payload_length; - u32 padding = 0, pad_bytes = 0, text_length = 0; + u32 padding = 0, text_length = 0; struct iscsi_cmd *cmd; struct kvec iov[3]; struct iscsi_text *hdr; @@ -1896,7 +1896,7 @@ static int iscsit_handle_text_cmd( padding = ((-payload_length) & 3); if (padding != 0) { - iov[niov].iov_base = &pad_bytes; + iov[niov].iov_base = cmd->pad_bytes; iov[niov++].iov_len = padding; rx_size += padding; pr_debug("Receiving %u additional bytes" @@ -1917,7 +1917,7 @@ static int iscsit_handle_text_cmd( if (conn->conn_ops->DataDigest) { iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, text_in, text_length, - padding, (u8 *)&pad_bytes, + padding, cmd->pad_bytes, (u8 *)&data_crc); if (checksum != data_crc) { @@ -3468,12 +3468,7 @@ static inline void iscsit_thread_check_cpumask( } #else - -void iscsit_thread_get_cpumask(struct iscsi_conn *conn) -{ - return; -} - +#define iscsit_thread_get_cpumask(X) ({}) #define iscsit_thread_check_cpumask(X, Y, Z) ({}) #endif /* CONFIG_SMP */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_configfs.c b/trunk/drivers/target/iscsi/iscsi_target_configfs.c index f095e65b1ccf..32bb92c44450 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_configfs.c +++ b/trunk/drivers/target/iscsi/iscsi_target_configfs.c @@ -181,7 +181,7 @@ struct se_tpg_np *lio_target_call_addnptotpg( return ERR_PTR(-EOVERFLOW); } memset(buf, 0, MAX_PORTAL_LEN + 1); - snprintf(buf, MAX_PORTAL_LEN + 1, "%s", name); + snprintf(buf, MAX_PORTAL_LEN, "%s", name); memset(&sockaddr, 0, sizeof(struct __kernel_sockaddr_storage)); diff --git a/trunk/drivers/target/iscsi/iscsi_target_nego.c b/trunk/drivers/target/iscsi/iscsi_target_nego.c index 4d087ac11067..713a4d23557a 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_nego.c +++ b/trunk/drivers/target/iscsi/iscsi_target_nego.c @@ -978,7 +978,7 @@ struct iscsi_login *iscsi_target_init_negotiation( pr_err("Unable to allocate memory for struct iscsi_login.\n"); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); - return NULL; + goto out; } login->req = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); diff --git a/trunk/drivers/target/target_core_transport.c b/trunk/drivers/target/target_core_transport.c index 89760329d5d0..c75a01a1c475 100644 --- a/trunk/drivers/target/target_core_transport.c +++ b/trunk/drivers/target/target_core_transport.c @@ -1747,8 +1747,6 @@ int transport_generic_handle_cdb( } EXPORT_SYMBOL(transport_generic_handle_cdb); -static void transport_generic_request_failure(struct se_cmd *, - struct se_device *, int, int); /* * Used by fabric module frontends to queue tasks directly. * Many only be used from process context only @@ -1756,8 +1754,6 @@ static void transport_generic_request_failure(struct se_cmd *, int transport_handle_cdb_direct( struct se_cmd *cmd) { - int ret; - if (!cmd->se_lun) { dump_stack(); pr_err("cmd->se_lun is NULL\n"); @@ -1769,31 +1765,8 @@ int transport_handle_cdb_direct( " from interrupt context\n"); return -EINVAL; } - /* - * Set TRANSPORT_NEW_CMD state and cmd->t_transport_active=1 following - * transport_generic_handle_cdb*() -> transport_add_cmd_to_queue() - * in existing usage to ensure that outstanding descriptors are handled - * correctly during shutdown via transport_generic_wait_for_tasks() - * - * Also, we don't take cmd->t_state_lock here as we only expect - * this to be called for initial descriptor submission. - */ - cmd->t_state = TRANSPORT_NEW_CMD; - atomic_set(&cmd->t_transport_active, 1); - /* - * transport_generic_new_cmd() is already handling QUEUE_FULL, - * so follow TRANSPORT_NEW_CMD processing thread context usage - * and call transport_generic_request_failure() if necessary.. - */ - ret = transport_generic_new_cmd(cmd); - if (ret == -EAGAIN) - return 0; - else if (ret < 0) { - cmd->transport_error_status = ret; - transport_generic_request_failure(cmd, NULL, 0, - (cmd->data_direction != DMA_TO_DEVICE)); - } - return 0; + + return transport_generic_new_cmd(cmd); } EXPORT_SYMBOL(transport_handle_cdb_direct); @@ -3351,7 +3324,7 @@ static int transport_generic_cmd_sequencer( goto out_invalid_cdb_field; } - cmd->t_task_lba = get_unaligned_be64(&cdb[2]); + cmd->t_task_lba = get_unaligned_be16(&cdb[2]); passthrough = (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV); /* diff --git a/trunk/drivers/target/tcm_fc/tcm_fc.h b/trunk/drivers/target/tcm_fc/tcm_fc.h index bd4fe21a23b8..f7fff7ed63c3 100644 --- a/trunk/drivers/target/tcm_fc/tcm_fc.h +++ b/trunk/drivers/target/tcm_fc/tcm_fc.h @@ -187,9 +187,4 @@ void ft_dump_cmd(struct ft_cmd *, const char *caller); ssize_t ft_format_wwn(char *, size_t, u64); -/* - * Underlying HW specific helper function - */ -void ft_invl_hw_context(struct ft_cmd *); - #endif /* __TCM_FC_H__ */ diff --git a/trunk/drivers/target/tcm_fc/tfc_cmd.c b/trunk/drivers/target/tcm_fc/tfc_cmd.c index 5654dc22f7ae..09df38b4610c 100644 --- a/trunk/drivers/target/tcm_fc/tfc_cmd.c +++ b/trunk/drivers/target/tcm_fc/tfc_cmd.c @@ -320,7 +320,6 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) default: pr_debug("%s: unhandled frame r_ctl %x\n", __func__, fh->fh_r_ctl); - ft_invl_hw_context(cmd); fc_frame_free(fp); transport_generic_free_cmd(&cmd->se_cmd, 0, 0); break; diff --git a/trunk/drivers/target/tcm_fc/tfc_io.c b/trunk/drivers/target/tcm_fc/tfc_io.c index c37f4cd96452..8e2a46ddcccb 100644 --- a/trunk/drivers/target/tcm_fc/tfc_io.c +++ b/trunk/drivers/target/tcm_fc/tfc_io.c @@ -213,49 +213,62 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) goto drop; - f_ctl = ntoh24(fh->fh_f_ctl); - ep = fc_seq_exch(seq); - lport = ep->lp; - if (cmd->was_ddp_setup) { - BUG_ON(!ep); - BUG_ON(!lport); - } - /* - * Doesn't expect payload if DDP is setup. Payload + * Doesn't expect even single byte of payload. Payload * is expected to be copied directly to user buffers - * due to DDP (Large Rx offload), + * due to DDP (Large Rx offload) feature, hence + * BUG_ON if BUF is non-NULL */ buf = fc_frame_payload_get(fp, 1); - if (buf) - pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, " - "cmd->sg_cnt 0x%x. DDP was setup" - " hence not expected to receive frame with " - "payload, Frame will be dropped if " - "'Sequence Initiative' bit in f_ctl is " - "not set\n", __func__, ep->xid, f_ctl, - cmd->sg, cmd->sg_cnt); - /* - * Invalidate HW DDP context if it was setup for respective - * command. Invalidation of HW DDP context is requited in both - * situation (success and error). - */ - ft_invl_hw_context(cmd); + if (cmd->was_ddp_setup && buf) { + pr_debug("%s: When DDP was setup, not expected to" + "receive frame with payload, Payload shall be" + "copied directly to buffer instead of coming " + "via. legacy receive queues\n", __func__); + BUG_ON(buf); + } /* - * If "Sequence Initiative (TSI)" bit set in f_ctl, means last - * write data frame is received successfully where payload is - * posted directly to user buffer and only the last frame's - * header is posted in receive queue. - * - * If "Sequence Initiative (TSI)" bit is not set, means error - * condition w.r.t. DDP, hence drop the packet and let explict - * ABORTS from other end of exchange timer trigger the recovery. + * If ft_cmd indicated 'ddp_setup', in that case only the last frame + * should come with 'TSI bit being set'. If 'TSI bit is not set and if + * data frame appears here, means error condition. In both the cases + * release the DDP context (ddp_put) and in error case, as well + * initiate error recovery mechanism. */ - if (f_ctl & FC_FC_SEQ_INIT) - goto last_frame; - else - goto drop; + ep = fc_seq_exch(seq); + if (cmd->was_ddp_setup) { + BUG_ON(!ep); + lport = ep->lp; + BUG_ON(!lport); + } + if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) { + f_ctl = ntoh24(fh->fh_f_ctl); + /* + * If TSI bit set in f_ctl, means last write data frame is + * received successfully where payload is posted directly + * to user buffer and only the last frame's header is posted + * in legacy receive queue + */ + if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */ + cmd->write_data_len = lport->tt.ddp_done(lport, + ep->xid); + goto last_frame; + } else { + /* + * Updating the write_data_len may be meaningless at + * this point, but just in case if required in future + * for debugging or any other purpose + */ + pr_err("%s: Received frame with TSI bit not" + " being SET, dropping the frame, " + "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n", + __func__, cmd->sg, cmd->sg_cnt); + cmd->write_data_len = lport->tt.ddp_done(lport, + ep->xid); + lport->tt.seq_exch_abort(cmd->seq, 0); + goto drop; + } + } rel_off = ntohl(fh->fh_parm_offset); frame_len = fr_len(fp); @@ -318,39 +331,3 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) drop: fc_frame_free(fp); } - -/* - * Handle and cleanup any HW specific resources if - * received ABORTS, errors, timeouts. - */ -void ft_invl_hw_context(struct ft_cmd *cmd) -{ - struct fc_seq *seq = cmd->seq; - struct fc_exch *ep = NULL; - struct fc_lport *lport = NULL; - - BUG_ON(!cmd); - - /* Cleanup the DDP context in HW if DDP was setup */ - if (cmd->was_ddp_setup && seq) { - ep = fc_seq_exch(seq); - if (ep) { - lport = ep->lp; - if (lport && (ep->xid <= lport->lro_xid)) - /* - * "ddp_done" trigger invalidation of HW - * specific DDP context - */ - cmd->write_data_len = lport->tt.ddp_done(lport, - ep->xid); - - /* - * Resetting same variable to indicate HW's - * DDP context has been invalidated to avoid - * re_invalidation of same context (context is - * identified using ep->xid) - */ - cmd->was_ddp_setup = 0; - } - } -} diff --git a/trunk/drivers/thermal/Kconfig b/trunk/drivers/thermal/Kconfig index f7f71b2d3101..bf7c687519ef 100644 --- a/trunk/drivers/thermal/Kconfig +++ b/trunk/drivers/thermal/Kconfig @@ -14,7 +14,11 @@ menuconfig THERMAL If you want this support, you should say Y or M here. config THERMAL_HWMON - bool + bool "Hardware monitoring support" depends on THERMAL depends on HWMON=y || HWMON=THERMAL - default y + help + The generic thermal sysfs driver's hardware monitoring support + requires a 2.10.7/3.0.2 or later lm-sensors userspace. + + Say Y if your user-space is new enough. diff --git a/trunk/drivers/thermal/thermal_sys.c b/trunk/drivers/thermal/thermal_sys.c index 708f8e92771a..0b1c82ad6805 100644 --- a/trunk/drivers/thermal/thermal_sys.c +++ b/trunk/drivers/thermal/thermal_sys.c @@ -420,29 +420,6 @@ thermal_cooling_device_trip_point_show(struct device *dev, /* hwmon sys I/F */ #include - -/* thermal zone devices with the same type share one hwmon device */ -struct thermal_hwmon_device { - char type[THERMAL_NAME_LENGTH]; - struct device *device; - int count; - struct list_head tz_list; - struct list_head node; -}; - -struct thermal_hwmon_attr { - struct device_attribute attr; - char name[16]; -}; - -/* one temperature input for each thermal zone */ -struct thermal_hwmon_temp { - struct list_head hwmon_node; - struct thermal_zone_device *tz; - struct thermal_hwmon_attr temp_input; /* hwmon sys attr */ - struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */ -}; - static LIST_HEAD(thermal_hwmon_list); static ssize_t @@ -460,10 +437,9 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) int ret; struct thermal_hwmon_attr *hwmon_attr = container_of(attr, struct thermal_hwmon_attr, attr); - struct thermal_hwmon_temp *temp - = container_of(hwmon_attr, struct thermal_hwmon_temp, + struct thermal_zone_device *tz + = container_of(hwmon_attr, struct thermal_zone_device, temp_input); - struct thermal_zone_device *tz = temp->tz; ret = tz->ops->get_temp(tz, &temperature); @@ -479,10 +455,9 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, { struct thermal_hwmon_attr *hwmon_attr = container_of(attr, struct thermal_hwmon_attr, attr); - struct thermal_hwmon_temp *temp - = container_of(hwmon_attr, struct thermal_hwmon_temp, + struct thermal_zone_device *tz + = container_of(hwmon_attr, struct thermal_zone_device, temp_crit); - struct thermal_zone_device *tz = temp->tz; long temperature; int ret; @@ -494,54 +469,22 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, } -static struct thermal_hwmon_device * -thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz) +static int +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) { struct thermal_hwmon_device *hwmon; + int new_hwmon_device = 1; + int result; mutex_lock(&thermal_list_lock); list_for_each_entry(hwmon, &thermal_hwmon_list, node) if (!strcmp(hwmon->type, tz->type)) { + new_hwmon_device = 0; mutex_unlock(&thermal_list_lock); - return hwmon; - } - mutex_unlock(&thermal_list_lock); - - return NULL; -} - -/* Find the temperature input matching a given thermal zone */ -static struct thermal_hwmon_temp * -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon, - const struct thermal_zone_device *tz) -{ - struct thermal_hwmon_temp *temp; - - mutex_lock(&thermal_list_lock); - list_for_each_entry(temp, &hwmon->tz_list, hwmon_node) - if (temp->tz == tz) { - mutex_unlock(&thermal_list_lock); - return temp; + goto register_sys_interface; } mutex_unlock(&thermal_list_lock); - return NULL; -} - -static int -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) -{ - struct thermal_hwmon_device *hwmon; - struct thermal_hwmon_temp *temp; - int new_hwmon_device = 1; - int result; - - hwmon = thermal_hwmon_lookup_by_type(tz); - if (hwmon) { - new_hwmon_device = 0; - goto register_sys_interface; - } - hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL); if (!hwmon) return -ENOMEM; @@ -559,36 +502,30 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) goto free_mem; register_sys_interface: - temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL); - if (!temp) { - result = -ENOMEM; - goto unregister_name; - } - - temp->tz = tz; + tz->hwmon = hwmon; hwmon->count++; - snprintf(temp->temp_input.name, THERMAL_NAME_LENGTH, + snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH, "temp%d_input", hwmon->count); - temp->temp_input.attr.attr.name = temp->temp_input.name; - temp->temp_input.attr.attr.mode = 0444; - temp->temp_input.attr.show = temp_input_show; - sysfs_attr_init(&temp->temp_input.attr.attr); - result = device_create_file(hwmon->device, &temp->temp_input.attr); + tz->temp_input.attr.attr.name = tz->temp_input.name; + tz->temp_input.attr.attr.mode = 0444; + tz->temp_input.attr.show = temp_input_show; + sysfs_attr_init(&tz->temp_input.attr.attr); + result = device_create_file(hwmon->device, &tz->temp_input.attr); if (result) - goto free_temp_mem; + goto unregister_name; if (tz->ops->get_crit_temp) { unsigned long temperature; if (!tz->ops->get_crit_temp(tz, &temperature)) { - snprintf(temp->temp_crit.name, THERMAL_NAME_LENGTH, + snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH, "temp%d_crit", hwmon->count); - temp->temp_crit.attr.attr.name = temp->temp_crit.name; - temp->temp_crit.attr.attr.mode = 0444; - temp->temp_crit.attr.show = temp_crit_show; - sysfs_attr_init(&temp->temp_crit.attr.attr); + tz->temp_crit.attr.attr.name = tz->temp_crit.name; + tz->temp_crit.attr.attr.mode = 0444; + tz->temp_crit.attr.show = temp_crit_show; + sysfs_attr_init(&tz->temp_crit.attr.attr); result = device_create_file(hwmon->device, - &temp->temp_crit.attr); + &tz->temp_crit.attr); if (result) goto unregister_input; } @@ -597,15 +534,13 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) mutex_lock(&thermal_list_lock); if (new_hwmon_device) list_add_tail(&hwmon->node, &thermal_hwmon_list); - list_add_tail(&temp->hwmon_node, &hwmon->tz_list); + list_add_tail(&tz->hwmon_node, &hwmon->tz_list); mutex_unlock(&thermal_list_lock); return 0; unregister_input: - device_remove_file(hwmon->device, &temp->temp_input.attr); - free_temp_mem: - kfree(temp); + device_remove_file(hwmon->device, &tz->temp_input.attr); unregister_name: if (new_hwmon_device) { device_remove_file(hwmon->device, &dev_attr_name); @@ -621,30 +556,15 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) static void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) { - struct thermal_hwmon_device *hwmon; - struct thermal_hwmon_temp *temp; - - hwmon = thermal_hwmon_lookup_by_type(tz); - if (unlikely(!hwmon)) { - /* Should never happen... */ - dev_dbg(&tz->device, "hwmon device lookup failed!\n"); - return; - } - - temp = thermal_hwmon_lookup_temp(hwmon, tz); - if (unlikely(!temp)) { - /* Should never happen... */ - dev_dbg(&tz->device, "temperature input lookup failed!\n"); - return; - } + struct thermal_hwmon_device *hwmon = tz->hwmon; - device_remove_file(hwmon->device, &temp->temp_input.attr); + tz->hwmon = NULL; + device_remove_file(hwmon->device, &tz->temp_input.attr); if (tz->ops->get_crit_temp) - device_remove_file(hwmon->device, &temp->temp_crit.attr); + device_remove_file(hwmon->device, &tz->temp_crit.attr); mutex_lock(&thermal_list_lock); - list_del(&temp->hwmon_node); - kfree(temp); + list_del(&tz->hwmon_node); if (!list_empty(&hwmon->tz_list)) { mutex_unlock(&thermal_list_lock); return; diff --git a/trunk/drivers/tty/serial/imx.c b/trunk/drivers/tty/serial/imx.c index 7e91b3d368cd..827db7654594 100644 --- a/trunk/drivers/tty/serial/imx.c +++ b/trunk/drivers/tty/serial/imx.c @@ -1286,17 +1286,22 @@ static int serial_imx_resume(struct platform_device *dev) static int serial_imx_probe_dt(struct imx_port *sport, struct platform_device *pdev) { - static int portnum = 0; struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(imx_uart_dt_ids, &pdev->dev); + int ret; if (!np) return -ENODEV; - sport->port.line = portnum++; - if (sport->port.line >= UART_NR) - return -EINVAL; + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + pr_err("%s: failed to get alias id, errno %d\n", + __func__, ret); + return -ENODEV; + } else { + sport->port.line = ret; + } if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) sport->have_rtscts = 1; diff --git a/trunk/drivers/video/backlight/Kconfig b/trunk/drivers/video/backlight/Kconfig index 278aeaa92505..69407e72aac1 100644 --- a/trunk/drivers/video/backlight/Kconfig +++ b/trunk/drivers/video/backlight/Kconfig @@ -336,7 +336,7 @@ config BACKLIGHT_PCF50633 enable its driver. config BACKLIGHT_AAT2870 - tristate "AnalogicTech AAT2870 Backlight" + bool "AnalogicTech AAT2870 Backlight" depends on BACKLIGHT_CLASS_DEVICE && MFD_AAT2870_CORE help If you have a AnalogicTech AAT2870 say Y to enable the diff --git a/trunk/drivers/video/backlight/aat2870_bl.c b/trunk/drivers/video/backlight/aat2870_bl.c index 331f1ef1dad5..4952a617563d 100644 --- a/trunk/drivers/video/backlight/aat2870_bl.c +++ b/trunk/drivers/video/backlight/aat2870_bl.c @@ -44,7 +44,7 @@ static inline int aat2870_brightness(struct aat2870_bl_driver_data *aat2870_bl, struct backlight_device *bd = aat2870_bl->bd; int val; - val = brightness * (aat2870_bl->max_current - 1); + val = brightness * aat2870_bl->max_current; val /= bd->props.max_brightness; return val; @@ -158,10 +158,10 @@ static int aat2870_bl_probe(struct platform_device *pdev) props.type = BACKLIGHT_RAW; bd = backlight_device_register("aat2870-backlight", &pdev->dev, aat2870_bl, &aat2870_bl_ops, &props); - if (IS_ERR(bd)) { + if (!bd) { dev_err(&pdev->dev, "Failed allocate memory for backlight device\n"); - ret = PTR_ERR(bd); + ret = -ENOMEM; goto out_kfree; } @@ -175,7 +175,7 @@ static int aat2870_bl_probe(struct platform_device *pdev) else aat2870_bl->channels = AAT2870_BL_CH_ALL; - if (pdata->max_current > 0) + if (pdata->max_brightness > 0) aat2870_bl->max_current = pdata->max_current; else aat2870_bl->max_current = AAT2870_CURRENT_27_9; diff --git a/trunk/drivers/video/savage/savagefb.h b/trunk/drivers/video/savage/savagefb.h index dcaab9012ca2..32549d177b19 100644 --- a/trunk/drivers/video/savage/savagefb.h +++ b/trunk/drivers/video/savage/savagefb.h @@ -55,7 +55,7 @@ #define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX)) -#define S3_SAVAGE4_SERIES(chip) ((chip>=S3_SAVAGE4) && (chip<=S3_PROSAVAGEDDR)) +#define S3_SAVAGE4_SERIES(chip) ((chip>=S3_SAVAGE4) || (chip<=S3_PROSAVAGEDDR)) #define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE)) diff --git a/trunk/drivers/watchdog/Kconfig b/trunk/drivers/watchdog/Kconfig index 86b0735e6aa0..f441726ddf2b 100644 --- a/trunk/drivers/watchdog/Kconfig +++ b/trunk/drivers/watchdog/Kconfig @@ -36,6 +36,9 @@ config WATCHDOG_CORE and gives them the /dev/watchdog interface (and later also the sysfs interface). + To compile this driver as a module, choose M here: the module will + be called watchdog. + config WATCHDOG_NOWAYOUT bool "Disable watchdog shutdown on close" help diff --git a/trunk/drivers/watchdog/nv_tco.c b/trunk/drivers/watchdog/nv_tco.c index 809f41c30c44..afa78a54711e 100644 --- a/trunk/drivers/watchdog/nv_tco.c +++ b/trunk/drivers/watchdog/nv_tco.c @@ -458,15 +458,7 @@ static int __devexit nv_tco_remove(struct platform_device *dev) static void nv_tco_shutdown(struct platform_device *dev) { - u32 val; - tco_timer_stop(); - - /* Some BIOSes fail the POST (once) if the NO_REBOOT flag is not - * unset during shutdown. */ - pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val); - val &= ~MCP51_SMBUS_SETUP_B_TCO_REBOOT; - pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val); } static struct platform_driver nv_tco_driver = { diff --git a/trunk/drivers/watchdog/shwdt.c b/trunk/drivers/watchdog/shwdt.c index a267dc078daf..db84f2322d1a 100644 --- a/trunk/drivers/watchdog/shwdt.c +++ b/trunk/drivers/watchdog/shwdt.c @@ -64,7 +64,7 @@ * misses its deadline, the kernel timer will allow the WDT to overflow. */ static int clock_division_ratio = WTCSR_CKS_4096; -#define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4)) +#define next_ping_period(cks) msecs_to_jiffies(cks - 4) static const struct watchdog_info sh_wdt_info; static struct platform_device *sh_wdt_dev; diff --git a/trunk/drivers/xen/Kconfig b/trunk/drivers/xen/Kconfig index 5f7ff8e2fc14..f815283667af 100644 --- a/trunk/drivers/xen/Kconfig +++ b/trunk/drivers/xen/Kconfig @@ -11,7 +11,7 @@ config XEN_BALLOON config XEN_SELFBALLOONING bool "Dynamically self-balloon kernel memory to target" - depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP && XEN_TMEM + depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP default n help Self-ballooning dynamically balloons available kernel memory driven diff --git a/trunk/fs/9p/acl.c b/trunk/fs/9p/acl.c index 9a1d42630751..e9cb57f07546 100644 --- a/trunk/fs/9p/acl.c +++ b/trunk/fs/9p/acl.c @@ -182,11 +182,11 @@ int v9fs_set_create_acl(struct dentry *dentry, return 0; } -int v9fs_acl_mode(struct inode *dir, umode_t *modep, +int v9fs_acl_mode(struct inode *dir, mode_t *modep, struct posix_acl **dpacl, struct posix_acl **pacl) { int retval = 0; - umode_t mode = *modep; + mode_t mode = *modep; struct posix_acl *acl = NULL; if (!S_ISLNK(mode)) { @@ -319,7 +319,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name, case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { - umode_t mode = inode->i_mode; + mode_t mode = inode->i_mode; retval = posix_acl_equiv_mode(acl, &mode); if (retval < 0) goto err_out; diff --git a/trunk/fs/9p/acl.h b/trunk/fs/9p/acl.h index 559556411965..ddb7ae19d971 100644 --- a/trunk/fs/9p/acl.h +++ b/trunk/fs/9p/acl.h @@ -20,7 +20,7 @@ extern struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type); extern int v9fs_acl_chmod(struct dentry *); extern int v9fs_set_create_acl(struct dentry *, struct posix_acl **, struct posix_acl **); -extern int v9fs_acl_mode(struct inode *dir, umode_t *modep, +extern int v9fs_acl_mode(struct inode *dir, mode_t *modep, struct posix_acl **dpacl, struct posix_acl **pacl); #else #define v9fs_iop_get_acl NULL @@ -38,7 +38,7 @@ static inline int v9fs_set_create_acl(struct dentry *dentry, { return 0; } -static inline int v9fs_acl_mode(struct inode *dir, umode_t *modep, +static inline int v9fs_acl_mode(struct inode *dir, mode_t *modep, struct posix_acl **dpacl, struct posix_acl **pacl) { diff --git a/trunk/fs/9p/vfs_inode_dotl.c b/trunk/fs/9p/vfs_inode_dotl.c index b6c8ed205192..9a26dce5a99f 100644 --- a/trunk/fs/9p/vfs_inode_dotl.c +++ b/trunk/fs/9p/vfs_inode_dotl.c @@ -206,7 +206,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, int err = 0; gid_t gid; int flags; - umode_t mode; + mode_t mode; char *name = NULL; struct file *filp; struct p9_qid qid; @@ -348,7 +348,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct p9_fid *fid = NULL, *dfid = NULL; gid_t gid; char *name; - umode_t mode; + mode_t mode; struct inode *inode; struct p9_qid qid; struct dentry *dir_dentry; @@ -751,7 +751,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, int err; gid_t gid; char *name; - umode_t mode; + mode_t mode; struct v9fs_session_info *v9ses; struct p9_fid *fid = NULL, *dfid = NULL; struct inode *inode; diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig index 9fe0b349f4cd..19891aab9c6e 100644 --- a/trunk/fs/Kconfig +++ b/trunk/fs/Kconfig @@ -127,21 +127,14 @@ config TMPFS_POSIX_ACL select TMPFS_XATTR select GENERIC_ACL help - POSIX Access Control Lists (ACLs) support additional access rights - for users and groups beyond the standard owner/group/world scheme, - and this option selects support for ACLs specifically for tmpfs - filesystems. - - If you've selected TMPFS, it's possible that you'll also need - this option as there are a number of Linux distros that require - POSIX ACL support under /dev for certain features to work properly. - For example, some distros need this feature for ALSA-related /dev - files for sound to work properly. In short, if you're not sure, - say Y. + POSIX Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. To learn more about Access Control Lists, visit the POSIX ACLs for Linux website . + If you don't know what Access Control Lists are, say N. + config TMPFS_XATTR bool "Tmpfs extended attributes" depends on TMPFS diff --git a/trunk/fs/block_dev.c b/trunk/fs/block_dev.c index ff77262e887c..f55aad4d1611 100644 --- a/trunk/fs/block_dev.c +++ b/trunk/fs/block_dev.c @@ -387,10 +387,6 @@ int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync) struct inode *bd_inode = filp->f_mapping->host; struct block_device *bdev = I_BDEV(bd_inode); int error; - - error = filemap_write_and_wait_range(filp->f_mapping, start, end); - if (error) - return error; /* * There is no need to serialise calls to blkdev_issue_flush with @@ -556,7 +552,6 @@ struct block_device *bdget(dev_t dev) if (inode->i_state & I_NEW) { bdev->bd_contains = NULL; - bdev->bd_super = NULL; bdev->bd_inode = inode; bdev->bd_block_size = (1 << inode->i_blkbits); bdev->bd_part_count = 0; diff --git a/trunk/fs/btrfs/Makefile b/trunk/fs/btrfs/Makefile index 40e6ac08c21f..9b72dcf1cd25 100644 --- a/trunk/fs/btrfs/Makefile +++ b/trunk/fs/btrfs/Makefile @@ -6,7 +6,5 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ transaction.o inode.o file.o tree-defrag.o \ extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ - export.o tree-log.o free-space-cache.o zlib.o lzo.o \ + export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o - -btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o diff --git a/trunk/fs/btrfs/acl.c b/trunk/fs/btrfs/acl.c index eb159aaa5a11..65a735d8f6e4 100644 --- a/trunk/fs/btrfs/acl.c +++ b/trunk/fs/btrfs/acl.c @@ -28,6 +28,8 @@ #include "btrfs_inode.h" #include "xattr.h" +#ifdef CONFIG_BTRFS_FS_POSIX_ACL + struct posix_acl *btrfs_get_acl(struct inode *inode, int type) { int size; @@ -109,6 +111,7 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans, int ret, size = 0; const char *name; char *value = NULL; + mode_t mode; if (acl) { ret = posix_acl_valid(acl); @@ -119,11 +122,13 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans, switch (type) { case ACL_TYPE_ACCESS: + mode = inode->i_mode; name = POSIX_ACL_XATTR_ACCESS; if (acl) { - ret = posix_acl_equiv_mode(acl, &inode->i_mode); + ret = posix_acl_equiv_mode(acl, &mode); if (ret < 0) return ret; + inode->i_mode = mode; } ret = 0; break; @@ -217,16 +222,19 @@ int btrfs_init_acl(struct btrfs_trans_handle *trans, } if (IS_POSIXACL(dir) && acl) { + mode_t mode = inode->i_mode; + if (S_ISDIR(inode->i_mode)) { ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_DEFAULT); if (ret) goto failed; } - ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + ret = posix_acl_create(&acl, GFP_NOFS, &mode); if (ret < 0) return ret; + inode->i_mode = mode; if (ret > 0) { /* we need an acl */ ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS); @@ -274,3 +282,18 @@ const struct xattr_handler btrfs_xattr_acl_access_handler = { .get = btrfs_xattr_acl_get, .set = btrfs_xattr_acl_set, }; + +#else /* CONFIG_BTRFS_FS_POSIX_ACL */ + +int btrfs_acl_chmod(struct inode *inode) +{ + return 0; +} + +int btrfs_init_acl(struct btrfs_trans_handle *trans, + struct inode *inode, struct inode *dir) +{ + return 0; +} + +#endif /* CONFIG_BTRFS_FS_POSIX_ACL */ diff --git a/trunk/fs/btrfs/compression.c b/trunk/fs/btrfs/compression.c index 8ec5d86f1734..bfe42b03eaf9 100644 --- a/trunk/fs/btrfs/compression.c +++ b/trunk/fs/btrfs/compression.c @@ -338,7 +338,6 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, u64 first_byte = disk_start; struct block_device *bdev; int ret; - int skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; WARN_ON(start & ((u64)PAGE_CACHE_SIZE - 1)); cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS); @@ -393,11 +392,8 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0); BUG_ON(ret); - if (!skip_sum) { - ret = btrfs_csum_one_bio(root, inode, bio, - start, 1); - BUG_ON(ret); - } + ret = btrfs_csum_one_bio(root, inode, bio, start, 1); + BUG_ON(ret); ret = btrfs_map_bio(root, WRITE, bio, 0, 1); BUG_ON(ret); @@ -422,10 +418,8 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0); BUG_ON(ret); - if (!skip_sum) { - ret = btrfs_csum_one_bio(root, inode, bio, start, 1); - BUG_ON(ret); - } + ret = btrfs_csum_one_bio(root, inode, bio, start, 1); + BUG_ON(ret); ret = btrfs_map_bio(root, WRITE, bio, 0, 1); BUG_ON(ret); diff --git a/trunk/fs/btrfs/ctree.h b/trunk/fs/btrfs/ctree.h index 0469263e327e..365c4e1dde04 100644 --- a/trunk/fs/btrfs/ctree.h +++ b/trunk/fs/btrfs/ctree.h @@ -2406,8 +2406,8 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct btrfs_root_item *item, struct btrfs_key *key); int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid); int btrfs_find_orphan_roots(struct btrfs_root *tree_root); -void btrfs_set_root_node(struct btrfs_root_item *item, - struct extent_buffer *node); +int btrfs_set_root_node(struct btrfs_root_item *item, + struct extent_buffer *node); void btrfs_check_and_init_root_item(struct btrfs_root_item *item); /* dir-item.c */ @@ -2523,14 +2523,6 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag #define PageChecked PageFsMisc #endif -/* This forces readahead on a given range of bytes in an inode */ -static inline void btrfs_force_ra(struct address_space *mapping, - struct file_ra_state *ra, struct file *file, - pgoff_t offset, unsigned long req_size) -{ - page_cache_sync_readahead(mapping, ra, file, offset, req_size); -} - struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry); int btrfs_set_inode_index(struct inode *dir, u64 *index); int btrfs_unlink_inode(struct btrfs_trans_handle *trans, @@ -2559,6 +2551,9 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, int btrfs_merge_bio_hook(struct page *page, unsigned long offset, size_t size, struct bio *bio, unsigned long bio_flags); +unsigned long btrfs_force_ra(struct address_space *mapping, + struct file_ra_state *ra, struct file *file, + pgoff_t offset, pgoff_t last_index); int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); int btrfs_readpage(struct file *file, struct page *page); void btrfs_evict_inode(struct inode *inode); @@ -2653,21 +2648,12 @@ do { \ /* acl.c */ #ifdef CONFIG_BTRFS_FS_POSIX_ACL struct posix_acl *btrfs_get_acl(struct inode *inode, int type); -int btrfs_init_acl(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *dir); -int btrfs_acl_chmod(struct inode *inode); #else #define btrfs_get_acl NULL -static inline int btrfs_init_acl(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *dir) -{ - return 0; -} -static inline int btrfs_acl_chmod(struct inode *inode) -{ - return 0; -} #endif +int btrfs_init_acl(struct btrfs_trans_handle *trans, + struct inode *inode, struct inode *dir); +int btrfs_acl_chmod(struct inode *inode); /* relocation.c */ int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start); diff --git a/trunk/fs/btrfs/dir-item.c b/trunk/fs/btrfs/dir-item.c index 31d84e78129b..c360a848d97f 100644 --- a/trunk/fs/btrfs/dir-item.c +++ b/trunk/fs/btrfs/dir-item.c @@ -198,6 +198,8 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_key key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; + struct btrfs_key found_key; + struct extent_buffer *leaf; key.objectid = dir; btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); @@ -207,7 +209,18 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); - if (ret > 0) + if (ret > 0) { + if (path->slots[0] == 0) + return NULL; + path->slots[0]--; + } + + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + + if (found_key.objectid != dir || + btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY || + found_key.offset != key.offset) return NULL; return btrfs_match_dir_item_name(root, path, name, name_len); @@ -302,6 +315,8 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, struct btrfs_key key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; + struct btrfs_key found_key; + struct extent_buffer *leaf; key.objectid = dir; btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); @@ -309,7 +324,18 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); - if (ret > 0) + if (ret > 0) { + if (path->slots[0] == 0) + return NULL; + path->slots[0]--; + } + + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + + if (found_key.objectid != dir || + btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY || + found_key.offset != key.offset) return NULL; return btrfs_match_dir_item_name(root, path, name, name_len); diff --git a/trunk/fs/btrfs/extent-tree.c b/trunk/fs/btrfs/extent-tree.c index 66bac226944e..4d08ed79405d 100644 --- a/trunk/fs/btrfs/extent-tree.c +++ b/trunk/fs/btrfs/extent-tree.c @@ -663,9 +663,7 @@ int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len) struct btrfs_path *path; path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - + BUG_ON(!path); key.objectid = start; key.offset = len; btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); @@ -3274,9 +3272,6 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, } ret = btrfs_alloc_chunk(trans, extent_root, flags); - if (ret < 0 && ret != -ENOSPC) - goto out; - spin_lock(&space_info->lock); if (ret) space_info->full = 1; @@ -3286,7 +3281,6 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, space_info->force_alloc = CHUNK_ALLOC_NO_FORCE; space_info->chunk_alloc = 0; spin_unlock(&space_info->lock); -out: mutex_unlock(&extent_root->fs_info->chunk_mutex); return ret; } @@ -4462,9 +4456,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, printk(KERN_ERR "umm, got %d back from search" ", was looking for %llu\n", ret, (unsigned long long)bytenr); - if (ret > 0) - btrfs_print_leaf(extent_root, - path->nodes[0]); + btrfs_print_leaf(extent_root, path->nodes[0]); } BUG_ON(ret); extent_slot = path->slots[0]; @@ -5081,9 +5073,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, * group is does point to and try again */ if (!last_ptr_loop && last_ptr->block_group && - last_ptr->block_group != block_group && - index <= - get_block_group_index(last_ptr->block_group)) { + last_ptr->block_group != block_group) { btrfs_put_block_group(block_group); block_group = last_ptr->block_group; @@ -5511,8 +5501,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, u32 size = sizeof(*extent_item) + sizeof(*block_info) + sizeof(*iref); path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + BUG_ON(!path); path->leave_spinning = 1; ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, @@ -6283,14 +6272,10 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int level; path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + BUG_ON(!path); wc = kzalloc(sizeof(*wc), GFP_NOFS); - if (!wc) { - btrfs_free_path(path); - return -ENOMEM; - } + BUG_ON(!wc); trans = btrfs_start_transaction(tree_root, 0); BUG_ON(IS_ERR(trans)); @@ -6553,6 +6538,8 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force) u64 min_allocable_bytes; int ret = -ENOSPC; + if (cache->ro) + return 0; /* * We need some metadata space and system metadata space for @@ -6568,12 +6555,6 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force) spin_lock(&sinfo->lock); spin_lock(&cache->lock); - - if (cache->ro) { - ret = 0; - goto out; - } - num_bytes = cache->key.offset - cache->reserved - cache->pinned - cache->bytes_super - btrfs_block_group_used(&cache->item); @@ -6587,7 +6568,7 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force) cache->ro = 1; ret = 0; } -out: + spin_unlock(&cache->lock); spin_unlock(&sinfo->lock); return ret; @@ -7202,15 +7183,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, spin_unlock(&cluster->refill_lock); path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } + BUG_ON(!path); inode = lookup_free_space_inode(root, block_group, path); if (!IS_ERR(inode)) { - ret = btrfs_orphan_add(trans, inode); - BUG_ON(ret); + btrfs_orphan_add(trans, inode); clear_nlink(inode); /* One for the block groups ref */ spin_lock(&block_group->lock); diff --git a/trunk/fs/btrfs/extent_io.c b/trunk/fs/btrfs/extent_io.c index d418164a35f1..067b1747421b 100644 --- a/trunk/fs/btrfs/extent_io.c +++ b/trunk/fs/btrfs/extent_io.c @@ -254,14 +254,14 @@ static void merge_cb(struct extent_io_tree *tree, struct extent_state *new, * * This should be called with the tree lock held. */ -static void merge_state(struct extent_io_tree *tree, - struct extent_state *state) +static int merge_state(struct extent_io_tree *tree, + struct extent_state *state) { struct extent_state *other; struct rb_node *other_node; if (state->state & (EXTENT_IOBITS | EXTENT_BOUNDARY)) - return; + return 0; other_node = rb_prev(&state->rb_node); if (other_node) { @@ -287,13 +287,19 @@ static void merge_state(struct extent_io_tree *tree, free_extent_state(other); } } + + return 0; } -static void set_state_cb(struct extent_io_tree *tree, +static int set_state_cb(struct extent_io_tree *tree, struct extent_state *state, int *bits) { - if (tree->ops && tree->ops->set_bit_hook) - tree->ops->set_bit_hook(tree->mapping->host, state, bits); + if (tree->ops && tree->ops->set_bit_hook) { + return tree->ops->set_bit_hook(tree->mapping->host, + state, bits); + } + + return 0; } static void clear_state_cb(struct extent_io_tree *tree, @@ -303,9 +309,6 @@ static void clear_state_cb(struct extent_io_tree *tree, tree->ops->clear_bit_hook(tree->mapping->host, state, bits); } -static void set_state_bits(struct extent_io_tree *tree, - struct extent_state *state, int *bits); - /* * insert an extent_state struct into the tree. 'bits' are set on the * struct before it is inserted. @@ -321,6 +324,8 @@ static int insert_state(struct extent_io_tree *tree, int *bits) { struct rb_node *node; + int bits_to_set = *bits & ~EXTENT_CTLBITS; + int ret; if (end < start) { printk(KERN_ERR "btrfs end < start %llu %llu\n", @@ -330,9 +335,13 @@ static int insert_state(struct extent_io_tree *tree, } state->start = start; state->end = end; + ret = set_state_cb(tree, state, bits); + if (ret) + return ret; - set_state_bits(tree, state, bits); - + if (bits_to_set & EXTENT_DIRTY) + tree->dirty_bytes += end - start + 1; + state->state |= bits_to_set; node = tree_insert(&tree->state, end, &state->rb_node); if (node) { struct extent_state *found; @@ -348,11 +357,13 @@ static int insert_state(struct extent_io_tree *tree, return 0; } -static void split_cb(struct extent_io_tree *tree, struct extent_state *orig, +static int split_cb(struct extent_io_tree *tree, struct extent_state *orig, u64 split) { if (tree->ops && tree->ops->split_extent_hook) - tree->ops->split_extent_hook(tree->mapping->host, orig, split); + return tree->ops->split_extent_hook(tree->mapping->host, + orig, split); + return 0; } /* @@ -648,25 +659,34 @@ int wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits) if (start > end) break; - cond_resched_lock(&tree->lock); + if (need_resched()) { + spin_unlock(&tree->lock); + cond_resched(); + spin_lock(&tree->lock); + } } out: spin_unlock(&tree->lock); return 0; } -static void set_state_bits(struct extent_io_tree *tree, +static int set_state_bits(struct extent_io_tree *tree, struct extent_state *state, int *bits) { + int ret; int bits_to_set = *bits & ~EXTENT_CTLBITS; - set_state_cb(tree, state, bits); + ret = set_state_cb(tree, state, bits); + if (ret) + return ret; if ((bits_to_set & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) { u64 range = state->end - state->start + 1; tree->dirty_bytes += range; } state->state |= bits_to_set; + + return 0; } static void cache_state(struct extent_state *state, @@ -759,7 +779,9 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, goto out; } - set_state_bits(tree, state, &bits); + err = set_state_bits(tree, state, &bits); + if (err) + goto out; cache_state(state, cached_state); merge_state(tree, state); @@ -808,7 +830,9 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, if (err) goto out; if (state->end <= end) { - set_state_bits(tree, state, &bits); + err = set_state_bits(tree, state, &bits); + if (err) + goto out; cache_state(state, cached_state); merge_state(tree, state); if (last_end == (u64)-1) @@ -869,7 +893,11 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, err = split_state(tree, state, prealloc, end + 1); BUG_ON(err == -EEXIST); - set_state_bits(tree, prealloc, &bits); + err = set_state_bits(tree, prealloc, &bits); + if (err) { + prealloc = NULL; + goto out; + } cache_state(prealloc, cached_state); merge_state(tree, prealloc); prealloc = NULL; @@ -1031,6 +1059,46 @@ static int set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end) return 0; } +/* + * find the first offset in the io tree with 'bits' set. zero is + * returned if we find something, and *start_ret and *end_ret are + * set to reflect the state struct that was found. + * + * If nothing was found, 1 is returned, < 0 on error + */ +int find_first_extent_bit(struct extent_io_tree *tree, u64 start, + u64 *start_ret, u64 *end_ret, int bits) +{ + struct rb_node *node; + struct extent_state *state; + int ret = 1; + + spin_lock(&tree->lock); + /* + * this search will find all the extents that end after + * our range starts. + */ + node = tree_search(tree, start); + if (!node) + goto out; + + while (1) { + state = rb_entry(node, struct extent_state, rb_node); + if (state->end >= start && (state->state & bits)) { + *start_ret = state->start; + *end_ret = state->end; + ret = 0; + break; + } + node = rb_next(node); + if (!node) + break; + } +out: + spin_unlock(&tree->lock); + return ret; +} + /* find the first state struct with 'bits' set after 'start', and * return it. tree->lock must be held. NULL will returned if * nothing was found after 'start' @@ -1062,30 +1130,6 @@ struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree, return NULL; } -/* - * find the first offset in the io tree with 'bits' set. zero is - * returned if we find something, and *start_ret and *end_ret are - * set to reflect the state struct that was found. - * - * If nothing was found, 1 is returned, < 0 on error - */ -int find_first_extent_bit(struct extent_io_tree *tree, u64 start, - u64 *start_ret, u64 *end_ret, int bits) -{ - struct extent_state *state; - int ret = 1; - - spin_lock(&tree->lock); - state = find_first_extent_bit_state(tree, start, bits); - if (state) { - *start_ret = state->start; - *end_ret = state->end; - ret = 0; - } - spin_unlock(&tree->lock); - return ret; -} - /* * find a contiguous range of bytes in the file marked as delalloc, not * more than 'max_bytes'. start and end are used to return the range, @@ -2502,6 +2546,7 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page, struct writeback_control *wbc) { int ret; + struct address_space *mapping = page->mapping; struct extent_page_data epd = { .bio = NULL, .tree = tree, @@ -2509,9 +2554,17 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page, .extent_locked = 0, .sync_io = wbc->sync_mode == WB_SYNC_ALL, }; + struct writeback_control wbc_writepages = { + .sync_mode = wbc->sync_mode, + .nr_to_write = 64, + .range_start = page_offset(page) + PAGE_CACHE_SIZE, + .range_end = (loff_t)-1, + }; ret = __extent_writepage(page, wbc, &epd); + extent_write_cache_pages(tree, mapping, &wbc_writepages, + __extent_writepage, &epd, flush_write_bio); flush_epd_write_bio(&epd); return ret; } diff --git a/trunk/fs/btrfs/extent_io.h b/trunk/fs/btrfs/extent_io.h index 7b2f0c3e7929..21a7ca9e7282 100644 --- a/trunk/fs/btrfs/extent_io.h +++ b/trunk/fs/btrfs/extent_io.h @@ -76,15 +76,15 @@ struct extent_io_ops { struct extent_state *state); int (*writepage_end_io_hook)(struct page *page, u64 start, u64 end, struct extent_state *state, int uptodate); - void (*set_bit_hook)(struct inode *inode, struct extent_state *state, - int *bits); - void (*clear_bit_hook)(struct inode *inode, struct extent_state *state, - int *bits); - void (*merge_extent_hook)(struct inode *inode, - struct extent_state *new, - struct extent_state *other); - void (*split_extent_hook)(struct inode *inode, - struct extent_state *orig, u64 split); + int (*set_bit_hook)(struct inode *inode, struct extent_state *state, + int *bits); + int (*clear_bit_hook)(struct inode *inode, struct extent_state *state, + int *bits); + int (*merge_extent_hook)(struct inode *inode, + struct extent_state *new, + struct extent_state *other); + int (*split_extent_hook)(struct inode *inode, + struct extent_state *orig, u64 split); int (*write_cache_pages_lock_hook)(struct page *page); }; @@ -108,6 +108,8 @@ struct extent_state { wait_queue_head_t wq; atomic_t refs; unsigned long state; + u64 split_start; + u64 split_end; /* for use by the FS */ u64 private; diff --git a/trunk/fs/btrfs/extent_map.c b/trunk/fs/btrfs/extent_map.c index 7c97b3301459..2d0410344ea3 100644 --- a/trunk/fs/btrfs/extent_map.c +++ b/trunk/fs/btrfs/extent_map.c @@ -183,10 +183,22 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next) return 0; } -static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) +int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len) { + int ret = 0; struct extent_map *merge = NULL; struct rb_node *rb; + struct extent_map *em; + + write_lock(&tree->lock); + em = lookup_extent_mapping(tree, start, len); + + WARN_ON(!em || em->start != start); + + if (!em) + goto out; + + clear_bit(EXTENT_FLAG_PINNED, &em->flags); if (em->start != 0) { rb = rb_prev(&em->rb_node); @@ -213,24 +225,6 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) merge->in_tree = 0; free_extent_map(merge); } -} - -int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len) -{ - int ret = 0; - struct extent_map *em; - - write_lock(&tree->lock); - em = lookup_extent_mapping(tree, start, len); - - WARN_ON(!em || em->start != start); - - if (!em) - goto out; - - clear_bit(EXTENT_FLAG_PINNED, &em->flags); - - try_merge_map(tree, em); free_extent_map(em); out: @@ -253,6 +247,7 @@ int add_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) { int ret = 0; + struct extent_map *merge = NULL; struct rb_node *rb; struct extent_map *exist; @@ -268,8 +263,30 @@ int add_extent_mapping(struct extent_map_tree *tree, goto out; } atomic_inc(&em->refs); - - try_merge_map(tree, em); + if (em->start != 0) { + rb = rb_prev(&em->rb_node); + if (rb) + merge = rb_entry(rb, struct extent_map, rb_node); + if (rb && mergable_maps(merge, em)) { + em->start = merge->start; + em->len += merge->len; + em->block_len += merge->block_len; + em->block_start = merge->block_start; + merge->in_tree = 0; + rb_erase(&merge->rb_node, &tree->map); + free_extent_map(merge); + } + } + rb = rb_next(&em->rb_node); + if (rb) + merge = rb_entry(rb, struct extent_map, rb_node); + if (rb && mergable_maps(em, merge)) { + em->len += merge->len; + em->block_len += merge->len; + rb_erase(&merge->rb_node, &tree->map); + merge->in_tree = 0; + free_extent_map(merge); + } out: return ret; } @@ -282,8 +299,19 @@ static u64 range_end(u64 start, u64 len) return start + len; } -struct extent_map *__lookup_extent_mapping(struct extent_map_tree *tree, - u64 start, u64 len, int strict) +/** + * lookup_extent_mapping - lookup extent_map + * @tree: tree to lookup in + * @start: byte offset to start the search + * @len: length of the lookup range + * + * Find and return the first extent_map struct in @tree that intersects the + * [start, len] range. There may be additional objects in the tree that + * intersect, so check the object returned carefully to make sure that no + * additional lookups are needed. + */ +struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, + u64 start, u64 len) { struct extent_map *em; struct rb_node *rb_node; @@ -292,41 +320,37 @@ struct extent_map *__lookup_extent_mapping(struct extent_map_tree *tree, u64 end = range_end(start, len); rb_node = __tree_search(&tree->map, start, &prev, &next); + if (!rb_node && prev) { + em = rb_entry(prev, struct extent_map, rb_node); + if (end > em->start && start < extent_map_end(em)) + goto found; + } + if (!rb_node && next) { + em = rb_entry(next, struct extent_map, rb_node); + if (end > em->start && start < extent_map_end(em)) + goto found; + } if (!rb_node) { - if (prev) - rb_node = prev; - else if (next) - rb_node = next; - else - return NULL; + em = NULL; + goto out; + } + if (IS_ERR(rb_node)) { + em = ERR_CAST(rb_node); + goto out; } - em = rb_entry(rb_node, struct extent_map, rb_node); + if (end > em->start && start < extent_map_end(em)) + goto found; - if (strict && !(end > em->start && start < extent_map_end(em))) - return NULL; + em = NULL; + goto out; +found: atomic_inc(&em->refs); +out: return em; } -/** - * lookup_extent_mapping - lookup extent_map - * @tree: tree to lookup in - * @start: byte offset to start the search - * @len: length of the lookup range - * - * Find and return the first extent_map struct in @tree that intersects the - * [start, len] range. There may be additional objects in the tree that - * intersect, so check the object returned carefully to make sure that no - * additional lookups are needed. - */ -struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, - u64 start, u64 len) -{ - return __lookup_extent_mapping(tree, start, len, 1); -} - /** * search_extent_mapping - find a nearby extent map * @tree: tree to lookup in @@ -341,7 +365,38 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, struct extent_map *search_extent_mapping(struct extent_map_tree *tree, u64 start, u64 len) { - return __lookup_extent_mapping(tree, start, len, 0); + struct extent_map *em; + struct rb_node *rb_node; + struct rb_node *prev = NULL; + struct rb_node *next = NULL; + + rb_node = __tree_search(&tree->map, start, &prev, &next); + if (!rb_node && prev) { + em = rb_entry(prev, struct extent_map, rb_node); + goto found; + } + if (!rb_node && next) { + em = rb_entry(next, struct extent_map, rb_node); + goto found; + } + if (!rb_node) { + em = NULL; + goto out; + } + if (IS_ERR(rb_node)) { + em = ERR_CAST(rb_node); + goto out; + } + em = rb_entry(rb_node, struct extent_map, rb_node); + goto found; + + em = NULL; + goto out; + +found: + atomic_inc(&em->refs); +out: + return em; } /** diff --git a/trunk/fs/btrfs/file-item.c b/trunk/fs/btrfs/file-item.c index b910694f61ed..08bcfa92a222 100644 --- a/trunk/fs/btrfs/file-item.c +++ b/trunk/fs/btrfs/file-item.c @@ -291,8 +291,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + BUG_ON(!path); if (search_commit) { path->skip_locking = 1; @@ -678,9 +677,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, btrfs_super_csum_size(&root->fs_info->super_copy); path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - + BUG_ON(!path); sector_sum = sums->sums; again: next_offset = (u64)-1; diff --git a/trunk/fs/btrfs/file.c b/trunk/fs/btrfs/file.c index 658d66959abe..a35e51c9f235 100644 --- a/trunk/fs/btrfs/file.c +++ b/trunk/fs/btrfs/file.c @@ -74,7 +74,7 @@ struct inode_defrag { * If an existing record is found the defrag item you * pass in is freed */ -static void __btrfs_add_inode_defrag(struct inode *inode, +static int __btrfs_add_inode_defrag(struct inode *inode, struct inode_defrag *defrag) { struct btrfs_root *root = BTRFS_I(inode)->root; @@ -106,11 +106,11 @@ static void __btrfs_add_inode_defrag(struct inode *inode, BTRFS_I(inode)->in_defrag = 1; rb_link_node(&defrag->rb_node, parent, p); rb_insert_color(&defrag->rb_node, &root->fs_info->defrag_inodes); - return; + return 0; exists: kfree(defrag); - return; + return 0; } @@ -123,6 +123,7 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, { struct btrfs_root *root = BTRFS_I(inode)->root; struct inode_defrag *defrag; + int ret = 0; u64 transid; if (!btrfs_test_opt(root, AUTO_DEFRAG)) @@ -149,9 +150,9 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, spin_lock(&root->fs_info->defrag_inodes_lock); if (!BTRFS_I(inode)->in_defrag) - __btrfs_add_inode_defrag(inode, defrag); + ret = __btrfs_add_inode_defrag(inode, defrag); spin_unlock(&root->fs_info->defrag_inodes_lock); - return 0; + return ret; } /* @@ -854,8 +855,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, btrfs_drop_extent_cache(inode, start, end - 1, 0); path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + BUG_ON(!path); again: recow = 0; split = start; @@ -1059,7 +1059,7 @@ static int prepare_uptodate_page(struct page *page, u64 pos) static noinline int prepare_pages(struct btrfs_root *root, struct file *file, struct page **pages, size_t num_pages, loff_t pos, unsigned long first_index, - size_t write_bytes) + unsigned long last_index, size_t write_bytes) { struct extent_state *cached_state = NULL; int i; @@ -1159,6 +1159,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, struct btrfs_root *root = BTRFS_I(inode)->root; struct page **pages = NULL; unsigned long first_index; + unsigned long last_index; size_t num_written = 0; int nrptrs; int ret = 0; @@ -1171,6 +1172,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, return -ENOMEM; first_index = pos >> PAGE_CACHE_SHIFT; + last_index = (pos + iov_iter_count(i)) >> PAGE_CACHE_SHIFT; while (iov_iter_count(i) > 0) { size_t offset = pos & (PAGE_CACHE_SIZE - 1); @@ -1204,7 +1206,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, * contents of pages from loop to loop */ ret = prepare_pages(root, file, pages, num_pages, - pos, first_index, write_bytes); + pos, first_index, last_index, + write_bytes); if (ret) { btrfs_delalloc_release_space(inode, num_pages << PAGE_CACHE_SHIFT); diff --git a/trunk/fs/btrfs/inode.c b/trunk/fs/btrfs/inode.c index 15fceefbca0a..13e6255182e3 100644 --- a/trunk/fs/btrfs/inode.c +++ b/trunk/fs/btrfs/inode.c @@ -1061,8 +1061,7 @@ static noinline int run_delalloc_nocow(struct inode *inode, u64 ino = btrfs_ino(inode); path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + BUG_ON(!path); nolock = btrfs_is_free_space_inode(root, inode); @@ -1283,16 +1282,17 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page, return ret; } -static void btrfs_split_extent_hook(struct inode *inode, - struct extent_state *orig, u64 split) +static int btrfs_split_extent_hook(struct inode *inode, + struct extent_state *orig, u64 split) { /* not delalloc, ignore it */ if (!(orig->state & EXTENT_DELALLOC)) - return; + return 0; spin_lock(&BTRFS_I(inode)->lock); BTRFS_I(inode)->outstanding_extents++; spin_unlock(&BTRFS_I(inode)->lock); + return 0; } /* @@ -1301,17 +1301,18 @@ static void btrfs_split_extent_hook(struct inode *inode, * extents, such as when we are doing sequential writes, so we can properly * account for the metadata space we'll need. */ -static void btrfs_merge_extent_hook(struct inode *inode, - struct extent_state *new, - struct extent_state *other) +static int btrfs_merge_extent_hook(struct inode *inode, + struct extent_state *new, + struct extent_state *other) { /* not delalloc, ignore it */ if (!(other->state & EXTENT_DELALLOC)) - return; + return 0; spin_lock(&BTRFS_I(inode)->lock); BTRFS_I(inode)->outstanding_extents--; spin_unlock(&BTRFS_I(inode)->lock); + return 0; } /* @@ -1319,8 +1320,8 @@ static void btrfs_merge_extent_hook(struct inode *inode, * bytes in this file, and to maintain the list of inodes that * have pending delalloc work to be done. */ -static void btrfs_set_bit_hook(struct inode *inode, - struct extent_state *state, int *bits) +static int btrfs_set_bit_hook(struct inode *inode, + struct extent_state *state, int *bits) { /* @@ -1350,13 +1351,14 @@ static void btrfs_set_bit_hook(struct inode *inode, } spin_unlock(&root->fs_info->delalloc_lock); } + return 0; } /* * extent_io.c clear_bit_hook, see set_bit_hook for why */ -static void btrfs_clear_bit_hook(struct inode *inode, - struct extent_state *state, int *bits) +static int btrfs_clear_bit_hook(struct inode *inode, + struct extent_state *state, int *bits) { /* * set_bit and clear bit hooks normally require _irqsave/restore @@ -1393,6 +1395,7 @@ static void btrfs_clear_bit_hook(struct inode *inode, } spin_unlock(&root->fs_info->delalloc_lock); } + return 0; } /* @@ -1642,8 +1645,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, int ret; path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + BUG_ON(!path); path->leave_spinning = 1; @@ -2213,8 +2215,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode) if (!root->orphan_block_rsv) { block_rsv = btrfs_alloc_block_rsv(root); - if (!block_rsv) - return -ENOMEM; + BUG_ON(!block_rsv); } spin_lock(&root->orphan_lock); @@ -2516,9 +2517,7 @@ static void btrfs_read_locked_inode(struct inode *inode) filled = true; path = btrfs_alloc_path(); - if (!path) - goto make_bad; - + BUG_ON(!path); path->leave_spinning = 1; memcpy(&location, &BTRFS_I(inode)->location, sizeof(location)); @@ -2999,16 +2998,13 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode, dentry->d_name.name, dentry->d_name.len); - if (ret) - goto out; + BUG_ON(ret); if (inode->i_nlink == 0) { ret = btrfs_orphan_add(trans, inode); - if (ret) - goto out; + BUG_ON(ret); } -out: nr = trans->blocks_used; __unlink_end_trans(trans, root); btrfs_btree_balance_dirty(root, nr); @@ -3151,11 +3147,6 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY); - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = -1; - if (root->ref_cows || root == root->fs_info->tree_root) btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); @@ -3168,6 +3159,10 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, if (min_type == 0 && root == BTRFS_I(inode)->root) btrfs_kill_delayed_inode_items(inode); + path = btrfs_alloc_path(); + BUG_ON(!path); + path->reada = -1; + key.objectid = ino; key.offset = (u64)-1; key.type = (u8)-1; @@ -3695,8 +3690,7 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, int ret = 0; path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + BUG_ON(!path); di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(dir), name, namelen, 0); @@ -3952,7 +3946,6 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, struct btrfs_root *root, int *new) { struct inode *inode; - int bad_inode = 0; inode = btrfs_iget_locked(s, location->objectid, root); if (!inode) @@ -3962,19 +3955,10 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, BTRFS_I(inode)->root = root; memcpy(&BTRFS_I(inode)->location, location, sizeof(*location)); btrfs_read_locked_inode(inode); - if (!is_bad_inode(inode)) { - inode_tree_add(inode); - unlock_new_inode(inode); - if (new) - *new = 1; - } else { - bad_inode = 1; - } - } - - if (bad_inode) { - iput(inode); - inode = ERR_PTR(-ESTALE); + inode_tree_add(inode); + unlock_new_inode(inode); + if (new) + *new = 1; } return inode; @@ -4009,19 +3993,12 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) struct btrfs_root *sub_root = root; struct btrfs_key location; int index; - int ret = 0; + int ret; if (dentry->d_name.len > BTRFS_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); - if (unlikely(d_need_lookup(dentry))) { - memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key)); - kfree(dentry->d_fsdata); - dentry->d_fsdata = NULL; - d_clear_need_lookup(dentry); - } else { - ret = btrfs_inode_by_name(dir, dentry, &location); - } + ret = btrfs_inode_by_name(dir, dentry, &location); if (ret < 0) return ERR_PTR(ret); @@ -4076,12 +4053,6 @@ static int btrfs_dentry_delete(const struct dentry *dentry) return 0; } -static void btrfs_dentry_release(struct dentry *dentry) -{ - if (dentry->d_fsdata) - kfree(dentry->d_fsdata); -} - static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { @@ -4104,7 +4075,6 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, struct btrfs_path *path; struct list_head ins_list; struct list_head del_list; - struct qstr q; int ret; struct extent_buffer *leaf; int slot; @@ -4194,7 +4164,6 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, while (di_cur < di_total) { struct btrfs_key location; - struct dentry *tmp; if (verify_dir_item(root, leaf, di)) break; @@ -4215,33 +4184,6 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; btrfs_dir_item_key_to_cpu(leaf, di, &location); - q.name = name_ptr; - q.len = name_len; - q.hash = full_name_hash(q.name, q.len); - tmp = d_lookup(filp->f_dentry, &q); - if (!tmp) { - struct btrfs_key *newkey; - - newkey = kzalloc(sizeof(struct btrfs_key), - GFP_NOFS); - if (!newkey) - goto no_dentry; - tmp = d_alloc(filp->f_dentry, &q); - if (!tmp) { - kfree(newkey); - dput(tmp); - goto no_dentry; - } - memcpy(newkey, &location, - sizeof(struct btrfs_key)); - tmp->d_fsdata = newkey; - tmp->d_flags |= DCACHE_NEED_LOOKUP; - d_rehash(tmp); - dput(tmp); - } else { - dput(tmp); - } -no_dentry: /* is this a reference to our own snapshot? If so * skip it */ @@ -4467,8 +4409,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, int owner; path = btrfs_alloc_path(); - if (!path) - return ERR_PTR(-ENOMEM); + BUG_ON(!path); inode = new_inode(root->fs_info->sb); if (!inode) { @@ -6728,6 +6669,19 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, return 0; } +/* helper function for file defrag and space balancing. This + * forces readahead on a given range of bytes in an inode + */ +unsigned long btrfs_force_ra(struct address_space *mapping, + struct file_ra_state *ra, struct file *file, + pgoff_t offset, pgoff_t last_index) +{ + pgoff_t req_size = last_index - offset + 1; + + page_cache_sync_readahead(mapping, ra, file, offset, req_size); + return offset + req_size; +} + struct inode *btrfs_alloc_inode(struct super_block *sb) { struct btrfs_inode *ei; @@ -7210,11 +7164,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, goto out_unlock; path = btrfs_alloc_path(); - if (!path) { - err = -ENOMEM; - drop_inode = 1; - goto out_unlock; - } + BUG_ON(!path); key.objectid = btrfs_ino(inode); key.offset = 0; btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); @@ -7480,5 +7430,4 @@ static const struct inode_operations btrfs_symlink_inode_operations = { const struct dentry_operations btrfs_dentry_operations = { .d_delete = btrfs_dentry_delete, - .d_release = btrfs_dentry_release, }; diff --git a/trunk/fs/btrfs/ioctl.c b/trunk/fs/btrfs/ioctl.c index 7cf013349941..0b980afc5edd 100644 --- a/trunk/fs/btrfs/ioctl.c +++ b/trunk/fs/btrfs/ioctl.c @@ -1749,10 +1749,11 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, key.objectid = key.offset; key.offset = (u64)-1; dirid = key.objectid; + } if (ptr < name) goto out; - memmove(name, ptr, total_len); + memcpy(name, ptr, total_len); name[total_len]='\0'; ret = 0; out: diff --git a/trunk/fs/btrfs/ref-cache.c b/trunk/fs/btrfs/ref-cache.c new file mode 100644 index 000000000000..82d569cb6267 --- /dev/null +++ b/trunk/fs/btrfs/ref-cache.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008 Oracle. 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 v2 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., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include +#include +#include +#include "ctree.h" +#include "ref-cache.h" +#include "transaction.h" + +static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr, + struct rb_node *node) +{ + struct rb_node **p = &root->rb_node; + struct rb_node *parent = NULL; + struct btrfs_leaf_ref *entry; + + while (*p) { + parent = *p; + entry = rb_entry(parent, struct btrfs_leaf_ref, rb_node); + + if (bytenr < entry->bytenr) + p = &(*p)->rb_left; + else if (bytenr > entry->bytenr) + p = &(*p)->rb_right; + else + return parent; + } + + entry = rb_entry(node, struct btrfs_leaf_ref, rb_node); + rb_link_node(node, parent, p); + rb_insert_color(node, root); + return NULL; +} + +static struct rb_node *tree_search(struct rb_root *root, u64 bytenr) +{ + struct rb_node *n = root->rb_node; + struct btrfs_leaf_ref *entry; + + while (n) { + entry = rb_entry(n, struct btrfs_leaf_ref, rb_node); + WARN_ON(!entry->in_tree); + + if (bytenr < entry->bytenr) + n = n->rb_left; + else if (bytenr > entry->bytenr) + n = n->rb_right; + else + return n; + } + return NULL; +} diff --git a/trunk/fs/btrfs/ref-cache.h b/trunk/fs/btrfs/ref-cache.h new file mode 100644 index 000000000000..24f7001f6387 --- /dev/null +++ b/trunk/fs/btrfs/ref-cache.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 Oracle. 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 v2 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., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ +#ifndef __REFCACHE__ +#define __REFCACHE__ + +struct btrfs_extent_info { + /* bytenr and num_bytes find the extent in the extent allocation tree */ + u64 bytenr; + u64 num_bytes; + + /* objectid and offset find the back reference for the file */ + u64 objectid; + u64 offset; +}; + +struct btrfs_leaf_ref { + struct rb_node rb_node; + struct btrfs_leaf_ref_tree *tree; + int in_tree; + atomic_t usage; + + u64 root_gen; + u64 bytenr; + u64 owner; + u64 generation; + int nritems; + + struct list_head list; + struct btrfs_extent_info extents[]; +}; + +static inline size_t btrfs_leaf_ref_size(int nr_extents) +{ + return sizeof(struct btrfs_leaf_ref) + + sizeof(struct btrfs_extent_info) * nr_extents; +} +#endif diff --git a/trunk/fs/btrfs/root-tree.c b/trunk/fs/btrfs/root-tree.c index f4099904565a..ebe45443de06 100644 --- a/trunk/fs/btrfs/root-tree.c +++ b/trunk/fs/btrfs/root-tree.c @@ -71,12 +71,13 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, return ret; } -void btrfs_set_root_node(struct btrfs_root_item *item, - struct extent_buffer *node) +int btrfs_set_root_node(struct btrfs_root_item *item, + struct extent_buffer *node) { btrfs_set_root_bytenr(item, node->start); btrfs_set_root_level(item, btrfs_header_level(node)); btrfs_set_root_generation(item, btrfs_header_generation(node)); + return 0; } /* diff --git a/trunk/fs/btrfs/transaction.c b/trunk/fs/btrfs/transaction.c index 7dc36fab4afc..eb55863bb4ae 100644 --- a/trunk/fs/btrfs/transaction.c +++ b/trunk/fs/btrfs/transaction.c @@ -216,11 +216,17 @@ static void wait_current_trans(struct btrfs_root *root) spin_lock(&root->fs_info->trans_lock); cur_trans = root->fs_info->running_transaction; if (cur_trans && cur_trans->blocked) { + DEFINE_WAIT(wait); atomic_inc(&cur_trans->use_count); spin_unlock(&root->fs_info->trans_lock); - - wait_event(root->fs_info->transaction_wait, - !cur_trans->blocked); + while (1) { + prepare_to_wait(&root->fs_info->transaction_wait, &wait, + TASK_UNINTERRUPTIBLE); + if (!cur_trans->blocked) + break; + schedule(); + } + finish_wait(&root->fs_info->transaction_wait, &wait); put_transaction(cur_trans); } else { spin_unlock(&root->fs_info->trans_lock); @@ -351,10 +357,19 @@ struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root } /* wait for a transaction commit to be fully complete */ -static noinline void wait_for_commit(struct btrfs_root *root, +static noinline int wait_for_commit(struct btrfs_root *root, struct btrfs_transaction *commit) { - wait_event(commit->commit_wait, commit->commit_done); + DEFINE_WAIT(wait); + while (!commit->commit_done) { + prepare_to_wait(&commit->commit_wait, &wait, + TASK_UNINTERRUPTIBLE); + if (commit->commit_done) + break; + schedule(); + } + finish_wait(&commit->commit_wait, &wait); + return 0; } int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) @@ -1070,7 +1085,22 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info) static void wait_current_trans_commit_start(struct btrfs_root *root, struct btrfs_transaction *trans) { - wait_event(root->fs_info->transaction_blocked_wait, trans->in_commit); + DEFINE_WAIT(wait); + + if (trans->in_commit) + return; + + while (1) { + prepare_to_wait(&root->fs_info->transaction_blocked_wait, &wait, + TASK_UNINTERRUPTIBLE); + if (trans->in_commit) { + finish_wait(&root->fs_info->transaction_blocked_wait, + &wait); + break; + } + schedule(); + finish_wait(&root->fs_info->transaction_blocked_wait, &wait); + } } /* @@ -1080,8 +1110,24 @@ static void wait_current_trans_commit_start(struct btrfs_root *root, static void wait_current_trans_commit_start_and_unblock(struct btrfs_root *root, struct btrfs_transaction *trans) { - wait_event(root->fs_info->transaction_wait, - trans->commit_done || (trans->in_commit && !trans->blocked)); + DEFINE_WAIT(wait); + + if (trans->commit_done || (trans->in_commit && !trans->blocked)) + return; + + while (1) { + prepare_to_wait(&root->fs_info->transaction_wait, &wait, + TASK_UNINTERRUPTIBLE); + if (trans->commit_done || + (trans->in_commit && !trans->blocked)) { + finish_wait(&root->fs_info->transaction_wait, + &wait); + break; + } + schedule(); + finish_wait(&root->fs_info->transaction_wait, + &wait); + } } /* @@ -1188,7 +1234,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, atomic_inc(&cur_trans->use_count); btrfs_end_transaction(trans, root); - wait_for_commit(root, cur_trans); + ret = wait_for_commit(root, cur_trans); + BUG_ON(ret); put_transaction(cur_trans); diff --git a/trunk/fs/btrfs/tree-log.c b/trunk/fs/btrfs/tree-log.c index babee65f8eda..ac278dd83175 100644 --- a/trunk/fs/btrfs/tree-log.c +++ b/trunk/fs/btrfs/tree-log.c @@ -1617,8 +1617,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, return 0; path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + BUG_ON(!path); nritems = btrfs_header_nritems(eb); for (i = 0; i < nritems; i++) { @@ -1724,9 +1723,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, return -ENOMEM; if (*level == 1) { - ret = wc->process_func(root, next, wc, ptr_gen); - if (ret) - return ret; + wc->process_func(root, next, wc, ptr_gen); path->slots[*level]++; if (wc->free) { @@ -1791,11 +1788,8 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, parent = path->nodes[*level + 1]; root_owner = btrfs_header_owner(parent); - ret = wc->process_func(root, path->nodes[*level], wc, + wc->process_func(root, path->nodes[*level], wc, btrfs_header_generation(path->nodes[*level])); - if (ret) - return ret; - if (wc->free) { struct extent_buffer *next; diff --git a/trunk/fs/btrfs/volumes.c b/trunk/fs/btrfs/volumes.c index 53875ae73ad4..b89e372c7544 100644 --- a/trunk/fs/btrfs/volumes.c +++ b/trunk/fs/btrfs/volumes.c @@ -1037,8 +1037,7 @@ static noinline int find_next_chunk(struct btrfs_root *root, struct btrfs_key found_key; path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + BUG_ON(!path); key.objectid = objectid; key.offset = (u64)-1; @@ -2062,10 +2061,8 @@ int btrfs_balance(struct btrfs_root *dev_root) /* step two, relocate all the chunks */ path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto error; - } + BUG_ON(!path); + key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; key.offset = (u64)-1; key.type = BTRFS_CHUNK_ITEM_KEY; @@ -2664,8 +2661,7 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans, ret = find_next_chunk(fs_info->chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID, &chunk_offset); - if (ret) - return ret; + BUG_ON(ret); alloc_profile = BTRFS_BLOCK_GROUP_METADATA | (fs_info->metadata_alloc_profile & diff --git a/trunk/fs/cifs/sess.c b/trunk/fs/cifs/sess.c index 243d58720513..d3e619692ee0 100644 --- a/trunk/fs/cifs/sess.c +++ b/trunk/fs/cifs/sess.c @@ -124,8 +124,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB) /* that we use in next few lines */ /* Note that header is initialized to zero in header_assemble */ pSMB->req.AndXCommand = 0xFF; - pSMB->req.MaxBufferSize = cpu_to_le16(min_t(u32, CIFSMaxBufSize - 4, - USHRT_MAX)); + pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); pSMB->req.VcNumber = get_next_vcnum(ses); diff --git a/trunk/fs/dcache.c b/trunk/fs/dcache.c index c83cae19161e..b05aac3a8cfc 100644 --- a/trunk/fs/dcache.c +++ b/trunk/fs/dcache.c @@ -301,27 +301,6 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) return parent; } -/* - * Unhash a dentry without inserting an RCU walk barrier or checking that - * dentry->d_lock is locked. The caller must take care of that, if - * appropriate. - */ -static void __d_shrink(struct dentry *dentry) -{ - if (!d_unhashed(dentry)) { - struct hlist_bl_head *b; - if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) - b = &dentry->d_sb->s_anon; - else - b = d_hash(dentry->d_parent, dentry->d_name.hash); - - hlist_bl_lock(b); - __hlist_bl_del(&dentry->d_hash); - dentry->d_hash.pprev = NULL; - hlist_bl_unlock(b); - } -} - /** * d_drop - drop a dentry * @dentry: dentry to drop @@ -340,7 +319,17 @@ static void __d_shrink(struct dentry *dentry) void __d_drop(struct dentry *dentry) { if (!d_unhashed(dentry)) { - __d_shrink(dentry); + struct hlist_bl_head *b; + if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) + b = &dentry->d_sb->s_anon; + else + b = d_hash(dentry->d_parent, dentry->d_name.hash); + + hlist_bl_lock(b); + __hlist_bl_del(&dentry->d_hash); + dentry->d_hash.pprev = NULL; + hlist_bl_unlock(b); + dentry_rcuwalk_barrier(dentry); } } @@ -795,7 +784,6 @@ static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) /** * prune_dcache_sb - shrink the dcache - * @sb: superblock * @nr_to_scan: number of entries to try to free * * Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is @@ -840,24 +828,44 @@ EXPORT_SYMBOL(shrink_dcache_sb); static void shrink_dcache_for_umount_subtree(struct dentry *dentry) { struct dentry *parent; + unsigned detached = 0; BUG_ON(!IS_ROOT(dentry)); + /* detach this root from the system */ + spin_lock(&dentry->d_lock); + dentry_lru_del(dentry); + __d_drop(dentry); + spin_unlock(&dentry->d_lock); + for (;;) { /* descend to the first leaf in the current subtree */ - while (!list_empty(&dentry->d_subdirs)) + while (!list_empty(&dentry->d_subdirs)) { + struct dentry *loop; + + /* this is a branch with children - detach all of them + * from the system in one go */ + spin_lock(&dentry->d_lock); + list_for_each_entry(loop, &dentry->d_subdirs, + d_u.d_child) { + spin_lock_nested(&loop->d_lock, + DENTRY_D_LOCK_NESTED); + dentry_lru_del(loop); + __d_drop(loop); + spin_unlock(&loop->d_lock); + } + spin_unlock(&dentry->d_lock); + + /* move to the first child */ dentry = list_entry(dentry->d_subdirs.next, struct dentry, d_u.d_child); + } /* consume the dentries from this leaf up through its parents * until we find one with children or run out altogether */ do { struct inode *inode; - /* detach from the system */ - dentry_lru_del(dentry); - __d_shrink(dentry); - if (dentry->d_count != 0) { printk(KERN_ERR "BUG: Dentry %p{i=%lx,n=%s}" @@ -878,10 +886,14 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) list_del(&dentry->d_u.d_child); } else { parent = dentry->d_parent; + spin_lock(&parent->d_lock); parent->d_count--; list_del(&dentry->d_u.d_child); + spin_unlock(&parent->d_lock); } + detached++; + inode = dentry->d_inode; if (inode) { dentry->d_inode = NULL; @@ -926,7 +938,9 @@ void shrink_dcache_for_umount(struct super_block *sb) dentry = sb->s_root; sb->s_root = NULL; + spin_lock(&dentry->d_lock); dentry->d_count--; + spin_unlock(&dentry->d_lock); shrink_dcache_for_umount_subtree(dentry); while (!hlist_bl_empty(&sb->s_anon)) { diff --git a/trunk/fs/ext2/acl.c b/trunk/fs/ext2/acl.c index 35d6a3cfd9ff..52c053763942 100644 --- a/trunk/fs/ext2/acl.c +++ b/trunk/fs/ext2/acl.c @@ -194,10 +194,12 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) case ACL_TYPE_ACCESS: name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); + mode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { + inode->i_mode = mode; inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); if (error == 0) @@ -251,14 +253,16 @@ ext2_init_acl(struct inode *inode, struct inode *dir) inode->i_mode &= ~current_umask(); } if (test_opt(inode->i_sb, POSIX_ACL) && acl) { + mode_t mode = inode->i_mode; if (S_ISDIR(inode->i_mode)) { error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl); if (error) goto cleanup; } - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); + error = posix_acl_create(&acl, GFP_KERNEL, &mode); if (error < 0) return error; + inode->i_mode = mode; if (error > 0) { /* This is an extended ACL */ error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); diff --git a/trunk/fs/ext3/acl.c b/trunk/fs/ext3/acl.c index 3091f62e55b6..6c29bf0df04a 100644 --- a/trunk/fs/ext3/acl.c +++ b/trunk/fs/ext3/acl.c @@ -199,10 +199,12 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); + mode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { + inode->i_mode = mode; inode->i_ctime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); if (error == 0) @@ -259,16 +261,19 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) inode->i_mode &= ~current_umask(); } if (test_opt(inode->i_sb, POSIX_ACL) && acl) { + mode_t mode = inode->i_mode; + if (S_ISDIR(inode->i_mode)) { error = ext3_set_acl(handle, inode, ACL_TYPE_DEFAULT, acl); if (error) goto cleanup; } - error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + error = posix_acl_create(&acl, GFP_NOFS, &mode); if (error < 0) return error; + inode->i_mode = mode; if (error > 0) { /* This is an extended ACL */ error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); diff --git a/trunk/fs/ext4/Makefile b/trunk/fs/ext4/Makefile index 56fd8f865930..04109460ba9e 100644 --- a/trunk/fs/ext4/Makefile +++ b/trunk/fs/ext4/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_EXT4_FS) += ext4.o ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \ ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \ - mmp.o indirect.o + mmp.o ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o diff --git a/trunk/fs/ext4/acl.c b/trunk/fs/ext4/acl.c index a5c29bb3b835..dca2d1ded931 100644 --- a/trunk/fs/ext4/acl.c +++ b/trunk/fs/ext4/acl.c @@ -198,10 +198,12 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, case ACL_TYPE_ACCESS: name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); + mode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { + inode->i_mode = mode; inode->i_ctime = ext4_current_time(inode); ext4_mark_inode_dirty(handle, inode); if (error == 0) @@ -257,16 +259,19 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) inode->i_mode &= ~current_umask(); } if (test_opt(inode->i_sb, POSIX_ACL) && acl) { + mode_t mode = inode->i_mode; + if (S_ISDIR(inode->i_mode)) { error = ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT, acl); if (error) goto cleanup; } - error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + error = posix_acl_create(&acl, GFP_NOFS, &mode); if (error < 0) return error; + inode->i_mode = mode; if (error > 0) { /* This is an extended ACL */ error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); diff --git a/trunk/fs/ext4/balloc.c b/trunk/fs/ext4/balloc.c index f8224adf496e..264f6949511e 100644 --- a/trunk/fs/ext4/balloc.c +++ b/trunk/fs/ext4/balloc.c @@ -620,51 +620,3 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group) } -/** - * ext4_inode_to_goal_block - return a hint for block allocation - * @inode: inode for block allocation - * - * Return the ideal location to start allocating blocks for a - * newly created inode. - */ -ext4_fsblk_t ext4_inode_to_goal_block(struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - ext4_group_t block_group; - ext4_grpblk_t colour; - int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb)); - ext4_fsblk_t bg_start; - ext4_fsblk_t last_block; - - block_group = ei->i_block_group; - if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) { - /* - * If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME - * block groups per flexgroup, reserve the first block - * group for directories and special files. Regular - * files will start at the second block group. This - * tends to speed up directory access and improves - * fsck times. - */ - block_group &= ~(flex_size-1); - if (S_ISREG(inode->i_mode)) - block_group++; - } - bg_start = ext4_group_first_block_no(inode->i_sb, block_group); - last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1; - - /* - * If we are doing delayed allocation, we don't need take - * colour into account. - */ - if (test_opt(inode->i_sb, DELALLOC)) - return bg_start; - - if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block) - colour = (current->pid % 16) * - (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16); - else - colour = (current->pid % 16) * ((last_block - bg_start) / 16); - return bg_start + colour; -} - diff --git a/trunk/fs/ext4/block_validity.c b/trunk/fs/ext4/block_validity.c index 8efb2f0a3447..fac90f3fba80 100644 --- a/trunk/fs/ext4/block_validity.c +++ b/trunk/fs/ext4/block_validity.c @@ -246,24 +246,3 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, return 1; } -int ext4_check_blockref(const char *function, unsigned int line, - struct inode *inode, __le32 *p, unsigned int max) -{ - struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; - __le32 *bref = p; - unsigned int blk; - - while (bref < p+max) { - blk = le32_to_cpu(*bref++); - if (blk && - unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), - blk, 1))) { - es->s_last_error_block = cpu_to_le64(blk); - ext4_error_inode(inode, function, line, blk, - "invalid block"); - return -EIO; - } - } - return 0; -} - diff --git a/trunk/fs/ext4/ext4.h b/trunk/fs/ext4/ext4.h index e717dfd2f2b4..fa44df879711 100644 --- a/trunk/fs/ext4/ext4.h +++ b/trunk/fs/ext4/ext4.h @@ -526,7 +526,6 @@ struct ext4_new_group_data { #define EXT4_FREE_BLOCKS_METADATA 0x0001 #define EXT4_FREE_BLOCKS_FORGET 0x0002 #define EXT4_FREE_BLOCKS_VALIDATED 0x0004 -#define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008 /* * ioctl commands @@ -940,8 +939,6 @@ struct ext4_inode_info { #define ext4_find_next_zero_bit find_next_zero_bit_le #define ext4_find_next_bit find_next_bit_le -extern void ext4_set_bits(void *bm, int cur, int len); - /* * Maximal mount counts between two filesystem checks */ @@ -1129,8 +1126,7 @@ struct ext4_sb_info { struct journal_s *s_journal; struct list_head s_orphan; struct mutex s_orphan_lock; - unsigned long s_resize_flags; /* Flags indicating if there - is a resizer */ + struct mutex s_resize_lock; unsigned long s_commit_interval; u32 s_max_batch_time; u32 s_min_batch_time; @@ -1218,9 +1214,6 @@ struct ext4_sb_info { /* Kernel thread for multiple mount protection */ struct task_struct *s_mmp_tsk; - - /* record the last minlen when FITRIM is called. */ - atomic_t s_last_trim_minblks; }; static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) @@ -1750,7 +1743,6 @@ extern unsigned ext4_init_block_bitmap(struct super_block *sb, struct ext4_group_desc *desc); #define ext4_free_blocks_after_init(sb, group, desc) \ ext4_init_block_bitmap(sb, NULL, group, desc) -ext4_fsblk_t ext4_inode_to_goal_block(struct inode *); /* dir.c */ extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, @@ -1801,7 +1793,7 @@ extern void ext4_free_blocks(handle_t *handle, struct inode *inode, unsigned long count, int flags); extern int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t i, struct ext4_group_desc *desc); -extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, +extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, ext4_fsblk_t block, unsigned long count); extern int ext4_trim_fs(struct super_block *, struct fstrim_range *); @@ -1842,17 +1834,6 @@ extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); extern qsize_t *ext4_get_reserved_space(struct inode *inode); extern void ext4_da_update_reserve_space(struct inode *inode, int used, int quota_claim); - -/* indirect.c */ -extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, int flags); -extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs); -extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock); -extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk); -extern void ext4_ind_truncate(struct inode *inode); - /* ioctl.c */ extern long ext4_ioctl(struct file *, unsigned int, unsigned long); extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); @@ -1874,9 +1855,6 @@ extern int ext4_group_extend(struct super_block *sb, ext4_fsblk_t n_blocks_count); /* super.c */ -extern void *ext4_kvmalloc(size_t size, gfp_t flags); -extern void *ext4_kvzalloc(size_t size, gfp_t flags); -extern void ext4_kvfree(void *ptr); extern void __ext4_error(struct super_block *, const char *, unsigned int, const char *, ...) __attribute__ ((format (printf, 4, 5))); @@ -2089,19 +2067,11 @@ struct ext4_group_info { * 5 free 8-block regions. */ }; -#define EXT4_GROUP_INFO_NEED_INIT_BIT 0 -#define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1 +#define EXT4_GROUP_INFO_NEED_INIT_BIT 0 #define EXT4_MB_GRP_NEED_INIT(grp) \ (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) -#define EXT4_MB_GRP_WAS_TRIMMED(grp) \ - (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) -#define EXT4_MB_GRP_SET_TRIMMED(grp) \ - (set_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) -#define EXT4_MB_GRP_CLEAR_TRIMMED(grp) \ - (clear_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) - #define EXT4_MAX_CONTENTION 8 #define EXT4_CONTENTION_THRESHOLD 2 @@ -2152,19 +2122,6 @@ static inline void ext4_mark_super_dirty(struct super_block *sb) sb->s_dirt =1; } -/* - * Block validity checking - */ -#define ext4_check_indirect_blockref(inode, bh) \ - ext4_check_blockref(__func__, __LINE__, inode, \ - (__le32 *)(bh)->b_data, \ - EXT4_ADDR_PER_BLOCK((inode)->i_sb)) - -#define ext4_ind_check_inode(inode) \ - ext4_check_blockref(__func__, __LINE__, inode, \ - EXT4_I(inode)->i_data, \ - EXT4_NDIR_BLOCKS) - /* * Inodes and files operations */ @@ -2194,8 +2151,6 @@ extern void ext4_exit_system_zone(void); extern int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, unsigned int count); -extern int ext4_check_blockref(const char *, unsigned int, - struct inode *, __le32 *, unsigned int); /* extents.c */ extern int ext4_ext_tree_init(handle_t *handle, struct inode *); @@ -2275,10 +2230,6 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh) extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ]; -#define EXT4_RESIZING 0 -extern int ext4_resize_begin(struct super_block *sb); -extern void ext4_resize_end(struct super_block *sb); - #endif /* __KERNEL__ */ #endif /* _EXT4_H */ diff --git a/trunk/fs/ext4/extents.c b/trunk/fs/ext4/extents.c index 57cf568a98ab..f815cc81e7a2 100644 --- a/trunk/fs/ext4/extents.c +++ b/trunk/fs/ext4/extents.c @@ -114,6 +114,12 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode, struct ext4_ext_path *path, ext4_lblk_t block) { + struct ext4_inode_info *ei = EXT4_I(inode); + ext4_fsblk_t bg_start; + ext4_fsblk_t last_block; + ext4_grpblk_t colour; + ext4_group_t block_group; + int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb)); int depth; if (path) { @@ -155,7 +161,36 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode, } /* OK. use inode's group */ - return ext4_inode_to_goal_block(inode); + block_group = ei->i_block_group; + if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) { + /* + * If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME + * block groups per flexgroup, reserve the first block + * group for directories and special files. Regular + * files will start at the second block group. This + * tends to speed up directory access and improves + * fsck times. + */ + block_group &= ~(flex_size-1); + if (S_ISREG(inode->i_mode)) + block_group++; + } + bg_start = ext4_group_first_block_no(inode->i_sb, block_group); + last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1; + + /* + * If we are doing delayed allocation, we don't need take + * colour into account. + */ + if (test_opt(inode->i_sb, DELALLOC)) + return bg_start; + + if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block) + colour = (current->pid % 16) * + (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16); + else + colour = (current->pid % 16) * ((last_block - bg_start) / 16); + return bg_start + colour + block; } /* @@ -741,16 +776,6 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, logical, le32_to_cpu(curp->p_idx->ei_block)); return -EIO; } - - if (unlikely(le16_to_cpu(curp->p_hdr->eh_entries) - >= le16_to_cpu(curp->p_hdr->eh_max))) { - EXT4_ERROR_INODE(inode, - "eh_entries %d >= eh_max %d!", - le16_to_cpu(curp->p_hdr->eh_entries), - le16_to_cpu(curp->p_hdr->eh_max)); - return -EIO; - } - len = EXT_MAX_INDEX(curp->p_hdr) - curp->p_idx; if (logical > le32_to_cpu(curp->p_idx->ei_block)) { /* insert after */ @@ -780,6 +805,13 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, ext4_idx_store_pblock(ix, ptr); le16_add_cpu(&curp->p_hdr->eh_entries, 1); + if (unlikely(le16_to_cpu(curp->p_hdr->eh_entries) + > le16_to_cpu(curp->p_hdr->eh_max))) { + EXT4_ERROR_INODE(inode, + "logical %d == ei_block %d!", + logical, le32_to_cpu(curp->p_idx->ei_block)); + return -EIO; + } if (unlikely(ix > EXT_LAST_INDEX(curp->p_hdr))) { EXT4_ERROR_INODE(inode, "ix > EXT_LAST_INDEX!"); return -EIO; @@ -1414,7 +1446,8 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) * ext4_ext_next_leaf_block: * returns first allocated block from next leaf or EXT_MAX_BLOCKS */ -static ext4_lblk_t ext4_ext_next_leaf_block(struct ext4_ext_path *path) +static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode, + struct ext4_ext_path *path) { int depth; @@ -1724,6 +1757,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, goto merge; } +repeat: depth = ext_depth(inode); eh = path[depth].p_hdr; if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) @@ -1731,10 +1765,9 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, /* probably next leaf has space for us? */ fex = EXT_LAST_EXTENT(eh); - next = EXT_MAX_BLOCKS; - if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block)) - next = ext4_ext_next_leaf_block(path); - if (next != EXT_MAX_BLOCKS) { + next = ext4_ext_next_leaf_block(inode, path); + if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block) + && next != EXT_MAX_BLOCKS) { ext_debug("next leaf block - %d\n", next); BUG_ON(npath != NULL); npath = ext4_ext_find_extent(inode, next, NULL); @@ -1746,7 +1779,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, ext_debug("next leaf isn't full(%d)\n", le16_to_cpu(eh->eh_entries)); path = npath; - goto has_space; + goto repeat; } ext_debug("next leaf has no free space(%d,%d)\n", le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); @@ -1806,7 +1839,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, ext4_ext_pblock(newext), ext4_ext_is_uninitialized(newext), ext4_ext_get_actual_len(newext), - nearex, len, nearex, nearex + 1); + nearex, len, nearex + 1, nearex + 2); memmove(nearex + 1, nearex, len); path[depth].p_ext = nearex; } @@ -2019,7 +2052,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path, } /* - * ext4_ext_check_cache() + * ext4_ext_in_cache() * Checks to see if the given block is in the cache. * If it is, the cached extent is stored in the given * cache extent pointer. If the cached extent is a hole, @@ -2101,6 +2134,8 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block, /* * ext4_ext_rm_idx: * removes index from the index block. + * It's used in truncate case only, thus all requests are for + * last index in the block only. */ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, struct ext4_ext_path *path) @@ -2118,13 +2153,6 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, err = ext4_ext_get_access(handle, inode, path); if (err) return err; - - if (path->p_idx != EXT_LAST_INDEX(path->p_hdr)) { - int len = EXT_LAST_INDEX(path->p_hdr) - path->p_idx; - len *= sizeof(struct ext4_extent_idx); - memmove(path->p_idx, path->p_idx + 1, len); - } - le16_add_cpu(&path->p_hdr->eh_entries, -1); err = ext4_ext_dirty(handle, inode, path); if (err) @@ -2506,7 +2534,8 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path) return 1; } -static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) +static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, + ext4_lblk_t end) { struct super_block *sb = inode->i_sb; int depth = ext_depth(inode); @@ -2546,7 +2575,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) if (i == depth) { /* this is leaf block */ err = ext4_ext_rm_leaf(handle, inode, path, - start, EXT_MAX_BLOCKS - 1); + start, end); /* root level has p_bh == NULL, brelse() eats this */ brelse(path[i].p_bh); path[i].p_bh = NULL; @@ -3078,10 +3107,12 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle, struct ext4_ext_path *path) { struct ext4_extent *ex; + struct ext4_extent_header *eh; int depth; int err = 0; depth = ext_depth(inode); + eh = path[depth].p_hdr; ex = path[depth].p_ext; ext_debug("ext4_convert_unwritten_extents_endio: inode %lu, logical" @@ -3326,8 +3357,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); /* check in cache */ - if (!(flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) && - ext4_ext_in_cache(inode, map->m_lblk, &newex)) { + if (ext4_ext_in_cache(inode, map->m_lblk, &newex) && + ((flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) == 0)) { if (!newex.ee_start_lo && !newex.ee_start_hi) { if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { /* @@ -3466,27 +3497,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ext4_ext_mark_uninitialized(ex); - ext4_ext_invalidate_cache(inode); - - err = ext4_ext_rm_leaf(handle, inode, path, - map->m_lblk, map->m_lblk + punched_out); - - if (!err && path->p_hdr->eh_entries == 0) { - /* - * Punch hole freed all of this sub tree, - * so we need to correct eh_depth - */ - err = ext4_ext_get_access(handle, inode, path); - if (err == 0) { - ext_inode_hdr(inode)->eh_depth = 0; - ext_inode_hdr(inode)->eh_max = - cpu_to_le16(ext4_ext_space_root( - inode, 0)); - - err = ext4_ext_dirty( - handle, inode, path); - } - } + err = ext4_ext_remove_space(inode, map->m_lblk, + map->m_lblk + punched_out); goto out2; } @@ -3584,18 +3596,17 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, } err = check_eofblocks_fl(handle, inode, map->m_lblk, path, ar.len); - if (!err) - err = ext4_ext_insert_extent(handle, inode, path, - &newex, flags); + if (err) + goto out2; + + err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); if (err) { - int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ? - EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0; /* free data blocks we just allocated */ /* not a good idea to call discard here directly, * but otherwise we'd need to call it every free() */ ext4_discard_preallocations(inode); ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex), - ext4_ext_get_actual_len(&newex), fb_flags); + ext4_ext_get_actual_len(&newex), 0); goto out2; } @@ -3688,7 +3699,7 @@ void ext4_ext_truncate(struct inode *inode) last_block = (inode->i_size + sb->s_blocksize - 1) >> EXT4_BLOCK_SIZE_BITS(sb); - err = ext4_ext_remove_space(inode, last_block); + err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1); /* In a multi-transaction truncate, we only make the final * transaction synchronous. @@ -3824,7 +3835,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) blkbits) >> blkbits)) new_size = offset + len; else - new_size = ((loff_t) map.m_lblk + ret) << blkbits; + new_size = (map.m_lblk + ret) << blkbits; ext4_falloc_update_inode(inode, mode, new_size, (map.m_flags & EXT4_MAP_NEW)); diff --git a/trunk/fs/ext4/fsync.c b/trunk/fs/ext4/fsync.c index 036f78f7a1ef..da3bed3e0c29 100644 --- a/trunk/fs/ext4/fsync.c +++ b/trunk/fs/ext4/fsync.c @@ -129,30 +129,15 @@ static int ext4_sync_parent(struct inode *inode) { struct writeback_control wbc; struct dentry *dentry = NULL; - struct inode *next; int ret = 0; - if (!ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) - return 0; - inode = igrab(inode); - while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { + while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); - dentry = NULL; - spin_lock(&inode->i_lock); - if (!list_empty(&inode->i_dentry)) { - dentry = list_first_entry(&inode->i_dentry, - struct dentry, d_alias); - dget(dentry); - } - spin_unlock(&inode->i_lock); - if (!dentry) + dentry = list_entry(inode->i_dentry.next, + struct dentry, d_alias); + if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) break; - next = igrab(dentry->d_parent->d_inode); - dput(dentry); - if (!next) - break; - iput(inode); - inode = next; + inode = dentry->d_parent->d_inode; ret = sync_mapping_buffers(inode->i_mapping); if (ret) break; @@ -163,7 +148,6 @@ static int ext4_sync_parent(struct inode *inode) if (ret) break; } - iput(inode); return ret; } diff --git a/trunk/fs/ext4/ialloc.c b/trunk/fs/ext4/ialloc.c index 9c63f273b550..21bb2f61e502 100644 --- a/trunk/fs/ext4/ialloc.c +++ b/trunk/fs/ext4/ialloc.c @@ -1287,7 +1287,7 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, group, used_blks, ext4_itable_unused_count(sb, gdp)); ret = 1; - goto err_out; + goto out; } blk = ext4_inode_table(sb, gdp) + used_blks; diff --git a/trunk/fs/ext4/indirect.c b/trunk/fs/ext4/indirect.c deleted file mode 100644 index b8602cde5b5a..000000000000 --- a/trunk/fs/ext4/indirect.c +++ /dev/null @@ -1,1482 +0,0 @@ -/* - * linux/fs/ext4/indirect.c - * - * from - * - * linux/fs/ext4/inode.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/inode.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Goal-directed block allocation by Stephen Tweedie - * (sct@redhat.com), 1993, 1998 - */ - -#include -#include "ext4_jbd2.h" -#include "truncate.h" - -#include - -typedef struct { - __le32 *p; - __le32 key; - struct buffer_head *bh; -} Indirect; - -static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) -{ - p->key = *(p->p = v); - p->bh = bh; -} - -/** - * ext4_block_to_path - parse the block number into array of offsets - * @inode: inode in question (we are only interested in its superblock) - * @i_block: block number to be parsed - * @offsets: array to store the offsets in - * @boundary: set this non-zero if the referred-to block is likely to be - * followed (on disk) by an indirect block. - * - * To store the locations of file's data ext4 uses a data structure common - * for UNIX filesystems - tree of pointers anchored in the inode, with - * data blocks at leaves and indirect blocks in intermediate nodes. - * This function translates the block number into path in that tree - - * return value is the path length and @offsets[n] is the offset of - * pointer to (n+1)th node in the nth one. If @block is out of range - * (negative or too large) warning is printed and zero returned. - * - * Note: function doesn't find node addresses, so no IO is needed. All - * we need to know is the capacity of indirect blocks (taken from the - * inode->i_sb). - */ - -/* - * Portability note: the last comparison (check that we fit into triple - * indirect block) is spelled differently, because otherwise on an - * architecture with 32-bit longs and 8Kb pages we might get into trouble - * if our filesystem had 8Kb blocks. We might use long long, but that would - * kill us on x86. Oh, well, at least the sign propagation does not matter - - * i_block would have to be negative in the very beginning, so we would not - * get there at all. - */ - -static int ext4_block_to_path(struct inode *inode, - ext4_lblk_t i_block, - ext4_lblk_t offsets[4], int *boundary) -{ - int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb); - int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb); - const long direct_blocks = EXT4_NDIR_BLOCKS, - indirect_blocks = ptrs, - double_blocks = (1 << (ptrs_bits * 2)); - int n = 0; - int final = 0; - - if (i_block < direct_blocks) { - offsets[n++] = i_block; - final = direct_blocks; - } else if ((i_block -= direct_blocks) < indirect_blocks) { - offsets[n++] = EXT4_IND_BLOCK; - offsets[n++] = i_block; - final = ptrs; - } else if ((i_block -= indirect_blocks) < double_blocks) { - offsets[n++] = EXT4_DIND_BLOCK; - offsets[n++] = i_block >> ptrs_bits; - offsets[n++] = i_block & (ptrs - 1); - final = ptrs; - } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { - offsets[n++] = EXT4_TIND_BLOCK; - offsets[n++] = i_block >> (ptrs_bits * 2); - offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); - offsets[n++] = i_block & (ptrs - 1); - final = ptrs; - } else { - ext4_warning(inode->i_sb, "block %lu > max in inode %lu", - i_block + direct_blocks + - indirect_blocks + double_blocks, inode->i_ino); - } - if (boundary) - *boundary = final - 1 - (i_block & (ptrs - 1)); - return n; -} - -/** - * ext4_get_branch - read the chain of indirect blocks leading to data - * @inode: inode in question - * @depth: depth of the chain (1 - direct pointer, etc.) - * @offsets: offsets of pointers in inode/indirect blocks - * @chain: place to store the result - * @err: here we store the error value - * - * Function fills the array of triples and returns %NULL - * if everything went OK or the pointer to the last filled triple - * (incomplete one) otherwise. Upon the return chain[i].key contains - * the number of (i+1)-th block in the chain (as it is stored in memory, - * i.e. little-endian 32-bit), chain[i].p contains the address of that - * number (it points into struct inode for i==0 and into the bh->b_data - * for i>0) and chain[i].bh points to the buffer_head of i-th indirect - * block for i>0 and NULL for i==0. In other words, it holds the block - * numbers of the chain, addresses they were taken from (and where we can - * verify that chain did not change) and buffer_heads hosting these - * numbers. - * - * Function stops when it stumbles upon zero pointer (absent block) - * (pointer to last triple returned, *@err == 0) - * or when it gets an IO error reading an indirect block - * (ditto, *@err == -EIO) - * or when it reads all @depth-1 indirect blocks successfully and finds - * the whole chain, all way to the data (returns %NULL, *err == 0). - * - * Need to be called with - * down_read(&EXT4_I(inode)->i_data_sem) - */ -static Indirect *ext4_get_branch(struct inode *inode, int depth, - ext4_lblk_t *offsets, - Indirect chain[4], int *err) -{ - struct super_block *sb = inode->i_sb; - Indirect *p = chain; - struct buffer_head *bh; - - *err = 0; - /* i_data is not going away, no lock needed */ - add_chain(chain, NULL, EXT4_I(inode)->i_data + *offsets); - if (!p->key) - goto no_block; - while (--depth) { - bh = sb_getblk(sb, le32_to_cpu(p->key)); - if (unlikely(!bh)) - goto failure; - - if (!bh_uptodate_or_lock(bh)) { - if (bh_submit_read(bh) < 0) { - put_bh(bh); - goto failure; - } - /* validate block references */ - if (ext4_check_indirect_blockref(inode, bh)) { - put_bh(bh); - goto failure; - } - } - - add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets); - /* Reader: end */ - if (!p->key) - goto no_block; - } - return NULL; - -failure: - *err = -EIO; -no_block: - return p; -} - -/** - * ext4_find_near - find a place for allocation with sufficient locality - * @inode: owner - * @ind: descriptor of indirect block. - * - * This function returns the preferred place for block allocation. - * It is used when heuristic for sequential allocation fails. - * Rules are: - * + if there is a block to the left of our position - allocate near it. - * + if pointer will live in indirect block - allocate near that block. - * + if pointer will live in inode - allocate in the same - * cylinder group. - * - * In the latter case we colour the starting block by the callers PID to - * prevent it from clashing with concurrent allocations for a different inode - * in the same block group. The PID is used here so that functionally related - * files will be close-by on-disk. - * - * Caller must make sure that @ind is valid and will stay that way. - */ -static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data; - __le32 *p; - - /* Try to find previous block */ - for (p = ind->p - 1; p >= start; p--) { - if (*p) - return le32_to_cpu(*p); - } - - /* No such thing, so let's try location of indirect block */ - if (ind->bh) - return ind->bh->b_blocknr; - - /* - * It is going to be referred to from the inode itself? OK, just put it - * into the same cylinder group then. - */ - return ext4_inode_to_goal_block(inode); -} - -/** - * ext4_find_goal - find a preferred place for allocation. - * @inode: owner - * @block: block we want - * @partial: pointer to the last triple within a chain - * - * Normally this function find the preferred place for block allocation, - * returns it. - * Because this is only used for non-extent files, we limit the block nr - * to 32 bits. - */ -static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, - Indirect *partial) -{ - ext4_fsblk_t goal; - - /* - * XXX need to get goal block from mballoc's data structures - */ - - goal = ext4_find_near(inode, partial); - goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; - return goal; -} - -/** - * ext4_blks_to_allocate - Look up the block map and count the number - * of direct blocks need to be allocated for the given branch. - * - * @branch: chain of indirect blocks - * @k: number of blocks need for indirect blocks - * @blks: number of data blocks to be mapped. - * @blocks_to_boundary: the offset in the indirect block - * - * return the total number of blocks to be allocate, including the - * direct and indirect blocks. - */ -static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, - int blocks_to_boundary) -{ - unsigned int count = 0; - - /* - * Simple case, [t,d]Indirect block(s) has not allocated yet - * then it's clear blocks on that path have not allocated - */ - if (k > 0) { - /* right now we don't handle cross boundary allocation */ - if (blks < blocks_to_boundary + 1) - count += blks; - else - count += blocks_to_boundary + 1; - return count; - } - - count++; - while (count < blks && count <= blocks_to_boundary && - le32_to_cpu(*(branch[0].p + count)) == 0) { - count++; - } - return count; -} - -/** - * ext4_alloc_blocks: multiple allocate blocks needed for a branch - * @handle: handle for this transaction - * @inode: inode which needs allocated blocks - * @iblock: the logical block to start allocated at - * @goal: preferred physical block of allocation - * @indirect_blks: the number of blocks need to allocate for indirect - * blocks - * @blks: number of desired blocks - * @new_blocks: on return it will store the new block numbers for - * the indirect blocks(if needed) and the first direct block, - * @err: on return it will store the error code - * - * This function will return the number of blocks allocated as - * requested by the passed-in parameters. - */ -static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, - ext4_lblk_t iblock, ext4_fsblk_t goal, - int indirect_blks, int blks, - ext4_fsblk_t new_blocks[4], int *err) -{ - struct ext4_allocation_request ar; - int target, i; - unsigned long count = 0, blk_allocated = 0; - int index = 0; - ext4_fsblk_t current_block = 0; - int ret = 0; - - /* - * Here we try to allocate the requested multiple blocks at once, - * on a best-effort basis. - * To build a branch, we should allocate blocks for - * the indirect blocks(if not allocated yet), and at least - * the first direct block of this branch. That's the - * minimum number of blocks need to allocate(required) - */ - /* first we try to allocate the indirect blocks */ - target = indirect_blks; - while (target > 0) { - count = target; - /* allocating blocks for indirect blocks and direct blocks */ - current_block = ext4_new_meta_blocks(handle, inode, goal, - 0, &count, err); - if (*err) - goto failed_out; - - if (unlikely(current_block + count > EXT4_MAX_BLOCK_FILE_PHYS)) { - EXT4_ERROR_INODE(inode, - "current_block %llu + count %lu > %d!", - current_block, count, - EXT4_MAX_BLOCK_FILE_PHYS); - *err = -EIO; - goto failed_out; - } - - target -= count; - /* allocate blocks for indirect blocks */ - while (index < indirect_blks && count) { - new_blocks[index++] = current_block++; - count--; - } - if (count > 0) { - /* - * save the new block number - * for the first direct block - */ - new_blocks[index] = current_block; - printk(KERN_INFO "%s returned more blocks than " - "requested\n", __func__); - WARN_ON(1); - break; - } - } - - target = blks - count ; - blk_allocated = count; - if (!target) - goto allocated; - /* Now allocate data blocks */ - memset(&ar, 0, sizeof(ar)); - ar.inode = inode; - ar.goal = goal; - ar.len = target; - ar.logical = iblock; - if (S_ISREG(inode->i_mode)) - /* enable in-core preallocation only for regular files */ - ar.flags = EXT4_MB_HINT_DATA; - - current_block = ext4_mb_new_blocks(handle, &ar, err); - if (unlikely(current_block + ar.len > EXT4_MAX_BLOCK_FILE_PHYS)) { - EXT4_ERROR_INODE(inode, - "current_block %llu + ar.len %d > %d!", - current_block, ar.len, - EXT4_MAX_BLOCK_FILE_PHYS); - *err = -EIO; - goto failed_out; - } - - if (*err && (target == blks)) { - /* - * if the allocation failed and we didn't allocate - * any blocks before - */ - goto failed_out; - } - if (!*err) { - if (target == blks) { - /* - * save the new block number - * for the first direct block - */ - new_blocks[index] = current_block; - } - blk_allocated += ar.len; - } -allocated: - /* total number of blocks allocated for direct blocks */ - ret = blk_allocated; - *err = 0; - return ret; -failed_out: - for (i = 0; i < index; i++) - ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0); - return ret; -} - -/** - * ext4_alloc_branch - allocate and set up a chain of blocks. - * @handle: handle for this transaction - * @inode: owner - * @indirect_blks: number of allocated indirect blocks - * @blks: number of allocated direct blocks - * @goal: preferred place for allocation - * @offsets: offsets (in the blocks) to store the pointers to next. - * @branch: place to store the chain in. - * - * This function allocates blocks, zeroes out all but the last one, - * links them into chain and (if we are synchronous) writes them to disk. - * In other words, it prepares a branch that can be spliced onto the - * inode. It stores the information about that chain in the branch[], in - * the same format as ext4_get_branch() would do. We are calling it after - * we had read the existing part of chain and partial points to the last - * triple of that (one with zero ->key). Upon the exit we have the same - * picture as after the successful ext4_get_block(), except that in one - * place chain is disconnected - *branch->p is still zero (we did not - * set the last link), but branch->key contains the number that should - * be placed into *branch->p to fill that gap. - * - * If allocation fails we free all blocks we've allocated (and forget - * their buffer_heads) and return the error value the from failed - * ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain - * as described above and return 0. - */ -static int ext4_alloc_branch(handle_t *handle, struct inode *inode, - ext4_lblk_t iblock, int indirect_blks, - int *blks, ext4_fsblk_t goal, - ext4_lblk_t *offsets, Indirect *branch) -{ - int blocksize = inode->i_sb->s_blocksize; - int i, n = 0; - int err = 0; - struct buffer_head *bh; - int num; - ext4_fsblk_t new_blocks[4]; - ext4_fsblk_t current_block; - - num = ext4_alloc_blocks(handle, inode, iblock, goal, indirect_blks, - *blks, new_blocks, &err); - if (err) - return err; - - branch[0].key = cpu_to_le32(new_blocks[0]); - /* - * metadata blocks and data blocks are allocated. - */ - for (n = 1; n <= indirect_blks; n++) { - /* - * Get buffer_head for parent block, zero it out - * and set the pointer to new one, then send - * parent to disk. - */ - bh = sb_getblk(inode->i_sb, new_blocks[n-1]); - if (unlikely(!bh)) { - err = -EIO; - goto failed; - } - - branch[n].bh = bh; - lock_buffer(bh); - BUFFER_TRACE(bh, "call get_create_access"); - err = ext4_journal_get_create_access(handle, bh); - if (err) { - /* Don't brelse(bh) here; it's done in - * ext4_journal_forget() below */ - unlock_buffer(bh); - goto failed; - } - - memset(bh->b_data, 0, blocksize); - branch[n].p = (__le32 *) bh->b_data + offsets[n]; - branch[n].key = cpu_to_le32(new_blocks[n]); - *branch[n].p = branch[n].key; - if (n == indirect_blks) { - current_block = new_blocks[n]; - /* - * End of chain, update the last new metablock of - * the chain to point to the new allocated - * data blocks numbers - */ - for (i = 1; i < num; i++) - *(branch[n].p + i) = cpu_to_le32(++current_block); - } - BUFFER_TRACE(bh, "marking uptodate"); - set_buffer_uptodate(bh); - unlock_buffer(bh); - - BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, inode, bh); - if (err) - goto failed; - } - *blks = num; - return err; -failed: - /* Allocation failed, free what we already allocated */ - ext4_free_blocks(handle, inode, NULL, new_blocks[0], 1, 0); - for (i = 1; i <= n ; i++) { - /* - * branch[i].bh is newly allocated, so there is no - * need to revoke the block, which is why we don't - * need to set EXT4_FREE_BLOCKS_METADATA. - */ - ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, - EXT4_FREE_BLOCKS_FORGET); - } - for (i = n+1; i < indirect_blks; i++) - ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0); - - ext4_free_blocks(handle, inode, NULL, new_blocks[i], num, 0); - - return err; -} - -/** - * ext4_splice_branch - splice the allocated branch onto inode. - * @handle: handle for this transaction - * @inode: owner - * @block: (logical) number of block we are adding - * @chain: chain of indirect blocks (with a missing link - see - * ext4_alloc_branch) - * @where: location of missing link - * @num: number of indirect blocks we are adding - * @blks: number of direct blocks we are adding - * - * This function fills the missing link and does all housekeeping needed in - * inode (->i_blocks, etc.). In case of success we end up with the full - * chain to new block and return 0. - */ -static int ext4_splice_branch(handle_t *handle, struct inode *inode, - ext4_lblk_t block, Indirect *where, int num, - int blks) -{ - int i; - int err = 0; - ext4_fsblk_t current_block; - - /* - * If we're splicing into a [td]indirect block (as opposed to the - * inode) then we need to get write access to the [td]indirect block - * before the splice. - */ - if (where->bh) { - BUFFER_TRACE(where->bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, where->bh); - if (err) - goto err_out; - } - /* That's it */ - - *where->p = where->key; - - /* - * Update the host buffer_head or inode to point to more just allocated - * direct blocks blocks - */ - if (num == 0 && blks > 1) { - current_block = le32_to_cpu(where->key) + 1; - for (i = 1; i < blks; i++) - *(where->p + i) = cpu_to_le32(current_block++); - } - - /* We are done with atomic stuff, now do the rest of housekeeping */ - /* had we spliced it onto indirect block? */ - if (where->bh) { - /* - * If we spliced it onto an indirect block, we haven't - * altered the inode. Note however that if it is being spliced - * onto an indirect block at the very end of the file (the - * file is growing) then we *will* alter the inode to reflect - * the new i_size. But that is not done here - it is done in - * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode. - */ - jbd_debug(5, "splicing indirect only\n"); - BUFFER_TRACE(where->bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, inode, where->bh); - if (err) - goto err_out; - } else { - /* - * OK, we spliced it into the inode itself on a direct block. - */ - ext4_mark_inode_dirty(handle, inode); - jbd_debug(5, "splicing direct\n"); - } - return err; - -err_out: - for (i = 1; i <= num; i++) { - /* - * branch[i].bh is newly allocated, so there is no - * need to revoke the block, which is why we don't - * need to set EXT4_FREE_BLOCKS_METADATA. - */ - ext4_free_blocks(handle, inode, where[i].bh, 0, 1, - EXT4_FREE_BLOCKS_FORGET); - } - ext4_free_blocks(handle, inode, NULL, le32_to_cpu(where[num].key), - blks, 0); - - return err; -} - -/* - * The ext4_ind_map_blocks() function handles non-extents inodes - * (i.e., using the traditional indirect/double-indirect i_blocks - * scheme) for ext4_map_blocks(). - * - * Allocation strategy is simple: if we have to allocate something, we will - * have to go the whole way to leaf. So let's do it before attaching anything - * to tree, set linkage between the newborn blocks, write them if sync is - * required, recheck the path, free and repeat if check fails, otherwise - * set the last missing link (that will protect us from any truncate-generated - * removals - all blocks on the path are immune now) and possibly force the - * write on the parent block. - * That has a nice additional property: no special recovery from the failed - * allocations is needed - we simply release blocks and do not touch anything - * reachable from inode. - * - * `handle' can be NULL if create == 0. - * - * return > 0, # of blocks mapped or allocated. - * return = 0, if plain lookup failed. - * return < 0, error case. - * - * The ext4_ind_get_blocks() function should be called with - * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem - * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or - * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system - * blocks. - */ -int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, - int flags) -{ - int err = -EIO; - ext4_lblk_t offsets[4]; - Indirect chain[4]; - Indirect *partial; - ext4_fsblk_t goal; - int indirect_blks; - int blocks_to_boundary = 0; - int depth; - int count = 0; - ext4_fsblk_t first_block = 0; - - trace_ext4_ind_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); - J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))); - J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0); - depth = ext4_block_to_path(inode, map->m_lblk, offsets, - &blocks_to_boundary); - - if (depth == 0) - goto out; - - partial = ext4_get_branch(inode, depth, offsets, chain, &err); - - /* Simplest case - block found, no allocation needed */ - if (!partial) { - first_block = le32_to_cpu(chain[depth - 1].key); - count++; - /*map more blocks*/ - while (count < map->m_len && count <= blocks_to_boundary) { - ext4_fsblk_t blk; - - blk = le32_to_cpu(*(chain[depth-1].p + count)); - - if (blk == first_block + count) - count++; - else - break; - } - goto got_it; - } - - /* Next simple case - plain lookup or failed read of indirect block */ - if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO) - goto cleanup; - - /* - * Okay, we need to do block allocation. - */ - goal = ext4_find_goal(inode, map->m_lblk, partial); - - /* the number of blocks need to allocate for [d,t]indirect blocks */ - indirect_blks = (chain + depth) - partial - 1; - - /* - * Next look up the indirect map to count the totoal number of - * direct blocks to allocate for this branch. - */ - count = ext4_blks_to_allocate(partial, indirect_blks, - map->m_len, blocks_to_boundary); - /* - * Block out ext4_truncate while we alter the tree - */ - err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks, - &count, goal, - offsets + (partial - chain), partial); - - /* - * The ext4_splice_branch call will free and forget any buffers - * on the new chain if there is a failure, but that risks using - * up transaction credits, especially for bitmaps where the - * credits cannot be returned. Can we handle this somehow? We - * may need to return -EAGAIN upwards in the worst case. --sct - */ - if (!err) - err = ext4_splice_branch(handle, inode, map->m_lblk, - partial, indirect_blks, count); - if (err) - goto cleanup; - - map->m_flags |= EXT4_MAP_NEW; - - ext4_update_inode_fsync_trans(handle, inode, 1); -got_it: - map->m_flags |= EXT4_MAP_MAPPED; - map->m_pblk = le32_to_cpu(chain[depth-1].key); - map->m_len = count; - if (count > blocks_to_boundary) - map->m_flags |= EXT4_MAP_BOUNDARY; - err = count; - /* Clean up and exit */ - partial = chain + depth - 1; /* the whole chain */ -cleanup: - while (partial > chain) { - BUFFER_TRACE(partial->bh, "call brelse"); - brelse(partial->bh); - partial--; - } -out: - trace_ext4_ind_map_blocks_exit(inode, map->m_lblk, - map->m_pblk, map->m_len, err); - return err; -} - -/* - * O_DIRECT for ext3 (or indirect map) based files - * - * If the O_DIRECT write will extend the file then add this inode to the - * orphan list. So recovery will truncate it back to the original size - * if the machine crashes during the write. - * - * If the O_DIRECT write is intantiating holes inside i_size and the machine - * crashes then stale disk data _may_ be exposed inside the file. But current - * VFS code falls back into buffered path in that case so we are safe. - */ -ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - struct ext4_inode_info *ei = EXT4_I(inode); - handle_t *handle; - ssize_t ret; - int orphan = 0; - size_t count = iov_length(iov, nr_segs); - int retries = 0; - - if (rw == WRITE) { - loff_t final_size = offset + count; - - if (final_size > inode->i_size) { - /* Credits for sb + inode write */ - handle = ext4_journal_start(inode, 2); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out; - } - ret = ext4_orphan_add(handle, inode); - if (ret) { - ext4_journal_stop(handle); - goto out; - } - orphan = 1; - ei->i_disksize = inode->i_size; - ext4_journal_stop(handle); - } - } - -retry: - if (rw == READ && ext4_should_dioread_nolock(inode)) - ret = __blockdev_direct_IO(rw, iocb, inode, - inode->i_sb->s_bdev, iov, - offset, nr_segs, - ext4_get_block, NULL, NULL, 0); - else { - ret = blockdev_direct_IO(rw, iocb, inode, iov, - offset, nr_segs, ext4_get_block); - - if (unlikely((rw & WRITE) && ret < 0)) { - loff_t isize = i_size_read(inode); - loff_t end = offset + iov_length(iov, nr_segs); - - if (end > isize) - ext4_truncate_failed_write(inode); - } - } - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry; - - if (orphan) { - int err; - - /* Credits for sb + inode write */ - handle = ext4_journal_start(inode, 2); - if (IS_ERR(handle)) { - /* This is really bad luck. We've written the data - * but cannot extend i_size. Bail out and pretend - * the write failed... */ - ret = PTR_ERR(handle); - if (inode->i_nlink) - ext4_orphan_del(NULL, inode); - - goto out; - } - if (inode->i_nlink) - ext4_orphan_del(handle, inode); - if (ret > 0) { - loff_t end = offset + ret; - if (end > inode->i_size) { - ei->i_disksize = end; - i_size_write(inode, end); - /* - * We're going to return a positive `ret' - * here due to non-zero-length I/O, so there's - * no way of reporting error returns from - * ext4_mark_inode_dirty() to userspace. So - * ignore it. - */ - ext4_mark_inode_dirty(handle, inode); - } - } - err = ext4_journal_stop(handle); - if (ret == 0) - ret = err; - } -out: - return ret; -} - -/* - * Calculate the number of metadata blocks need to reserve - * to allocate a new block at @lblocks for non extent file based file - */ -int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - sector_t dind_mask = ~((sector_t)EXT4_ADDR_PER_BLOCK(inode->i_sb) - 1); - int blk_bits; - - if (lblock < EXT4_NDIR_BLOCKS) - return 0; - - lblock -= EXT4_NDIR_BLOCKS; - - if (ei->i_da_metadata_calc_len && - (lblock & dind_mask) == ei->i_da_metadata_calc_last_lblock) { - ei->i_da_metadata_calc_len++; - return 0; - } - ei->i_da_metadata_calc_last_lblock = lblock & dind_mask; - ei->i_da_metadata_calc_len = 1; - blk_bits = order_base_2(lblock); - return (blk_bits / EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb)) + 1; -} - -int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk) -{ - int indirects; - - /* if nrblocks are contiguous */ - if (chunk) { - /* - * With N contiguous data blocks, we need at most - * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) + 1 indirect blocks, - * 2 dindirect blocks, and 1 tindirect block - */ - return DIV_ROUND_UP(nrblocks, - EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4; - } - /* - * if nrblocks are not contiguous, worse case, each block touch - * a indirect block, and each indirect block touch a double indirect - * block, plus a triple indirect block - */ - indirects = nrblocks * 2 + 1; - return indirects; -} - -/* - * Truncate transactions can be complex and absolutely huge. So we need to - * be able to restart the transaction at a conventient checkpoint to make - * sure we don't overflow the journal. - * - * start_transaction gets us a new handle for a truncate transaction, - * and extend_transaction tries to extend the existing one a bit. If - * extend fails, we need to propagate the failure up and restart the - * transaction in the top-level truncate loop. --sct - */ -static handle_t *start_transaction(struct inode *inode) -{ - handle_t *result; - - result = ext4_journal_start(inode, ext4_blocks_for_truncate(inode)); - if (!IS_ERR(result)) - return result; - - ext4_std_error(inode->i_sb, PTR_ERR(result)); - return result; -} - -/* - * Try to extend this transaction for the purposes of truncation. - * - * Returns 0 if we managed to create more room. If we can't create more - * room, and the transaction must be restarted we return 1. - */ -static int try_to_extend_transaction(handle_t *handle, struct inode *inode) -{ - if (!ext4_handle_valid(handle)) - return 0; - if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1)) - return 0; - if (!ext4_journal_extend(handle, ext4_blocks_for_truncate(inode))) - return 0; - return 1; -} - -/* - * Probably it should be a library function... search for first non-zero word - * or memcmp with zero_page, whatever is better for particular architecture. - * Linus? - */ -static inline int all_zeroes(__le32 *p, __le32 *q) -{ - while (p < q) - if (*p++) - return 0; - return 1; -} - -/** - * ext4_find_shared - find the indirect blocks for partial truncation. - * @inode: inode in question - * @depth: depth of the affected branch - * @offsets: offsets of pointers in that branch (see ext4_block_to_path) - * @chain: place to store the pointers to partial indirect blocks - * @top: place to the (detached) top of branch - * - * This is a helper function used by ext4_truncate(). - * - * When we do truncate() we may have to clean the ends of several - * indirect blocks but leave the blocks themselves alive. Block is - * partially truncated if some data below the new i_size is referred - * from it (and it is on the path to the first completely truncated - * data block, indeed). We have to free the top of that path along - * with everything to the right of the path. Since no allocation - * past the truncation point is possible until ext4_truncate() - * finishes, we may safely do the latter, but top of branch may - * require special attention - pageout below the truncation point - * might try to populate it. - * - * We atomically detach the top of branch from the tree, store the - * block number of its root in *@top, pointers to buffer_heads of - * partially truncated blocks - in @chain[].bh and pointers to - * their last elements that should not be removed - in - * @chain[].p. Return value is the pointer to last filled element - * of @chain. - * - * The work left to caller to do the actual freeing of subtrees: - * a) free the subtree starting from *@top - * b) free the subtrees whose roots are stored in - * (@chain[i].p+1 .. end of @chain[i].bh->b_data) - * c) free the subtrees growing from the inode past the @chain[0]. - * (no partially truncated stuff there). */ - -static Indirect *ext4_find_shared(struct inode *inode, int depth, - ext4_lblk_t offsets[4], Indirect chain[4], - __le32 *top) -{ - Indirect *partial, *p; - int k, err; - - *top = 0; - /* Make k index the deepest non-null offset + 1 */ - for (k = depth; k > 1 && !offsets[k-1]; k--) - ; - partial = ext4_get_branch(inode, k, offsets, chain, &err); - /* Writer: pointers */ - if (!partial) - partial = chain + k-1; - /* - * If the branch acquired continuation since we've looked at it - - * fine, it should all survive and (new) top doesn't belong to us. - */ - if (!partial->key && *partial->p) - /* Writer: end */ - goto no_top; - for (p = partial; (p > chain) && all_zeroes((__le32 *) p->bh->b_data, p->p); p--) - ; - /* - * OK, we've found the last block that must survive. The rest of our - * branch should be detached before unlocking. However, if that rest - * of branch is all ours and does not grow immediately from the inode - * it's easier to cheat and just decrement partial->p. - */ - if (p == chain + k - 1 && p > chain) { - p->p--; - } else { - *top = *p->p; - /* Nope, don't do this in ext4. Must leave the tree intact */ -#if 0 - *p->p = 0; -#endif - } - /* Writer: end */ - - while (partial > p) { - brelse(partial->bh); - partial--; - } -no_top: - return partial; -} - -/* - * Zero a number of block pointers in either an inode or an indirect block. - * If we restart the transaction we must again get write access to the - * indirect block for further modification. - * - * We release `count' blocks on disk, but (last - first) may be greater - * than `count' because there can be holes in there. - * - * Return 0 on success, 1 on invalid block range - * and < 0 on fatal error. - */ -static int ext4_clear_blocks(handle_t *handle, struct inode *inode, - struct buffer_head *bh, - ext4_fsblk_t block_to_free, - unsigned long count, __le32 *first, - __le32 *last) -{ - __le32 *p; - int flags = EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_VALIDATED; - int err; - - if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) - flags |= EXT4_FREE_BLOCKS_METADATA; - - if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), block_to_free, - count)) { - EXT4_ERROR_INODE(inode, "attempt to clear invalid " - "blocks %llu len %lu", - (unsigned long long) block_to_free, count); - return 1; - } - - if (try_to_extend_transaction(handle, inode)) { - if (bh) { - BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, inode, bh); - if (unlikely(err)) - goto out_err; - } - err = ext4_mark_inode_dirty(handle, inode); - if (unlikely(err)) - goto out_err; - err = ext4_truncate_restart_trans(handle, inode, - ext4_blocks_for_truncate(inode)); - if (unlikely(err)) - goto out_err; - if (bh) { - BUFFER_TRACE(bh, "retaking write access"); - err = ext4_journal_get_write_access(handle, bh); - if (unlikely(err)) - goto out_err; - } - } - - for (p = first; p < last; p++) - *p = 0; - - ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags); - return 0; -out_err: - ext4_std_error(inode->i_sb, err); - return err; -} - -/** - * ext4_free_data - free a list of data blocks - * @handle: handle for this transaction - * @inode: inode we are dealing with - * @this_bh: indirect buffer_head which contains *@first and *@last - * @first: array of block numbers - * @last: points immediately past the end of array - * - * We are freeing all blocks referred from that array (numbers are stored as - * little-endian 32-bit) and updating @inode->i_blocks appropriately. - * - * We accumulate contiguous runs of blocks to free. Conveniently, if these - * blocks are contiguous then releasing them at one time will only affect one - * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't - * actually use a lot of journal space. - * - * @this_bh will be %NULL if @first and @last point into the inode's direct - * block pointers. - */ -static void ext4_free_data(handle_t *handle, struct inode *inode, - struct buffer_head *this_bh, - __le32 *first, __le32 *last) -{ - ext4_fsblk_t block_to_free = 0; /* Starting block # of a run */ - unsigned long count = 0; /* Number of blocks in the run */ - __le32 *block_to_free_p = NULL; /* Pointer into inode/ind - corresponding to - block_to_free */ - ext4_fsblk_t nr; /* Current block # */ - __le32 *p; /* Pointer into inode/ind - for current block */ - int err = 0; - - if (this_bh) { /* For indirect block */ - BUFFER_TRACE(this_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, this_bh); - /* Important: if we can't update the indirect pointers - * to the blocks, we can't free them. */ - if (err) - return; - } - - for (p = first; p < last; p++) { - nr = le32_to_cpu(*p); - if (nr) { - /* accumulate blocks to free if they're contiguous */ - if (count == 0) { - block_to_free = nr; - block_to_free_p = p; - count = 1; - } else if (nr == block_to_free + count) { - count++; - } else { - err = ext4_clear_blocks(handle, inode, this_bh, - block_to_free, count, - block_to_free_p, p); - if (err) - break; - block_to_free = nr; - block_to_free_p = p; - count = 1; - } - } - } - - if (!err && count > 0) - err = ext4_clear_blocks(handle, inode, this_bh, block_to_free, - count, block_to_free_p, p); - if (err < 0) - /* fatal error */ - return; - - if (this_bh) { - BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata"); - - /* - * The buffer head should have an attached journal head at this - * point. However, if the data is corrupted and an indirect - * block pointed to itself, it would have been detached when - * the block was cleared. Check for this instead of OOPSing. - */ - if ((EXT4_JOURNAL(inode) == NULL) || bh2jh(this_bh)) - ext4_handle_dirty_metadata(handle, inode, this_bh); - else - EXT4_ERROR_INODE(inode, - "circular indirect block detected at " - "block %llu", - (unsigned long long) this_bh->b_blocknr); - } -} - -/** - * ext4_free_branches - free an array of branches - * @handle: JBD handle for this transaction - * @inode: inode we are dealing with - * @parent_bh: the buffer_head which contains *@first and *@last - * @first: array of block numbers - * @last: pointer immediately past the end of array - * @depth: depth of the branches to free - * - * We are freeing all blocks referred from these branches (numbers are - * stored as little-endian 32-bit) and updating @inode->i_blocks - * appropriately. - */ -static void ext4_free_branches(handle_t *handle, struct inode *inode, - struct buffer_head *parent_bh, - __le32 *first, __le32 *last, int depth) -{ - ext4_fsblk_t nr; - __le32 *p; - - if (ext4_handle_is_aborted(handle)) - return; - - if (depth--) { - struct buffer_head *bh; - int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); - p = last; - while (--p >= first) { - nr = le32_to_cpu(*p); - if (!nr) - continue; /* A hole */ - - if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), - nr, 1)) { - EXT4_ERROR_INODE(inode, - "invalid indirect mapped " - "block %lu (level %d)", - (unsigned long) nr, depth); - break; - } - - /* Go read the buffer for the next level down */ - bh = sb_bread(inode->i_sb, nr); - - /* - * A read failure? Report error and clear slot - * (should be rare). - */ - if (!bh) { - EXT4_ERROR_INODE_BLOCK(inode, nr, - "Read failure"); - continue; - } - - /* This zaps the entire block. Bottom up. */ - BUFFER_TRACE(bh, "free child branches"); - ext4_free_branches(handle, inode, bh, - (__le32 *) bh->b_data, - (__le32 *) bh->b_data + addr_per_block, - depth); - brelse(bh); - - /* - * Everything below this this pointer has been - * released. Now let this top-of-subtree go. - * - * We want the freeing of this indirect block to be - * atomic in the journal with the updating of the - * bitmap block which owns it. So make some room in - * the journal. - * - * We zero the parent pointer *after* freeing its - * pointee in the bitmaps, so if extend_transaction() - * for some reason fails to put the bitmap changes and - * the release into the same transaction, recovery - * will merely complain about releasing a free block, - * rather than leaking blocks. - */ - if (ext4_handle_is_aborted(handle)) - return; - if (try_to_extend_transaction(handle, inode)) { - ext4_mark_inode_dirty(handle, inode); - ext4_truncate_restart_trans(handle, inode, - ext4_blocks_for_truncate(inode)); - } - - /* - * The forget flag here is critical because if - * we are journaling (and not doing data - * journaling), we have to make sure a revoke - * record is written to prevent the journal - * replay from overwriting the (former) - * indirect block if it gets reallocated as a - * data block. This must happen in the same - * transaction where the data blocks are - * actually freed. - */ - ext4_free_blocks(handle, inode, NULL, nr, 1, - EXT4_FREE_BLOCKS_METADATA| - EXT4_FREE_BLOCKS_FORGET); - - if (parent_bh) { - /* - * The block which we have just freed is - * pointed to by an indirect block: journal it - */ - BUFFER_TRACE(parent_bh, "get_write_access"); - if (!ext4_journal_get_write_access(handle, - parent_bh)){ - *p = 0; - BUFFER_TRACE(parent_bh, - "call ext4_handle_dirty_metadata"); - ext4_handle_dirty_metadata(handle, - inode, - parent_bh); - } - } - } - } else { - /* We have reached the bottom of the tree. */ - BUFFER_TRACE(parent_bh, "free data blocks"); - ext4_free_data(handle, inode, parent_bh, first, last); - } -} - -void ext4_ind_truncate(struct inode *inode) -{ - handle_t *handle; - struct ext4_inode_info *ei = EXT4_I(inode); - __le32 *i_data = ei->i_data; - int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); - struct address_space *mapping = inode->i_mapping; - ext4_lblk_t offsets[4]; - Indirect chain[4]; - Indirect *partial; - __le32 nr = 0; - int n = 0; - ext4_lblk_t last_block, max_block; - unsigned blocksize = inode->i_sb->s_blocksize; - - handle = start_transaction(inode); - if (IS_ERR(handle)) - return; /* AKPM: return what? */ - - last_block = (inode->i_size + blocksize-1) - >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); - max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1) - >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); - - if (inode->i_size & (blocksize - 1)) - if (ext4_block_truncate_page(handle, mapping, inode->i_size)) - goto out_stop; - - if (last_block != max_block) { - n = ext4_block_to_path(inode, last_block, offsets, NULL); - if (n == 0) - goto out_stop; /* error */ - } - - /* - * OK. This truncate is going to happen. We add the inode to the - * orphan list, so that if this truncate spans multiple transactions, - * and we crash, we will resume the truncate when the filesystem - * recovers. It also marks the inode dirty, to catch the new size. - * - * Implication: the file must always be in a sane, consistent - * truncatable state while each transaction commits. - */ - if (ext4_orphan_add(handle, inode)) - goto out_stop; - - /* - * From here we block out all ext4_get_block() callers who want to - * modify the block allocation tree. - */ - down_write(&ei->i_data_sem); - - ext4_discard_preallocations(inode); - - /* - * The orphan list entry will now protect us from any crash which - * occurs before the truncate completes, so it is now safe to propagate - * the new, shorter inode size (held for now in i_size) into the - * on-disk inode. We do this via i_disksize, which is the value which - * ext4 *really* writes onto the disk inode. - */ - ei->i_disksize = inode->i_size; - - if (last_block == max_block) { - /* - * It is unnecessary to free any data blocks if last_block is - * equal to the indirect block limit. - */ - goto out_unlock; - } else if (n == 1) { /* direct blocks */ - ext4_free_data(handle, inode, NULL, i_data+offsets[0], - i_data + EXT4_NDIR_BLOCKS); - goto do_indirects; - } - - partial = ext4_find_shared(inode, n, offsets, chain, &nr); - /* Kill the top of shared branch (not detached) */ - if (nr) { - if (partial == chain) { - /* Shared branch grows from the inode */ - ext4_free_branches(handle, inode, NULL, - &nr, &nr+1, (chain+n-1) - partial); - *partial->p = 0; - /* - * We mark the inode dirty prior to restart, - * and prior to stop. No need for it here. - */ - } else { - /* Shared branch grows from an indirect block */ - BUFFER_TRACE(partial->bh, "get_write_access"); - ext4_free_branches(handle, inode, partial->bh, - partial->p, - partial->p+1, (chain+n-1) - partial); - } - } - /* Clear the ends of indirect blocks on the shared branch */ - while (partial > chain) { - ext4_free_branches(handle, inode, partial->bh, partial->p + 1, - (__le32*)partial->bh->b_data+addr_per_block, - (chain+n-1) - partial); - BUFFER_TRACE(partial->bh, "call brelse"); - brelse(partial->bh); - partial--; - } -do_indirects: - /* Kill the remaining (whole) subtrees */ - switch (offsets[0]) { - default: - nr = i_data[EXT4_IND_BLOCK]; - if (nr) { - ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); - i_data[EXT4_IND_BLOCK] = 0; - } - case EXT4_IND_BLOCK: - nr = i_data[EXT4_DIND_BLOCK]; - if (nr) { - ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); - i_data[EXT4_DIND_BLOCK] = 0; - } - case EXT4_DIND_BLOCK: - nr = i_data[EXT4_TIND_BLOCK]; - if (nr) { - ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); - i_data[EXT4_TIND_BLOCK] = 0; - } - case EXT4_TIND_BLOCK: - ; - } - -out_unlock: - up_write(&ei->i_data_sem); - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); - - /* - * In a multi-transaction truncate, we only make the final transaction - * synchronous - */ - if (IS_SYNC(inode)) - ext4_handle_sync(handle); -out_stop: - /* - * If this was a simple ftruncate(), and the file will remain alive - * then we need to clear up the orphan record which we created above. - * However, if this was a real unlink then we were called by - * ext4_delete_inode(), and we allow that function to clean up the - * orphan info for us. - */ - if (inode->i_nlink) - ext4_orphan_del(handle, inode); - - ext4_journal_stop(handle); - trace_ext4_truncate_exit(inode); -} - diff --git a/trunk/fs/ext4/inode.c b/trunk/fs/ext4/inode.c index d47264cafee0..3e5191f9f398 100644 --- a/trunk/fs/ext4/inode.c +++ b/trunk/fs/ext4/inode.c @@ -12,6 +12,10 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * + * Goal-directed block allocation by Stephen Tweedie + * (sct@redhat.com), 1993, 1998 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 * 64-bit file support on 64-bit platforms by Jakub Jelinek * (jj@sunsite.ms.mff.cuni.cz) * @@ -43,7 +47,6 @@ #include "xattr.h" #include "acl.h" #include "ext4_extents.h" -#include "truncate.h" #include @@ -85,6 +88,72 @@ static int ext4_inode_is_fast_symlink(struct inode *inode) return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0); } +/* + * Work out how many blocks we need to proceed with the next chunk of a + * truncate transaction. + */ +static unsigned long blocks_for_truncate(struct inode *inode) +{ + ext4_lblk_t needed; + + needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); + + /* Give ourselves just enough room to cope with inodes in which + * i_blocks is corrupt: we've seen disk corruptions in the past + * which resulted in random data in an inode which looked enough + * like a regular file for ext4 to try to delete it. Things + * will go a bit crazy if that happens, but at least we should + * try not to panic the whole kernel. */ + if (needed < 2) + needed = 2; + + /* But we need to bound the transaction so we don't overflow the + * journal. */ + if (needed > EXT4_MAX_TRANS_DATA) + needed = EXT4_MAX_TRANS_DATA; + + return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed; +} + +/* + * Truncate transactions can be complex and absolutely huge. So we need to + * be able to restart the transaction at a conventient checkpoint to make + * sure we don't overflow the journal. + * + * start_transaction gets us a new handle for a truncate transaction, + * and extend_transaction tries to extend the existing one a bit. If + * extend fails, we need to propagate the failure up and restart the + * transaction in the top-level truncate loop. --sct + */ +static handle_t *start_transaction(struct inode *inode) +{ + handle_t *result; + + result = ext4_journal_start(inode, blocks_for_truncate(inode)); + if (!IS_ERR(result)) + return result; + + ext4_std_error(inode->i_sb, PTR_ERR(result)); + return result; +} + +/* + * Try to extend this transaction for the purposes of truncation. + * + * Returns 0 if we managed to create more room. If we can't create more + * room, and the transaction must be restarted we return 1. + */ +static int try_to_extend_transaction(handle_t *handle, struct inode *inode) +{ + if (!ext4_handle_valid(handle)) + return 0; + if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1)) + return 0; + if (!ext4_journal_extend(handle, blocks_for_truncate(inode))) + return 0; + return 1; +} + /* * Restart the transaction associated with *handle. This does a commit, * so before we call here everything must be consistently dirtied against @@ -121,33 +190,6 @@ void ext4_evict_inode(struct inode *inode) trace_ext4_evict_inode(inode); if (inode->i_nlink) { - /* - * When journalling data dirty buffers are tracked only in the - * journal. So although mm thinks everything is clean and - * ready for reaping the inode might still have some pages to - * write in the running transaction or waiting to be - * checkpointed. Thus calling jbd2_journal_invalidatepage() - * (via truncate_inode_pages()) to discard these buffers can - * cause data loss. Also even if we did not discard these - * buffers, we would have no way to find them after the inode - * is reaped and thus user could see stale data if he tries to - * read them before the transaction is checkpointed. So be - * careful and force everything to disk here... We use - * ei->i_datasync_tid to store the newest transaction - * containing inode's data. - * - * Note that directories do not have this problem because they - * don't use page cache. - */ - if (ext4_should_journal_data(inode) && - (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) { - journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; - tid_t commit_tid = EXT4_I(inode)->i_datasync_tid; - - jbd2_log_start_commit(journal, commit_tid); - jbd2_log_wait_commit(journal, commit_tid); - filemap_write_and_wait(&inode->i_data); - } truncate_inode_pages(&inode->i_data, 0); goto no_delete; } @@ -162,7 +204,7 @@ void ext4_evict_inode(struct inode *inode) if (is_bad_inode(inode)) goto no_delete; - handle = ext4_journal_start(inode, ext4_blocks_for_truncate(inode)+3); + handle = ext4_journal_start(inode, blocks_for_truncate(inode)+3); if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); /* @@ -235,6 +277,793 @@ void ext4_evict_inode(struct inode *inode) ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ } +typedef struct { + __le32 *p; + __le32 key; + struct buffer_head *bh; +} Indirect; + +static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) +{ + p->key = *(p->p = v); + p->bh = bh; +} + +/** + * ext4_block_to_path - parse the block number into array of offsets + * @inode: inode in question (we are only interested in its superblock) + * @i_block: block number to be parsed + * @offsets: array to store the offsets in + * @boundary: set this non-zero if the referred-to block is likely to be + * followed (on disk) by an indirect block. + * + * To store the locations of file's data ext4 uses a data structure common + * for UNIX filesystems - tree of pointers anchored in the inode, with + * data blocks at leaves and indirect blocks in intermediate nodes. + * This function translates the block number into path in that tree - + * return value is the path length and @offsets[n] is the offset of + * pointer to (n+1)th node in the nth one. If @block is out of range + * (negative or too large) warning is printed and zero returned. + * + * Note: function doesn't find node addresses, so no IO is needed. All + * we need to know is the capacity of indirect blocks (taken from the + * inode->i_sb). + */ + +/* + * Portability note: the last comparison (check that we fit into triple + * indirect block) is spelled differently, because otherwise on an + * architecture with 32-bit longs and 8Kb pages we might get into trouble + * if our filesystem had 8Kb blocks. We might use long long, but that would + * kill us on x86. Oh, well, at least the sign propagation does not matter - + * i_block would have to be negative in the very beginning, so we would not + * get there at all. + */ + +static int ext4_block_to_path(struct inode *inode, + ext4_lblk_t i_block, + ext4_lblk_t offsets[4], int *boundary) +{ + int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb); + int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb); + const long direct_blocks = EXT4_NDIR_BLOCKS, + indirect_blocks = ptrs, + double_blocks = (1 << (ptrs_bits * 2)); + int n = 0; + int final = 0; + + if (i_block < direct_blocks) { + offsets[n++] = i_block; + final = direct_blocks; + } else if ((i_block -= direct_blocks) < indirect_blocks) { + offsets[n++] = EXT4_IND_BLOCK; + offsets[n++] = i_block; + final = ptrs; + } else if ((i_block -= indirect_blocks) < double_blocks) { + offsets[n++] = EXT4_DIND_BLOCK; + offsets[n++] = i_block >> ptrs_bits; + offsets[n++] = i_block & (ptrs - 1); + final = ptrs; + } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { + offsets[n++] = EXT4_TIND_BLOCK; + offsets[n++] = i_block >> (ptrs_bits * 2); + offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); + offsets[n++] = i_block & (ptrs - 1); + final = ptrs; + } else { + ext4_warning(inode->i_sb, "block %lu > max in inode %lu", + i_block + direct_blocks + + indirect_blocks + double_blocks, inode->i_ino); + } + if (boundary) + *boundary = final - 1 - (i_block & (ptrs - 1)); + return n; +} + +static int __ext4_check_blockref(const char *function, unsigned int line, + struct inode *inode, + __le32 *p, unsigned int max) +{ + struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; + __le32 *bref = p; + unsigned int blk; + + while (bref < p+max) { + blk = le32_to_cpu(*bref++); + if (blk && + unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), + blk, 1))) { + es->s_last_error_block = cpu_to_le64(blk); + ext4_error_inode(inode, function, line, blk, + "invalid block"); + return -EIO; + } + } + return 0; +} + + +#define ext4_check_indirect_blockref(inode, bh) \ + __ext4_check_blockref(__func__, __LINE__, inode, \ + (__le32 *)(bh)->b_data, \ + EXT4_ADDR_PER_BLOCK((inode)->i_sb)) + +#define ext4_check_inode_blockref(inode) \ + __ext4_check_blockref(__func__, __LINE__, inode, \ + EXT4_I(inode)->i_data, \ + EXT4_NDIR_BLOCKS) + +/** + * ext4_get_branch - read the chain of indirect blocks leading to data + * @inode: inode in question + * @depth: depth of the chain (1 - direct pointer, etc.) + * @offsets: offsets of pointers in inode/indirect blocks + * @chain: place to store the result + * @err: here we store the error value + * + * Function fills the array of triples and returns %NULL + * if everything went OK or the pointer to the last filled triple + * (incomplete one) otherwise. Upon the return chain[i].key contains + * the number of (i+1)-th block in the chain (as it is stored in memory, + * i.e. little-endian 32-bit), chain[i].p contains the address of that + * number (it points into struct inode for i==0 and into the bh->b_data + * for i>0) and chain[i].bh points to the buffer_head of i-th indirect + * block for i>0 and NULL for i==0. In other words, it holds the block + * numbers of the chain, addresses they were taken from (and where we can + * verify that chain did not change) and buffer_heads hosting these + * numbers. + * + * Function stops when it stumbles upon zero pointer (absent block) + * (pointer to last triple returned, *@err == 0) + * or when it gets an IO error reading an indirect block + * (ditto, *@err == -EIO) + * or when it reads all @depth-1 indirect blocks successfully and finds + * the whole chain, all way to the data (returns %NULL, *err == 0). + * + * Need to be called with + * down_read(&EXT4_I(inode)->i_data_sem) + */ +static Indirect *ext4_get_branch(struct inode *inode, int depth, + ext4_lblk_t *offsets, + Indirect chain[4], int *err) +{ + struct super_block *sb = inode->i_sb; + Indirect *p = chain; + struct buffer_head *bh; + + *err = 0; + /* i_data is not going away, no lock needed */ + add_chain(chain, NULL, EXT4_I(inode)->i_data + *offsets); + if (!p->key) + goto no_block; + while (--depth) { + bh = sb_getblk(sb, le32_to_cpu(p->key)); + if (unlikely(!bh)) + goto failure; + + if (!bh_uptodate_or_lock(bh)) { + if (bh_submit_read(bh) < 0) { + put_bh(bh); + goto failure; + } + /* validate block references */ + if (ext4_check_indirect_blockref(inode, bh)) { + put_bh(bh); + goto failure; + } + } + + add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; + } + return NULL; + +failure: + *err = -EIO; +no_block: + return p; +} + +/** + * ext4_find_near - find a place for allocation with sufficient locality + * @inode: owner + * @ind: descriptor of indirect block. + * + * This function returns the preferred place for block allocation. + * It is used when heuristic for sequential allocation fails. + * Rules are: + * + if there is a block to the left of our position - allocate near it. + * + if pointer will live in indirect block - allocate near that block. + * + if pointer will live in inode - allocate in the same + * cylinder group. + * + * In the latter case we colour the starting block by the callers PID to + * prevent it from clashing with concurrent allocations for a different inode + * in the same block group. The PID is used here so that functionally related + * files will be close-by on-disk. + * + * Caller must make sure that @ind is valid and will stay that way. + */ +static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) +{ + struct ext4_inode_info *ei = EXT4_I(inode); + __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data; + __le32 *p; + ext4_fsblk_t bg_start; + ext4_fsblk_t last_block; + ext4_grpblk_t colour; + ext4_group_t block_group; + int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb)); + + /* Try to find previous block */ + for (p = ind->p - 1; p >= start; p--) { + if (*p) + return le32_to_cpu(*p); + } + + /* No such thing, so let's try location of indirect block */ + if (ind->bh) + return ind->bh->b_blocknr; + + /* + * It is going to be referred to from the inode itself? OK, just put it + * into the same cylinder group then. + */ + block_group = ei->i_block_group; + if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) { + block_group &= ~(flex_size-1); + if (S_ISREG(inode->i_mode)) + block_group++; + } + bg_start = ext4_group_first_block_no(inode->i_sb, block_group); + last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1; + + /* + * If we are doing delayed allocation, we don't need take + * colour into account. + */ + if (test_opt(inode->i_sb, DELALLOC)) + return bg_start; + + if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block) + colour = (current->pid % 16) * + (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16); + else + colour = (current->pid % 16) * ((last_block - bg_start) / 16); + return bg_start + colour; +} + +/** + * ext4_find_goal - find a preferred place for allocation. + * @inode: owner + * @block: block we want + * @partial: pointer to the last triple within a chain + * + * Normally this function find the preferred place for block allocation, + * returns it. + * Because this is only used for non-extent files, we limit the block nr + * to 32 bits. + */ +static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, + Indirect *partial) +{ + ext4_fsblk_t goal; + + /* + * XXX need to get goal block from mballoc's data structures + */ + + goal = ext4_find_near(inode, partial); + goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; + return goal; +} + +/** + * ext4_blks_to_allocate - Look up the block map and count the number + * of direct blocks need to be allocated for the given branch. + * + * @branch: chain of indirect blocks + * @k: number of blocks need for indirect blocks + * @blks: number of data blocks to be mapped. + * @blocks_to_boundary: the offset in the indirect block + * + * return the total number of blocks to be allocate, including the + * direct and indirect blocks. + */ +static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, + int blocks_to_boundary) +{ + unsigned int count = 0; + + /* + * Simple case, [t,d]Indirect block(s) has not allocated yet + * then it's clear blocks on that path have not allocated + */ + if (k > 0) { + /* right now we don't handle cross boundary allocation */ + if (blks < blocks_to_boundary + 1) + count += blks; + else + count += blocks_to_boundary + 1; + return count; + } + + count++; + while (count < blks && count <= blocks_to_boundary && + le32_to_cpu(*(branch[0].p + count)) == 0) { + count++; + } + return count; +} + +/** + * ext4_alloc_blocks: multiple allocate blocks needed for a branch + * @handle: handle for this transaction + * @inode: inode which needs allocated blocks + * @iblock: the logical block to start allocated at + * @goal: preferred physical block of allocation + * @indirect_blks: the number of blocks need to allocate for indirect + * blocks + * @blks: number of desired blocks + * @new_blocks: on return it will store the new block numbers for + * the indirect blocks(if needed) and the first direct block, + * @err: on return it will store the error code + * + * This function will return the number of blocks allocated as + * requested by the passed-in parameters. + */ +static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, + ext4_lblk_t iblock, ext4_fsblk_t goal, + int indirect_blks, int blks, + ext4_fsblk_t new_blocks[4], int *err) +{ + struct ext4_allocation_request ar; + int target, i; + unsigned long count = 0, blk_allocated = 0; + int index = 0; + ext4_fsblk_t current_block = 0; + int ret = 0; + + /* + * Here we try to allocate the requested multiple blocks at once, + * on a best-effort basis. + * To build a branch, we should allocate blocks for + * the indirect blocks(if not allocated yet), and at least + * the first direct block of this branch. That's the + * minimum number of blocks need to allocate(required) + */ + /* first we try to allocate the indirect blocks */ + target = indirect_blks; + while (target > 0) { + count = target; + /* allocating blocks for indirect blocks and direct blocks */ + current_block = ext4_new_meta_blocks(handle, inode, goal, + 0, &count, err); + if (*err) + goto failed_out; + + if (unlikely(current_block + count > EXT4_MAX_BLOCK_FILE_PHYS)) { + EXT4_ERROR_INODE(inode, + "current_block %llu + count %lu > %d!", + current_block, count, + EXT4_MAX_BLOCK_FILE_PHYS); + *err = -EIO; + goto failed_out; + } + + target -= count; + /* allocate blocks for indirect blocks */ + while (index < indirect_blks && count) { + new_blocks[index++] = current_block++; + count--; + } + if (count > 0) { + /* + * save the new block number + * for the first direct block + */ + new_blocks[index] = current_block; + printk(KERN_INFO "%s returned more blocks than " + "requested\n", __func__); + WARN_ON(1); + break; + } + } + + target = blks - count ; + blk_allocated = count; + if (!target) + goto allocated; + /* Now allocate data blocks */ + memset(&ar, 0, sizeof(ar)); + ar.inode = inode; + ar.goal = goal; + ar.len = target; + ar.logical = iblock; + if (S_ISREG(inode->i_mode)) + /* enable in-core preallocation only for regular files */ + ar.flags = EXT4_MB_HINT_DATA; + + current_block = ext4_mb_new_blocks(handle, &ar, err); + if (unlikely(current_block + ar.len > EXT4_MAX_BLOCK_FILE_PHYS)) { + EXT4_ERROR_INODE(inode, + "current_block %llu + ar.len %d > %d!", + current_block, ar.len, + EXT4_MAX_BLOCK_FILE_PHYS); + *err = -EIO; + goto failed_out; + } + + if (*err && (target == blks)) { + /* + * if the allocation failed and we didn't allocate + * any blocks before + */ + goto failed_out; + } + if (!*err) { + if (target == blks) { + /* + * save the new block number + * for the first direct block + */ + new_blocks[index] = current_block; + } + blk_allocated += ar.len; + } +allocated: + /* total number of blocks allocated for direct blocks */ + ret = blk_allocated; + *err = 0; + return ret; +failed_out: + for (i = 0; i < index; i++) + ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0); + return ret; +} + +/** + * ext4_alloc_branch - allocate and set up a chain of blocks. + * @handle: handle for this transaction + * @inode: owner + * @indirect_blks: number of allocated indirect blocks + * @blks: number of allocated direct blocks + * @goal: preferred place for allocation + * @offsets: offsets (in the blocks) to store the pointers to next. + * @branch: place to store the chain in. + * + * This function allocates blocks, zeroes out all but the last one, + * links them into chain and (if we are synchronous) writes them to disk. + * In other words, it prepares a branch that can be spliced onto the + * inode. It stores the information about that chain in the branch[], in + * the same format as ext4_get_branch() would do. We are calling it after + * we had read the existing part of chain and partial points to the last + * triple of that (one with zero ->key). Upon the exit we have the same + * picture as after the successful ext4_get_block(), except that in one + * place chain is disconnected - *branch->p is still zero (we did not + * set the last link), but branch->key contains the number that should + * be placed into *branch->p to fill that gap. + * + * If allocation fails we free all blocks we've allocated (and forget + * their buffer_heads) and return the error value the from failed + * ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain + * as described above and return 0. + */ +static int ext4_alloc_branch(handle_t *handle, struct inode *inode, + ext4_lblk_t iblock, int indirect_blks, + int *blks, ext4_fsblk_t goal, + ext4_lblk_t *offsets, Indirect *branch) +{ + int blocksize = inode->i_sb->s_blocksize; + int i, n = 0; + int err = 0; + struct buffer_head *bh; + int num; + ext4_fsblk_t new_blocks[4]; + ext4_fsblk_t current_block; + + num = ext4_alloc_blocks(handle, inode, iblock, goal, indirect_blks, + *blks, new_blocks, &err); + if (err) + return err; + + branch[0].key = cpu_to_le32(new_blocks[0]); + /* + * metadata blocks and data blocks are allocated. + */ + for (n = 1; n <= indirect_blks; n++) { + /* + * Get buffer_head for parent block, zero it out + * and set the pointer to new one, then send + * parent to disk. + */ + bh = sb_getblk(inode->i_sb, new_blocks[n-1]); + if (unlikely(!bh)) { + err = -EIO; + goto failed; + } + + branch[n].bh = bh; + lock_buffer(bh); + BUFFER_TRACE(bh, "call get_create_access"); + err = ext4_journal_get_create_access(handle, bh); + if (err) { + /* Don't brelse(bh) here; it's done in + * ext4_journal_forget() below */ + unlock_buffer(bh); + goto failed; + } + + memset(bh->b_data, 0, blocksize); + branch[n].p = (__le32 *) bh->b_data + offsets[n]; + branch[n].key = cpu_to_le32(new_blocks[n]); + *branch[n].p = branch[n].key; + if (n == indirect_blks) { + current_block = new_blocks[n]; + /* + * End of chain, update the last new metablock of + * the chain to point to the new allocated + * data blocks numbers + */ + for (i = 1; i < num; i++) + *(branch[n].p + i) = cpu_to_le32(++current_block); + } + BUFFER_TRACE(bh, "marking uptodate"); + set_buffer_uptodate(bh); + unlock_buffer(bh); + + BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); + err = ext4_handle_dirty_metadata(handle, inode, bh); + if (err) + goto failed; + } + *blks = num; + return err; +failed: + /* Allocation failed, free what we already allocated */ + ext4_free_blocks(handle, inode, NULL, new_blocks[0], 1, 0); + for (i = 1; i <= n ; i++) { + /* + * branch[i].bh is newly allocated, so there is no + * need to revoke the block, which is why we don't + * need to set EXT4_FREE_BLOCKS_METADATA. + */ + ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, + EXT4_FREE_BLOCKS_FORGET); + } + for (i = n+1; i < indirect_blks; i++) + ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0); + + ext4_free_blocks(handle, inode, NULL, new_blocks[i], num, 0); + + return err; +} + +/** + * ext4_splice_branch - splice the allocated branch onto inode. + * @handle: handle for this transaction + * @inode: owner + * @block: (logical) number of block we are adding + * @chain: chain of indirect blocks (with a missing link - see + * ext4_alloc_branch) + * @where: location of missing link + * @num: number of indirect blocks we are adding + * @blks: number of direct blocks we are adding + * + * This function fills the missing link and does all housekeeping needed in + * inode (->i_blocks, etc.). In case of success we end up with the full + * chain to new block and return 0. + */ +static int ext4_splice_branch(handle_t *handle, struct inode *inode, + ext4_lblk_t block, Indirect *where, int num, + int blks) +{ + int i; + int err = 0; + ext4_fsblk_t current_block; + + /* + * If we're splicing into a [td]indirect block (as opposed to the + * inode) then we need to get write access to the [td]indirect block + * before the splice. + */ + if (where->bh) { + BUFFER_TRACE(where->bh, "get_write_access"); + err = ext4_journal_get_write_access(handle, where->bh); + if (err) + goto err_out; + } + /* That's it */ + + *where->p = where->key; + + /* + * Update the host buffer_head or inode to point to more just allocated + * direct blocks blocks + */ + if (num == 0 && blks > 1) { + current_block = le32_to_cpu(where->key) + 1; + for (i = 1; i < blks; i++) + *(where->p + i) = cpu_to_le32(current_block++); + } + + /* We are done with atomic stuff, now do the rest of housekeeping */ + /* had we spliced it onto indirect block? */ + if (where->bh) { + /* + * If we spliced it onto an indirect block, we haven't + * altered the inode. Note however that if it is being spliced + * onto an indirect block at the very end of the file (the + * file is growing) then we *will* alter the inode to reflect + * the new i_size. But that is not done here - it is done in + * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode. + */ + jbd_debug(5, "splicing indirect only\n"); + BUFFER_TRACE(where->bh, "call ext4_handle_dirty_metadata"); + err = ext4_handle_dirty_metadata(handle, inode, where->bh); + if (err) + goto err_out; + } else { + /* + * OK, we spliced it into the inode itself on a direct block. + */ + ext4_mark_inode_dirty(handle, inode); + jbd_debug(5, "splicing direct\n"); + } + return err; + +err_out: + for (i = 1; i <= num; i++) { + /* + * branch[i].bh is newly allocated, so there is no + * need to revoke the block, which is why we don't + * need to set EXT4_FREE_BLOCKS_METADATA. + */ + ext4_free_blocks(handle, inode, where[i].bh, 0, 1, + EXT4_FREE_BLOCKS_FORGET); + } + ext4_free_blocks(handle, inode, NULL, le32_to_cpu(where[num].key), + blks, 0); + + return err; +} + +/* + * The ext4_ind_map_blocks() function handles non-extents inodes + * (i.e., using the traditional indirect/double-indirect i_blocks + * scheme) for ext4_map_blocks(). + * + * Allocation strategy is simple: if we have to allocate something, we will + * have to go the whole way to leaf. So let's do it before attaching anything + * to tree, set linkage between the newborn blocks, write them if sync is + * required, recheck the path, free and repeat if check fails, otherwise + * set the last missing link (that will protect us from any truncate-generated + * removals - all blocks on the path are immune now) and possibly force the + * write on the parent block. + * That has a nice additional property: no special recovery from the failed + * allocations is needed - we simply release blocks and do not touch anything + * reachable from inode. + * + * `handle' can be NULL if create == 0. + * + * return > 0, # of blocks mapped or allocated. + * return = 0, if plain lookup failed. + * return < 0, error case. + * + * The ext4_ind_get_blocks() function should be called with + * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem + * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or + * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system + * blocks. + */ +static int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, + struct ext4_map_blocks *map, + int flags) +{ + int err = -EIO; + ext4_lblk_t offsets[4]; + Indirect chain[4]; + Indirect *partial; + ext4_fsblk_t goal; + int indirect_blks; + int blocks_to_boundary = 0; + int depth; + int count = 0; + ext4_fsblk_t first_block = 0; + + trace_ext4_ind_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); + J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))); + J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0); + depth = ext4_block_to_path(inode, map->m_lblk, offsets, + &blocks_to_boundary); + + if (depth == 0) + goto out; + + partial = ext4_get_branch(inode, depth, offsets, chain, &err); + + /* Simplest case - block found, no allocation needed */ + if (!partial) { + first_block = le32_to_cpu(chain[depth - 1].key); + count++; + /*map more blocks*/ + while (count < map->m_len && count <= blocks_to_boundary) { + ext4_fsblk_t blk; + + blk = le32_to_cpu(*(chain[depth-1].p + count)); + + if (blk == first_block + count) + count++; + else + break; + } + goto got_it; + } + + /* Next simple case - plain lookup or failed read of indirect block */ + if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO) + goto cleanup; + + /* + * Okay, we need to do block allocation. + */ + goal = ext4_find_goal(inode, map->m_lblk, partial); + + /* the number of blocks need to allocate for [d,t]indirect blocks */ + indirect_blks = (chain + depth) - partial - 1; + + /* + * Next look up the indirect map to count the totoal number of + * direct blocks to allocate for this branch. + */ + count = ext4_blks_to_allocate(partial, indirect_blks, + map->m_len, blocks_to_boundary); + /* + * Block out ext4_truncate while we alter the tree + */ + err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks, + &count, goal, + offsets + (partial - chain), partial); + + /* + * The ext4_splice_branch call will free and forget any buffers + * on the new chain if there is a failure, but that risks using + * up transaction credits, especially for bitmaps where the + * credits cannot be returned. Can we handle this somehow? We + * may need to return -EAGAIN upwards in the worst case. --sct + */ + if (!err) + err = ext4_splice_branch(handle, inode, map->m_lblk, + partial, indirect_blks, count); + if (err) + goto cleanup; + + map->m_flags |= EXT4_MAP_NEW; + + ext4_update_inode_fsync_trans(handle, inode, 1); +got_it: + map->m_flags |= EXT4_MAP_MAPPED; + map->m_pblk = le32_to_cpu(chain[depth-1].key); + map->m_len = count; + if (count > blocks_to_boundary) + map->m_flags |= EXT4_MAP_BOUNDARY; + err = count; + /* Clean up and exit */ + partial = chain + depth - 1; /* the whole chain */ +cleanup: + while (partial > chain) { + BUFFER_TRACE(partial->bh, "call brelse"); + brelse(partial->bh); + partial--; + } +out: + trace_ext4_ind_map_blocks_exit(inode, map->m_lblk, + map->m_pblk, map->m_len, err); + return err; +} + #ifdef CONFIG_QUOTA qsize_t *ext4_get_reserved_space(struct inode *inode) { @@ -242,6 +1071,33 @@ qsize_t *ext4_get_reserved_space(struct inode *inode) } #endif +/* + * Calculate the number of metadata blocks need to reserve + * to allocate a new block at @lblocks for non extent file based file + */ +static int ext4_indirect_calc_metadata_amount(struct inode *inode, + sector_t lblock) +{ + struct ext4_inode_info *ei = EXT4_I(inode); + sector_t dind_mask = ~((sector_t)EXT4_ADDR_PER_BLOCK(inode->i_sb) - 1); + int blk_bits; + + if (lblock < EXT4_NDIR_BLOCKS) + return 0; + + lblock -= EXT4_NDIR_BLOCKS; + + if (ei->i_da_metadata_calc_len && + (lblock & dind_mask) == ei->i_da_metadata_calc_last_lblock) { + ei->i_da_metadata_calc_len++; + return 0; + } + ei->i_da_metadata_calc_last_lblock = lblock & dind_mask; + ei->i_da_metadata_calc_len = 1; + blk_bits = order_base_2(lblock); + return (blk_bits / EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb)) + 1; +} + /* * Calculate the number of metadata blocks need to reserve * to allocate a block located at @lblock @@ -251,7 +1107,7 @@ static int ext4_calc_metadata_amount(struct inode *inode, ext4_lblk_t lblock) if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) return ext4_ext_calc_metadata_amount(inode, lblock); - return ext4_ind_calc_metadata_amount(inode, lblock); + return ext4_indirect_calc_metadata_amount(inode, lblock); } /* @@ -733,6 +1589,16 @@ static int do_journal_get_write_access(handle_t *handle, return ret; } +/* + * Truncate blocks that were not used by write. We have to truncate the + * pagecache as well so that corresponding buffers get properly unmapped. + */ +static void ext4_truncate_failed_write(struct inode *inode) +{ + truncate_inode_pages(inode->i_mapping, inode->i_size); + ext4_truncate(inode); +} + static int ext4_get_block_write(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create); static int ext4_write_begin(struct file *file, struct address_space *mapping, @@ -997,7 +1863,6 @@ static int ext4_journalled_write_end(struct file *file, if (new_i_size > inode->i_size) i_size_write(inode, pos+copied); ext4_set_inode_state(inode, EXT4_STATE_JDATA); - EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid; if (new_i_size > EXT4_I(inode)->i_disksize) { ext4_update_i_disksize(inode, new_i_size); ret2 = ext4_mark_inode_dirty(handle, inode); @@ -1706,7 +2571,6 @@ static int __ext4_journalled_writepage(struct page *page, write_end_fn); if (ret == 0) ret = err; - EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid; err = ext4_journal_stop(handle); if (!ret) ret = err; @@ -2585,6 +3449,112 @@ static int ext4_releasepage(struct page *page, gfp_t wait) return try_to_free_buffers(page); } +/* + * O_DIRECT for ext3 (or indirect map) based files + * + * If the O_DIRECT write will extend the file then add this inode to the + * orphan list. So recovery will truncate it back to the original size + * if the machine crashes during the write. + * + * If the O_DIRECT write is intantiating holes inside i_size and the machine + * crashes then stale disk data _may_ be exposed inside the file. But current + * VFS code falls back into buffered path in that case so we are safe. + */ +static ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + struct ext4_inode_info *ei = EXT4_I(inode); + handle_t *handle; + ssize_t ret; + int orphan = 0; + size_t count = iov_length(iov, nr_segs); + int retries = 0; + + if (rw == WRITE) { + loff_t final_size = offset + count; + + if (final_size > inode->i_size) { + /* Credits for sb + inode write */ + handle = ext4_journal_start(inode, 2); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } + ret = ext4_orphan_add(handle, inode); + if (ret) { + ext4_journal_stop(handle); + goto out; + } + orphan = 1; + ei->i_disksize = inode->i_size; + ext4_journal_stop(handle); + } + } + +retry: + if (rw == READ && ext4_should_dioread_nolock(inode)) + ret = __blockdev_direct_IO(rw, iocb, inode, + inode->i_sb->s_bdev, iov, + offset, nr_segs, + ext4_get_block, NULL, NULL, 0); + else { + ret = blockdev_direct_IO(rw, iocb, inode, iov, + offset, nr_segs, ext4_get_block); + + if (unlikely((rw & WRITE) && ret < 0)) { + loff_t isize = i_size_read(inode); + loff_t end = offset + iov_length(iov, nr_segs); + + if (end > isize) + ext4_truncate_failed_write(inode); + } + } + if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) + goto retry; + + if (orphan) { + int err; + + /* Credits for sb + inode write */ + handle = ext4_journal_start(inode, 2); + if (IS_ERR(handle)) { + /* This is really bad luck. We've written the data + * but cannot extend i_size. Bail out and pretend + * the write failed... */ + ret = PTR_ERR(handle); + if (inode->i_nlink) + ext4_orphan_del(NULL, inode); + + goto out; + } + if (inode->i_nlink) + ext4_orphan_del(handle, inode); + if (ret > 0) { + loff_t end = offset + ret; + if (end > inode->i_size) { + ei->i_disksize = end; + i_size_write(inode, end); + /* + * We're going to return a positive `ret' + * here due to non-zero-length I/O, so there's + * no way of reporting error returns from + * ext4_mark_inode_dirty() to userspace. So + * ignore it. + */ + ext4_mark_inode_dirty(handle, inode); + } + } + err = ext4_journal_stop(handle); + if (ret == 0) + ret = err; + } +out: + return ret; +} + /* * ext4_get_block used when preparing for a DIO write or buffer write. * We allocate an uinitialized extent if blocks haven't been allocated. @@ -3063,6 +4033,383 @@ int ext4_block_zero_page_range(handle_t *handle, return err; } +/* + * Probably it should be a library function... search for first non-zero word + * or memcmp with zero_page, whatever is better for particular architecture. + * Linus? + */ +static inline int all_zeroes(__le32 *p, __le32 *q) +{ + while (p < q) + if (*p++) + return 0; + return 1; +} + +/** + * ext4_find_shared - find the indirect blocks for partial truncation. + * @inode: inode in question + * @depth: depth of the affected branch + * @offsets: offsets of pointers in that branch (see ext4_block_to_path) + * @chain: place to store the pointers to partial indirect blocks + * @top: place to the (detached) top of branch + * + * This is a helper function used by ext4_truncate(). + * + * When we do truncate() we may have to clean the ends of several + * indirect blocks but leave the blocks themselves alive. Block is + * partially truncated if some data below the new i_size is referred + * from it (and it is on the path to the first completely truncated + * data block, indeed). We have to free the top of that path along + * with everything to the right of the path. Since no allocation + * past the truncation point is possible until ext4_truncate() + * finishes, we may safely do the latter, but top of branch may + * require special attention - pageout below the truncation point + * might try to populate it. + * + * We atomically detach the top of branch from the tree, store the + * block number of its root in *@top, pointers to buffer_heads of + * partially truncated blocks - in @chain[].bh and pointers to + * their last elements that should not be removed - in + * @chain[].p. Return value is the pointer to last filled element + * of @chain. + * + * The work left to caller to do the actual freeing of subtrees: + * a) free the subtree starting from *@top + * b) free the subtrees whose roots are stored in + * (@chain[i].p+1 .. end of @chain[i].bh->b_data) + * c) free the subtrees growing from the inode past the @chain[0]. + * (no partially truncated stuff there). */ + +static Indirect *ext4_find_shared(struct inode *inode, int depth, + ext4_lblk_t offsets[4], Indirect chain[4], + __le32 *top) +{ + Indirect *partial, *p; + int k, err; + + *top = 0; + /* Make k index the deepest non-null offset + 1 */ + for (k = depth; k > 1 && !offsets[k-1]; k--) + ; + partial = ext4_get_branch(inode, k, offsets, chain, &err); + /* Writer: pointers */ + if (!partial) + partial = chain + k-1; + /* + * If the branch acquired continuation since we've looked at it - + * fine, it should all survive and (new) top doesn't belong to us. + */ + if (!partial->key && *partial->p) + /* Writer: end */ + goto no_top; + for (p = partial; (p > chain) && all_zeroes((__le32 *) p->bh->b_data, p->p); p--) + ; + /* + * OK, we've found the last block that must survive. The rest of our + * branch should be detached before unlocking. However, if that rest + * of branch is all ours and does not grow immediately from the inode + * it's easier to cheat and just decrement partial->p. + */ + if (p == chain + k - 1 && p > chain) { + p->p--; + } else { + *top = *p->p; + /* Nope, don't do this in ext4. Must leave the tree intact */ +#if 0 + *p->p = 0; +#endif + } + /* Writer: end */ + + while (partial > p) { + brelse(partial->bh); + partial--; + } +no_top: + return partial; +} + +/* + * Zero a number of block pointers in either an inode or an indirect block. + * If we restart the transaction we must again get write access to the + * indirect block for further modification. + * + * We release `count' blocks on disk, but (last - first) may be greater + * than `count' because there can be holes in there. + * + * Return 0 on success, 1 on invalid block range + * and < 0 on fatal error. + */ +static int ext4_clear_blocks(handle_t *handle, struct inode *inode, + struct buffer_head *bh, + ext4_fsblk_t block_to_free, + unsigned long count, __le32 *first, + __le32 *last) +{ + __le32 *p; + int flags = EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_VALIDATED; + int err; + + if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) + flags |= EXT4_FREE_BLOCKS_METADATA; + + if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), block_to_free, + count)) { + EXT4_ERROR_INODE(inode, "attempt to clear invalid " + "blocks %llu len %lu", + (unsigned long long) block_to_free, count); + return 1; + } + + if (try_to_extend_transaction(handle, inode)) { + if (bh) { + BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); + err = ext4_handle_dirty_metadata(handle, inode, bh); + if (unlikely(err)) + goto out_err; + } + err = ext4_mark_inode_dirty(handle, inode); + if (unlikely(err)) + goto out_err; + err = ext4_truncate_restart_trans(handle, inode, + blocks_for_truncate(inode)); + if (unlikely(err)) + goto out_err; + if (bh) { + BUFFER_TRACE(bh, "retaking write access"); + err = ext4_journal_get_write_access(handle, bh); + if (unlikely(err)) + goto out_err; + } + } + + for (p = first; p < last; p++) + *p = 0; + + ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags); + return 0; +out_err: + ext4_std_error(inode->i_sb, err); + return err; +} + +/** + * ext4_free_data - free a list of data blocks + * @handle: handle for this transaction + * @inode: inode we are dealing with + * @this_bh: indirect buffer_head which contains *@first and *@last + * @first: array of block numbers + * @last: points immediately past the end of array + * + * We are freeing all blocks referred from that array (numbers are stored as + * little-endian 32-bit) and updating @inode->i_blocks appropriately. + * + * We accumulate contiguous runs of blocks to free. Conveniently, if these + * blocks are contiguous then releasing them at one time will only affect one + * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't + * actually use a lot of journal space. + * + * @this_bh will be %NULL if @first and @last point into the inode's direct + * block pointers. + */ +static void ext4_free_data(handle_t *handle, struct inode *inode, + struct buffer_head *this_bh, + __le32 *first, __le32 *last) +{ + ext4_fsblk_t block_to_free = 0; /* Starting block # of a run */ + unsigned long count = 0; /* Number of blocks in the run */ + __le32 *block_to_free_p = NULL; /* Pointer into inode/ind + corresponding to + block_to_free */ + ext4_fsblk_t nr; /* Current block # */ + __le32 *p; /* Pointer into inode/ind + for current block */ + int err = 0; + + if (this_bh) { /* For indirect block */ + BUFFER_TRACE(this_bh, "get_write_access"); + err = ext4_journal_get_write_access(handle, this_bh); + /* Important: if we can't update the indirect pointers + * to the blocks, we can't free them. */ + if (err) + return; + } + + for (p = first; p < last; p++) { + nr = le32_to_cpu(*p); + if (nr) { + /* accumulate blocks to free if they're contiguous */ + if (count == 0) { + block_to_free = nr; + block_to_free_p = p; + count = 1; + } else if (nr == block_to_free + count) { + count++; + } else { + err = ext4_clear_blocks(handle, inode, this_bh, + block_to_free, count, + block_to_free_p, p); + if (err) + break; + block_to_free = nr; + block_to_free_p = p; + count = 1; + } + } + } + + if (!err && count > 0) + err = ext4_clear_blocks(handle, inode, this_bh, block_to_free, + count, block_to_free_p, p); + if (err < 0) + /* fatal error */ + return; + + if (this_bh) { + BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata"); + + /* + * The buffer head should have an attached journal head at this + * point. However, if the data is corrupted and an indirect + * block pointed to itself, it would have been detached when + * the block was cleared. Check for this instead of OOPSing. + */ + if ((EXT4_JOURNAL(inode) == NULL) || bh2jh(this_bh)) + ext4_handle_dirty_metadata(handle, inode, this_bh); + else + EXT4_ERROR_INODE(inode, + "circular indirect block detected at " + "block %llu", + (unsigned long long) this_bh->b_blocknr); + } +} + +/** + * ext4_free_branches - free an array of branches + * @handle: JBD handle for this transaction + * @inode: inode we are dealing with + * @parent_bh: the buffer_head which contains *@first and *@last + * @first: array of block numbers + * @last: pointer immediately past the end of array + * @depth: depth of the branches to free + * + * We are freeing all blocks referred from these branches (numbers are + * stored as little-endian 32-bit) and updating @inode->i_blocks + * appropriately. + */ +static void ext4_free_branches(handle_t *handle, struct inode *inode, + struct buffer_head *parent_bh, + __le32 *first, __le32 *last, int depth) +{ + ext4_fsblk_t nr; + __le32 *p; + + if (ext4_handle_is_aborted(handle)) + return; + + if (depth--) { + struct buffer_head *bh; + int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); + p = last; + while (--p >= first) { + nr = le32_to_cpu(*p); + if (!nr) + continue; /* A hole */ + + if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), + nr, 1)) { + EXT4_ERROR_INODE(inode, + "invalid indirect mapped " + "block %lu (level %d)", + (unsigned long) nr, depth); + break; + } + + /* Go read the buffer for the next level down */ + bh = sb_bread(inode->i_sb, nr); + + /* + * A read failure? Report error and clear slot + * (should be rare). + */ + if (!bh) { + EXT4_ERROR_INODE_BLOCK(inode, nr, + "Read failure"); + continue; + } + + /* This zaps the entire block. Bottom up. */ + BUFFER_TRACE(bh, "free child branches"); + ext4_free_branches(handle, inode, bh, + (__le32 *) bh->b_data, + (__le32 *) bh->b_data + addr_per_block, + depth); + brelse(bh); + + /* + * Everything below this this pointer has been + * released. Now let this top-of-subtree go. + * + * We want the freeing of this indirect block to be + * atomic in the journal with the updating of the + * bitmap block which owns it. So make some room in + * the journal. + * + * We zero the parent pointer *after* freeing its + * pointee in the bitmaps, so if extend_transaction() + * for some reason fails to put the bitmap changes and + * the release into the same transaction, recovery + * will merely complain about releasing a free block, + * rather than leaking blocks. + */ + if (ext4_handle_is_aborted(handle)) + return; + if (try_to_extend_transaction(handle, inode)) { + ext4_mark_inode_dirty(handle, inode); + ext4_truncate_restart_trans(handle, inode, + blocks_for_truncate(inode)); + } + + /* + * The forget flag here is critical because if + * we are journaling (and not doing data + * journaling), we have to make sure a revoke + * record is written to prevent the journal + * replay from overwriting the (former) + * indirect block if it gets reallocated as a + * data block. This must happen in the same + * transaction where the data blocks are + * actually freed. + */ + ext4_free_blocks(handle, inode, NULL, nr, 1, + EXT4_FREE_BLOCKS_METADATA| + EXT4_FREE_BLOCKS_FORGET); + + if (parent_bh) { + /* + * The block which we have just freed is + * pointed to by an indirect block: journal it + */ + BUFFER_TRACE(parent_bh, "get_write_access"); + if (!ext4_journal_get_write_access(handle, + parent_bh)){ + *p = 0; + BUFFER_TRACE(parent_bh, + "call ext4_handle_dirty_metadata"); + ext4_handle_dirty_metadata(handle, + inode, + parent_bh); + } + } + } + } else { + /* We have reached the bottom of the tree. */ + BUFFER_TRACE(parent_bh, "free data blocks"); + ext4_free_data(handle, inode, parent_bh, first, last); + } +} + int ext4_can_truncate(struct inode *inode) { if (S_ISREG(inode->i_mode)) @@ -3129,6 +4476,19 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) */ void ext4_truncate(struct inode *inode) { + handle_t *handle; + struct ext4_inode_info *ei = EXT4_I(inode); + __le32 *i_data = ei->i_data; + int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); + struct address_space *mapping = inode->i_mapping; + ext4_lblk_t offsets[4]; + Indirect chain[4]; + Indirect *partial; + __le32 nr = 0; + int n = 0; + ext4_lblk_t last_block, max_block; + unsigned blocksize = inode->i_sb->s_blocksize; + trace_ext4_truncate_enter(inode); if (!ext4_can_truncate(inode)) @@ -3139,11 +4499,149 @@ void ext4_truncate(struct inode *inode) if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC)) ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE); - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) + if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { ext4_ext_truncate(inode); - else - ext4_ind_truncate(inode); + trace_ext4_truncate_exit(inode); + return; + } + + handle = start_transaction(inode); + if (IS_ERR(handle)) + return; /* AKPM: return what? */ + + last_block = (inode->i_size + blocksize-1) + >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); + max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1) + >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); + + if (inode->i_size & (blocksize - 1)) + if (ext4_block_truncate_page(handle, mapping, inode->i_size)) + goto out_stop; + + if (last_block != max_block) { + n = ext4_block_to_path(inode, last_block, offsets, NULL); + if (n == 0) + goto out_stop; /* error */ + } + + /* + * OK. This truncate is going to happen. We add the inode to the + * orphan list, so that if this truncate spans multiple transactions, + * and we crash, we will resume the truncate when the filesystem + * recovers. It also marks the inode dirty, to catch the new size. + * + * Implication: the file must always be in a sane, consistent + * truncatable state while each transaction commits. + */ + if (ext4_orphan_add(handle, inode)) + goto out_stop; + + /* + * From here we block out all ext4_get_block() callers who want to + * modify the block allocation tree. + */ + down_write(&ei->i_data_sem); + + ext4_discard_preallocations(inode); + + /* + * The orphan list entry will now protect us from any crash which + * occurs before the truncate completes, so it is now safe to propagate + * the new, shorter inode size (held for now in i_size) into the + * on-disk inode. We do this via i_disksize, which is the value which + * ext4 *really* writes onto the disk inode. + */ + ei->i_disksize = inode->i_size; + + if (last_block == max_block) { + /* + * It is unnecessary to free any data blocks if last_block is + * equal to the indirect block limit. + */ + goto out_unlock; + } else if (n == 1) { /* direct blocks */ + ext4_free_data(handle, inode, NULL, i_data+offsets[0], + i_data + EXT4_NDIR_BLOCKS); + goto do_indirects; + } + + partial = ext4_find_shared(inode, n, offsets, chain, &nr); + /* Kill the top of shared branch (not detached) */ + if (nr) { + if (partial == chain) { + /* Shared branch grows from the inode */ + ext4_free_branches(handle, inode, NULL, + &nr, &nr+1, (chain+n-1) - partial); + *partial->p = 0; + /* + * We mark the inode dirty prior to restart, + * and prior to stop. No need for it here. + */ + } else { + /* Shared branch grows from an indirect block */ + BUFFER_TRACE(partial->bh, "get_write_access"); + ext4_free_branches(handle, inode, partial->bh, + partial->p, + partial->p+1, (chain+n-1) - partial); + } + } + /* Clear the ends of indirect blocks on the shared branch */ + while (partial > chain) { + ext4_free_branches(handle, inode, partial->bh, partial->p + 1, + (__le32*)partial->bh->b_data+addr_per_block, + (chain+n-1) - partial); + BUFFER_TRACE(partial->bh, "call brelse"); + brelse(partial->bh); + partial--; + } +do_indirects: + /* Kill the remaining (whole) subtrees */ + switch (offsets[0]) { + default: + nr = i_data[EXT4_IND_BLOCK]; + if (nr) { + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); + i_data[EXT4_IND_BLOCK] = 0; + } + case EXT4_IND_BLOCK: + nr = i_data[EXT4_DIND_BLOCK]; + if (nr) { + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); + i_data[EXT4_DIND_BLOCK] = 0; + } + case EXT4_DIND_BLOCK: + nr = i_data[EXT4_TIND_BLOCK]; + if (nr) { + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); + i_data[EXT4_TIND_BLOCK] = 0; + } + case EXT4_TIND_BLOCK: + ; + } +out_unlock: + up_write(&ei->i_data_sem); + inode->i_mtime = inode->i_ctime = ext4_current_time(inode); + ext4_mark_inode_dirty(handle, inode); + + /* + * In a multi-transaction truncate, we only make the final transaction + * synchronous + */ + if (IS_SYNC(inode)) + ext4_handle_sync(handle); +out_stop: + /* + * If this was a simple ftruncate(), and the file will remain alive + * then we need to clear up the orphan record which we created above. + * However, if this was a real unlink then we were called by + * ext4_delete_inode(), and we allow that function to clean up the + * orphan info for us. + */ + if (inode->i_nlink) + ext4_orphan_del(handle, inode); + + ext4_journal_stop(handle); trace_ext4_truncate_exit(inode); } @@ -3514,7 +5012,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) (S_ISLNK(inode->i_mode) && !ext4_inode_is_fast_symlink(inode))) { /* Validate block references which are part of inode */ - ret = ext4_ind_check_inode(inode); + ret = ext4_check_inode_blockref(inode); } if (ret) goto bad_inode; @@ -3961,10 +5459,34 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, return 0; } +static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks, + int chunk) +{ + int indirects; + + /* if nrblocks are contiguous */ + if (chunk) { + /* + * With N contiguous data blocks, we need at most + * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) + 1 indirect blocks, + * 2 dindirect blocks, and 1 tindirect block + */ + return DIV_ROUND_UP(nrblocks, + EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4; + } + /* + * if nrblocks are not contiguous, worse case, each block touch + * a indirect block, and each indirect block touch a double indirect + * block, plus a triple indirect block + */ + indirects = nrblocks * 2 + 1; + return indirects; +} + static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk) { if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) - return ext4_ind_trans_blocks(inode, nrblocks, chunk); + return ext4_indirect_trans_blocks(inode, nrblocks, chunk); return ext4_ext_index_trans_blocks(inode, nrblocks, chunk); } diff --git a/trunk/fs/ext4/ioctl.c b/trunk/fs/ext4/ioctl.c index f18bfe37aff8..808c554e773f 100644 --- a/trunk/fs/ext4/ioctl.c +++ b/trunk/fs/ext4/ioctl.c @@ -202,9 +202,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct super_block *sb = inode->i_sb; int err, err2=0; - err = ext4_resize_begin(sb); - if (err) - return err; + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; if (get_user(n_blocks_count, (__u32 __user *)arg)) return -EFAULT; @@ -222,7 +221,6 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (err == 0) err = err2; mnt_drop_write(filp->f_path.mnt); - ext4_resize_end(sb); return err; } @@ -273,9 +271,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct super_block *sb = inode->i_sb; int err, err2=0; - err = ext4_resize_begin(sb); - if (err) - return err; + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, sizeof(input))) @@ -294,7 +291,6 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (err == 0) err = err2; mnt_drop_write(filp->f_path.mnt); - ext4_resize_end(sb); return err; } diff --git a/trunk/fs/ext4/mballoc.c b/trunk/fs/ext4/mballoc.c index 17a5a57c415a..6ed859d56850 100644 --- a/trunk/fs/ext4/mballoc.c +++ b/trunk/fs/ext4/mballoc.c @@ -75,8 +75,8 @@ * * The inode preallocation space is used looking at the _logical_ start * block. If only the logical file block falls within the range of prealloc - * space we will consume the particular prealloc space. This makes sure that - * we have contiguous physical blocks representing the file blocks + * space we will consume the particular prealloc space. This make sure that + * that the we have contiguous physical blocks representing the file blocks * * The important thing to be noted in case of inode prealloc space is that * we don't modify the values associated to inode prealloc space except @@ -84,7 +84,7 @@ * * If we are not able to find blocks in the inode prealloc space and if we * have the group allocation flag set then we look at the locality group - * prealloc space. These are per CPU prealloc list represented as + * prealloc space. These are per CPU prealloc list repreasented as * * ext4_sb_info.s_locality_groups[smp_processor_id()] * @@ -128,13 +128,12 @@ * we are doing a group prealloc we try to normalize the request to * sbi->s_mb_group_prealloc. Default value of s_mb_group_prealloc is * 512 blocks. This can be tuned via - * /sys/fs/ext4//mb_group_prealloc. The value is represented in + * /sys/fs/ext4/ option the group prealloc request is normalized to the - * the smallest multiple of the stripe value (sbi->s_stripe) which is - * greater than the default mb_group_prealloc. + * stripe value (sbi->s_stripe) * - * The regular allocator (using the buddy cache) supports a few tunables. + * The regular allocator(using the buddy cache) supports few tunables. * * /sys/fs/ext4//mb_min_to_scan * /sys/fs/ext4//mb_max_to_scan @@ -153,7 +152,7 @@ * best extent in the found extents. Searching for the blocks starts with * the group specified as the goal value in allocation context via * ac_g_ex. Each group is first checked based on the criteria whether it - * can be used for allocation. ext4_mb_good_group explains how the groups are + * can used for allocation. ext4_mb_good_group explains how the groups are * checked. * * Both the prealloc space are getting populated as above. So for the first @@ -493,11 +492,10 @@ static void mb_cmp_bitmaps(struct ext4_buddy *e4b, void *bitmap) b2 = (unsigned char *) bitmap; for (i = 0; i < e4b->bd_sb->s_blocksize; i++) { if (b1[i] != b2[i]) { - ext4_msg(e4b->bd_sb, KERN_ERR, - "corruption in group %u " - "at byte %u(%u): %x in copy != %x " - "on disk/prealloc", - e4b->bd_group, i, i * 8, b1[i], b2[i]); + printk(KERN_ERR "corruption in group %u " + "at byte %u(%u): %x in copy != %x " + "on disk/prealloc\n", + e4b->bd_group, i, i * 8, b1[i], b2[i]); BUG(); } } @@ -1127,7 +1125,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, grp = ext4_get_group_info(sb, group); e4b->bd_blkbits = sb->s_blocksize_bits; - e4b->bd_info = grp; + e4b->bd_info = ext4_get_group_info(sb, group); e4b->bd_sb = sb; e4b->bd_group = group; e4b->bd_buddy_page = NULL; @@ -1283,7 +1281,7 @@ static void mb_clear_bits(void *bm, int cur, int len) } } -void ext4_set_bits(void *bm, int cur, int len) +static void mb_set_bits(void *bm, int cur, int len) { __u32 *addr; @@ -1512,7 +1510,7 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex) } mb_set_largest_free_order(e4b->bd_sb, e4b->bd_info); - ext4_set_bits(EXT4_MB_BITMAP(e4b), ex->fe_start, len0); + mb_set_bits(EXT4_MB_BITMAP(e4b), ex->fe_start, len0); mb_check_buddy(e4b); return ret; @@ -2225,8 +2223,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, EXT4_DESC_PER_BLOCK_BITS(sb); meta_group_info = kmalloc(metalen, GFP_KERNEL); if (meta_group_info == NULL) { - ext4_msg(sb, KERN_ERR, "EXT4-fs: can't allocate mem " - "for a buddy group"); + printk(KERN_ERR "EXT4-fs: can't allocate mem for a " + "buddy group\n"); goto exit_meta_group_info; } sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] = @@ -2239,7 +2237,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, meta_group_info[i] = kmem_cache_alloc(cachep, GFP_KERNEL); if (meta_group_info[i] == NULL) { - ext4_msg(sb, KERN_ERR, "EXT4-fs: can't allocate buddy mem"); + printk(KERN_ERR "EXT4-fs: can't allocate buddy mem\n"); goto exit_group_info; } memset(meta_group_info[i], 0, kmem_cache_size(cachep)); @@ -2281,10 +2279,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, exit_group_info: /* If a meta_group_info table has been allocated, release it now */ - if (group % EXT4_DESC_PER_BLOCK(sb) == 0) { + if (group % EXT4_DESC_PER_BLOCK(sb) == 0) kfree(sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)]); - sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] = NULL; - } exit_meta_group_info: return -ENOMEM; } /* ext4_mb_add_groupinfo */ @@ -2332,26 +2328,23 @@ static int ext4_mb_init_backend(struct super_block *sb) /* An 8TB filesystem with 64-bit pointers requires a 4096 byte * kmalloc. A 128kb malloc should suffice for a 256TB filesystem. * So a two level scheme suffices for now. */ - sbi->s_group_info = ext4_kvzalloc(array_size, GFP_KERNEL); + sbi->s_group_info = kzalloc(array_size, GFP_KERNEL); if (sbi->s_group_info == NULL) { - ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group"); + printk(KERN_ERR "EXT4-fs: can't allocate buddy meta group\n"); return -ENOMEM; } sbi->s_buddy_cache = new_inode(sb); if (sbi->s_buddy_cache == NULL) { - ext4_msg(sb, KERN_ERR, "can't get new inode"); + printk(KERN_ERR "EXT4-fs: can't get new inode\n"); goto err_freesgi; } - /* To avoid potentially colliding with an valid on-disk inode number, - * use EXT4_BAD_INO for the buddy cache inode number. This inode is - * not in the inode hash, so it should never be found by iget(), but - * this will avoid confusion if it ever shows up during debugging. */ - sbi->s_buddy_cache->i_ino = EXT4_BAD_INO; + sbi->s_buddy_cache->i_ino = get_next_ino(); EXT4_I(sbi->s_buddy_cache)->i_disksize = 0; for (i = 0; i < ngroups; i++) { desc = ext4_get_group_desc(sb, i, NULL); if (desc == NULL) { - ext4_msg(sb, KERN_ERR, "can't read descriptor %u", i); + printk(KERN_ERR + "EXT4-fs: can't read descriptor %u\n", i); goto err_freebuddy; } if (ext4_mb_add_groupinfo(sb, i, desc) != 0) @@ -2369,7 +2362,7 @@ static int ext4_mb_init_backend(struct super_block *sb) kfree(sbi->s_group_info[i]); iput(sbi->s_buddy_cache); err_freesgi: - ext4_kvfree(sbi->s_group_info); + kfree(sbi->s_group_info); return -ENOMEM; } @@ -2411,15 +2404,14 @@ static int ext4_groupinfo_create_slab(size_t size) slab_size, 0, SLAB_RECLAIM_ACCOUNT, NULL); - ext4_groupinfo_caches[cache_index] = cachep; - mutex_unlock(&ext4_grpinfo_slab_create_mutex); if (!cachep) { - printk(KERN_EMERG - "EXT4-fs: no memory for groupinfo slab cache\n"); + printk(KERN_EMERG "EXT4: no memory for groupinfo slab cache\n"); return -ENOMEM; } + ext4_groupinfo_caches[cache_index] = cachep; + return 0; } @@ -2465,6 +2457,12 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) i++; } while (i <= sb->s_blocksize_bits + 1); + /* init file for buddy data */ + ret = ext4_mb_init_backend(sb); + if (ret != 0) { + goto out; + } + spin_lock_init(&sbi->s_md_lock); spin_lock_init(&sbi->s_bal_lock); @@ -2474,18 +2472,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) sbi->s_mb_stream_request = MB_DEFAULT_STREAM_THRESHOLD; sbi->s_mb_order2_reqs = MB_DEFAULT_ORDER2_REQS; sbi->s_mb_group_prealloc = MB_DEFAULT_GROUP_PREALLOC; - /* - * If there is a s_stripe > 1, then we set the s_mb_group_prealloc - * to the lowest multiple of s_stripe which is bigger than - * the s_mb_group_prealloc as determined above. We want - * the preallocation size to be an exact multiple of the - * RAID stripe size so that preallocations don't fragment - * the stripes. - */ - if (sbi->s_stripe > 1) { - sbi->s_mb_group_prealloc = roundup( - sbi->s_mb_group_prealloc, sbi->s_stripe); - } sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group); if (sbi->s_locality_groups == NULL) { @@ -2501,12 +2487,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) spin_lock_init(&lg->lg_prealloc_lock); } - /* init file for buddy data */ - ret = ext4_mb_init_backend(sb); - if (ret != 0) { - goto out; - } - if (sbi->s_proc) proc_create_data("mb_groups", S_IRUGO, sbi->s_proc, &ext4_mb_seq_groups_fops, sb); @@ -2564,32 +2544,32 @@ int ext4_mb_release(struct super_block *sb) EXT4_DESC_PER_BLOCK_BITS(sb); for (i = 0; i < num_meta_group_infos; i++) kfree(sbi->s_group_info[i]); - ext4_kvfree(sbi->s_group_info); + kfree(sbi->s_group_info); } kfree(sbi->s_mb_offsets); kfree(sbi->s_mb_maxs); if (sbi->s_buddy_cache) iput(sbi->s_buddy_cache); if (sbi->s_mb_stats) { - ext4_msg(sb, KERN_INFO, - "mballoc: %u blocks %u reqs (%u success)", + printk(KERN_INFO + "EXT4-fs: mballoc: %u blocks %u reqs (%u success)\n", atomic_read(&sbi->s_bal_allocated), atomic_read(&sbi->s_bal_reqs), atomic_read(&sbi->s_bal_success)); - ext4_msg(sb, KERN_INFO, - "mballoc: %u extents scanned, %u goal hits, " - "%u 2^N hits, %u breaks, %u lost", + printk(KERN_INFO + "EXT4-fs: mballoc: %u extents scanned, %u goal hits, " + "%u 2^N hits, %u breaks, %u lost\n", atomic_read(&sbi->s_bal_ex_scanned), atomic_read(&sbi->s_bal_goals), atomic_read(&sbi->s_bal_2orders), atomic_read(&sbi->s_bal_breaks), atomic_read(&sbi->s_mb_lost_chunks)); - ext4_msg(sb, KERN_INFO, - "mballoc: %lu generated and it took %Lu", - sbi->s_mb_buddies_generated, + printk(KERN_INFO + "EXT4-fs: mballoc: %lu generated and it took %Lu\n", + sbi->s_mb_buddies_generated++, sbi->s_mb_generation_time); - ext4_msg(sb, KERN_INFO, - "mballoc: %u preallocated, %u discarded", + printk(KERN_INFO + "EXT4-fs: mballoc: %u preallocated, %u discarded\n", atomic_read(&sbi->s_mb_preallocated), atomic_read(&sbi->s_mb_discarded)); } @@ -2648,15 +2628,6 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) rb_erase(&entry->node, &(db->bb_free_root)); mb_free_blocks(NULL, &e4b, entry->start_blk, entry->count); - /* - * Clear the trimmed flag for the group so that the next - * ext4_trim_fs can trim it. - * If the volume is mounted with -o discard, online discard - * is supported and the free blocks will be trimmed online. - */ - if (!test_opt(sb, DISCARD)) - EXT4_MB_GRP_CLEAR_TRIMMED(db); - if (!db->bb_free_root.rb_node) { /* No more items in the per group rb tree * balance refcounts from ext4_mb_free_metadata() @@ -2800,8 +2771,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, * We leak some of the blocks here. */ ext4_lock_group(sb, ac->ac_b_ex.fe_group); - ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, - ac->ac_b_ex.fe_len); + mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, + ac->ac_b_ex.fe_len); ext4_unlock_group(sb, ac->ac_b_ex.fe_group); err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); if (!err) @@ -2819,8 +2790,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, } } #endif - ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, - ac->ac_b_ex.fe_len); + mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,ac->ac_b_ex.fe_len); if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); ext4_free_blks_set(sb, gdp, @@ -2860,9 +2830,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, /* * here we normalize request for locality group - * Group request are normalized to s_mb_group_prealloc, which goes to - * s_strip if we set the same via mount option. - * s_mb_group_prealloc can be configured via + * Group request are normalized to s_strip size if we set the same via mount + * option. If not we set it to s_mb_group_prealloc which can be configured via * /sys/fs/ext4//mb_group_prealloc * * XXX: should we try to preallocate more than the group has now? @@ -2873,7 +2842,10 @@ static void ext4_mb_normalize_group_request(struct ext4_allocation_context *ac) struct ext4_locality_group *lg = ac->ac_lg; BUG_ON(lg == NULL); - ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc; + if (EXT4_SB(sb)->s_stripe) + ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_stripe; + else + ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc; mb_debug(1, "#%u: goal %u blocks for locality group\n", current->pid, ac->ac_g_ex.fe_len); } @@ -3029,10 +3001,9 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, if (start + size <= ac->ac_o_ex.fe_logical && start > ac->ac_o_ex.fe_logical) { - ext4_msg(ac->ac_sb, KERN_ERR, - "start %lu, size %lu, fe_logical %lu", - (unsigned long) start, (unsigned long) size, - (unsigned long) ac->ac_o_ex.fe_logical); + printk(KERN_ERR "start %lu, size %lu, fe_logical %lu\n", + (unsigned long) start, (unsigned long) size, + (unsigned long) ac->ac_o_ex.fe_logical); } BUG_ON(start + size <= ac->ac_o_ex.fe_logical && start > ac->ac_o_ex.fe_logical); @@ -3291,7 +3262,7 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, while (n) { entry = rb_entry(n, struct ext4_free_data, node); - ext4_set_bits(bitmap, entry->start_blk, entry->count); + mb_set_bits(bitmap, entry->start_blk, entry->count); n = rb_next(n); } return; @@ -3333,7 +3304,7 @@ void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, if (unlikely(len == 0)) continue; BUG_ON(groupnr != group); - ext4_set_bits(bitmap, start, len); + mb_set_bits(bitmap, start, len); preallocated += len; count++; } @@ -3613,11 +3584,10 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, bit = next + 1; } if (free != pa->pa_free) { - ext4_msg(e4b->bd_sb, KERN_CRIT, - "pa %p: logic %lu, phys. %lu, len %lu", - pa, (unsigned long) pa->pa_lstart, - (unsigned long) pa->pa_pstart, - (unsigned long) pa->pa_len); + printk(KERN_CRIT "pa %p: logic %lu, phys. %lu, len %lu\n", + pa, (unsigned long) pa->pa_lstart, + (unsigned long) pa->pa_pstart, + (unsigned long) pa->pa_len); ext4_grp_locked_error(sb, group, 0, 0, "free %u, pa_free %u", free, pa->pa_free); /* @@ -3805,8 +3775,7 @@ void ext4_discard_preallocations(struct inode *inode) * use preallocation while we're discarding it */ spin_unlock(&pa->pa_lock); spin_unlock(&ei->i_prealloc_lock); - ext4_msg(sb, KERN_ERR, - "uh-oh! used pa while discarding"); + printk(KERN_ERR "uh-oh! used pa while discarding\n"); WARN_ON(1); schedule_timeout_uninterruptible(HZ); goto repeat; @@ -3883,13 +3852,12 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac) (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)) return; - ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: Can't allocate:" - " Allocation context details:"); - ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: status %d flags %d", + printk(KERN_ERR "EXT4-fs: Can't allocate:" + " Allocation context details:\n"); + printk(KERN_ERR "EXT4-fs: status %d flags %d\n", ac->ac_status, ac->ac_flags); - ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: orig %lu/%lu/%lu@%lu, " - "goal %lu/%lu/%lu@%lu, " - "best %lu/%lu/%lu@%lu cr %d", + printk(KERN_ERR "EXT4-fs: orig %lu/%lu/%lu@%lu, goal %lu/%lu/%lu@%lu, " + "best %lu/%lu/%lu@%lu cr %d\n", (unsigned long)ac->ac_o_ex.fe_group, (unsigned long)ac->ac_o_ex.fe_start, (unsigned long)ac->ac_o_ex.fe_len, @@ -3903,9 +3871,9 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac) (unsigned long)ac->ac_b_ex.fe_len, (unsigned long)ac->ac_b_ex.fe_logical, (int)ac->ac_criteria); - ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: %lu scanned, %d found", - ac->ac_ex_scanned, ac->ac_found); - ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: groups: "); + printk(KERN_ERR "EXT4-fs: %lu scanned, %d found\n", ac->ac_ex_scanned, + ac->ac_found); + printk(KERN_ERR "EXT4-fs: groups: \n"); ngroups = ext4_get_groups_count(sb); for (i = 0; i < ngroups; i++) { struct ext4_group_info *grp = ext4_get_group_info(sb, i); @@ -4669,7 +4637,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, } ext4_mark_super_dirty(sb); error_return: - if (freed && !(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) + if (freed) dquot_free_block(inode, freed); brelse(bitmap_bh); ext4_std_error(sb, err); @@ -4677,7 +4645,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, } /** - * ext4_group_add_blocks() -- Add given blocks to an existing group + * ext4_add_groupblocks() -- Add given blocks to an existing group * @handle: handle to this transaction * @sb: super block * @block: start physcial block to add to the block group @@ -4685,7 +4653,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, * * This marks the blocks as free in the bitmap and buddy. */ -int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, +void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, ext4_fsblk_t block, unsigned long count) { struct buffer_head *bitmap_bh = NULL; @@ -4698,35 +4666,25 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, struct ext4_buddy e4b; int err = 0, ret, blk_free_count; ext4_grpblk_t blocks_freed; + struct ext4_group_info *grp; ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1); - if (count == 0) - return 0; - ext4_get_group_no_and_offset(sb, block, &block_group, &bit); + grp = ext4_get_group_info(sb, block_group); /* * Check to see if we are freeing blocks across a group * boundary. */ - if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) { - ext4_warning(sb, "too much blocks added to group %u\n", - block_group); - err = -EINVAL; + if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) goto error_return; - } bitmap_bh = ext4_read_block_bitmap(sb, block_group); - if (!bitmap_bh) { - err = -EIO; + if (!bitmap_bh) goto error_return; - } - desc = ext4_get_group_desc(sb, block_group, &gd_bh); - if (!desc) { - err = -EIO; + if (!desc) goto error_return; - } if (in_range(ext4_block_bitmap(sb, desc), block, count) || in_range(ext4_inode_bitmap(sb, desc), block, count) || @@ -4736,7 +4694,6 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, ext4_error(sb, "Adding blocks in system zones - " "Block = %llu, count = %lu", block, count); - err = -EINVAL; goto error_return; } @@ -4805,7 +4762,7 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, error_return: brelse(bitmap_bh); ext4_std_error(sb, err); - return err; + return; } /** @@ -4825,8 +4782,6 @@ static void ext4_trim_extent(struct super_block *sb, int start, int count, { struct ext4_free_extent ex; - trace_ext4_trim_extent(sb, group, start, count); - assert_spin_locked(ext4_group_lock_ptr(sb, group)); ex.fe_start = start; @@ -4847,7 +4802,7 @@ static void ext4_trim_extent(struct super_block *sb, int start, int count, /** * ext4_trim_all_free -- function to trim all free space in alloc. group * @sb: super block for file system - * @group: group to be trimmed + * @e4b: ext4 buddy * @start: first group block to examine * @max: last group block to examine * @minblocks: minimum extent block count @@ -4868,12 +4823,10 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, ext4_grpblk_t minblocks) { void *bitmap; - ext4_grpblk_t next, count = 0, free_count = 0; + ext4_grpblk_t next, count = 0; struct ext4_buddy e4b; int ret; - trace_ext4_trim_all_free(sb, group, start, max); - ret = ext4_mb_load_buddy(sb, group, &e4b); if (ret) { ext4_error(sb, "Error in loading buddy " @@ -4883,10 +4836,6 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, bitmap = e4b.bd_bitmap; ext4_lock_group(sb, group); - if (EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) && - minblocks >= atomic_read(&EXT4_SB(sb)->s_last_trim_minblks)) - goto out; - start = (e4b.bd_info->bb_first_free > start) ? e4b.bd_info->bb_first_free : start; @@ -4901,7 +4850,6 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, next - start, group, &e4b); count += next - start; } - free_count += next - start; start = next + 1; if (fatal_signal_pending(current)) { @@ -4915,13 +4863,9 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, ext4_lock_group(sb, group); } - if ((e4b.bd_info->bb_free - free_count) < minblocks) + if ((e4b.bd_info->bb_free - count) < minblocks) break; } - - if (!ret) - EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info); -out: ext4_unlock_group(sb, group); ext4_mb_unload_buddy(&e4b); @@ -4960,8 +4904,6 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) if (unlikely(minlen > EXT4_BLOCKS_PER_GROUP(sb))) return -EINVAL; - if (start + len <= first_data_blk) - goto out; if (start < first_data_blk) { len -= first_data_blk - start; start = first_data_blk; @@ -5010,9 +4952,5 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) } range->len = trimmed * sb->s_blocksize; - if (!ret) - atomic_set(&EXT4_SB(sb)->s_last_trim_minblks, minlen); - -out: return ret; } diff --git a/trunk/fs/ext4/mballoc.h b/trunk/fs/ext4/mballoc.h index 9d4a636b546c..20b5e7bfebd1 100644 --- a/trunk/fs/ext4/mballoc.h +++ b/trunk/fs/ext4/mballoc.h @@ -187,6 +187,7 @@ struct ext4_allocation_context { __u16 ac_flags; /* allocation hints */ __u8 ac_status; __u8 ac_criteria; + __u8 ac_repeats; __u8 ac_2order; /* if request is to allocate 2^N blocks and * N > 0, the field stores N, otherwise 0 */ __u8 ac_op; /* operation, for history only */ diff --git a/trunk/fs/ext4/namei.c b/trunk/fs/ext4/namei.c index 565a154e22d4..8c9babac43dc 100644 --- a/trunk/fs/ext4/namei.c +++ b/trunk/fs/ext4/namei.c @@ -289,7 +289,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_ent while (len--) printk("%c", *name++); ext4fs_dirhash(de->name, de->name_len, &h); printk(":%x.%u ", h.hash, - (unsigned) ((char *) de - base)); + ((char *) de - base)); } space += EXT4_DIR_REC_LEN(de->name_len); names++; @@ -1013,7 +1013,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q *err = -ENOENT; errout: - dxtrace(printk(KERN_DEBUG "%s not found\n", d_name->name)); + dxtrace(printk(KERN_DEBUG "%s not found\n", name)); dx_release (frames); return NULL; } @@ -1985,11 +1985,18 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) if (!list_empty(&EXT4_I(inode)->i_orphan)) goto out_unlock; - /* - * Orphan handling is only valid for files with data blocks - * being truncated, or files being unlinked. Note that we either - * hold i_mutex, or the inode can not be referenced from outside, - * so i_nlink should not be bumped due to race + /* Orphan handling is only valid for files with data blocks + * being truncated, or files being unlinked. */ + + /* @@@ FIXME: Observation from aviro: + * I think I can trigger J_ASSERT in ext4_orphan_add(). We block + * here (on s_orphan_lock), so race with ext4_link() which might bump + * ->i_nlink. For, say it, character device. Not a regular file, + * not a directory, not a symlink and ->i_nlink > 0. + * + * tytso, 4/25/2009: I'm not sure how that could happen; + * shouldn't the fs core protect us from these sort of + * unlink()/link() races? */ J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); diff --git a/trunk/fs/ext4/page-io.c b/trunk/fs/ext4/page-io.c index 430c401d0895..7bb8f76d470a 100644 --- a/trunk/fs/ext4/page-io.c +++ b/trunk/fs/ext4/page-io.c @@ -285,7 +285,11 @@ static int io_submit_init(struct ext4_io_submit *io, io_end = ext4_init_io_end(inode, GFP_NOFS); if (!io_end) return -ENOMEM; - bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES)); + do { + bio = bio_alloc(GFP_NOIO, nvecs); + nvecs >>= 1; + } while (bio == NULL); + bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; bio->bi_private = io->io_end = io_end; diff --git a/trunk/fs/ext4/resize.c b/trunk/fs/ext4/resize.c index 707d3f16f7ce..80bbc9c60c24 100644 --- a/trunk/fs/ext4/resize.c +++ b/trunk/fs/ext4/resize.c @@ -16,35 +16,6 @@ #include "ext4_jbd2.h" -int ext4_resize_begin(struct super_block *sb) -{ - int ret = 0; - - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - - /* - * We are not allowed to do online-resizing on a filesystem mounted - * with error, because it can destroy the filesystem easily. - */ - if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { - ext4_warning(sb, "There are errors in the filesystem, " - "so online resizing is not allowed\n"); - return -EPERM; - } - - if (test_and_set_bit_lock(EXT4_RESIZING, &EXT4_SB(sb)->s_resize_flags)) - ret = -EBUSY; - - return ret; -} - -void ext4_resize_end(struct super_block *sb) -{ - clear_bit_unlock(EXT4_RESIZING, &EXT4_SB(sb)->s_resize_flags); - smp_mb__after_clear_bit(); -} - #define outside(b, first, last) ((b) < (first) || (b) >= (last)) #define inside(b, first, last) ((b) >= (first) && (b) < (last)) @@ -147,8 +118,10 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, brelse(bh); bh = ERR_PTR(err); } else { + lock_buffer(bh); memset(bh->b_data, 0, sb->s_blocksize); set_buffer_uptodate(bh); + unlock_buffer(bh); } return bh; @@ -159,7 +132,8 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, * If that fails, restart the transaction & regain write access for the * buffer head which is used for block_bitmap modifications. */ -static int extend_or_restart_transaction(handle_t *handle, int thresh) +static int extend_or_restart_transaction(handle_t *handle, int thresh, + struct buffer_head *bh) { int err; @@ -170,8 +144,9 @@ static int extend_or_restart_transaction(handle_t *handle, int thresh) if (err < 0) return err; if (err) { - err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA); - if (err) + if ((err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) + return err; + if ((err = ext4_journal_get_write_access(handle, bh))) return err; } @@ -206,7 +181,21 @@ static int setup_new_group_blocks(struct super_block *sb, if (IS_ERR(handle)) return PTR_ERR(handle); - BUG_ON(input->group != sbi->s_groups_count); + mutex_lock(&sbi->s_resize_lock); + if (input->group != sbi->s_groups_count) { + err = -EBUSY; + goto exit_journal; + } + + if (IS_ERR(bh = bclean(handle, sb, input->block_bitmap))) { + err = PTR_ERR(bh); + goto exit_journal; + } + + if (ext4_bg_has_super(sb, input->group)) { + ext4_debug("mark backup superblock %#04llx (+0)\n", start); + ext4_set_bit(0, bh->b_data); + } /* Copy all of the GDT blocks into the backup in this group */ for (i = 0, bit = 1, block = start + 1; @@ -214,26 +203,29 @@ static int setup_new_group_blocks(struct super_block *sb, struct buffer_head *gdb; ext4_debug("update backup group %#04llx (+%d)\n", block, bit); - err = extend_or_restart_transaction(handle, 1); - if (err) - goto exit_journal; + + if ((err = extend_or_restart_transaction(handle, 1, bh))) + goto exit_bh; gdb = sb_getblk(sb, block); if (!gdb) { err = -EIO; - goto exit_journal; + goto exit_bh; } if ((err = ext4_journal_get_write_access(handle, gdb))) { brelse(gdb); - goto exit_journal; + goto exit_bh; } + lock_buffer(gdb); memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size); set_buffer_uptodate(gdb); + unlock_buffer(gdb); err = ext4_handle_dirty_metadata(handle, NULL, gdb); if (unlikely(err)) { brelse(gdb); - goto exit_journal; + goto exit_bh; } + ext4_set_bit(bit, bh->b_data); brelse(gdb); } @@ -243,22 +235,9 @@ static int setup_new_group_blocks(struct super_block *sb, err = sb_issue_zeroout(sb, gdblocks + start + 1, reserved_gdb, GFP_NOFS); if (err) - goto exit_journal; - - err = extend_or_restart_transaction(handle, 2); - if (err) - goto exit_journal; - - bh = bclean(handle, sb, input->block_bitmap); - if (IS_ERR(bh)) { - err = PTR_ERR(bh); - goto exit_journal; - } - - if (ext4_bg_has_super(sb, input->group)) { - ext4_debug("mark backup group tables %#04llx (+0)\n", start); - ext4_set_bits(bh->b_data, 0, gdblocks + reserved_gdb + 1); - } + goto exit_bh; + for (i = 0, bit = gdblocks + 1; i < reserved_gdb; i++, bit++) + ext4_set_bit(bit, bh->b_data); ext4_debug("mark block bitmap %#04llx (+%llu)\n", input->block_bitmap, input->block_bitmap - start); @@ -274,9 +253,12 @@ static int setup_new_group_blocks(struct super_block *sb, err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS); if (err) goto exit_bh; - ext4_set_bits(bh->b_data, input->inode_table - start, - sbi->s_itb_per_group); + for (i = 0, bit = input->inode_table - start; + i < sbi->s_itb_per_group; i++, bit++) + ext4_set_bit(bit, bh->b_data); + if ((err = extend_or_restart_transaction(handle, 2, bh))) + goto exit_bh; ext4_mark_bitmap_end(input->blocks_count, sb->s_blocksize * 8, bh->b_data); @@ -303,6 +285,7 @@ static int setup_new_group_blocks(struct super_block *sb, brelse(bh); exit_journal: + mutex_unlock(&sbi->s_resize_lock); if ((err2 = ext4_journal_stop(handle)) && !err) err = err2; @@ -394,15 +377,15 @@ static int verify_reserved_gdb(struct super_block *sb, * fail once we start modifying the data on disk, because JBD has no rollback. */ static int add_new_gdb(handle_t *handle, struct inode *inode, - ext4_group_t group) + struct ext4_new_group_data *input, + struct buffer_head **primary) { struct super_block *sb = inode->i_sb; struct ext4_super_block *es = EXT4_SB(sb)->s_es; - unsigned long gdb_num = group / EXT4_DESC_PER_BLOCK(sb); + unsigned long gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb); ext4_fsblk_t gdblock = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; struct buffer_head **o_group_desc, **n_group_desc; struct buffer_head *dind; - struct buffer_head *gdb_bh; int gdbackups; struct ext4_iloc iloc; __le32 *data; @@ -425,12 +408,11 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, return -EPERM; } - gdb_bh = sb_bread(sb, gdblock); - if (!gdb_bh) + *primary = sb_bread(sb, gdblock); + if (!*primary) return -EIO; - gdbackups = verify_reserved_gdb(sb, gdb_bh); - if (gdbackups < 0) { + if ((gdbackups = verify_reserved_gdb(sb, *primary)) < 0) { err = gdbackups; goto exit_bh; } @@ -445,7 +427,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, data = (__le32 *)dind->b_data; if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) { ext4_warning(sb, "new group %u GDT block %llu not reserved", - group, gdblock); + input->group, gdblock); err = -EINVAL; goto exit_dind; } @@ -454,7 +436,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, if (unlikely(err)) goto exit_dind; - err = ext4_journal_get_write_access(handle, gdb_bh); + err = ext4_journal_get_write_access(handle, *primary); if (unlikely(err)) goto exit_sbh; @@ -467,13 +449,12 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, if (unlikely(err)) goto exit_dindj; - n_group_desc = ext4_kvmalloc((gdb_num + 1) * - sizeof(struct buffer_head *), - GFP_NOFS); + n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *), + GFP_NOFS); if (!n_group_desc) { err = -ENOMEM; - ext4_warning(sb, "not enough memory for %lu groups", - gdb_num + 1); + ext4_warning(sb, + "not enough memory for %lu groups", gdb_num + 1); goto exit_inode; } @@ -494,8 +475,8 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, } inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9; ext4_mark_iloc_dirty(handle, inode, &iloc); - memset(gdb_bh->b_data, 0, sb->s_blocksize); - err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh); + memset((*primary)->b_data, 0, sb->s_blocksize); + err = ext4_handle_dirty_metadata(handle, NULL, *primary); if (unlikely(err)) { ext4_std_error(sb, err); goto exit_inode; @@ -505,10 +486,10 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, o_group_desc = EXT4_SB(sb)->s_group_desc; memcpy(n_group_desc, o_group_desc, EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); - n_group_desc[gdb_num] = gdb_bh; + n_group_desc[gdb_num] = *primary; EXT4_SB(sb)->s_group_desc = n_group_desc; EXT4_SB(sb)->s_gdb_count++; - ext4_kvfree(o_group_desc); + kfree(o_group_desc); le16_add_cpu(&es->s_reserved_gdt_blocks, -1); err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); @@ -518,7 +499,6 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, return err; exit_inode: - ext4_kvfree(n_group_desc); /* ext4_handle_release_buffer(handle, iloc.bh); */ brelse(iloc.bh); exit_dindj: @@ -528,7 +508,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, exit_dind: brelse(dind); exit_bh: - brelse(gdb_bh); + brelse(*primary); ext4_debug("leaving with error %d\n", err); return err; @@ -548,7 +528,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, * backup GDT blocks are stored in their reserved primary GDT block. */ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, - ext4_group_t group) + struct ext4_new_group_data *input) { struct super_block *sb = inode->i_sb; int reserved_gdb =le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks); @@ -619,7 +599,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, * Finally we can add each of the reserved backup GDT blocks from * the new group to its reserved primary GDT block. */ - blk = group * EXT4_BLOCKS_PER_GROUP(sb); + blk = input->group * EXT4_BLOCKS_PER_GROUP(sb); for (i = 0; i < reserved_gdb; i++) { int err2; data = (__le32 *)primary[i]->b_data; @@ -819,6 +799,13 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) goto exit_put; } + mutex_lock(&sbi->s_resize_lock); + if (input->group != sbi->s_groups_count) { + ext4_warning(sb, "multiple resizers run on filesystem!"); + err = -EBUSY; + goto exit_journal; + } + if ((err = ext4_journal_get_write_access(handle, sbi->s_sbh))) goto exit_journal; @@ -833,25 +820,16 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) if ((err = ext4_journal_get_write_access(handle, primary))) goto exit_journal; - if (reserved_gdb && ext4_bg_num_gdb(sb, input->group)) { - err = reserve_backup_gdb(handle, inode, input->group); - if (err) - goto exit_journal; - } - } else { - /* - * Note that we can access new group descriptor block safely - * only if add_new_gdb() succeeds. - */ - err = add_new_gdb(handle, inode, input->group); - if (err) + if (reserved_gdb && ext4_bg_num_gdb(sb, input->group) && + (err = reserve_backup_gdb(handle, inode, input))) goto exit_journal; - primary = sbi->s_group_desc[gdb_num]; - } + } else if ((err = add_new_gdb(handle, inode, input, &primary))) + goto exit_journal; /* * OK, now we've set up the new group. Time to make it active. * + * We do not lock all allocations via s_resize_lock * so we have to be safe wrt. concurrent accesses the group * data. So we need to be careful to set all of the relevant * group descriptor data etc. *before* we enable the group. @@ -908,9 +886,13 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) * * The precise rules we use are: * + * * Writers of s_groups_count *must* hold s_resize_lock + * AND * * Writers must perform a smp_wmb() after updating all dependent * data and before modifying the groups count * + * * Readers must hold s_resize_lock over the access + * OR * * Readers must perform an smp_rmb() after reading the groups count * and before reading any dependent data. * @@ -955,9 +937,10 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) ext4_handle_dirty_super(handle, sb); exit_journal: + mutex_unlock(&sbi->s_resize_lock); if ((err2 = ext4_journal_stop(handle)) && !err) err = err2; - if (!err && primary) { + if (!err) { update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, sizeof(struct ext4_super_block)); update_backups(sb, primary->b_blocknr, primary->b_data, @@ -986,13 +969,16 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, ext4_grpblk_t add; struct buffer_head *bh; handle_t *handle; - int err, err2; + int err; ext4_group_t group; + /* We don't need to worry about locking wrt other resizers just + * yet: we're going to revalidate es->s_blocks_count after + * taking the s_resize_lock below. */ o_blocks_count = ext4_blocks_count(es); if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT4-fs: extending last group from %llu to %llu blocks\n", + printk(KERN_DEBUG "EXT4-fs: extending last group from %llu uto %llu blocks\n", o_blocks_count, n_blocks_count); if (n_blocks_count == 0 || n_blocks_count == o_blocks_count) @@ -1009,7 +995,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, if (n_blocks_count < o_blocks_count) { ext4_warning(sb, "can't shrink FS - resize aborted"); - return -EINVAL; + return -EBUSY; } /* Handle the remaining blocks in the last group only. */ @@ -1052,25 +1038,32 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, goto exit_put; } + mutex_lock(&EXT4_SB(sb)->s_resize_lock); + if (o_blocks_count != ext4_blocks_count(es)) { + ext4_warning(sb, "multiple resizers run on filesystem!"); + mutex_unlock(&EXT4_SB(sb)->s_resize_lock); + ext4_journal_stop(handle); + err = -EBUSY; + goto exit_put; + } + if ((err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh))) { ext4_warning(sb, "error %d on journal write access", err); + mutex_unlock(&EXT4_SB(sb)->s_resize_lock); ext4_journal_stop(handle); goto exit_put; } ext4_blocks_count_set(es, o_blocks_count + add); + mutex_unlock(&EXT4_SB(sb)->s_resize_lock); ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count, o_blocks_count + add); /* We add the blocks to the bitmap and set the group need init bit */ - err = ext4_group_add_blocks(handle, sb, o_blocks_count, add); + ext4_add_groupblocks(handle, sb, o_blocks_count, add); ext4_handle_dirty_super(handle, sb); ext4_debug("freed blocks %llu through %llu\n", o_blocks_count, o_blocks_count + add); - err2 = ext4_journal_stop(handle); - if (!err && err2) - err = err2; - - if (err) + if ((err = ext4_journal_stop(handle))) goto exit_put; if (test_opt(sb, DEBUG)) diff --git a/trunk/fs/ext4/super.c b/trunk/fs/ext4/super.c index 4687fea0c00f..9ea71aa864b3 100644 --- a/trunk/fs/ext4/super.c +++ b/trunk/fs/ext4/super.c @@ -110,35 +110,6 @@ static struct file_system_type ext3_fs_type = { #define IS_EXT3_SB(sb) (0) #endif -void *ext4_kvmalloc(size_t size, gfp_t flags) -{ - void *ret; - - ret = kmalloc(size, flags); - if (!ret) - ret = __vmalloc(size, flags, PAGE_KERNEL); - return ret; -} - -void *ext4_kvzalloc(size_t size, gfp_t flags) -{ - void *ret; - - ret = kzalloc(size, flags); - if (!ret) - ret = __vmalloc(size, flags | __GFP_ZERO, PAGE_KERNEL); - return ret; -} - -void ext4_kvfree(void *ptr) -{ - if (is_vmalloc_addr(ptr)) - vfree(ptr); - else - kfree(ptr); - -} - ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, struct ext4_group_desc *bg) { @@ -298,7 +269,6 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) journal_t *journal; handle_t *handle; - trace_ext4_journal_start(sb, nblocks, _RET_IP_); if (sb->s_flags & MS_RDONLY) return ERR_PTR(-EROFS); @@ -819,8 +789,11 @@ static void ext4_put_super(struct super_block *sb) for (i = 0; i < sbi->s_gdb_count; i++) brelse(sbi->s_group_desc[i]); - ext4_kvfree(sbi->s_group_desc); - ext4_kvfree(sbi->s_flex_groups); + kfree(sbi->s_group_desc); + if (is_vmalloc_addr(sbi->s_flex_groups)) + vfree(sbi->s_flex_groups); + else + kfree(sbi->s_flex_groups); percpu_counter_destroy(&sbi->s_freeblocks_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter); percpu_counter_destroy(&sbi->s_dirs_counter); @@ -2003,11 +1976,15 @@ static int ext4_fill_flex_info(struct super_block *sb) ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) << EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex; size = flex_group_count * sizeof(struct flex_groups); - sbi->s_flex_groups = ext4_kvzalloc(size, GFP_KERNEL); + sbi->s_flex_groups = kzalloc(size, GFP_KERNEL); if (sbi->s_flex_groups == NULL) { - ext4_msg(sb, KERN_ERR, "not enough memory for %u flex groups", - flex_group_count); - goto failed; + sbi->s_flex_groups = vzalloc(size); + if (sbi->s_flex_groups == NULL) { + ext4_msg(sb, KERN_ERR, + "not enough memory for %u flex groups", + flex_group_count); + goto failed; + } } for (i = 0; i < sbi->s_groups_count; i++) { @@ -2406,25 +2383,17 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi) unsigned long stride = le16_to_cpu(sbi->s_es->s_raid_stride); unsigned long stripe_width = le32_to_cpu(sbi->s_es->s_raid_stripe_width); - int ret; if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group) - ret = sbi->s_stripe; - else if (stripe_width <= sbi->s_blocks_per_group) - ret = stripe_width; - else if (stride <= sbi->s_blocks_per_group) - ret = stride; - else - ret = 0; + return sbi->s_stripe; - /* - * If the stripe width is 1, this makes no sense and - * we set it to 0 to turn off stripe handling code. - */ - if (ret <= 1) - ret = 0; + if (stripe_width <= sbi->s_blocks_per_group) + return stripe_width; - return ret; + if (stride <= sbi->s_blocks_per_group) + return stride; + + return 0; } /* sysfs supprt */ @@ -3439,9 +3408,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); - sbi->s_group_desc = ext4_kvmalloc(db_count * - sizeof(struct buffer_head *), - GFP_KERNEL); + sbi->s_group_desc = kmalloc(db_count * sizeof(struct buffer_head *), + GFP_KERNEL); if (sbi->s_group_desc == NULL) { ext4_msg(sb, KERN_ERR, "not enough memory"); goto failed_mount; @@ -3523,7 +3491,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ mutex_init(&sbi->s_orphan_lock); - sbi->s_resize_flags = 0; + mutex_init(&sbi->s_resize_lock); sb->s_root = NULL; @@ -3773,8 +3741,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } failed_mount3: del_timer(&sbi->s_err_report); - if (sbi->s_flex_groups) - ext4_kvfree(sbi->s_flex_groups); + if (sbi->s_flex_groups) { + if (is_vmalloc_addr(sbi->s_flex_groups)) + vfree(sbi->s_flex_groups); + else + kfree(sbi->s_flex_groups); + } percpu_counter_destroy(&sbi->s_freeblocks_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter); percpu_counter_destroy(&sbi->s_dirs_counter); @@ -3784,7 +3756,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) failed_mount2: for (i = 0; i < db_count; i++) brelse(sbi->s_group_desc[i]); - ext4_kvfree(sbi->s_group_desc); + kfree(sbi->s_group_desc); failed_mount: if (sbi->s_proc) { remove_proc_entry(sb->s_id, ext4_proc_root); diff --git a/trunk/fs/ext4/truncate.h b/trunk/fs/ext4/truncate.h deleted file mode 100644 index 011ba6670d99..000000000000 --- a/trunk/fs/ext4/truncate.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * linux/fs/ext4/truncate.h - * - * Common inline functions needed for truncate support - */ - -/* - * Truncate blocks that were not used by write. We have to truncate the - * pagecache as well so that corresponding buffers get properly unmapped. - */ -static inline void ext4_truncate_failed_write(struct inode *inode) -{ - truncate_inode_pages(inode->i_mapping, inode->i_size); - ext4_truncate(inode); -} - -/* - * Work out how many blocks we need to proceed with the next chunk of a - * truncate transaction. - */ -static inline unsigned long ext4_blocks_for_truncate(struct inode *inode) -{ - ext4_lblk_t needed; - - needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); - - /* Give ourselves just enough room to cope with inodes in which - * i_blocks is corrupt: we've seen disk corruptions in the past - * which resulted in random data in an inode which looked enough - * like a regular file for ext4 to try to delete it. Things - * will go a bit crazy if that happens, but at least we should - * try not to panic the whole kernel. */ - if (needed < 2) - needed = 2; - - /* But we need to bound the transaction so we don't overflow the - * journal. */ - if (needed > EXT4_MAX_TRANS_DATA) - needed = EXT4_MAX_TRANS_DATA; - - return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed; -} - diff --git a/trunk/fs/generic_acl.c b/trunk/fs/generic_acl.c index d0dddaceac59..d5e33a077a67 100644 --- a/trunk/fs/generic_acl.c +++ b/trunk/fs/generic_acl.c @@ -82,14 +82,18 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value, return PTR_ERR(acl); } if (acl) { + mode_t mode; + error = posix_acl_valid(acl); if (error) goto failed; switch (type) { case ACL_TYPE_ACCESS: - error = posix_acl_equiv_mode(acl, &inode->i_mode); + mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); if (error < 0) goto failed; + inode->i_mode = mode; inode->i_ctime = CURRENT_TIME; if (error == 0) { posix_acl_release(acl); @@ -121,20 +125,21 @@ int generic_acl_init(struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; + mode_t mode = inode->i_mode; int error; + inode->i_mode = mode & ~current_umask(); if (!S_ISLNK(inode->i_mode)) acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); if (acl) { if (S_ISDIR(inode->i_mode)) set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); + error = posix_acl_create(&acl, GFP_KERNEL, &mode); if (error < 0) return error; + inode->i_mode = mode; if (error > 0) set_cached_acl(inode, ACL_TYPE_ACCESS, acl); - } else { - inode->i_mode &= ~current_umask(); } error = 0; diff --git a/trunk/fs/gfs2/acl.c b/trunk/fs/gfs2/acl.c index 34501b64bc47..884c9af0542f 100644 --- a/trunk/fs/gfs2/acl.c +++ b/trunk/fs/gfs2/acl.c @@ -72,7 +72,7 @@ struct posix_acl *gfs2_get_acl(struct inode *inode, int type) return gfs2_acl_get(GFS2_I(inode), type); } -static int gfs2_set_mode(struct inode *inode, umode_t mode) +static int gfs2_set_mode(struct inode *inode, mode_t mode) { int error = 0; @@ -117,7 +117,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct posix_acl *acl; - umode_t mode = inode->i_mode; + mode_t mode = inode->i_mode; int error = 0; if (!sdp->sd_args.ar_posix_acl) @@ -276,7 +276,7 @@ static int gfs2_xattr_system_set(struct dentry *dentry, const char *name, goto out_release; if (type == ACL_TYPE_ACCESS) { - umode_t mode = inode->i_mode; + mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error <= 0) { diff --git a/trunk/fs/hppfs/hppfs.c b/trunk/fs/hppfs/hppfs.c index 970ea987b3f6..8635be5ffd97 100644 --- a/trunk/fs/hppfs/hppfs.c +++ b/trunk/fs/hppfs/hppfs.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include "os.h" diff --git a/trunk/fs/inode.c b/trunk/fs/inode.c index 5aab80dc008c..d0c72ff6b30e 100644 --- a/trunk/fs/inode.c +++ b/trunk/fs/inode.c @@ -399,12 +399,12 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval) EXPORT_SYMBOL(__insert_inode_hash); /** - * __remove_inode_hash - remove an inode from the hash + * remove_inode_hash - remove an inode from the hash * @inode: inode to unhash * * Remove an inode from the superblock. */ -void __remove_inode_hash(struct inode *inode) +void remove_inode_hash(struct inode *inode) { spin_lock(&inode_hash_lock); spin_lock(&inode->i_lock); @@ -412,7 +412,7 @@ void __remove_inode_hash(struct inode *inode) spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); } -EXPORT_SYMBOL(__remove_inode_hash); +EXPORT_SYMBOL(remove_inode_hash); void end_writeback(struct inode *inode) { @@ -454,9 +454,7 @@ static void evict(struct inode *inode) BUG_ON(!(inode->i_state & I_FREEING)); BUG_ON(!list_empty(&inode->i_lru)); - if (!list_empty(&inode->i_wb_list)) - inode_wb_list_del(inode); - + inode_wb_list_del(inode); inode_sb_list_del(inode); if (op->evict_inode) { @@ -1330,8 +1328,7 @@ static void iput_final(struct inode *inode) } inode->i_state |= I_FREEING; - if (!list_empty(&inode->i_lru)) - inode_lru_list_del(inode); + inode_lru_list_del(inode); spin_unlock(&inode->i_lock); evict(inode); diff --git a/trunk/fs/jbd2/checkpoint.c b/trunk/fs/jbd2/checkpoint.c index 16a698bd906d..2c62c5aae82f 100644 --- a/trunk/fs/jbd2/checkpoint.c +++ b/trunk/fs/jbd2/checkpoint.c @@ -257,12 +257,9 @@ static void __flush_batch(journal_t *journal, int *batch_count) { int i; - struct blk_plug plug; - blk_start_plug(&plug); for (i = 0; i < *batch_count; i++) - write_dirty_buffer(journal->j_chkpt_bhs[i], WRITE_SYNC); - blk_finish_plug(&plug); + write_dirty_buffer(journal->j_chkpt_bhs[i], WRITE); for (i = 0; i < *batch_count; i++) { struct buffer_head *bh = journal->j_chkpt_bhs[i]; diff --git a/trunk/fs/jbd2/journal.c b/trunk/fs/jbd2/journal.c index f24df13adc4e..0dfa5b598e68 100644 --- a/trunk/fs/jbd2/journal.c +++ b/trunk/fs/jbd2/journal.c @@ -2390,6 +2390,73 @@ static void __exit journal_exit(void) jbd2_journal_destroy_caches(); } +/* + * jbd2_dev_to_name is a utility function used by the jbd2 and ext4 + * tracing infrastructure to map a dev_t to a device name. + * + * The caller should use rcu_read_lock() in order to make sure the + * device name stays valid until its done with it. We use + * rcu_read_lock() as well to make sure we're safe in case the caller + * gets sloppy, and because rcu_read_lock() is cheap and can be safely + * nested. + */ +struct devname_cache { + struct rcu_head rcu; + dev_t device; + char devname[BDEVNAME_SIZE]; +}; +#define CACHE_SIZE_BITS 6 +static struct devname_cache *devcache[1 << CACHE_SIZE_BITS]; +static DEFINE_SPINLOCK(devname_cache_lock); + +static void free_devcache(struct rcu_head *rcu) +{ + kfree(rcu); +} + +const char *jbd2_dev_to_name(dev_t device) +{ + int i = hash_32(device, CACHE_SIZE_BITS); + char *ret; + struct block_device *bd; + static struct devname_cache *new_dev; + + rcu_read_lock(); + if (devcache[i] && devcache[i]->device == device) { + ret = devcache[i]->devname; + rcu_read_unlock(); + return ret; + } + rcu_read_unlock(); + + new_dev = kmalloc(sizeof(struct devname_cache), GFP_KERNEL); + if (!new_dev) + return "NODEV-ALLOCFAILURE"; /* Something non-NULL */ + bd = bdget(device); + spin_lock(&devname_cache_lock); + if (devcache[i]) { + if (devcache[i]->device == device) { + kfree(new_dev); + bdput(bd); + ret = devcache[i]->devname; + spin_unlock(&devname_cache_lock); + return ret; + } + call_rcu(&devcache[i]->rcu, free_devcache); + } + devcache[i] = new_dev; + devcache[i]->device = device; + if (bd) { + bdevname(bd, devcache[i]->devname); + bdput(bd); + } else + __bdevname(device, devcache[i]->devname); + ret = devcache[i]->devname; + spin_unlock(&devname_cache_lock); + return ret; +} +EXPORT_SYMBOL(jbd2_dev_to_name); + MODULE_LICENSE("GPL"); module_init(journal_init); module_exit(journal_exit); diff --git a/trunk/fs/jffs2/acl.c b/trunk/fs/jffs2/acl.c index 926d02068a14..27c511a1cf05 100644 --- a/trunk/fs/jffs2/acl.c +++ b/trunk/fs/jffs2/acl.c @@ -227,7 +227,7 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; if (acl) { - umode_t mode = inode->i_mode; + mode_t mode = inode->i_mode; rc = posix_acl_equiv_mode(acl, &mode); if (rc < 0) return rc; @@ -259,7 +259,7 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) return rc; } -int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode) +int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, mode_t *i_mode) { struct posix_acl *acl; int rc; diff --git a/trunk/fs/jffs2/acl.h b/trunk/fs/jffs2/acl.h index 9b477246f2a6..b3421c78d9f8 100644 --- a/trunk/fs/jffs2/acl.h +++ b/trunk/fs/jffs2/acl.h @@ -28,7 +28,7 @@ struct jffs2_acl_header { struct posix_acl *jffs2_get_acl(struct inode *inode, int type); extern int jffs2_acl_chmod(struct inode *); -extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *); +extern int jffs2_init_acl_pre(struct inode *, struct inode *, mode_t *); extern int jffs2_init_acl_post(struct inode *); extern const struct xattr_handler jffs2_acl_access_xattr_handler; diff --git a/trunk/fs/jffs2/fs.c b/trunk/fs/jffs2/fs.c index bbcb9755dd2b..b81b35ddf4e4 100644 --- a/trunk/fs/jffs2/fs.c +++ b/trunk/fs/jffs2/fs.c @@ -406,7 +406,7 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, fill in the raw_inode while you're at it. */ -struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_raw_inode *ri) +struct inode *jffs2_new_inode (struct inode *dir_i, mode_t mode, struct jffs2_raw_inode *ri) { struct inode *inode; struct super_block *sb = dir_i->i_sb; diff --git a/trunk/fs/jffs2/os-linux.h b/trunk/fs/jffs2/os-linux.h index 6c1755c59c0f..526979c607b6 100644 --- a/trunk/fs/jffs2/os-linux.h +++ b/trunk/fs/jffs2/os-linux.h @@ -173,7 +173,7 @@ int jffs2_do_setattr (struct inode *, struct iattr *); struct inode *jffs2_iget(struct super_block *, unsigned long); void jffs2_evict_inode (struct inode *); void jffs2_dirty_inode(struct inode *inode, int flags); -struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, +struct inode *jffs2_new_inode (struct inode *dir_i, mode_t mode, struct jffs2_raw_inode *ri); int jffs2_statfs (struct dentry *, struct kstatfs *); int jffs2_remount_fs (struct super_block *, int *, char *); diff --git a/trunk/fs/jfs/acl.c b/trunk/fs/jfs/acl.c index 45559dc3ea2f..b3a32caf2b45 100644 --- a/trunk/fs/jfs/acl.c +++ b/trunk/fs/jfs/acl.c @@ -127,14 +127,16 @@ int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) return PTR_ERR(acl); if (acl) { + mode_t mode = inode->i_mode; if (S_ISDIR(inode->i_mode)) { rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl); if (rc) goto cleanup; } - rc = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); + rc = posix_acl_create(&acl, GFP_KERNEL, &mode); if (rc < 0) goto cleanup; /* posix_acl_release(NULL) is no-op */ + inode->i_mode = mode; if (rc > 0) rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); cleanup: diff --git a/trunk/fs/jfs/xattr.c b/trunk/fs/jfs/xattr.c index e87fedef23db..24838f1eeee5 100644 --- a/trunk/fs/jfs/xattr.c +++ b/trunk/fs/jfs/xattr.c @@ -693,7 +693,8 @@ static int can_set_system_xattr(struct inode *inode, const char *name, return rc; } if (acl) { - rc = posix_acl_equiv_mode(acl, &inode->i_mode); + mode_t mode = inode->i_mode; + rc = posix_acl_equiv_mode(acl, &mode); posix_acl_release(acl); if (rc < 0) { printk(KERN_ERR @@ -701,6 +702,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name, rc); return rc; } + inode->i_mode = mode; mark_inode_dirty(inode); } /* diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index 3d607bd80e09..f8c69d373793 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -179,14 +179,19 @@ static int check_acl(struct inode *inode, int mask) #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *acl; + /* + * Under RCU walk, we cannot even do a "get_cached_acl()", + * because that involves locking and getting a refcount on + * a cached ACL. + * + * So the only case we handle during RCU walking is the + * case of a cached "no ACL at all", which needs no locks + * or refcounts. + */ if (mask & MAY_NOT_BLOCK) { - acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS); - if (!acl) + if (negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -EAGAIN; - /* no ->get_acl() calls in RCU mode... */ - if (acl == ACL_NOT_CACHED) - return -ECHILD; - return posix_acl_permission(inode, acl, mask); + return -ECHILD; } acl = get_cached_acl(inode, ACL_TYPE_ACCESS); @@ -711,25 +716,19 @@ static int follow_automount(struct path *path, unsigned flags, if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_PARENT)) return -EISDIR; /* we actually want to stop here */ - /* + /* We want to mount if someone is trying to open/create a file of any + * type under the mountpoint, wants to traverse through the mountpoint + * or wants to open the mounted directory. + * * We don't want to mount if someone's just doing a stat and they've * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and * appended a '/' to the name. */ - if (!(flags & LOOKUP_FOLLOW)) { - /* We do, however, want to mount if someone wants to open or - * create a file of any type under the mountpoint, wants to - * traverse through the mountpoint or wants to open the mounted - * directory. - * Also, autofs may mark negative dentries as being automount - * points. These will need the attentions of the daemon to - * instantiate them before they can be used. - */ - if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | - LOOKUP_OPEN | LOOKUP_CREATE)) && - path->dentry->d_inode) - return -EISDIR; - } + if (!(flags & LOOKUP_FOLLOW) && + !(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | + LOOKUP_OPEN | LOOKUP_CREATE))) + return -EISDIR; + current->total_link_count++; if (current->total_link_count >= 40) return -ELOOP; diff --git a/trunk/fs/nfs/nfs3acl.c b/trunk/fs/nfs/nfs3acl.c index 7ef23979896d..e49e73107e62 100644 --- a/trunk/fs/nfs/nfs3acl.c +++ b/trunk/fs/nfs/nfs3acl.c @@ -415,7 +415,7 @@ int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl) } int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, - umode_t mode) + mode_t mode) { struct posix_acl *dfacl, *acl; int error = 0; diff --git a/trunk/fs/nfs/nfs3proc.c b/trunk/fs/nfs/nfs3proc.c index 85f1690ca08c..38053d823eb0 100644 --- a/trunk/fs/nfs/nfs3proc.c +++ b/trunk/fs/nfs/nfs3proc.c @@ -316,7 +316,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nfs_open_context *ctx) { struct nfs3_createdata *data; - umode_t mode = sattr->ia_mode; + mode_t mode = sattr->ia_mode; int status = -ENOMEM; dprintk("NFS call create %s\n", dentry->d_name.name); @@ -562,7 +562,7 @@ static int nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { struct nfs3_createdata *data; - umode_t mode = sattr->ia_mode; + int mode = sattr->ia_mode; int status = -ENOMEM; dprintk("NFS call mkdir %s\n", dentry->d_name.name); @@ -681,7 +681,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, dev_t rdev) { struct nfs3_createdata *data; - umode_t mode = sattr->ia_mode; + mode_t mode = sattr->ia_mode; int status = -ENOMEM; dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, diff --git a/trunk/fs/ocfs2/acl.c b/trunk/fs/ocfs2/acl.c index a7219075b4de..783c58d9daf1 100644 --- a/trunk/fs/ocfs2/acl.c +++ b/trunk/fs/ocfs2/acl.c @@ -247,7 +247,7 @@ static int ocfs2_set_acl(handle_t *handle, case ACL_TYPE_ACCESS: name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - umode_t mode = inode->i_mode; + mode_t mode = inode->i_mode; ret = posix_acl_equiv_mode(acl, &mode); if (ret < 0) return ret; @@ -351,7 +351,7 @@ int ocfs2_init_acl(handle_t *handle, struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct posix_acl *acl = NULL; int ret = 0, ret2; - umode_t mode; + mode_t mode; if (!S_ISLNK(inode->i_mode)) { if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { diff --git a/trunk/fs/posix_acl.c b/trunk/fs/posix_acl.c index 10027b42b7e2..d43729a760e2 100644 --- a/trunk/fs/posix_acl.c +++ b/trunk/fs/posix_acl.c @@ -149,10 +149,10 @@ posix_acl_valid(const struct posix_acl *acl) * file mode permission bits, or else 1. Returns -E... on error. */ int -posix_acl_equiv_mode(const struct posix_acl *acl, umode_t *mode_p) +posix_acl_equiv_mode(const struct posix_acl *acl, mode_t *mode_p) { const struct posix_acl_entry *pa, *pe; - umode_t mode = 0; + mode_t mode = 0; int not_equiv = 0; FOREACH_ACL_ENTRY(pa, acl, pe) { @@ -188,7 +188,7 @@ posix_acl_equiv_mode(const struct posix_acl *acl, umode_t *mode_p) * Create an ACL representing the file mode permission bits of an inode. */ struct posix_acl * -posix_acl_from_mode(umode_t mode, gfp_t flags) +posix_acl_from_mode(mode_t mode, gfp_t flags) { struct posix_acl *acl = posix_acl_alloc(3, flags); if (!acl) @@ -279,11 +279,11 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want) * system calls. All permissions that are not granted by the acl are removed. * The permissions in the acl are changed to reflect the mode_p parameter. */ -static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p) +static int posix_acl_create_masq(struct posix_acl *acl, mode_t *mode_p) { struct posix_acl_entry *pa, *pe; struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; - umode_t mode = *mode_p; + mode_t mode = *mode_p; int not_equiv = 0; /* assert(atomic_read(acl->a_refcount) == 1); */ @@ -336,7 +336,7 @@ static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p) /* * Modify the ACL for the chmod syscall. */ -static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) +static int posix_acl_chmod_masq(struct posix_acl *acl, mode_t mode) { struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; struct posix_acl_entry *pa, *pe; @@ -382,7 +382,7 @@ static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) } int -posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) +posix_acl_create(struct posix_acl **acl, gfp_t gfp, mode_t *mode_p) { struct posix_acl *clone = posix_acl_clone(*acl, gfp); int err = -ENOMEM; @@ -400,7 +400,7 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) EXPORT_SYMBOL(posix_acl_create); int -posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) +posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, mode_t mode) { struct posix_acl *clone = posix_acl_clone(*acl, gfp); int err = -ENOMEM; diff --git a/trunk/fs/proc/base.c b/trunk/fs/proc/base.c index 5eb02069e1b8..08e3eccf9a12 100644 --- a/trunk/fs/proc/base.c +++ b/trunk/fs/proc/base.c @@ -1118,7 +1118,7 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, * Warn that /proc/pid/oom_adj is deprecated, see * Documentation/feature-removal-schedule.txt. */ - printk_once(KERN_WARNING "%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n", + WARN_ONCE(1, "%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n", current->comm, task_pid_nr(current), task_pid_nr(task), task_pid_nr(task)); task->signal->oom_adj = oom_adjust; @@ -1919,14 +1919,6 @@ static int proc_fd_info(struct inode *inode, struct path *path, char *info) spin_lock(&files->file_lock); file = fcheck_files(files, fd); if (file) { - unsigned int f_flags; - struct fdtable *fdt; - - fdt = files_fdtable(files); - f_flags = file->f_flags & ~O_CLOEXEC; - if (FD_ISSET(fd, fdt->close_on_exec)) - f_flags |= O_CLOEXEC; - if (path) { *path = file->f_path; path_get(&file->f_path); @@ -1936,7 +1928,7 @@ static int proc_fd_info(struct inode *inode, struct path *path, char *info) "pos:\t%lli\n" "flags:\t0%o\n", (long long) file->f_pos, - f_flags); + file->f_flags); spin_unlock(&files->file_lock); put_files_struct(files); return 0; diff --git a/trunk/fs/pstore/inode.c b/trunk/fs/pstore/inode.c index 893b961dcfd8..977ed2723845 100644 --- a/trunk/fs/pstore/inode.c +++ b/trunk/fs/pstore/inode.c @@ -39,9 +39,8 @@ #define PSTORE_NAMELEN 64 struct pstore_private { - struct pstore_info *psi; - enum pstore_type_id type; u64 id; + int (*erase)(u64); ssize_t size; char data[]; }; @@ -74,7 +73,7 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry) { struct pstore_private *p = dentry->d_inode->i_private; - p->psi->erase(p->type, p->id, p->psi); + p->erase(p->id); return simple_unlink(dir, dentry); } @@ -176,8 +175,8 @@ int pstore_is_mounted(void) * Set the mtime & ctime to the date that this record was originally stored. */ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, - char *data, size_t size, struct timespec time, - struct pstore_info *psi) + char *data, size_t size, + struct timespec time, int (*erase)(u64)) { struct dentry *root = pstore_sb->s_root; struct dentry *dentry; @@ -193,9 +192,8 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, private = kmalloc(sizeof *private + size, GFP_KERNEL); if (!private) goto fail_alloc; - private->type = type; private->id = id; - private->psi = psi; + private->erase = erase; switch (type) { case PSTORE_TYPE_DMESG: diff --git a/trunk/fs/pstore/internal.h b/trunk/fs/pstore/internal.h index 611c1b3c46fa..8c9f23eb1645 100644 --- a/trunk/fs/pstore/internal.h +++ b/trunk/fs/pstore/internal.h @@ -2,5 +2,5 @@ extern void pstore_set_kmsg_bytes(int); extern void pstore_get_records(void); extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, char *data, size_t size, - struct timespec time, struct pstore_info *psi); + struct timespec time, int (*erase)(u64)); extern int pstore_is_mounted(void); diff --git a/trunk/fs/pstore/platform.c b/trunk/fs/pstore/platform.c index c5300ec31696..f2c3ff20ea68 100644 --- a/trunk/fs/pstore/platform.c +++ b/trunk/fs/pstore/platform.c @@ -37,8 +37,6 @@ static DEFINE_SPINLOCK(pstore_lock); static struct pstore_info *psinfo; -static char *backend; - /* How much of the console log to snapshot */ static unsigned long kmsg_bytes = 10240; @@ -69,8 +67,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, unsigned long size, total = 0; char *dst, *why; u64 id; - int hsize; - unsigned int part = 1; + int hsize, part = 1; if (reason < ARRAY_SIZE(reason_str)) why = reason_str[reason]; @@ -81,7 +78,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, oopscount++; while (total < kmsg_bytes) { dst = psinfo->buf; - hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part); + hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part++); size = psinfo->bufsize - hsize; dst += hsize; @@ -97,16 +94,14 @@ static void pstore_dump(struct kmsg_dumper *dumper, memcpy(dst, s1 + s1_start, l1_cpy); memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy); - id = psinfo->write(PSTORE_TYPE_DMESG, part, - hsize + l1_cpy + l2_cpy, psinfo); + id = psinfo->write(PSTORE_TYPE_DMESG, hsize + l1_cpy + l2_cpy); if (reason == KMSG_DUMP_OOPS && pstore_is_mounted()) pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, hsize + l1_cpy + l2_cpy, - CURRENT_TIME, psinfo); + CURRENT_TIME, psinfo->erase); l1 -= l1_cpy; l2 -= l2_cpy; total += l1_cpy + l2_cpy; - part++; } mutex_unlock(&psinfo->buf_mutex); } @@ -133,12 +128,6 @@ int pstore_register(struct pstore_info *psi) spin_unlock(&pstore_lock); return -EBUSY; } - - if (backend && strcmp(backend, psi->name)) { - spin_unlock(&pstore_lock); - return -EINVAL; - } - psinfo = psi; spin_unlock(&pstore_lock); @@ -177,9 +166,9 @@ void pstore_get_records(void) if (rc) goto out; - while ((size = psi->read(&id, &type, &time, psi)) > 0) { + while ((size = psi->read(&id, &type, &time)) > 0) { if (pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, - time, psi)) + time, psi->erase)) failed++; } psi->close(psi); @@ -207,15 +196,12 @@ int pstore_write(enum pstore_type_id type, char *buf, size_t size) mutex_lock(&psinfo->buf_mutex); memcpy(psinfo->buf, buf, size); - id = psinfo->write(type, 0, size, psinfo); + id = psinfo->write(type, size); if (pstore_is_mounted()) pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, - size, CURRENT_TIME, psinfo); + size, CURRENT_TIME, psinfo->erase); mutex_unlock(&psinfo->buf_mutex); return 0; } EXPORT_SYMBOL_GPL(pstore_write); - -module_param(backend, charp, 0444); -MODULE_PARM_DESC(backend, "Pstore backend to use"); diff --git a/trunk/fs/reiserfs/xattr_acl.c b/trunk/fs/reiserfs/xattr_acl.c index 6da0396e5052..7362cf4c946a 100644 --- a/trunk/fs/reiserfs/xattr_acl.c +++ b/trunk/fs/reiserfs/xattr_acl.c @@ -272,10 +272,12 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); + mode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { + inode->i_mode = mode; if (error == 0) acl = NULL; } @@ -352,6 +354,8 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, return PTR_ERR(acl); if (acl) { + mode_t mode = inode->i_mode; + /* Copy the default ACL to the default ACL of a new directory */ if (S_ISDIR(inode->i_mode)) { err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT, @@ -362,10 +366,12 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, /* Now we reconcile the new ACL and the mode, potentially modifying both */ - err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + err = posix_acl_create(&acl, GFP_NOFS, &mode); if (err < 0) return err; + inode->i_mode = mode; + /* If we need an ACL.. */ if (err > 0) err = reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl); diff --git a/trunk/fs/stack.c b/trunk/fs/stack.c index b4f2ab48a61f..4a6f7f440658 100644 --- a/trunk/fs/stack.c +++ b/trunk/fs/stack.c @@ -29,7 +29,10 @@ void fsstack_copy_inode_size(struct inode *dst, struct inode *src) * * We don't actually know what locking is used at the lower level; * but if it's a filesystem that supports quotas, it will be using - * i_lock as in inode_add_bytes(). + * i_lock as in inode_add_bytes(). tmpfs uses other locking, and + * its 32-bit is (just) able to exceed 2TB i_size with the aid of + * holes; but its i_blocks cannot carry into the upper long without + * almost 2TB swap - let's ignore that case. */ if (sizeof(i_blocks) > sizeof(long)) spin_lock(&src->i_lock); diff --git a/trunk/fs/xfs/linux-2.6/xfs_acl.c b/trunk/fs/xfs/linux-2.6/xfs_acl.c index b6c4b3795c4a..44ce51656804 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_acl.c +++ b/trunk/fs/xfs/linux-2.6/xfs_acl.c @@ -221,7 +221,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) } static int -xfs_set_mode(struct inode *inode, umode_t mode) +xfs_set_mode(struct inode *inode, mode_t mode) { int error = 0; @@ -267,7 +267,7 @@ posix_acl_default_exists(struct inode *inode) int xfs_inherit_acl(struct inode *inode, struct posix_acl *acl) { - umode_t mode = inode->i_mode; + mode_t mode = inode->i_mode; int error = 0, inherit = 0; if (S_ISDIR(inode->i_mode)) { @@ -381,7 +381,7 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name, goto out_release; if (type == ACL_TYPE_ACCESS) { - umode_t mode = inode->i_mode; + mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error <= 0) { diff --git a/trunk/include/acpi/acpi_drivers.h b/trunk/include/acpi/acpi_drivers.h index e49c36d38d7e..3090471b2a5e 100644 --- a/trunk/include/acpi/acpi_drivers.h +++ b/trunk/include/acpi/acpi_drivers.h @@ -128,7 +128,7 @@ extern int is_dock_device(acpi_handle handle); extern int register_dock_notifier(struct notifier_block *nb); extern void unregister_dock_notifier(struct notifier_block *nb); extern int register_hotplug_dock_device(acpi_handle handle, - const struct acpi_dock_ops *ops, + struct acpi_dock_ops *ops, void *context); extern void unregister_hotplug_dock_device(acpi_handle handle); #else diff --git a/trunk/include/acpi/acpixf.h b/trunk/include/acpi/acpixf.h index f554a9313b43..2ed0a8486c19 100644 --- a/trunk/include/acpi/acpixf.h +++ b/trunk/include/acpi/acpixf.h @@ -47,7 +47,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20110623 +#define ACPI_CA_VERSION 0x20110413 #include "actypes.h" #include "actbl.h" @@ -69,7 +69,6 @@ extern u32 acpi_gbl_trace_flags; extern u32 acpi_gbl_enable_aml_debug_object; extern u8 acpi_gbl_copy_dsdt_locally; extern u8 acpi_gbl_truncate_io_addresses; -extern u8 acpi_gbl_disable_auto_repair; extern u32 acpi_current_gpe_count; extern struct acpi_table_fadt acpi_gbl_FADT; diff --git a/trunk/include/acpi/apei.h b/trunk/include/acpi/apei.h index 51a527d24a8a..e67b523a50e1 100644 --- a/trunk/include/acpi/apei.h +++ b/trunk/include/acpi/apei.h @@ -18,11 +18,6 @@ extern int hest_disable; extern int erst_disable; -#ifdef CONFIG_ACPI_APEI_GHES -extern int ghes_disable; -#else -#define ghes_disable 1 -#endif #ifdef CONFIG_ACPI_APEI void __init acpi_hest_init(void); diff --git a/trunk/include/acpi/processor.h b/trunk/include/acpi/processor.h index 67055f180330..ba4928cae473 100644 --- a/trunk/include/acpi/processor.h +++ b/trunk/include/acpi/processor.h @@ -337,7 +337,7 @@ extern struct cpuidle_driver acpi_idle_driver; /* in processor_thermal.c */ int acpi_processor_get_limit_info(struct acpi_processor *pr); -extern const struct thermal_cooling_device_ops processor_cooling_ops; +extern struct thermal_cooling_device_ops processor_cooling_ops; #ifdef CONFIG_CPU_FREQ void acpi_thermal_cpufreq_init(void); void acpi_thermal_cpufreq_exit(void); diff --git a/trunk/include/drm/drm_crtc.h b/trunk/include/drm/drm_crtc.h index 44335e57eaaa..33d12f87f0e0 100644 --- a/trunk/include/drm/drm_crtc.h +++ b/trunk/include/drm/drm_crtc.h @@ -205,8 +205,6 @@ struct drm_display_info { enum subpixel_order subpixel_order; u32 color_formats; - u8 cea_rev; - char *raw_edid; /* if any */ }; @@ -804,7 +802,6 @@ extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev, extern int drm_add_modes_noedid(struct drm_connector *connector, int hdisplay, int vdisplay); -extern int drm_edid_header_is_valid(const u8 *raw_edid); extern bool drm_edid_is_valid(struct edid *edid); struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh); diff --git a/trunk/include/drm/i915_drm.h b/trunk/include/drm/i915_drm.h index 28c0d114cb52..c4d6dbfa3ff4 100644 --- a/trunk/include/drm/i915_drm.h +++ b/trunk/include/drm/i915_drm.h @@ -237,7 +237,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture) #define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id) #define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise) -#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image) +#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_IOCTL_I915_OVERLAY_ATTRS, struct drm_intel_overlay_put_image) #define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs) /* Allow drivers to submit batchbuffers directly to hardware, relying diff --git a/trunk/include/linux/acpi.h b/trunk/include/linux/acpi.h index 6001b4da39dd..1deb2a73c2da 100644 --- a/trunk/include/linux/acpi.h +++ b/trunk/include/linux/acpi.h @@ -238,6 +238,7 @@ extern int acpi_paddr_to_node(u64 start_addr, u64 size); extern int pnpacpi_disabled; #define PXM_INVAL (-1) +#define NID_INVAL (-1) int acpi_check_resource_conflict(const struct resource *res); @@ -279,8 +280,6 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); #define OSC_SB_CPUHP_OST_SUPPORT 8 #define OSC_SB_APEI_SUPPORT 16 -extern bool osc_sb_apei_support_acked; - /* PCI defined _OSC bits */ /* _OSC DW1 Definition (OS Support Fields) */ #define OSC_EXT_PCI_CONFIG_SUPPORT 1 diff --git a/trunk/include/linux/amba/pl08x.h b/trunk/include/linux/amba/pl08x.h index e6e28f37d8ec..3111385b8ca7 100644 --- a/trunk/include/linux/amba/pl08x.h +++ b/trunk/include/linux/amba/pl08x.h @@ -172,11 +172,8 @@ struct pl08x_dma_chan { int phychan_hold; struct tasklet_struct tasklet; char *name; - const struct pl08x_channel_data *cd; - dma_addr_t src_addr; - dma_addr_t dst_addr; - u32 src_cctl; - u32 dst_cctl; + struct pl08x_channel_data *cd; + dma_addr_t runtime_addr; enum dma_data_direction runtime_direction; dma_cookie_t lc; struct list_head pend_list; @@ -205,7 +202,7 @@ struct pl08x_dma_chan { * @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2 */ struct pl08x_platform_data { - const struct pl08x_channel_data *slave_channels; + struct pl08x_channel_data *slave_channels; unsigned int num_slave_channels; struct pl08x_channel_data memcpy_channel; int (*get_signal)(struct pl08x_dma_chan *); diff --git a/trunk/include/linux/bitmap.h b/trunk/include/linux/bitmap.h index 7ad634501e48..3bac44cce142 100644 --- a/trunk/include/linux/bitmap.h +++ b/trunk/include/linux/bitmap.h @@ -146,7 +146,6 @@ extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order); extern void bitmap_copy_le(void *dst, const unsigned long *src, int nbits); extern int bitmap_ord_to_pos(const unsigned long *bitmap, int n, int bits); -#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG)) #define BITMAP_LAST_WORD_MASK(nbits) \ ( \ ((nbits) % BITS_PER_LONG) ? \ diff --git a/trunk/include/linux/cpuidle.h b/trunk/include/linux/cpuidle.h index b51629e15cfc..36719ead50e8 100644 --- a/trunk/include/linux/cpuidle.h +++ b/trunk/include/linux/cpuidle.h @@ -122,8 +122,6 @@ struct cpuidle_driver { }; #ifdef CONFIG_CPU_IDLE -extern void disable_cpuidle(void); -extern int cpuidle_idle_call(void); extern int cpuidle_register_driver(struct cpuidle_driver *drv); struct cpuidle_driver *cpuidle_get_driver(void); @@ -137,8 +135,6 @@ extern int cpuidle_enable_device(struct cpuidle_device *dev); extern void cpuidle_disable_device(struct cpuidle_device *dev); #else -static inline void disable_cpuidle(void) { } -static inline int cpuidle_idle_call(void) { return -ENODEV; } static inline int cpuidle_register_driver(struct cpuidle_driver *drv) {return -ENODEV; } diff --git a/trunk/include/linux/cryptohash.h b/trunk/include/linux/cryptohash.h index f9452185b019..ec78a4bbe1d5 100644 --- a/trunk/include/linux/cryptohash.h +++ b/trunk/include/linux/cryptohash.h @@ -3,7 +3,7 @@ #define SHA_DIGEST_WORDS 5 #define SHA_MESSAGE_BYTES (512 /*bits*/ / 8) -#define SHA_WORKSPACE_WORDS 16 +#define SHA_WORKSPACE_WORDS 80 void sha_init(__u32 *buf); void sha_transform(__u32 *digest, const char *data, __u32 *W); diff --git a/trunk/include/linux/device-mapper.h b/trunk/include/linux/device-mapper.h index 3fa1f3d90ce0..4427e0454051 100644 --- a/trunk/include/linux/device-mapper.h +++ b/trunk/include/linux/device-mapper.h @@ -208,49 +208,6 @@ struct dm_target_callbacks { int dm_register_target(struct target_type *t); void dm_unregister_target(struct target_type *t); -/* - * Target argument parsing. - */ -struct dm_arg_set { - unsigned argc; - char **argv; -}; - -/* - * The minimum and maximum value of a numeric argument, together with - * the error message to use if the number is found to be outside that range. - */ -struct dm_arg { - unsigned min; - unsigned max; - char *error; -}; - -/* - * Validate the next argument, either returning it as *value or, if invalid, - * returning -EINVAL and setting *error. - */ -int dm_read_arg(struct dm_arg *arg, struct dm_arg_set *arg_set, - unsigned *value, char **error); - -/* - * Process the next argument as the start of a group containing between - * arg->min and arg->max further arguments. Either return the size as - * *num_args or, if invalid, return -EINVAL and set *error. - */ -int dm_read_arg_group(struct dm_arg *arg, struct dm_arg_set *arg_set, - unsigned *num_args, char **error); - -/* - * Return the current argument and shift to the next. - */ -const char *dm_shift_arg(struct dm_arg_set *as); - -/* - * Move through num_args arguments. - */ -void dm_consume_args(struct dm_arg_set *as, unsigned num_args); - /*----------------------------------------------------------------- * Functions for creating and manipulating mapped devices. * Drop the reference with dm_put when you finish with the object. diff --git a/trunk/include/linux/dm-ioctl.h b/trunk/include/linux/dm-ioctl.h index 0cb8eff76bd6..3708455ee6c3 100644 --- a/trunk/include/linux/dm-ioctl.h +++ b/trunk/include/linux/dm-ioctl.h @@ -267,9 +267,9 @@ enum { #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 21 +#define DM_VERSION_MINOR 20 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2011-07-06)" +#define DM_VERSION_EXTRA "-ioctl (2011-02-02)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ diff --git a/trunk/include/linux/dm-kcopyd.h b/trunk/include/linux/dm-kcopyd.h index 5e54458e920f..298d587e349b 100644 --- a/trunk/include/linux/dm-kcopyd.h +++ b/trunk/include/linux/dm-kcopyd.h @@ -42,20 +42,5 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, unsigned num_dests, struct dm_io_region *dests, unsigned flags, dm_kcopyd_notify_fn fn, void *context); -/* - * Prepare a callback and submit it via the kcopyd thread. - * - * dm_kcopyd_prepare_callback allocates a callback structure and returns it. - * It must not be called from interrupt context. - * The returned value should be passed into dm_kcopyd_do_callback. - * - * dm_kcopyd_do_callback submits the callback. - * It may be called from interrupt context. - * The callback is issued from the kcopyd thread. - */ -void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, - dm_kcopyd_notify_fn fn, void *context); -void dm_kcopyd_do_callback(void *job, int read_err, unsigned long write_err); - #endif /* __KERNEL__ */ #endif /* _LINUX_DM_KCOPYD_H */ diff --git a/trunk/include/linux/efi.h b/trunk/include/linux/efi.h index 2362a0bc7f0d..ec2572693925 100644 --- a/trunk/include/linux/efi.h +++ b/trunk/include/linux/efi.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -233,9 +232,6 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules, #define UV_SYSTEM_TABLE_GUID \ EFI_GUID( 0x3b13a7d4, 0x633e, 0x11dd, 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93 ) -#define LINUX_EFI_CRASH_GUID \ - EFI_GUID( 0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0 ) - typedef struct { efi_guid_t guid; unsigned long table; @@ -462,8 +458,6 @@ struct efivars { struct kset *kset; struct bin_attribute *new_var, *del_var; const struct efivar_operations *ops; - struct efivar_entry *walk_entry; - struct pstore_info efi_pstore_info; }; int register_efivars(struct efivars *efivars, diff --git a/trunk/include/linux/fault-inject.h b/trunk/include/linux/fault-inject.h index c6f996f2abb6..3ff060ac7810 100644 --- a/trunk/include/linux/fault-inject.h +++ b/trunk/include/linux/fault-inject.h @@ -25,6 +25,10 @@ struct fault_attr { unsigned long reject_end; unsigned long count; + +#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS + struct dentry *dir; +#endif }; #define FAULT_ATTR_INITIALIZER { \ @@ -41,15 +45,19 @@ bool should_fail(struct fault_attr *attr, ssize_t size); #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS -struct dentry *fault_create_debugfs_attr(const char *name, - struct dentry *parent, struct fault_attr *attr); +int init_fault_attr_dentries(struct fault_attr *attr, const char *name); +void cleanup_fault_attr_dentries(struct fault_attr *attr); #else /* CONFIG_FAULT_INJECTION_DEBUG_FS */ -static inline struct dentry *fault_create_debugfs_attr(const char *name, - struct dentry *parent, struct fault_attr *attr) +static inline int init_fault_attr_dentries(struct fault_attr *attr, + const char *name) +{ + return -ENODEV; +} + +static inline void cleanup_fault_attr_dentries(struct fault_attr *attr) { - return ERR_PTR(-ENODEV); } #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ diff --git a/trunk/include/linux/fs.h b/trunk/include/linux/fs.h index 786b3b1113cf..f23bcb77260c 100644 --- a/trunk/include/linux/fs.h +++ b/trunk/include/linux/fs.h @@ -2317,18 +2317,11 @@ extern int should_remove_suid(struct dentry *); extern int file_remove_suid(struct file *); extern void __insert_inode_hash(struct inode *, unsigned long hashval); +extern void remove_inode_hash(struct inode *); static inline void insert_inode_hash(struct inode *inode) { __insert_inode_hash(inode, inode->i_ino); } - -extern void __remove_inode_hash(struct inode *); -static inline void remove_inode_hash(struct inode *inode) -{ - if (!inode_unhashed(inode)) - __remove_inode_hash(inode); -} - extern void inode_sb_list_add(struct inode *inode); #ifdef CONFIG_BLOCK diff --git a/trunk/include/linux/genalloc.h b/trunk/include/linux/genalloc.h index 5e98eeb2af3b..5bbebda78b02 100644 --- a/trunk/include/linux/genalloc.h +++ b/trunk/include/linux/genalloc.h @@ -1,26 +1,8 @@ /* - * Basic general purpose allocator for managing special purpose - * memory, for example, memory that is not managed by the regular - * kmalloc/kfree interface. Uses for this includes on-device special - * memory, uncached memory etc. - * - * It is safe to use the allocator in NMI handlers and other special - * unblockable contexts that could otherwise deadlock on locks. This - * is implemented by using atomic operations and retries on any - * conflicts. The disadvantage is that there may be livelocks in - * extreme cases. For better scalability, one allocator can be used - * for each CPU. - * - * The lockless operation only works if there is enough memory - * available. If new memory is added to the pool a lock has to be - * still taken. So any user relying on locklessness has to ensure - * that sufficient memory is preallocated. - * - * The basic atomic operation of this allocator is cmpxchg on long. - * On architectures that don't have NMI-safe cmpxchg implementation, - * the allocator can NOT be used in NMI handler. So code uses the - * allocator in NMI handler should depend on - * CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG. + * Basic general purpose allocator for managing special purpose memory + * not managed by the regular kmalloc/kfree interface. + * Uses for this includes on-device special memory, uncached memory + * etc. * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. @@ -33,7 +15,7 @@ * General purpose special memory pool descriptor. */ struct gen_pool { - spinlock_t lock; + rwlock_t lock; struct list_head chunks; /* list of chunks in this pool */ int min_alloc_order; /* minimum allocation order */ }; @@ -42,8 +24,8 @@ struct gen_pool { * General purpose special memory pool chunk descriptor. */ struct gen_pool_chunk { + spinlock_t lock; struct list_head next_chunk; /* next chunk in pool */ - atomic_t avail; phys_addr_t phys_addr; /* physical starting address of memory chunk */ unsigned long start_addr; /* starting address of memory chunk */ unsigned long end_addr; /* ending address of memory chunk */ @@ -74,8 +56,4 @@ static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr, extern void gen_pool_destroy(struct gen_pool *); extern unsigned long gen_pool_alloc(struct gen_pool *, size_t); extern void gen_pool_free(struct gen_pool *, unsigned long, size_t); -extern void gen_pool_for_each_chunk(struct gen_pool *, - void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *); -extern size_t gen_pool_avail(struct gen_pool *); -extern size_t gen_pool_size(struct gen_pool *); #endif /* __GENALLOC_H__ */ diff --git a/trunk/include/linux/gfp.h b/trunk/include/linux/gfp.h index 3a76faf6a3ee..cb4089254f01 100644 --- a/trunk/include/linux/gfp.h +++ b/trunk/include/linux/gfp.h @@ -92,7 +92,7 @@ struct vm_area_struct; */ #define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK) -#define __GFP_BITS_SHIFT 24 /* Room for N __GFP_FOO bits */ +#define __GFP_BITS_SHIFT 23 /* Room for 23 __GFP_FOO bits */ #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) /* This equals 0, but use constants in case they ever change */ diff --git a/trunk/include/linux/idr.h b/trunk/include/linux/idr.h index 255491cf522e..13a801f3d028 100644 --- a/trunk/include/linux/idr.h +++ b/trunk/include/linux/idr.h @@ -146,10 +146,6 @@ void ida_remove(struct ida *ida, int id); void ida_destroy(struct ida *ida); void ida_init(struct ida *ida); -int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, - gfp_t gfp_mask); -void ida_simple_remove(struct ida *ida, unsigned int id); - void __init idr_init_cache(void); #endif /* __IDR_H__ */ diff --git a/trunk/include/linux/input.h b/trunk/include/linux/input.h index a637e7814334..068784e17972 100644 --- a/trunk/include/linux/input.h +++ b/trunk/include/linux/input.h @@ -438,8 +438,6 @@ struct input_keymap_entry { #define KEY_WIMAX 246 #define KEY_RFKILL 247 /* Key that controls all radios */ -#define KEY_MICMUTE 248 /* Mute / unmute the microphone */ - /* Code 255 is reserved for special needs of AT keyboard driver */ #define BTN_MISC 0x100 diff --git a/trunk/include/linux/jbd2.h b/trunk/include/linux/jbd2.h index 38f307b8c334..d087c2e7b2aa 100644 --- a/trunk/include/linux/jbd2.h +++ b/trunk/include/linux/jbd2.h @@ -1329,6 +1329,12 @@ extern int jbd_blocks_per_page(struct inode *inode); #define BUFFER_TRACE2(bh, bh2, info) do {} while (0) #define JBUFFER_TRACE(jh, info) do {} while (0) +/* + * jbd2_dev_to_name is a utility function used by the jbd2 and ext4 + * tracing infrastructure to map a dev_t to a device name. + */ +extern const char *jbd2_dev_to_name(dev_t device); + #endif /* __KERNEL__ */ #endif /* _LINUX_JBD2_H */ diff --git a/trunk/include/linux/llist.h b/trunk/include/linux/llist.h deleted file mode 100644 index aa0c8b5b3cd0..000000000000 --- a/trunk/include/linux/llist.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef LLIST_H -#define LLIST_H -/* - * Lock-less NULL terminated single linked list - * - * If there are multiple producers and multiple consumers, llist_add - * can be used in producers and llist_del_all can be used in - * consumers. They can work simultaneously without lock. But - * llist_del_first can not be used here. Because llist_del_first - * depends on list->first->next does not changed if list->first is not - * changed during its operation, but llist_del_first, llist_add, - * llist_add (or llist_del_all, llist_add, llist_add) sequence in - * another consumer may violate that. - * - * If there are multiple producers and one consumer, llist_add can be - * used in producers and llist_del_all or llist_del_first can be used - * in the consumer. - * - * This can be summarized as follow: - * - * | add | del_first | del_all - * add | - | - | - - * del_first | | L | L - * del_all | | | - - * - * Where "-" stands for no lock is needed, while "L" stands for lock - * is needed. - * - * The list entries deleted via llist_del_all can be traversed with - * traversing function such as llist_for_each etc. But the list - * entries can not be traversed safely before deleted from the list. - * The order of deleted entries is from the newest to the oldest added - * one. If you want to traverse from the oldest to the newest, you - * must reverse the order by yourself before traversing. - * - * The basic atomic operation of this list is cmpxchg on long. On - * architectures that don't have NMI-safe cmpxchg implementation, the - * list can NOT be used in NMI handler. So code uses the list in NMI - * handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG. - */ - -struct llist_head { - struct llist_node *first; -}; - -struct llist_node { - struct llist_node *next; -}; - -#define LLIST_HEAD_INIT(name) { NULL } -#define LLIST_HEAD(name) struct llist_head name = LLIST_HEAD_INIT(name) - -/** - * init_llist_head - initialize lock-less list head - * @head: the head for your lock-less list - */ -static inline void init_llist_head(struct llist_head *list) -{ - list->first = NULL; -} - -/** - * llist_entry - get the struct of this entry - * @ptr: the &struct llist_node pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the llist_node within the struct. - */ -#define llist_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * llist_for_each - iterate over some deleted entries of a lock-less list - * @pos: the &struct llist_node to use as a loop cursor - * @node: the first entry of deleted list entries - * - * In general, some entries of the lock-less list can be traversed - * safely only after being deleted from list, so start with an entry - * instead of list head. - * - * If being used on entries deleted from lock-less list directly, the - * traverse order is from the newest to the oldest added entry. If - * you want to traverse from the oldest to the newest, you must - * reverse the order by yourself before traversing. - */ -#define llist_for_each(pos, node) \ - for ((pos) = (node); pos; (pos) = (pos)->next) - -/** - * llist_for_each_entry - iterate over some deleted entries of lock-less list of given type - * @pos: the type * to use as a loop cursor. - * @node: the fist entry of deleted list entries. - * @member: the name of the llist_node with the struct. - * - * In general, some entries of the lock-less list can be traversed - * safely only after being removed from list, so start with an entry - * instead of list head. - * - * If being used on entries deleted from lock-less list directly, the - * traverse order is from the newest to the oldest added entry. If - * you want to traverse from the oldest to the newest, you must - * reverse the order by yourself before traversing. - */ -#define llist_for_each_entry(pos, node, member) \ - for ((pos) = llist_entry((node), typeof(*(pos)), member); \ - &(pos)->member != NULL; \ - (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member)) - -/** - * llist_empty - tests whether a lock-less list is empty - * @head: the list to test - * - * Not guaranteed to be accurate or up to date. Just a quick way to - * test whether the list is empty without deleting something from the - * list. - */ -static inline int llist_empty(const struct llist_head *head) -{ - return ACCESS_ONCE(head->first) == NULL; -} - -void llist_add(struct llist_node *new, struct llist_head *head); -void llist_add_batch(struct llist_node *new_first, struct llist_node *new_last, - struct llist_head *head); -struct llist_node *llist_del_first(struct llist_head *head); -struct llist_node *llist_del_all(struct llist_head *head); -#endif /* LLIST_H */ diff --git a/trunk/include/linux/memcontrol.h b/trunk/include/linux/memcontrol.h index 3b535db00a94..b96600786913 100644 --- a/trunk/include/linux/memcontrol.h +++ b/trunk/include/linux/memcontrol.h @@ -86,6 +86,8 @@ extern void mem_cgroup_uncharge_end(void); extern void mem_cgroup_uncharge_page(struct page *page); extern void mem_cgroup_uncharge_cache_page(struct page *page); +extern int mem_cgroup_shmem_charge_fallback(struct page *page, + struct mm_struct *mm, gfp_t gfp_mask); extern void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask); int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem); @@ -223,6 +225,12 @@ static inline void mem_cgroup_uncharge_cache_page(struct page *page) { } +static inline int mem_cgroup_shmem_charge_fallback(struct page *page, + struct mm_struct *mm, gfp_t gfp_mask) +{ + return 0; +} + static inline void mem_cgroup_add_lru_list(struct page *page, int lru) { } diff --git a/trunk/include/linux/mfd/aat2870.h b/trunk/include/linux/mfd/aat2870.h index f7316c29bdec..89212df05622 100644 --- a/trunk/include/linux/mfd/aat2870.h +++ b/trunk/include/linux/mfd/aat2870.h @@ -89,7 +89,7 @@ enum aat2870_id { /* Backlight current magnitude (mA) */ enum aat2870_current { - AAT2870_CURRENT_0_45 = 1, + AAT2870_CURRENT_0_45, AAT2870_CURRENT_0_90, AAT2870_CURRENT_1_80, AAT2870_CURRENT_2_70, diff --git a/trunk/include/linux/mm.h b/trunk/include/linux/mm.h index f2690cf49827..3172a1c0f08e 100644 --- a/trunk/include/linux/mm.h +++ b/trunk/include/linux/mm.h @@ -1600,7 +1600,6 @@ enum mf_flags { }; extern void memory_failure(unsigned long pfn, int trapno); extern int __memory_failure(unsigned long pfn, int trapno, int flags); -extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); extern int unpoison_memory(unsigned long pfn); extern int sysctl_memory_failure_early_kill; extern int sysctl_memory_failure_recovery; diff --git a/trunk/include/linux/nfs_fs.h b/trunk/include/linux/nfs_fs.h index eaac770f886e..b96fb99072ff 100644 --- a/trunk/include/linux/nfs_fs.h +++ b/trunk/include/linux/nfs_fs.h @@ -569,12 +569,12 @@ extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type); extern int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl); extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, - umode_t mode); + mode_t mode); extern void nfs3_forget_cached_acls(struct inode *inode); #else static inline int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, - umode_t mode) + mode_t mode) { return 0; } diff --git a/trunk/include/linux/of.h b/trunk/include/linux/of.h index 0085bb01c041..bd716f8908de 100644 --- a/trunk/include/linux/of.h +++ b/trunk/include/linux/of.h @@ -196,13 +196,12 @@ extern struct property *of_find_property(const struct device_node *np, const char *name, int *lenp); extern int of_property_read_u32_array(const struct device_node *np, - const char *propname, + char *propname, u32 *out_values, size_t sz); -extern int of_property_read_string(struct device_node *np, - const char *propname, - const char **out_string); +extern int of_property_read_string(struct device_node *np, char *propname, + const char **out_string); extern int of_device_is_compatible(const struct device_node *device, const char *); extern int of_device_is_available(const struct device_node *device); @@ -243,15 +242,13 @@ static inline bool of_have_populated_dt(void) } static inline int of_property_read_u32_array(const struct device_node *np, - const char *propname, - u32 *out_values, size_t sz) + char *propname, u32 *out_values, size_t sz) { return -ENOSYS; } static inline int of_property_read_string(struct device_node *np, - const char *propname, - const char **out_string) + char *propname, const char **out_string) { return -ENOSYS; } @@ -259,7 +256,7 @@ static inline int of_property_read_string(struct device_node *np, #endif /* CONFIG_OF */ static inline int of_property_read_u32(const struct device_node *np, - const char *propname, + char *propname, u32 *out_value) { return of_property_read_u32_array(np, propname, out_value, 1); diff --git a/trunk/include/linux/pci_ids.h b/trunk/include/linux/pci_ids.h index ae96bbe54518..b00c4ec5056e 100644 --- a/trunk/include/linux/pci_ids.h +++ b/trunk/include/linux/pci_ids.h @@ -2709,16 +2709,6 @@ #define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN 0x3b00 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX 0x3b1f -#define PCI_DEVICE_ID_INTEL_IOAT_SNB0 0x3c20 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB1 0x3c21 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB2 0x3c22 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB3 0x3c23 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB4 0x3c24 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB5 0x3c25 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB6 0x3c26 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e -#define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 diff --git a/trunk/include/linux/posix_acl.h b/trunk/include/linux/posix_acl.h index b7681102a4b9..9a53b99818e2 100644 --- a/trunk/include/linux/posix_acl.h +++ b/trunk/include/linux/posix_acl.h @@ -9,7 +9,6 @@ #define __LINUX_POSIX_ACL_H #include -#include #define ACL_UNDEFINED_ID (-1) @@ -39,10 +38,7 @@ struct posix_acl_entry { }; struct posix_acl { - union { - atomic_t a_refcount; - struct rcu_head a_rcu; - }; + atomic_t a_refcount; unsigned int a_count; struct posix_acl_entry a_entries[0]; }; @@ -69,7 +65,7 @@ static inline void posix_acl_release(struct posix_acl *acl) { if (acl && atomic_dec_and_test(&acl->a_refcount)) - kfree_rcu(acl, a_rcu); + kfree(acl); } @@ -79,31 +75,29 @@ extern void posix_acl_init(struct posix_acl *, int); extern struct posix_acl *posix_acl_alloc(int, gfp_t); extern int posix_acl_valid(const struct posix_acl *); extern int posix_acl_permission(struct inode *, const struct posix_acl *, int); -extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t); -extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *); -extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *); -extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t); +extern struct posix_acl *posix_acl_from_mode(mode_t, gfp_t); +extern int posix_acl_equiv_mode(const struct posix_acl *, mode_t *); +extern int posix_acl_create(struct posix_acl **, gfp_t, mode_t *); +extern int posix_acl_chmod(struct posix_acl **, gfp_t, mode_t); extern struct posix_acl *get_posix_acl(struct inode *, int); extern int set_posix_acl(struct inode *, int, struct posix_acl *); #ifdef CONFIG_FS_POSIX_ACL -static inline struct posix_acl **acl_by_type(struct inode *inode, int type) +static inline struct posix_acl *get_cached_acl(struct inode *inode, int type) { + struct posix_acl **p, *acl; switch (type) { case ACL_TYPE_ACCESS: - return &inode->i_acl; + p = &inode->i_acl; + break; case ACL_TYPE_DEFAULT: - return &inode->i_default_acl; + p = &inode->i_default_acl; + break; default: - BUG(); + return ERR_PTR(-EINVAL); } -} - -static inline struct posix_acl *get_cached_acl(struct inode *inode, int type) -{ - struct posix_acl **p = acl_by_type(inode, type); - struct posix_acl *acl = ACCESS_ONCE(*p); + acl = ACCESS_ONCE(*p); if (acl) { spin_lock(&inode->i_lock); acl = *p; @@ -114,20 +108,41 @@ static inline struct posix_acl *get_cached_acl(struct inode *inode, int type) return acl; } -static inline struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type) +static inline int negative_cached_acl(struct inode *inode, int type) { - return rcu_dereference(*acl_by_type(inode, type)); + struct posix_acl **p, *acl; + switch (type) { + case ACL_TYPE_ACCESS: + p = &inode->i_acl; + break; + case ACL_TYPE_DEFAULT: + p = &inode->i_default_acl; + break; + default: + BUG(); + } + acl = ACCESS_ONCE(*p); + if (acl) + return 0; + return 1; } static inline void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl) { - struct posix_acl **p = acl_by_type(inode, type); - struct posix_acl *old; + struct posix_acl *old = NULL; spin_lock(&inode->i_lock); - old = *p; - rcu_assign_pointer(*p, posix_acl_dup(acl)); + switch (type) { + case ACL_TYPE_ACCESS: + old = inode->i_acl; + inode->i_acl = posix_acl_dup(acl); + break; + case ACL_TYPE_DEFAULT: + old = inode->i_default_acl; + inode->i_default_acl = posix_acl_dup(acl); + break; + } spin_unlock(&inode->i_lock); if (old != ACL_NOT_CACHED) posix_acl_release(old); @@ -135,11 +150,18 @@ static inline void set_cached_acl(struct inode *inode, static inline void forget_cached_acl(struct inode *inode, int type) { - struct posix_acl **p = acl_by_type(inode, type); - struct posix_acl *old; + struct posix_acl *old = NULL; spin_lock(&inode->i_lock); - old = *p; - *p = ACL_NOT_CACHED; + switch (type) { + case ACL_TYPE_ACCESS: + old = inode->i_acl; + inode->i_acl = ACL_NOT_CACHED; + break; + case ACL_TYPE_DEFAULT: + old = inode->i_default_acl; + inode->i_default_acl = ACL_NOT_CACHED; + break; + } spin_unlock(&inode->i_lock); if (old != ACL_NOT_CACHED) posix_acl_release(old); diff --git a/trunk/include/linux/pstore.h b/trunk/include/linux/pstore.h index cc03bbf5c4b8..2455ef2683f0 100644 --- a/trunk/include/linux/pstore.h +++ b/trunk/include/linux/pstore.h @@ -38,12 +38,9 @@ struct pstore_info { int (*open)(struct pstore_info *psi); int (*close)(struct pstore_info *psi); ssize_t (*read)(u64 *id, enum pstore_type_id *type, - struct timespec *time, struct pstore_info *psi); - u64 (*write)(enum pstore_type_id type, unsigned int part, - size_t size, struct pstore_info *psi); - int (*erase)(enum pstore_type_id type, u64 id, - struct pstore_info *psi); - void *data; + struct timespec *time); + u64 (*write)(enum pstore_type_id type, size_t size); + int (*erase)(u64 id); }; #ifdef CONFIG_PSTORE diff --git a/trunk/include/linux/radix-tree.h b/trunk/include/linux/radix-tree.h index 9d4539c52e53..23241c2fecce 100644 --- a/trunk/include/linux/radix-tree.h +++ b/trunk/include/linux/radix-tree.h @@ -39,15 +39,7 @@ * when it is shrunk, before we rcu free the node. See shrink code for * details. */ -#define RADIX_TREE_INDIRECT_PTR 1 -/* - * A common use of the radix tree is to store pointers to struct pages; - * but shmem/tmpfs needs also to store swap entries in the same tree: - * those are marked as exceptional entries to distinguish them. - * EXCEPTIONAL_ENTRY tests the bit, EXCEPTIONAL_SHIFT shifts content past it. - */ -#define RADIX_TREE_EXCEPTIONAL_ENTRY 2 -#define RADIX_TREE_EXCEPTIONAL_SHIFT 2 +#define RADIX_TREE_INDIRECT_PTR 1 #define radix_tree_indirect_to_ptr(ptr) \ radix_tree_indirect_to_ptr((void __force *)(ptr)) @@ -181,28 +173,6 @@ static inline int radix_tree_deref_retry(void *arg) return unlikely((unsigned long)arg & RADIX_TREE_INDIRECT_PTR); } -/** - * radix_tree_exceptional_entry - radix_tree_deref_slot gave exceptional entry? - * @arg: value returned by radix_tree_deref_slot - * Returns: 0 if well-aligned pointer, non-0 if exceptional entry. - */ -static inline int radix_tree_exceptional_entry(void *arg) -{ - /* Not unlikely because radix_tree_exception often tested first */ - return (unsigned long)arg & RADIX_TREE_EXCEPTIONAL_ENTRY; -} - -/** - * radix_tree_exception - radix_tree_deref_slot returned either exception? - * @arg: value returned by radix_tree_deref_slot - * Returns: 0 if well-aligned pointer, non-0 if either kind of exception. - */ -static inline int radix_tree_exception(void *arg) -{ - return unlikely((unsigned long)arg & - (RADIX_TREE_INDIRECT_PTR | RADIX_TREE_EXCEPTIONAL_ENTRY)); -} - /** * radix_tree_replace_slot - replace item in a slot * @pslot: pointer to slot, returned by radix_tree_lookup_slot @@ -224,8 +194,8 @@ void *radix_tree_delete(struct radix_tree_root *, unsigned long); unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items); -unsigned int radix_tree_gang_lookup_slot(struct radix_tree_root *root, - void ***results, unsigned long *indices, +unsigned int +radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results, unsigned long first_index, unsigned int max_items); unsigned long radix_tree_next_hole(struct radix_tree_root *root, unsigned long index, unsigned long max_scan); @@ -252,7 +222,6 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, unsigned long nr_to_tag, unsigned int fromtag, unsigned int totag); int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag); -unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item); static inline void radix_tree_preload_end(void) { diff --git a/trunk/include/linux/regulator/consumer.h b/trunk/include/linux/regulator/consumer.h index 26f6ea4444e3..9e87c1cb7270 100644 --- a/trunk/include/linux/regulator/consumer.h +++ b/trunk/include/linux/regulator/consumer.h @@ -122,9 +122,6 @@ struct regulator; struct regulator_bulk_data { const char *supply; struct regulator *consumer; - - /* Internal use */ - int ret; }; #if defined(CONFIG_REGULATOR) diff --git a/trunk/include/linux/regulator/driver.h b/trunk/include/linux/regulator/driver.h index 1a80bc77517d..6c433b89c80d 100644 --- a/trunk/include/linux/regulator/driver.h +++ b/trunk/include/linux/regulator/driver.h @@ -188,16 +188,18 @@ struct regulator_dev { /* lists we belong to */ struct list_head list; /* list of all regulators */ + struct list_head slist; /* list of supplied regulators */ /* lists we own */ struct list_head consumer_list; /* consumers we supply */ + struct list_head supply_list; /* regulators we supply */ struct blocking_notifier_head notifier; struct mutex mutex; /* consumer lock */ struct module *owner; struct device dev; struct regulation_constraints *constraints; - struct regulator *supply; /* for tree */ + struct regulator_dev *supply; /* for tree */ void *reg_data; /* regulator_dev data */ diff --git a/trunk/include/linux/shmem_fs.h b/trunk/include/linux/shmem_fs.h index 9291ac3cc627..aa08fa8fd79b 100644 --- a/trunk/include/linux/shmem_fs.h +++ b/trunk/include/linux/shmem_fs.h @@ -8,15 +8,22 @@ /* inode in-kernel data */ +#define SHMEM_NR_DIRECT 16 + +#define SHMEM_SYMLINK_INLINE_LEN (SHMEM_NR_DIRECT * sizeof(swp_entry_t)) + struct shmem_inode_info { spinlock_t lock; unsigned long flags; unsigned long alloced; /* data pages alloced to file */ + unsigned long swapped; /* subtotal assigned to swap */ + unsigned long next_index; /* highest alloced index + 1 */ + struct shared_policy policy; /* NUMA memory alloc policy */ + struct page *i_indirect; /* top indirect blocks page */ union { - unsigned long swapped; /* subtotal assigned to swap */ - char *symlink; /* unswappable short symlink */ + swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */ + char inline_symlink[SHMEM_SYMLINK_INLINE_LEN]; }; - struct shared_policy policy; /* NUMA memory alloc policy */ struct list_head swaplist; /* chain of maybes on swap */ struct list_head xattr_list; /* list of shmem_xattr */ struct inode vfs_inode; @@ -42,7 +49,7 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode) /* * Functions in mm/shmem.c called directly from elsewhere: */ -extern int shmem_init(void); +extern int init_tmpfs(void); extern int shmem_fill_super(struct super_block *sb, void *data, int silent); extern struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags); @@ -52,6 +59,8 @@ extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp_mask); extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end); extern int shmem_unuse(swp_entry_t entry, struct page *page); +extern void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff, + struct page **pagep, swp_entry_t *ent); static inline struct page *shmem_read_mapping_page( struct address_space *mapping, pgoff_t index) diff --git a/trunk/include/linux/swapops.h b/trunk/include/linux/swapops.h index 2189d3ffc85d..cd42e30b7c6e 100644 --- a/trunk/include/linux/swapops.h +++ b/trunk/include/linux/swapops.h @@ -1,8 +1,3 @@ -#ifndef _LINUX_SWAPOPS_H -#define _LINUX_SWAPOPS_H - -#include - /* * swapcache pages are stored in the swapper_space radix tree. We want to * get good packing density in that tree, so the index should be dense in @@ -81,22 +76,6 @@ static inline pte_t swp_entry_to_pte(swp_entry_t entry) return __swp_entry_to_pte(arch_entry); } -static inline swp_entry_t radix_to_swp_entry(void *arg) -{ - swp_entry_t entry; - - entry.val = (unsigned long)arg >> RADIX_TREE_EXCEPTIONAL_SHIFT; - return entry; -} - -static inline void *swp_to_radix_entry(swp_entry_t entry) -{ - unsigned long value; - - value = entry.val << RADIX_TREE_EXCEPTIONAL_SHIFT; - return (void *)(value | RADIX_TREE_EXCEPTIONAL_ENTRY); -} - #ifdef CONFIG_MIGRATION static inline swp_entry_t make_migration_entry(struct page *page, int write) { @@ -190,5 +169,3 @@ static inline int non_swap_entry(swp_entry_t entry) return 0; } #endif - -#endif /* _LINUX_SWAPOPS_H */ diff --git a/trunk/include/linux/thermal.h b/trunk/include/linux/thermal.h index 47b4a27e6e97..d3ec89fb4122 100644 --- a/trunk/include/linux/thermal.h +++ b/trunk/include/linux/thermal.h @@ -85,6 +85,22 @@ struct thermal_cooling_device { ((long)t-2732+5)/10 : ((long)t-2732-5)/10) #define CELSIUS_TO_KELVIN(t) ((t)*10+2732) +#if defined(CONFIG_THERMAL_HWMON) +/* thermal zone devices with the same type share one hwmon device */ +struct thermal_hwmon_device { + char type[THERMAL_NAME_LENGTH]; + struct device *device; + int count; + struct list_head tz_list; + struct list_head node; +}; + +struct thermal_hwmon_attr { + struct device_attribute attr; + char name[16]; +}; +#endif + struct thermal_zone_device { int id; char type[THERMAL_NAME_LENGTH]; @@ -104,6 +120,12 @@ struct thermal_zone_device { struct mutex lock; /* protect cooling devices list */ struct list_head node; struct delayed_work poll_queue; +#if defined(CONFIG_THERMAL_HWMON) + struct list_head hwmon_node; + struct thermal_hwmon_device *hwmon; + struct thermal_hwmon_attr temp_input; /* hwmon sys attr */ + struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */ +#endif }; /* Adding event notification support elements */ #define THERMAL_GENL_FAMILY_NAME "thermal_event" diff --git a/trunk/include/net/cipso_ipv4.h b/trunk/include/net/cipso_ipv4.h index 9808877c2ab9..3b938743514b 100644 --- a/trunk/include/net/cipso_ipv4.h +++ b/trunk/include/net/cipso_ipv4.h @@ -8,7 +8,7 @@ * have chosen to adopt the protocol and over the years it has become a * de-facto standard for labeled networking. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/include/net/dst.h b/trunk/include/net/dst.h index 13d507d69ddb..29e255796ce1 100644 --- a/trunk/include/net/dst.h +++ b/trunk/include/net/dst.h @@ -37,7 +37,7 @@ struct dst_entry { unsigned long _metrics; unsigned long expires; struct dst_entry *path; - struct neighbour __rcu *_neighbour; + struct neighbour *_neighbour; #ifdef CONFIG_XFRM struct xfrm_state *xfrm; #else @@ -88,17 +88,12 @@ struct dst_entry { static inline struct neighbour *dst_get_neighbour(struct dst_entry *dst) { - return rcu_dereference(dst->_neighbour); -} - -static inline struct neighbour *dst_get_neighbour_raw(struct dst_entry *dst) -{ - return rcu_dereference_raw(dst->_neighbour); + return dst->_neighbour; } static inline void dst_set_neighbour(struct dst_entry *dst, struct neighbour *neigh) { - rcu_assign_pointer(dst->_neighbour, neigh); + dst->_neighbour = neigh; } extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old); @@ -387,12 +382,8 @@ static inline void dst_rcu_free(struct rcu_head *head) static inline void dst_confirm(struct dst_entry *dst) { if (dst) { - struct neighbour *n; - - rcu_read_lock(); - n = dst_get_neighbour(dst); + struct neighbour *n = dst_get_neighbour(dst); neigh_confirm(n); - rcu_read_unlock(); } } diff --git a/trunk/include/net/netlabel.h b/trunk/include/net/netlabel.h index f67440970d7e..f21a16ee3705 100644 --- a/trunk/include/net/netlabel.h +++ b/trunk/include/net/netlabel.h @@ -4,7 +4,7 @@ * The NetLabel system manages static and dynamic label mappings for network * protocols such as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/include/trace/events/ext4.h b/trunk/include/trace/events/ext4.h index b50a54736242..6363193a3418 100644 --- a/trunk/include/trace/events/ext4.h +++ b/trunk/include/trace/events/ext4.h @@ -23,7 +23,7 @@ TRACE_EVENT(ext4_free_inode, TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, ino ) - __field( __u16, mode ) + __field( umode_t, mode ) __field( uid_t, uid ) __field( gid_t, gid ) __field( __u64, blocks ) @@ -52,7 +52,7 @@ TRACE_EVENT(ext4_request_inode, TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, dir ) - __field( __u16, mode ) + __field( umode_t, mode ) ), TP_fast_assign( @@ -75,7 +75,7 @@ TRACE_EVENT(ext4_allocate_inode, __field( dev_t, dev ) __field( ino_t, ino ) __field( ino_t, dir ) - __field( __u16, mode ) + __field( umode_t, mode ) ), TP_fast_assign( @@ -725,7 +725,7 @@ TRACE_EVENT(ext4_free_blocks, TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, ino ) - __field( __u16, mode ) + __field( umode_t, mode ) __field( __u64, block ) __field( unsigned long, count ) __field( int, flags ) @@ -1012,7 +1012,7 @@ TRACE_EVENT(ext4_forget, TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, ino ) - __field( __u16, mode ) + __field( umode_t, mode ) __field( int, is_metadata ) __field( __u64, block ) ), @@ -1039,7 +1039,7 @@ TRACE_EVENT(ext4_da_update_reserve_space, TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, ino ) - __field( __u16, mode ) + __field( umode_t, mode ) __field( __u64, i_blocks ) __field( int, used_blocks ) __field( int, reserved_data_blocks ) @@ -1076,7 +1076,7 @@ TRACE_EVENT(ext4_da_reserve_space, TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, ino ) - __field( __u16, mode ) + __field( umode_t, mode ) __field( __u64, i_blocks ) __field( int, md_needed ) __field( int, reserved_data_blocks ) @@ -1110,7 +1110,7 @@ TRACE_EVENT(ext4_da_release_space, TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, ino ) - __field( __u16, mode ) + __field( umode_t, mode ) __field( __u64, i_blocks ) __field( int, freed_blocks ) __field( int, reserved_data_blocks ) @@ -1518,77 +1518,6 @@ TRACE_EVENT(ext4_load_inode, (unsigned long) __entry->ino) ); -TRACE_EVENT(ext4_journal_start, - TP_PROTO(struct super_block *sb, int nblocks, unsigned long IP), - - TP_ARGS(sb, nblocks, IP), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, nblocks ) - __field(unsigned long, ip ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->nblocks = nblocks; - __entry->ip = IP; - ), - - TP_printk("dev %d,%d nblocks %d caller %pF", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->nblocks, (void *)__entry->ip) -); - -DECLARE_EVENT_CLASS(ext4__trim, - TP_PROTO(struct super_block *sb, - ext4_group_t group, - ext4_grpblk_t start, - ext4_grpblk_t len), - - TP_ARGS(sb, group, start, len), - - TP_STRUCT__entry( - __field( int, dev_major ) - __field( int, dev_minor ) - __field( __u32, group ) - __field( int, start ) - __field( int, len ) - ), - - TP_fast_assign( - __entry->dev_major = MAJOR(sb->s_dev); - __entry->dev_minor = MINOR(sb->s_dev); - __entry->group = group; - __entry->start = start; - __entry->len = len; - ), - - TP_printk("dev %d,%d group %u, start %d, len %d", - __entry->dev_major, __entry->dev_minor, - __entry->group, __entry->start, __entry->len) -); - -DEFINE_EVENT(ext4__trim, ext4_trim_extent, - - TP_PROTO(struct super_block *sb, - ext4_group_t group, - ext4_grpblk_t start, - ext4_grpblk_t len), - - TP_ARGS(sb, group, start, len) -); - -DEFINE_EVENT(ext4__trim, ext4_trim_all_free, - - TP_PROTO(struct super_block *sb, - ext4_group_t group, - ext4_grpblk_t start, - ext4_grpblk_t len), - - TP_ARGS(sb, group, start, len) -); - #endif /* _TRACE_EXT4_H */ /* This part must be outside protection */ diff --git a/trunk/include/trace/events/jbd2.h b/trunk/include/trace/events/jbd2.h index 75964412ddbb..bf16545cc977 100644 --- a/trunk/include/trace/events/jbd2.h +++ b/trunk/include/trace/events/jbd2.h @@ -26,8 +26,8 @@ TRACE_EVENT(jbd2_checkpoint, __entry->result = result; ), - TP_printk("dev %d,%d result %d", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->result) + TP_printk("dev %s result %d", + jbd2_dev_to_name(__entry->dev), __entry->result) ); DECLARE_EVENT_CLASS(jbd2_commit, @@ -48,9 +48,9 @@ DECLARE_EVENT_CLASS(jbd2_commit, __entry->transaction = commit_transaction->t_tid; ), - TP_printk("dev %d,%d transaction %d sync %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->transaction, __entry->sync_commit) + TP_printk("dev %s transaction %d sync %d", + jbd2_dev_to_name(__entry->dev), __entry->transaction, + __entry->sync_commit) ); DEFINE_EVENT(jbd2_commit, jbd2_start_commit, @@ -100,9 +100,9 @@ TRACE_EVENT(jbd2_end_commit, __entry->head = journal->j_tail_sequence; ), - TP_printk("dev %d,%d transaction %d sync %d head %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->transaction, __entry->sync_commit, __entry->head) + TP_printk("dev %s transaction %d sync %d head %d", + jbd2_dev_to_name(__entry->dev), __entry->transaction, + __entry->sync_commit, __entry->head) ); TRACE_EVENT(jbd2_submit_inode_data, @@ -120,9 +120,8 @@ TRACE_EVENT(jbd2_submit_inode_data, __entry->ino = inode->i_ino; ), - TP_printk("dev %d,%d ino %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino) + TP_printk("dev %s ino %lu", + jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino) ); TRACE_EVENT(jbd2_run_stats, @@ -157,9 +156,9 @@ TRACE_EVENT(jbd2_run_stats, __entry->blocks_logged = stats->rs_blocks_logged; ), - TP_printk("dev %d,%d tid %lu wait %u running %u locked %u flushing %u " + TP_printk("dev %s tid %lu wait %u running %u locked %u flushing %u " "logging %u handle_count %u blocks %u blocks_logged %u", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid, + jbd2_dev_to_name(__entry->dev), __entry->tid, jiffies_to_msecs(__entry->wait), jiffies_to_msecs(__entry->running), jiffies_to_msecs(__entry->locked), @@ -193,9 +192,9 @@ TRACE_EVENT(jbd2_checkpoint_stats, __entry->dropped = stats->cs_dropped; ), - TP_printk("dev %d,%d tid %lu chp_time %u forced_to_close %u " + TP_printk("dev %s tid %lu chp_time %u forced_to_close %u " "written %u dropped %u", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid, + jbd2_dev_to_name(__entry->dev), __entry->tid, jiffies_to_msecs(__entry->chp_time), __entry->forced_to_close, __entry->written, __entry->dropped) ); @@ -223,10 +222,9 @@ TRACE_EVENT(jbd2_cleanup_journal_tail, __entry->freed = freed; ), - TP_printk("dev %d,%d from %u to %u offset %lu freed %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->tail_sequence, __entry->first_tid, - __entry->block_nr, __entry->freed) + TP_printk("dev %s from %u to %u offset %lu freed %lu", + jbd2_dev_to_name(__entry->dev), __entry->tail_sequence, + __entry->first_tid, __entry->block_nr, __entry->freed) ); #endif /* _TRACE_JBD2_H */ diff --git a/trunk/init/main.c b/trunk/init/main.c index 9c51ee7adf3d..d7211faed2ad 100644 --- a/trunk/init/main.c +++ b/trunk/init/main.c @@ -369,12 +369,9 @@ static noinline void __init_refok rest_init(void) init_idle_bootup_task(current); preempt_enable_no_resched(); schedule(); - - /* At this point, we can enable user mode helper functionality */ - usermodehelper_enable(); + preempt_disable(); /* Call into cpu_idle with preempt disabled */ - preempt_disable(); cpu_idle(); } @@ -718,7 +715,7 @@ static void __init do_basic_setup(void) { cpuset_init_smp(); usermodehelper_init(); - shmem_init(); + init_tmpfs(); driver_init(); init_irq_proc(); do_ctors(); diff --git a/trunk/ipc/shm.c b/trunk/ipc/shm.c index 02ecf2c078fc..9fb044f3b345 100644 --- a/trunk/ipc/shm.c +++ b/trunk/ipc/shm.c @@ -105,16 +105,9 @@ void shm_exit_ns(struct ipc_namespace *ns) } #endif -static int __init ipc_ns_init(void) -{ - shm_init_ns(&init_ipc_ns); - return 0; -} - -pure_initcall(ipc_ns_init); - void __init shm_init (void) { + shm_init_ns(&init_ipc_ns); ipc_init_proc_interface("sysvipc/shm", #if BITS_PER_LONG <= 32 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", @@ -301,7 +294,7 @@ static int shm_try_destroy_orphaned(int id, void *p, void *data) void shm_destroy_orphaned(struct ipc_namespace *ns) { down_write(&shm_ids(ns).rw_mutex); - if (shm_ids(ns).in_use) + if (&shm_ids(ns).in_use) idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns); up_write(&shm_ids(ns).rw_mutex); } @@ -311,12 +304,9 @@ void exit_shm(struct task_struct *task) { struct ipc_namespace *ns = task->nsproxy->ipc_ns; - if (shm_ids(ns).in_use == 0) - return; - /* Destroy all already created segments, but not mapped yet */ down_write(&shm_ids(ns).rw_mutex); - if (shm_ids(ns).in_use) + if (&shm_ids(ns).in_use) idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns); up_write(&shm_ids(ns).rw_mutex); } diff --git a/trunk/kernel/debug/gdbstub.c b/trunk/kernel/debug/gdbstub.c index 34872482315e..a11db956dd62 100644 --- a/trunk/kernel/debug/gdbstub.c +++ b/trunk/kernel/debug/gdbstub.c @@ -42,8 +42,6 @@ /* Our I/O buffers. */ static char remcom_in_buffer[BUFMAX]; static char remcom_out_buffer[BUFMAX]; -static int gdbstub_use_prev_in_buf; -static int gdbstub_prev_in_buf_pos; /* Storage for the registers, in GDB format. */ static unsigned long gdb_regs[(NUMREGBYTES + @@ -60,13 +58,6 @@ static int gdbstub_read_wait(void) int ret = -1; int i; - if (unlikely(gdbstub_use_prev_in_buf)) { - if (gdbstub_prev_in_buf_pos < gdbstub_use_prev_in_buf) - return remcom_in_buffer[gdbstub_prev_in_buf_pos++]; - else - gdbstub_use_prev_in_buf = 0; - } - /* poll any additional I/O interfaces that are defined */ while (ret < 0) for (i = 0; kdb_poll_funcs[i] != NULL; i++) { @@ -118,6 +109,7 @@ static void get_packet(char *buffer) buffer[count] = ch; count = count + 1; } + buffer[count] = 0; if (ch == '#') { xmitcsum = hex_to_bin(gdbstub_read_wait()) << 4; @@ -132,7 +124,6 @@ static void get_packet(char *buffer) if (dbg_io_ops->flush) dbg_io_ops->flush(); } - buffer[count] = 0; } while (checksum != xmitcsum); } @@ -1091,11 +1082,12 @@ int gdbstub_state(struct kgdb_state *ks, char *cmd) case 'c': strcpy(remcom_in_buffer, cmd); return 0; - case '$': - strcpy(remcom_in_buffer, cmd); - gdbstub_use_prev_in_buf = strlen(remcom_in_buffer); - gdbstub_prev_in_buf_pos = 0; - return 0; + case '?': + gdb_cmd_status(ks); + break; + case '\0': + strcpy(remcom_out_buffer, ""); + break; } dbg_io_ops->write_char('+'); put_packet(remcom_out_buffer); diff --git a/trunk/kernel/debug/kdb/kdb_bt.c b/trunk/kernel/debug/kdb/kdb_bt.c index 7179eac7b41c..2f62fe85f16a 100644 --- a/trunk/kernel/debug/kdb/kdb_bt.c +++ b/trunk/kernel/debug/kdb/kdb_bt.c @@ -112,8 +112,9 @@ kdb_bt(int argc, const char **argv) unsigned long addr; long offset; - /* Prompt after each proc in bta */ - kdbgetintenv("BTAPROMPT", &btaprompt); + kdbgetintenv("BTARGS", &argcount); /* Arguments to print */ + kdbgetintenv("BTAPROMPT", &btaprompt); /* Prompt after each + * proc in bta */ if (strcmp(argv[0], "bta") == 0) { struct task_struct *g, *p; diff --git a/trunk/kernel/debug/kdb/kdb_cmds b/trunk/kernel/debug/kdb/kdb_cmds index 9834ad303ab6..56c88e4db309 100644 --- a/trunk/kernel/debug/kdb/kdb_cmds +++ b/trunk/kernel/debug/kdb/kdb_cmds @@ -18,12 +18,16 @@ defcmd dumpcommon "" "Common kdb debugging" endefcmd defcmd dumpall "" "First line debugging" + set BTSYMARG 1 + set BTARGS 9 pid R -dumpcommon -bta endefcmd defcmd dumpcpu "" "Same as dumpall but only tasks on cpus" + set BTSYMARG 1 + set BTARGS 9 pid R -dumpcommon -btc diff --git a/trunk/kernel/debug/kdb/kdb_debugger.c b/trunk/kernel/debug/kdb/kdb_debugger.c index d9ca9aa481ec..dd0b1b7dd02c 100644 --- a/trunk/kernel/debug/kdb/kdb_debugger.c +++ b/trunk/kernel/debug/kdb/kdb_debugger.c @@ -30,8 +30,6 @@ EXPORT_SYMBOL_GPL(kdb_poll_funcs); int kdb_poll_idx = 1; EXPORT_SYMBOL_GPL(kdb_poll_idx); -static struct kgdb_state *kdb_ks; - int kdb_stub(struct kgdb_state *ks) { int error = 0; @@ -41,7 +39,6 @@ int kdb_stub(struct kgdb_state *ks) kdb_dbtrap_t db_result = KDB_DB_NOBPT; int i; - kdb_ks = ks; if (KDB_STATE(REENTRY)) { reason = KDB_REASON_SWITCH; KDB_STATE_CLEAR(REENTRY); @@ -126,8 +123,20 @@ int kdb_stub(struct kgdb_state *ks) KDB_STATE_CLEAR(PAGER); kdbnearsym_cleanup(); if (error == KDB_CMD_KGDB) { - if (KDB_STATE(DOING_KGDB)) + if (KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)) { + /* + * This inteface glue which allows kdb to transition in into + * the gdb stub. In order to do this the '?' or '' gdb serial + * packet response is processed here. And then control is + * passed to the gdbstub. + */ + if (KDB_STATE(DOING_KGDB)) + gdbstub_state(ks, "?"); + else + gdbstub_state(ks, ""); KDB_STATE_CLEAR(DOING_KGDB); + KDB_STATE_CLEAR(DOING_KGDB2); + } return DBG_PASS_EVENT; } kdb_bp_install(ks->linux_regs); @@ -157,7 +166,3 @@ int kdb_stub(struct kgdb_state *ks) return kgdb_info[ks->cpu].ret_state; } -void kdb_gdb_state_pass(char *buf) -{ - gdbstub_state(kdb_ks, buf); -} diff --git a/trunk/kernel/debug/kdb/kdb_io.c b/trunk/kernel/debug/kdb/kdb_io.c index 4802eb5840e1..96fdaac46a80 100644 --- a/trunk/kernel/debug/kdb/kdb_io.c +++ b/trunk/kernel/debug/kdb/kdb_io.c @@ -31,21 +31,15 @@ char kdb_prompt_str[CMD_BUFLEN]; int kdb_trap_printk; -static int kgdb_transition_check(char *buffer) +static void kgdb_transition_check(char *buffer) { - if (buffer[0] != '+' && buffer[0] != '$') { + int slen = strlen(buffer); + if (strncmp(buffer, "$?#3f", slen) != 0 && + strncmp(buffer, "$qSupported#37", slen) != 0 && + strncmp(buffer, "+$qSupported#37", slen) != 0) { KDB_STATE_SET(KGDB_TRANS); kdb_printf("%s", buffer); - } else { - int slen = strlen(buffer); - if (slen > 3 && buffer[slen - 3] == '#') { - kdb_gdb_state_pass(buffer); - strcpy(buffer, "kgdb"); - KDB_STATE_SET(DOING_KGDB); - return 1; - } } - return 0; } static int kdb_read_get_key(char *buffer, size_t bufsize) @@ -257,10 +251,6 @@ static char *kdb_read(char *buffer, size_t bufsize) case 13: /* enter */ *lastchar++ = '\n'; *lastchar++ = '\0'; - if (!KDB_STATE(KGDB_TRANS)) { - KDB_STATE_SET(KGDB_TRANS); - kdb_printf("%s", buffer); - } kdb_printf("\n"); return buffer; case 4: /* Del */ @@ -392,26 +382,22 @@ static char *kdb_read(char *buffer, size_t bufsize) * printed characters if we think that * kgdb is connecting, until the check * fails */ - if (!KDB_STATE(KGDB_TRANS)) { - if (kgdb_transition_check(buffer)) - return buffer; - } else { + if (!KDB_STATE(KGDB_TRANS)) + kgdb_transition_check(buffer); + else kdb_printf("%c", key); - } } /* Special escape to kgdb */ if (lastchar - buffer >= 5 && strcmp(lastchar - 5, "$?#3f") == 0) { - kdb_gdb_state_pass(lastchar - 5); strcpy(buffer, "kgdb"); KDB_STATE_SET(DOING_KGDB); return buffer; } - if (lastchar - buffer >= 11 && - strcmp(lastchar - 11, "$qSupported") == 0) { - kdb_gdb_state_pass(lastchar - 11); + if (lastchar - buffer >= 14 && + strcmp(lastchar - 14, "$qSupported#37") == 0) { strcpy(buffer, "kgdb"); - KDB_STATE_SET(DOING_KGDB); + KDB_STATE_SET(DOING_KGDB2); return buffer; } } diff --git a/trunk/kernel/debug/kdb/kdb_main.c b/trunk/kernel/debug/kdb/kdb_main.c index 63786e71a3cd..be14779bcef6 100644 --- a/trunk/kernel/debug/kdb/kdb_main.c +++ b/trunk/kernel/debug/kdb/kdb_main.c @@ -145,6 +145,7 @@ static char *__env[] = { #endif "RADIX=16", "MDCOUNT=8", /* lines of md output */ + "BTARGS=9", /* 9 possible args in bt */ KDB_PLATFORM_ENV, "DTABCOUNT=30", "NOSECT=1", @@ -171,7 +172,6 @@ static char *__env[] = { (char *)0, (char *)0, (char *)0, - (char *)0, }; static const int __nenv = (sizeof(__env) / sizeof(char *)); @@ -1386,7 +1386,7 @@ int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, } if (result == KDB_CMD_KGDB) { - if (!KDB_STATE(DOING_KGDB)) + if (!(KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2))) kdb_printf("Entering please attach debugger " "or use $D#44+ or $3#33\n"); break; diff --git a/trunk/kernel/debug/kdb/kdb_private.h b/trunk/kernel/debug/kdb/kdb_private.h index e381d105b40b..35d69ed1dfb5 100644 --- a/trunk/kernel/debug/kdb/kdb_private.h +++ b/trunk/kernel/debug/kdb/kdb_private.h @@ -21,6 +21,7 @@ #define KDB_CMD_SS (-1003) #define KDB_CMD_SSB (-1004) #define KDB_CMD_KGDB (-1005) +#define KDB_CMD_KGDB2 (-1006) /* Internal debug flags */ #define KDB_DEBUG_FLAG_BP 0x0002 /* Breakpoint subsystem debug */ @@ -145,6 +146,7 @@ extern int kdb_state; * keyboard on this cpu */ #define KDB_STATE_KEXEC 0x00040000 /* kexec issued */ #define KDB_STATE_DOING_KGDB 0x00080000 /* kgdb enter now issued */ +#define KDB_STATE_DOING_KGDB2 0x00100000 /* kgdb enter now issued */ #define KDB_STATE_KGDB_TRANS 0x00200000 /* Transition to kgdb */ #define KDB_STATE_ARCH 0xff000000 /* Reserved for arch * specific use */ @@ -216,7 +218,6 @@ extern void kdb_print_nameval(const char *name, unsigned long val); extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info); extern void kdb_meminfo_proc_show(void); extern char *kdb_getstr(char *, size_t, char *); -extern void kdb_gdb_state_pass(char *buf); /* Defines for kdb_symbol_print */ #define KDB_SP_SPACEB 0x0001 /* Space before string */ diff --git a/trunk/kernel/futex.c b/trunk/kernel/futex.c index 11cbe052b2e8..0a308970c24a 100644 --- a/trunk/kernel/futex.c +++ b/trunk/kernel/futex.c @@ -218,8 +218,6 @@ static void drop_futex_key_refs(union futex_key *key) * @uaddr: virtual address of the futex * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED * @key: address where result is stored. - * @rw: mapping needs to be read/write (values: VERIFY_READ, - * VERIFY_WRITE) * * Returns a negative error code or 0 * The key words are stored in *key on success. @@ -231,12 +229,12 @@ static void drop_futex_key_refs(union futex_key *key) * lock_page() might sleep, the caller should not hold a spinlock. */ static int -get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) +get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) { unsigned long address = (unsigned long)uaddr; struct mm_struct *mm = current->mm; struct page *page, *page_head; - int err, ro = 0; + int err; /* * The futex address must be "naturally" aligned. @@ -264,18 +262,8 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) again: err = get_user_pages_fast(address, 1, 1, &page); - /* - * If write access is not required (eg. FUTEX_WAIT), try - * and get read-only access. - */ - if (err == -EFAULT && rw == VERIFY_READ) { - err = get_user_pages_fast(address, 1, 0, &page); - ro = 1; - } if (err < 0) return err; - else - err = 0; #ifdef CONFIG_TRANSPARENT_HUGEPAGE page_head = page; @@ -317,13 +305,6 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) if (!page_head->mapping) { unlock_page(page_head); put_page(page_head); - /* - * ZERO_PAGE pages don't have a mapping. Avoid a busy loop - * trying to find one. RW mapping would have COW'd (and thus - * have a mapping) so this page is RO and won't ever change. - */ - if ((page_head == ZERO_PAGE(address))) - return -EFAULT; goto again; } @@ -335,15 +316,6 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) * the object not the particular process. */ if (PageAnon(page_head)) { - /* - * A RO anonymous page will never change and thus doesn't make - * sense for futex operations. - */ - if (ro) { - err = -EFAULT; - goto out; - } - key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */ key->private.mm = mm; key->private.address = address; @@ -355,10 +327,9 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) get_futex_key_refs(key); -out: unlock_page(page_head); put_page(page_head); - return err; + return 0; } static inline void put_futex_key(union futex_key *key) @@ -969,7 +940,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) if (!bitset) return -EINVAL; - ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ); + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key); if (unlikely(ret != 0)) goto out; @@ -1015,10 +986,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2, int ret, op_ret; retry: - ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); + ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1); if (unlikely(ret != 0)) goto out; - ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE); + ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2); if (unlikely(ret != 0)) goto out_put_key1; @@ -1272,11 +1243,10 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, pi_state = NULL; } - ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); + ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1); if (unlikely(ret != 0)) goto out; - ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, - requeue_pi ? VERIFY_WRITE : VERIFY_READ); + ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2); if (unlikely(ret != 0)) goto out_put_key1; @@ -1820,7 +1790,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags, * while the syscall executes. */ retry: - ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, VERIFY_READ); + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key); if (unlikely(ret != 0)) return ret; @@ -1971,7 +1941,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, int detect, } retry: - ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, VERIFY_WRITE); + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key); if (unlikely(ret != 0)) goto out; @@ -2090,7 +2060,7 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags) if ((uval & FUTEX_TID_MASK) != vpid) return -EPERM; - ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_WRITE); + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key); if (unlikely(ret != 0)) goto out; @@ -2279,7 +2249,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, debug_rt_mutex_init_waiter(&rt_waiter); rt_waiter.task = NULL; - ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE); + ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2); if (unlikely(ret != 0)) goto out; diff --git a/trunk/kernel/kmod.c b/trunk/kernel/kmod.c index ddc7644c1305..47613dfb7b28 100644 --- a/trunk/kernel/kmod.c +++ b/trunk/kernel/kmod.c @@ -274,7 +274,7 @@ static void __call_usermodehelper(struct work_struct *work) * (used for preventing user land processes from being created after the user * land has been frozen during a system-wide hibernation or suspend operation). */ -static int usermodehelper_disabled = 1; +static int usermodehelper_disabled; /* Number of helpers running */ static atomic_t running_helpers = ATOMIC_INIT(0); diff --git a/trunk/kernel/lockdep.c b/trunk/kernel/lockdep.c index 8c24294e477f..3956f5149e25 100644 --- a/trunk/kernel/lockdep.c +++ b/trunk/kernel/lockdep.c @@ -2468,7 +2468,7 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark) BUG_ON(usage_bit >= LOCK_USAGE_STATES); - if (hlock_class(hlock)->key == __lockdep_no_validate__.subkeys) + if (hlock_class(hlock)->key == &__lockdep_no_validate__) continue; if (!mark_lock(curr, hlock, usage_bit)) @@ -2485,9 +2485,23 @@ static void __trace_hardirqs_on_caller(unsigned long ip) { struct task_struct *curr = current; + if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled))) + return; + + if (unlikely(curr->hardirqs_enabled)) { + /* + * Neither irq nor preemption are disabled here + * so this is racy by nature but losing one hit + * in a stat is not a big deal. + */ + __debug_atomic_inc(redundant_hardirqs_on); + return; + } /* we'll do an OFF -> ON transition: */ curr->hardirqs_enabled = 1; + if (DEBUG_LOCKS_WARN_ON(current->hardirq_context)) + return; /* * We are going to turn hardirqs on, so set the * usage bit for all held locks: @@ -2515,25 +2529,9 @@ void trace_hardirqs_on_caller(unsigned long ip) if (unlikely(!debug_locks || current->lockdep_recursion)) return; - if (unlikely(current->hardirqs_enabled)) { - /* - * Neither irq nor preemption are disabled here - * so this is racy by nature but losing one hit - * in a stat is not a big deal. - */ - __debug_atomic_inc(redundant_hardirqs_on); - return; - } - if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) return; - if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled))) - return; - - if (DEBUG_LOCKS_WARN_ON(current->hardirq_context)) - return; - current->lockdep_recursion = 1; __trace_hardirqs_on_caller(ip); current->lockdep_recursion = 0; @@ -2874,7 +2872,10 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this, void lockdep_init_map(struct lockdep_map *lock, const char *name, struct lock_class_key *key, int subclass) { - memset(lock, 0, sizeof(*lock)); + int i; + + for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++) + lock->class_cache[i] = NULL; #ifdef CONFIG_LOCK_STAT lock->cpu = raw_smp_processor_id(); diff --git a/trunk/kernel/taskstats.c b/trunk/kernel/taskstats.c index e19ce1454ee1..d1db2880d1cf 100644 --- a/trunk/kernel/taskstats.c +++ b/trunk/kernel/taskstats.c @@ -291,28 +291,30 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd) if (!cpumask_subset(mask, cpu_possible_mask)) return -EINVAL; + s = NULL; if (isadd == REGISTER) { for_each_cpu(cpu, mask) { - s = kmalloc_node(sizeof(struct listener), - GFP_KERNEL, cpu_to_node(cpu)); + if (!s) + s = kmalloc_node(sizeof(struct listener), + GFP_KERNEL, cpu_to_node(cpu)); if (!s) goto cleanup; - s->pid = pid; + INIT_LIST_HEAD(&s->list); s->valid = 1; listeners = &per_cpu(listener_array, cpu); down_write(&listeners->sem); - list_for_each_entry(s2, &listeners->list, list) { - if (s2->pid == pid && s2->valid) - goto exists; + list_for_each_entry_safe(s2, tmp, &listeners->list, list) { + if (s2->pid == pid) + goto next_cpu; } list_add(&s->list, &listeners->list); s = NULL; -exists: +next_cpu: up_write(&listeners->sem); - kfree(s); /* nop if NULL */ } + kfree(s); return 0; } diff --git a/trunk/lib/Kconfig b/trunk/lib/Kconfig index 6c695ff9caba..32f3e5ae2be5 100644 --- a/trunk/lib/Kconfig +++ b/trunk/lib/Kconfig @@ -276,7 +276,4 @@ config CORDIC so its calculations are in fixed point. Modules can select this when they require this function. Module will be called cordic. -config LLIST - bool - endmenu diff --git a/trunk/lib/Makefile b/trunk/lib/Makefile index 6457af4a7caf..892f4e282ea1 100644 --- a/trunk/lib/Makefile +++ b/trunk/lib/Makefile @@ -115,8 +115,6 @@ obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o obj-$(CONFIG_CORDIC) += cordic.o -obj-$(CONFIG_LLIST) += llist.o - hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/trunk/lib/bitmap.c b/trunk/lib/bitmap.c index 2f4412e4d071..37ef4b048795 100644 --- a/trunk/lib/bitmap.c +++ b/trunk/lib/bitmap.c @@ -271,6 +271,8 @@ int __bitmap_weight(const unsigned long *bitmap, int bits) } EXPORT_SYMBOL(__bitmap_weight); +#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG)) + void bitmap_set(unsigned long *map, int start, int nr) { unsigned long *p = map + BIT_WORD(start); diff --git a/trunk/lib/fault-inject.c b/trunk/lib/fault-inject.c index f193b7796449..2577b121c7c1 100644 --- a/trunk/lib/fault-inject.c +++ b/trunk/lib/fault-inject.c @@ -197,15 +197,21 @@ static struct dentry *debugfs_create_atomic_t(const char *name, mode_t mode, return debugfs_create_file(name, mode, parent, value, &fops_atomic_t); } -struct dentry *fault_create_debugfs_attr(const char *name, - struct dentry *parent, struct fault_attr *attr) +void cleanup_fault_attr_dentries(struct fault_attr *attr) +{ + debugfs_remove_recursive(attr->dir); +} + +int init_fault_attr_dentries(struct fault_attr *attr, const char *name) { mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; struct dentry *dir; - dir = debugfs_create_dir(name, parent); + dir = debugfs_create_dir(name, NULL); if (!dir) - return ERR_PTR(-ENOMEM); + return -ENOMEM; + + attr->dir = dir; if (!debugfs_create_ul("probability", mode, dir, &attr->probability)) goto fail; @@ -237,11 +243,11 @@ struct dentry *fault_create_debugfs_attr(const char *name, #endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */ - return dir; + return 0; fail: - debugfs_remove_recursive(dir); + debugfs_remove_recursive(attr->dir); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ diff --git a/trunk/lib/genalloc.c b/trunk/lib/genalloc.c index f352cc42f4f8..577ddf805975 100644 --- a/trunk/lib/genalloc.c +++ b/trunk/lib/genalloc.c @@ -1,26 +1,8 @@ /* - * Basic general purpose allocator for managing special purpose - * memory, for example, memory that is not managed by the regular - * kmalloc/kfree interface. Uses for this includes on-device special - * memory, uncached memory etc. - * - * It is safe to use the allocator in NMI handlers and other special - * unblockable contexts that could otherwise deadlock on locks. This - * is implemented by using atomic operations and retries on any - * conflicts. The disadvantage is that there may be livelocks in - * extreme cases. For better scalability, one allocator can be used - * for each CPU. - * - * The lockless operation only works if there is enough memory - * available. If new memory is added to the pool a lock has to be - * still taken. So any user relying on locklessness has to ensure - * that sufficient memory is preallocated. - * - * The basic atomic operation of this allocator is cmpxchg on long. - * On architectures that don't have NMI-safe cmpxchg implementation, - * the allocator can NOT be used in NMI handler. So code uses the - * allocator in NMI handler should depend on - * CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG. + * Basic general purpose allocator for managing special purpose memory + * not managed by the regular kmalloc/kfree interface. + * Uses for this includes on-device special memory, uncached memory + * etc. * * Copyright 2005 (C) Jes Sorensen * @@ -31,109 +13,8 @@ #include #include #include -#include -#include #include -static int set_bits_ll(unsigned long *addr, unsigned long mask_to_set) -{ - unsigned long val, nval; - - nval = *addr; - do { - val = nval; - if (val & mask_to_set) - return -EBUSY; - cpu_relax(); - } while ((nval = cmpxchg(addr, val, val | mask_to_set)) != val); - - return 0; -} - -static int clear_bits_ll(unsigned long *addr, unsigned long mask_to_clear) -{ - unsigned long val, nval; - - nval = *addr; - do { - val = nval; - if ((val & mask_to_clear) != mask_to_clear) - return -EBUSY; - cpu_relax(); - } while ((nval = cmpxchg(addr, val, val & ~mask_to_clear)) != val); - - return 0; -} - -/* - * bitmap_set_ll - set the specified number of bits at the specified position - * @map: pointer to a bitmap - * @start: a bit position in @map - * @nr: number of bits to set - * - * Set @nr bits start from @start in @map lock-lessly. Several users - * can set/clear the same bitmap simultaneously without lock. If two - * users set the same bit, one user will return remain bits, otherwise - * return 0. - */ -static int bitmap_set_ll(unsigned long *map, int start, int nr) -{ - unsigned long *p = map + BIT_WORD(start); - const int size = start + nr; - int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG); - unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start); - - while (nr - bits_to_set >= 0) { - if (set_bits_ll(p, mask_to_set)) - return nr; - nr -= bits_to_set; - bits_to_set = BITS_PER_LONG; - mask_to_set = ~0UL; - p++; - } - if (nr) { - mask_to_set &= BITMAP_LAST_WORD_MASK(size); - if (set_bits_ll(p, mask_to_set)) - return nr; - } - - return 0; -} - -/* - * bitmap_clear_ll - clear the specified number of bits at the specified position - * @map: pointer to a bitmap - * @start: a bit position in @map - * @nr: number of bits to set - * - * Clear @nr bits start from @start in @map lock-lessly. Several users - * can set/clear the same bitmap simultaneously without lock. If two - * users clear the same bit, one user will return remain bits, - * otherwise return 0. - */ -static int bitmap_clear_ll(unsigned long *map, int start, int nr) -{ - unsigned long *p = map + BIT_WORD(start); - const int size = start + nr; - int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); - unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); - - while (nr - bits_to_clear >= 0) { - if (clear_bits_ll(p, mask_to_clear)) - return nr; - nr -= bits_to_clear; - bits_to_clear = BITS_PER_LONG; - mask_to_clear = ~0UL; - p++; - } - if (nr) { - mask_to_clear &= BITMAP_LAST_WORD_MASK(size); - if (clear_bits_ll(p, mask_to_clear)) - return nr; - } - - return 0; -} /** * gen_pool_create - create a new special memory pool @@ -149,7 +30,7 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid) pool = kmalloc_node(sizeof(struct gen_pool), GFP_KERNEL, nid); if (pool != NULL) { - spin_lock_init(&pool->lock); + rwlock_init(&pool->lock); INIT_LIST_HEAD(&pool->chunks); pool->min_alloc_order = min_alloc_order; } @@ -182,14 +63,14 @@ int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phy if (unlikely(chunk == NULL)) return -ENOMEM; + spin_lock_init(&chunk->lock); chunk->phys_addr = phys; chunk->start_addr = virt; chunk->end_addr = virt + size; - atomic_set(&chunk->avail, size); - spin_lock(&pool->lock); - list_add_rcu(&chunk->next_chunk, &pool->chunks); - spin_unlock(&pool->lock); + write_lock(&pool->lock); + list_add(&chunk->next_chunk, &pool->chunks); + write_unlock(&pool->lock); return 0; } @@ -204,19 +85,19 @@ EXPORT_SYMBOL(gen_pool_add_virt); */ phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr) { + struct list_head *_chunk; struct gen_pool_chunk *chunk; - phys_addr_t paddr = -1; - rcu_read_lock(); - list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) { - if (addr >= chunk->start_addr && addr < chunk->end_addr) { - paddr = chunk->phys_addr + (addr - chunk->start_addr); - break; - } + read_lock(&pool->lock); + list_for_each(_chunk, &pool->chunks) { + chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); + + if (addr >= chunk->start_addr && addr < chunk->end_addr) + return chunk->phys_addr + addr - chunk->start_addr; } - rcu_read_unlock(); + read_unlock(&pool->lock); - return paddr; + return -1; } EXPORT_SYMBOL(gen_pool_virt_to_phys); @@ -234,6 +115,7 @@ void gen_pool_destroy(struct gen_pool *pool) int order = pool->min_alloc_order; int bit, end_bit; + list_for_each_safe(_chunk, _next_chunk, &pool->chunks) { chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); list_del(&chunk->next_chunk); @@ -255,50 +137,44 @@ EXPORT_SYMBOL(gen_pool_destroy); * @size: number of bytes to allocate from the pool * * Allocate the requested number of bytes from the specified pool. - * Uses a first-fit algorithm. Can not be used in NMI handler on - * architectures without NMI-safe cmpxchg implementation. + * Uses a first-fit algorithm. */ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size) { + struct list_head *_chunk; struct gen_pool_chunk *chunk; - unsigned long addr = 0; + unsigned long addr, flags; int order = pool->min_alloc_order; - int nbits, start_bit = 0, end_bit, remain; - -#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - BUG_ON(in_nmi()); -#endif + int nbits, start_bit, end_bit; if (size == 0) return 0; nbits = (size + (1UL << order) - 1) >> order; - rcu_read_lock(); - list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) { - if (size > atomic_read(&chunk->avail)) - continue; + + read_lock(&pool->lock); + list_for_each(_chunk, &pool->chunks) { + chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); end_bit = (chunk->end_addr - chunk->start_addr) >> order; -retry: - start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit, - start_bit, nbits, 0); - if (start_bit >= end_bit) + + spin_lock_irqsave(&chunk->lock, flags); + start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit, 0, + nbits, 0); + if (start_bit >= end_bit) { + spin_unlock_irqrestore(&chunk->lock, flags); continue; - remain = bitmap_set_ll(chunk->bits, start_bit, nbits); - if (remain) { - remain = bitmap_clear_ll(chunk->bits, start_bit, - nbits - remain); - BUG_ON(remain); - goto retry; } addr = chunk->start_addr + ((unsigned long)start_bit << order); - size = nbits << order; - atomic_sub(size, &chunk->avail); - break; + + bitmap_set(chunk->bits, start_bit, nbits); + spin_unlock_irqrestore(&chunk->lock, flags); + read_unlock(&pool->lock); + return addr; } - rcu_read_unlock(); - return addr; + read_unlock(&pool->lock); + return 0; } EXPORT_SYMBOL(gen_pool_alloc); @@ -308,95 +184,33 @@ EXPORT_SYMBOL(gen_pool_alloc); * @addr: starting address of memory to free back to pool * @size: size in bytes of memory to free * - * Free previously allocated special memory back to the specified - * pool. Can not be used in NMI handler on architectures without - * NMI-safe cmpxchg implementation. + * Free previously allocated special memory back to the specified pool. */ void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size) { + struct list_head *_chunk; struct gen_pool_chunk *chunk; + unsigned long flags; int order = pool->min_alloc_order; - int start_bit, nbits, remain; - -#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - BUG_ON(in_nmi()); -#endif + int bit, nbits; nbits = (size + (1UL << order) - 1) >> order; - rcu_read_lock(); - list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) { + + read_lock(&pool->lock); + list_for_each(_chunk, &pool->chunks) { + chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); + if (addr >= chunk->start_addr && addr < chunk->end_addr) { BUG_ON(addr + size > chunk->end_addr); - start_bit = (addr - chunk->start_addr) >> order; - remain = bitmap_clear_ll(chunk->bits, start_bit, nbits); - BUG_ON(remain); - size = nbits << order; - atomic_add(size, &chunk->avail); - rcu_read_unlock(); - return; + spin_lock_irqsave(&chunk->lock, flags); + bit = (addr - chunk->start_addr) >> order; + while (nbits--) + __clear_bit(bit++, chunk->bits); + spin_unlock_irqrestore(&chunk->lock, flags); + break; } } - rcu_read_unlock(); - BUG(); + BUG_ON(nbits > 0); + read_unlock(&pool->lock); } EXPORT_SYMBOL(gen_pool_free); - -/** - * gen_pool_for_each_chunk - call func for every chunk of generic memory pool - * @pool: the generic memory pool - * @func: func to call - * @data: additional data used by @func - * - * Call @func for every chunk of generic memory pool. The @func is - * called with rcu_read_lock held. - */ -void gen_pool_for_each_chunk(struct gen_pool *pool, - void (*func)(struct gen_pool *pool, struct gen_pool_chunk *chunk, void *data), - void *data) -{ - struct gen_pool_chunk *chunk; - - rcu_read_lock(); - list_for_each_entry_rcu(chunk, &(pool)->chunks, next_chunk) - func(pool, chunk, data); - rcu_read_unlock(); -} -EXPORT_SYMBOL(gen_pool_for_each_chunk); - -/** - * gen_pool_avail - get available free space of the pool - * @pool: pool to get available free space - * - * Return available free space of the specified pool. - */ -size_t gen_pool_avail(struct gen_pool *pool) -{ - struct gen_pool_chunk *chunk; - size_t avail = 0; - - rcu_read_lock(); - list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) - avail += atomic_read(&chunk->avail); - rcu_read_unlock(); - return avail; -} -EXPORT_SYMBOL_GPL(gen_pool_avail); - -/** - * gen_pool_size - get size in bytes of memory managed by the pool - * @pool: pool to get size - * - * Return size in bytes of memory managed by the pool. - */ -size_t gen_pool_size(struct gen_pool *pool) -{ - struct gen_pool_chunk *chunk; - size_t size = 0; - - rcu_read_lock(); - list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) - size += chunk->end_addr - chunk->start_addr; - rcu_read_unlock(); - return size; -} -EXPORT_SYMBOL_GPL(gen_pool_size); diff --git a/trunk/lib/idr.c b/trunk/lib/idr.c index db040ce3fa73..e15502e8b21e 100644 --- a/trunk/lib/idr.c +++ b/trunk/lib/idr.c @@ -34,10 +34,8 @@ #include #include #include -#include static struct kmem_cache *idr_layer_cache; -static DEFINE_SPINLOCK(simple_ida_lock); static struct idr_layer *get_from_free_list(struct idr *idp) { @@ -927,71 +925,6 @@ void ida_destroy(struct ida *ida) } EXPORT_SYMBOL(ida_destroy); -/** - * ida_simple_get - get a new id. - * @ida: the (initialized) ida. - * @start: the minimum id (inclusive, < 0x8000000) - * @end: the maximum id (exclusive, < 0x8000000 or 0) - * @gfp_mask: memory allocation flags - * - * Allocates an id in the range start <= id < end, or returns -ENOSPC. - * On memory allocation failure, returns -ENOMEM. - * - * Use ida_simple_remove() to get rid of an id. - */ -int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, - gfp_t gfp_mask) -{ - int ret, id; - unsigned int max; - - BUG_ON((int)start < 0); - BUG_ON((int)end < 0); - - if (end == 0) - max = 0x80000000; - else { - BUG_ON(end < start); - max = end - 1; - } - -again: - if (!ida_pre_get(ida, gfp_mask)) - return -ENOMEM; - - spin_lock(&simple_ida_lock); - ret = ida_get_new_above(ida, start, &id); - if (!ret) { - if (id > max) { - ida_remove(ida, id); - ret = -ENOSPC; - } else { - ret = id; - } - } - spin_unlock(&simple_ida_lock); - - if (unlikely(ret == -EAGAIN)) - goto again; - - return ret; -} -EXPORT_SYMBOL(ida_simple_get); - -/** - * ida_simple_remove - remove an allocated id. - * @ida: the (initialized) ida. - * @id: the id returned by ida_simple_get. - */ -void ida_simple_remove(struct ida *ida, unsigned int id) -{ - BUG_ON((int)id < 0); - spin_lock(&simple_ida_lock); - ida_remove(ida, id); - spin_unlock(&simple_ida_lock); -} -EXPORT_SYMBOL(ida_simple_remove); - /** * ida_init - initialize ida handle * @ida: ida handle diff --git a/trunk/lib/llist.c b/trunk/lib/llist.c deleted file mode 100644 index da445724fa1f..000000000000 --- a/trunk/lib/llist.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Lock-less NULL terminated single linked list - * - * The basic atomic operation of this list is cmpxchg on long. On - * architectures that don't have NMI-safe cmpxchg implementation, the - * list can NOT be used in NMI handler. So code uses the list in NMI - * handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG. - * - * Copyright 2010,2011 Intel Corp. - * Author: Huang Ying - * - * 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; - * - * 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 - */ -#include -#include -#include -#include - -#include - -/** - * llist_add - add a new entry - * @new: new entry to be added - * @head: the head for your lock-less list - */ -void llist_add(struct llist_node *new, struct llist_head *head) -{ - struct llist_node *entry, *old_entry; - -#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - BUG_ON(in_nmi()); -#endif - - entry = head->first; - do { - old_entry = entry; - new->next = entry; - cpu_relax(); - } while ((entry = cmpxchg(&head->first, old_entry, new)) != old_entry); -} -EXPORT_SYMBOL_GPL(llist_add); - -/** - * llist_add_batch - add several linked entries in batch - * @new_first: first entry in batch to be added - * @new_last: last entry in batch to be added - * @head: the head for your lock-less list - */ -void llist_add_batch(struct llist_node *new_first, struct llist_node *new_last, - struct llist_head *head) -{ - struct llist_node *entry, *old_entry; - -#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - BUG_ON(in_nmi()); -#endif - - entry = head->first; - do { - old_entry = entry; - new_last->next = entry; - cpu_relax(); - } while ((entry = cmpxchg(&head->first, old_entry, new_first)) != old_entry); -} -EXPORT_SYMBOL_GPL(llist_add_batch); - -/** - * llist_del_first - delete the first entry of lock-less list - * @head: the head for your lock-less list - * - * If list is empty, return NULL, otherwise, return the first entry - * deleted, this is the newest added one. - * - * Only one llist_del_first user can be used simultaneously with - * multiple llist_add users without lock. Because otherwise - * llist_del_first, llist_add, llist_add (or llist_del_all, llist_add, - * llist_add) sequence in another user may change @head->first->next, - * but keep @head->first. If multiple consumers are needed, please - * use llist_del_all or use lock between consumers. - */ -struct llist_node *llist_del_first(struct llist_head *head) -{ - struct llist_node *entry, *old_entry, *next; - -#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - BUG_ON(in_nmi()); -#endif - - entry = head->first; - do { - if (entry == NULL) - return NULL; - old_entry = entry; - next = entry->next; - cpu_relax(); - } while ((entry = cmpxchg(&head->first, old_entry, next)) != old_entry); - - return entry; -} -EXPORT_SYMBOL_GPL(llist_del_first); - -/** - * llist_del_all - delete all entries from lock-less list - * @head: the head of lock-less list to delete all entries - * - * If list is empty, return NULL, otherwise, delete all entries and - * return the pointer to the first entry. The order of entries - * deleted is from the newest to the oldest added one. - */ -struct llist_node *llist_del_all(struct llist_head *head) -{ -#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - BUG_ON(in_nmi()); -#endif - - return xchg(&head->first, NULL); -} -EXPORT_SYMBOL_GPL(llist_del_all); diff --git a/trunk/lib/radix-tree.c b/trunk/lib/radix-tree.c index a2f9da59c197..7ea2e033d715 100644 --- a/trunk/lib/radix-tree.c +++ b/trunk/lib/radix-tree.c @@ -823,8 +823,8 @@ unsigned long radix_tree_prev_hole(struct radix_tree_root *root, EXPORT_SYMBOL(radix_tree_prev_hole); static unsigned int -__lookup(struct radix_tree_node *slot, void ***results, unsigned long *indices, - unsigned long index, unsigned int max_items, unsigned long *next_index) +__lookup(struct radix_tree_node *slot, void ***results, unsigned long index, + unsigned int max_items, unsigned long *next_index) { unsigned int nr_found = 0; unsigned int shift, height; @@ -857,16 +857,12 @@ __lookup(struct radix_tree_node *slot, void ***results, unsigned long *indices, /* Bottom level: grab some items */ for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) { + index++; if (slot->slots[i]) { - results[nr_found] = &(slot->slots[i]); - if (indices) - indices[nr_found] = index; - if (++nr_found == max_items) { - index++; + results[nr_found++] = &(slot->slots[i]); + if (nr_found == max_items) goto out; - } } - index++; } out: *next_index = index; @@ -922,8 +918,8 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results, if (cur_index > max_index) break; - slots_found = __lookup(node, (void ***)results + ret, NULL, - cur_index, max_items - ret, &next_index); + slots_found = __lookup(node, (void ***)results + ret, cur_index, + max_items - ret, &next_index); nr_found = 0; for (i = 0; i < slots_found; i++) { struct radix_tree_node *slot; @@ -948,7 +944,6 @@ EXPORT_SYMBOL(radix_tree_gang_lookup); * radix_tree_gang_lookup_slot - perform multiple slot lookup on radix tree * @root: radix tree root * @results: where the results of the lookup are placed - * @indices: where their indices should be placed (but usually NULL) * @first_index: start the lookup from this key * @max_items: place up to this many items at *results * @@ -963,8 +958,7 @@ EXPORT_SYMBOL(radix_tree_gang_lookup); * protection, radix_tree_deref_slot may fail requiring a retry. */ unsigned int -radix_tree_gang_lookup_slot(struct radix_tree_root *root, - void ***results, unsigned long *indices, +radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results, unsigned long first_index, unsigned int max_items) { unsigned long max_index; @@ -980,8 +974,6 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, if (first_index > 0) return 0; results[0] = (void **)&root->rnode; - if (indices) - indices[0] = 0; return 1; } node = indirect_to_ptr(node); @@ -995,9 +987,8 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, if (cur_index > max_index) break; - slots_found = __lookup(node, results + ret, - indices ? indices + ret : NULL, - cur_index, max_items - ret, &next_index); + slots_found = __lookup(node, results + ret, cur_index, + max_items - ret, &next_index); ret += slots_found; if (next_index == 0) break; @@ -1203,98 +1194,6 @@ radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results, } EXPORT_SYMBOL(radix_tree_gang_lookup_tag_slot); -#if defined(CONFIG_SHMEM) && defined(CONFIG_SWAP) -#include /* for cond_resched() */ - -/* - * This linear search is at present only useful to shmem_unuse_inode(). - */ -static unsigned long __locate(struct radix_tree_node *slot, void *item, - unsigned long index, unsigned long *found_index) -{ - unsigned int shift, height; - unsigned long i; - - height = slot->height; - shift = (height-1) * RADIX_TREE_MAP_SHIFT; - - for ( ; height > 1; height--) { - i = (index >> shift) & RADIX_TREE_MAP_MASK; - for (;;) { - if (slot->slots[i] != NULL) - break; - index &= ~((1UL << shift) - 1); - index += 1UL << shift; - if (index == 0) - goto out; /* 32-bit wraparound */ - i++; - if (i == RADIX_TREE_MAP_SIZE) - goto out; - } - - shift -= RADIX_TREE_MAP_SHIFT; - slot = rcu_dereference_raw(slot->slots[i]); - if (slot == NULL) - goto out; - } - - /* Bottom level: check items */ - for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) { - if (slot->slots[i] == item) { - *found_index = index + i; - index = 0; - goto out; - } - } - index += RADIX_TREE_MAP_SIZE; -out: - return index; -} - -/** - * radix_tree_locate_item - search through radix tree for item - * @root: radix tree root - * @item: item to be found - * - * Returns index where item was found, or -1 if not found. - * Caller must hold no lock (since this time-consuming function needs - * to be preemptible), and must check afterwards if item is still there. - */ -unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) -{ - struct radix_tree_node *node; - unsigned long max_index; - unsigned long cur_index = 0; - unsigned long found_index = -1; - - do { - rcu_read_lock(); - node = rcu_dereference_raw(root->rnode); - if (!radix_tree_is_indirect_ptr(node)) { - rcu_read_unlock(); - if (node == item) - found_index = 0; - break; - } - - node = indirect_to_ptr(node); - max_index = radix_tree_maxindex(node->height); - if (cur_index > max_index) - break; - - cur_index = __locate(node, item, cur_index, &found_index); - rcu_read_unlock(); - cond_resched(); - } while (cur_index != 0 && cur_index <= max_index); - - return found_index; -} -#else -unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) -{ - return -1; -} -#endif /* CONFIG_SHMEM && CONFIG_SWAP */ /** * radix_tree_shrink - shrink height of a radix tree to minimal diff --git a/trunk/lib/sha1.c b/trunk/lib/sha1.c index f33271dd00cb..4c45fd50e913 100644 --- a/trunk/lib/sha1.c +++ b/trunk/lib/sha1.c @@ -1,72 +1,31 @@ /* - * SHA1 routine optimized to do word accesses rather than byte accesses, - * and to avoid unnecessary copies into the context array. - * - * This was based on the git SHA1 implementation. + * SHA transform algorithm, originally taken from code written by + * Peter Gutmann, and placed in the public domain. */ #include #include -#include -#include +#include -/* - * If you have 32 registers or more, the compiler can (and should) - * try to change the array[] accesses into registers. However, on - * machines with less than ~25 registers, that won't really work, - * and at least gcc will make an unholy mess of it. - * - * So to avoid that mess which just slows things down, we force - * the stores to memory to actually happen (we might be better off - * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as - * suggested by Artur Skawina - that will also make gcc unable to - * try to do the silly "optimize away loads" part because it won't - * see what the value will be). - * - * Ben Herrenschmidt reports that on PPC, the C version comes close - * to the optimized asm with this (ie on PPC you don't want that - * 'volatile', since there are lots of registers). - * - * On ARM we get the best code generation by forcing a full memory barrier - * between each SHA_ROUND, otherwise gcc happily get wild with spilling and - * the stack frame size simply explode and performance goes down the drain. - */ +/* The SHA f()-functions. */ -#ifdef CONFIG_X86 - #define setW(x, val) (*(volatile __u32 *)&W(x) = (val)) -#elif defined(CONFIG_ARM) - #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0) -#else - #define setW(x, val) (W(x) = (val)) -#endif +#define f1(x,y,z) (z ^ (x & (y ^ z))) /* x ? y : z */ +#define f2(x,y,z) (x ^ y ^ z) /* XOR */ +#define f3(x,y,z) ((x & y) + (z & (x ^ y))) /* majority */ -/* This "rolls" over the 512-bit array */ -#define W(x) (array[(x)&15]) +/* The SHA Mysterious Constants */ -/* - * Where do we get the source from? The first 16 iterations get it from - * the input data, the next mix it from the 512-bit array. - */ -#define SHA_SRC(t) get_unaligned_be32((__u32 *)data + t) -#define SHA_MIX(t) rol32(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1) - -#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ - __u32 TEMP = input(t); setW(t, TEMP); \ - E += TEMP + rol32(A,5) + (fn) + (constant); \ - B = ror32(B, 2); } while (0) - -#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) -#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) -#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E ) -#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E ) -#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E ) +#define K1 0x5A827999L /* Rounds 0-19: sqrt(2) * 2^30 */ +#define K2 0x6ED9EBA1L /* Rounds 20-39: sqrt(3) * 2^30 */ +#define K3 0x8F1BBCDCL /* Rounds 40-59: sqrt(5) * 2^30 */ +#define K4 0xCA62C1D6L /* Rounds 60-79: sqrt(10) * 2^30 */ /** * sha_transform - single block SHA1 transform * * @digest: 160 bit digest to update * @data: 512 bits of data to hash - * @array: 16 words of workspace (see note) + * @W: 80 words of workspace (see note) * * This function generates a SHA1 digest for a single 512-bit block. * Be warned, it does not handle padding and message digest, do not @@ -77,111 +36,47 @@ * to clear the workspace. This is left to the caller to avoid * unnecessary clears between chained hashing operations. */ -void sha_transform(__u32 *digest, const char *data, __u32 *array) +void sha_transform(__u32 *digest, const char *in, __u32 *W) { - __u32 A, B, C, D, E; - - A = digest[0]; - B = digest[1]; - C = digest[2]; - D = digest[3]; - E = digest[4]; - - /* Round 1 - iterations 0-16 take their input from 'data' */ - T_0_15( 0, A, B, C, D, E); - T_0_15( 1, E, A, B, C, D); - T_0_15( 2, D, E, A, B, C); - T_0_15( 3, C, D, E, A, B); - T_0_15( 4, B, C, D, E, A); - T_0_15( 5, A, B, C, D, E); - T_0_15( 6, E, A, B, C, D); - T_0_15( 7, D, E, A, B, C); - T_0_15( 8, C, D, E, A, B); - T_0_15( 9, B, C, D, E, A); - T_0_15(10, A, B, C, D, E); - T_0_15(11, E, A, B, C, D); - T_0_15(12, D, E, A, B, C); - T_0_15(13, C, D, E, A, B); - T_0_15(14, B, C, D, E, A); - T_0_15(15, A, B, C, D, E); - - /* Round 1 - tail. Input from 512-bit mixing array */ - T_16_19(16, E, A, B, C, D); - T_16_19(17, D, E, A, B, C); - T_16_19(18, C, D, E, A, B); - T_16_19(19, B, C, D, E, A); - - /* Round 2 */ - T_20_39(20, A, B, C, D, E); - T_20_39(21, E, A, B, C, D); - T_20_39(22, D, E, A, B, C); - T_20_39(23, C, D, E, A, B); - T_20_39(24, B, C, D, E, A); - T_20_39(25, A, B, C, D, E); - T_20_39(26, E, A, B, C, D); - T_20_39(27, D, E, A, B, C); - T_20_39(28, C, D, E, A, B); - T_20_39(29, B, C, D, E, A); - T_20_39(30, A, B, C, D, E); - T_20_39(31, E, A, B, C, D); - T_20_39(32, D, E, A, B, C); - T_20_39(33, C, D, E, A, B); - T_20_39(34, B, C, D, E, A); - T_20_39(35, A, B, C, D, E); - T_20_39(36, E, A, B, C, D); - T_20_39(37, D, E, A, B, C); - T_20_39(38, C, D, E, A, B); - T_20_39(39, B, C, D, E, A); - - /* Round 3 */ - T_40_59(40, A, B, C, D, E); - T_40_59(41, E, A, B, C, D); - T_40_59(42, D, E, A, B, C); - T_40_59(43, C, D, E, A, B); - T_40_59(44, B, C, D, E, A); - T_40_59(45, A, B, C, D, E); - T_40_59(46, E, A, B, C, D); - T_40_59(47, D, E, A, B, C); - T_40_59(48, C, D, E, A, B); - T_40_59(49, B, C, D, E, A); - T_40_59(50, A, B, C, D, E); - T_40_59(51, E, A, B, C, D); - T_40_59(52, D, E, A, B, C); - T_40_59(53, C, D, E, A, B); - T_40_59(54, B, C, D, E, A); - T_40_59(55, A, B, C, D, E); - T_40_59(56, E, A, B, C, D); - T_40_59(57, D, E, A, B, C); - T_40_59(58, C, D, E, A, B); - T_40_59(59, B, C, D, E, A); - - /* Round 4 */ - T_60_79(60, A, B, C, D, E); - T_60_79(61, E, A, B, C, D); - T_60_79(62, D, E, A, B, C); - T_60_79(63, C, D, E, A, B); - T_60_79(64, B, C, D, E, A); - T_60_79(65, A, B, C, D, E); - T_60_79(66, E, A, B, C, D); - T_60_79(67, D, E, A, B, C); - T_60_79(68, C, D, E, A, B); - T_60_79(69, B, C, D, E, A); - T_60_79(70, A, B, C, D, E); - T_60_79(71, E, A, B, C, D); - T_60_79(72, D, E, A, B, C); - T_60_79(73, C, D, E, A, B); - T_60_79(74, B, C, D, E, A); - T_60_79(75, A, B, C, D, E); - T_60_79(76, E, A, B, C, D); - T_60_79(77, D, E, A, B, C); - T_60_79(78, C, D, E, A, B); - T_60_79(79, B, C, D, E, A); - - digest[0] += A; - digest[1] += B; - digest[2] += C; - digest[3] += D; - digest[4] += E; + __u32 a, b, c, d, e, t, i; + + for (i = 0; i < 16; i++) + W[i] = be32_to_cpu(((const __be32 *)in)[i]); + + for (i = 0; i < 64; i++) + W[i+16] = rol32(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 1); + + a = digest[0]; + b = digest[1]; + c = digest[2]; + d = digest[3]; + e = digest[4]; + + for (i = 0; i < 20; i++) { + t = f1(b, c, d) + K1 + rol32(a, 5) + e + W[i]; + e = d; d = c; c = rol32(b, 30); b = a; a = t; + } + + for (; i < 40; i ++) { + t = f2(b, c, d) + K2 + rol32(a, 5) + e + W[i]; + e = d; d = c; c = rol32(b, 30); b = a; a = t; + } + + for (; i < 60; i ++) { + t = f3(b, c, d) + K3 + rol32(a, 5) + e + W[i]; + e = d; d = c; c = rol32(b, 30); b = a; a = t; + } + + for (; i < 80; i ++) { + t = f2(b, c, d) + K4 + rol32(a, 5) + e + W[i]; + e = d; d = c; c = rol32(b, 30); b = a; a = t; + } + + digest[0] += a; + digest[1] += b; + digest[2] += c; + digest[3] += d; + digest[4] += e; } EXPORT_SYMBOL(sha_transform); @@ -197,3 +92,4 @@ void sha_init(__u32 *buf) buf[3] = 0x10325476; buf[4] = 0xc3d2e1f0; } + diff --git a/trunk/mm/failslab.c b/trunk/mm/failslab.c index 0dd7b8fec71c..1ce58c201dca 100644 --- a/trunk/mm/failslab.c +++ b/trunk/mm/failslab.c @@ -34,23 +34,23 @@ __setup("failslab=", setup_failslab); #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS static int __init failslab_debugfs_init(void) { - struct dentry *dir; mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; + int err; - dir = fault_create_debugfs_attr("failslab", NULL, &failslab.attr); - if (IS_ERR(dir)) - return PTR_ERR(dir); + err = init_fault_attr_dentries(&failslab.attr, "failslab"); + if (err) + return err; - if (!debugfs_create_bool("ignore-gfp-wait", mode, dir, + if (!debugfs_create_bool("ignore-gfp-wait", mode, failslab.attr.dir, &failslab.ignore_gfp_wait)) goto fail; - if (!debugfs_create_bool("cache-filter", mode, dir, + if (!debugfs_create_bool("cache-filter", mode, failslab.attr.dir, &failslab.cache_filter)) goto fail; return 0; fail: - debugfs_remove_recursive(dir); + cleanup_fault_attr_dentries(&failslab.attr); return -ENOMEM; } diff --git a/trunk/mm/filemap.c b/trunk/mm/filemap.c index 645a080ba4df..867d40222ec7 100644 --- a/trunk/mm/filemap.c +++ b/trunk/mm/filemap.c @@ -33,6 +33,7 @@ #include #include /* for BUG_ON(!in_atomic()) only */ #include +#include /* for page_is_file_cache() */ #include #include "internal.h" @@ -461,7 +462,6 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping, int error; VM_BUG_ON(!PageLocked(page)); - VM_BUG_ON(PageSwapBacked(page)); error = mem_cgroup_cache_charge(page, current->mm, gfp_mask & GFP_RECLAIM_MASK); @@ -479,6 +479,8 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping, if (likely(!error)) { mapping->nrpages++; __inc_zone_page_state(page, NR_FILE_PAGES); + if (PageSwapBacked(page)) + __inc_zone_page_state(page, NR_SHMEM); spin_unlock_irq(&mapping->tree_lock); } else { page->mapping = NULL; @@ -500,9 +502,22 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping, { int ret; + /* + * Splice_read and readahead add shmem/tmpfs pages into the page cache + * before shmem_readpage has a chance to mark them as SwapBacked: they + * need to go on the anon lru below, and mem_cgroup_cache_charge + * (called in add_to_page_cache) needs to know where they're going too. + */ + if (mapping_cap_swap_backed(mapping)) + SetPageSwapBacked(page); + ret = add_to_page_cache(page, mapping, offset, gfp_mask); - if (ret == 0) - lru_cache_add_file(page); + if (ret == 0) { + if (page_is_file_cache(page)) + lru_cache_add_file(page); + else + lru_cache_add_anon(page); + } return ret; } EXPORT_SYMBOL_GPL(add_to_page_cache_lru); @@ -699,16 +714,9 @@ struct page *find_get_page(struct address_space *mapping, pgoff_t offset) page = radix_tree_deref_slot(pagep); if (unlikely(!page)) goto out; - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) - goto repeat; - /* - * Otherwise, shmem/tmpfs must be storing a swap entry - * here as an exceptional entry: so return it without - * attempting to raise page count. - */ - goto out; - } + if (radix_tree_deref_retry(page)) + goto repeat; + if (!page_cache_get_speculative(page)) goto repeat; @@ -745,7 +753,7 @@ struct page *find_lock_page(struct address_space *mapping, pgoff_t offset) repeat: page = find_get_page(mapping, offset); - if (page && !radix_tree_exception(page)) { + if (page) { lock_page(page); /* Has the page been truncated? */ if (unlikely(page->mapping != mapping)) { @@ -832,7 +840,7 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start, rcu_read_lock(); restart: nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree, - (void ***)pages, NULL, start, nr_pages); + (void ***)pages, start, nr_pages); ret = 0; for (i = 0; i < nr_found; i++) { struct page *page; @@ -841,22 +849,13 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start, if (unlikely(!page)) continue; - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - /* - * Transient condition which can only trigger - * when entry at index 0 moves out of or back - * to root: none yet gotten, safe to restart. - */ - WARN_ON(start | i); - goto restart; - } - /* - * Otherwise, shmem/tmpfs must be storing a swap entry - * here as an exceptional entry: so skip over it - - * we only reach this from invalidate_mapping_pages(). - */ - continue; + /* + * This can only trigger when the entry at index 0 moves out + * of or back to the root: none yet gotten, safe to restart. + */ + if (radix_tree_deref_retry(page)) { + WARN_ON(start | i); + goto restart; } if (!page_cache_get_speculative(page)) @@ -904,7 +903,7 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index, rcu_read_lock(); restart: nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree, - (void ***)pages, NULL, index, nr_pages); + (void ***)pages, index, nr_pages); ret = 0; for (i = 0; i < nr_found; i++) { struct page *page; @@ -913,22 +912,12 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index, if (unlikely(!page)) continue; - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - /* - * Transient condition which can only trigger - * when entry at index 0 moves out of or back - * to root: none yet gotten, safe to restart. - */ - goto restart; - } - /* - * Otherwise, shmem/tmpfs must be storing a swap entry - * here as an exceptional entry: so stop looking for - * contiguous pages. - */ - break; - } + /* + * This can only trigger when the entry at index 0 moves out + * of or back to the root: none yet gotten, safe to restart. + */ + if (radix_tree_deref_retry(page)) + goto restart; if (!page_cache_get_speculative(page)) goto repeat; @@ -988,21 +977,12 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, if (unlikely(!page)) continue; - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - /* - * Transient condition which can only trigger - * when entry at index 0 moves out of or back - * to root: none yet gotten, safe to restart. - */ - goto restart; - } - /* - * This function is never used on a shmem/tmpfs - * mapping, so a swap entry won't be found here. - */ - BUG(); - } + /* + * This can only trigger when the entry at index 0 moves out + * of or back to the root: none yet gotten, safe to restart. + */ + if (radix_tree_deref_retry(page)) + goto restart; if (!page_cache_get_speculative(page)) goto repeat; diff --git a/trunk/mm/memcontrol.c b/trunk/mm/memcontrol.c index f4ec4e7ca4cd..5f84d2351ddb 100644 --- a/trunk/mm/memcontrol.c +++ b/trunk/mm/memcontrol.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -2872,6 +2873,30 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm, return 0; if (PageCompound(page)) return 0; + /* + * Corner case handling. This is called from add_to_page_cache() + * in usual. But some FS (shmem) precharges this page before calling it + * and call add_to_page_cache() with GFP_NOWAIT. + * + * For GFP_NOWAIT case, the page may be pre-charged before calling + * add_to_page_cache(). (See shmem.c) check it here and avoid to call + * charge twice. (It works but has to pay a bit larger cost.) + * And when the page is SwapCache, it should take swap information + * into account. This is under lock_page() now. + */ + if (!(gfp_mask & __GFP_WAIT)) { + struct page_cgroup *pc; + + pc = lookup_page_cgroup(page); + if (!pc) + return 0; + lock_page_cgroup(pc); + if (PageCgroupUsed(pc)) { + unlock_page_cgroup(pc); + return 0; + } + unlock_page_cgroup(pc); + } if (unlikely(!mm)) mm = &init_mm; @@ -3461,6 +3486,31 @@ void mem_cgroup_end_migration(struct mem_cgroup *mem, cgroup_release_and_wakeup_rmdir(&mem->css); } +/* + * A call to try to shrink memory usage on charge failure at shmem's swapin. + * Calling hierarchical_reclaim is not enough because we should update + * last_oom_jiffies to prevent pagefault_out_of_memory from invoking global OOM. + * Moreover considering hierarchy, we should reclaim from the mem_over_limit, + * not from the memcg which this page would be charged to. + * try_charge_swapin does all of these works properly. + */ +int mem_cgroup_shmem_charge_fallback(struct page *page, + struct mm_struct *mm, + gfp_t gfp_mask) +{ + struct mem_cgroup *mem; + int ret; + + if (mem_cgroup_disabled()) + return 0; + + ret = mem_cgroup_try_charge_swapin(mm, page, gfp_mask, &mem); + if (!ret) + mem_cgroup_cancel_charge_swapin(mem); /* it does !mem check */ + + return ret; +} + #ifdef CONFIG_DEBUG_VM static struct page_cgroup *lookup_page_cgroup_used(struct page *page) { @@ -5280,17 +5330,15 @@ static struct page *mc_handle_file_pte(struct vm_area_struct *vma, pgoff = pte_to_pgoff(ptent); /* page is moved even if it's not RSS of this task(page-faulted). */ - page = find_get_page(mapping, pgoff); - -#ifdef CONFIG_SWAP - /* shmem/tmpfs may report page out on swap: account for that too. */ - if (radix_tree_exceptional_entry(page)) { - swp_entry_t swap = radix_to_swp_entry(page); + if (!mapping_cap_swap_backed(mapping)) { /* normal file */ + page = find_get_page(mapping, pgoff); + } else { /* shmem/tmpfs file. we should take account of swap too. */ + swp_entry_t ent; + mem_cgroup_get_shmem_target(inode, pgoff, &page, &ent); if (do_swap_account) - *entry = swap; - page = find_get_page(&swapper_space, swap.val); + entry->val = ent.val; } -#endif + return page; } diff --git a/trunk/mm/memory-failure.c b/trunk/mm/memory-failure.c index 2b43ba051ac9..740c4f52059c 100644 --- a/trunk/mm/memory-failure.c +++ b/trunk/mm/memory-failure.c @@ -53,7 +53,6 @@ #include #include #include -#include #include "internal.h" int sysctl_memory_failure_early_kill __read_mostly = 0; @@ -1179,97 +1178,6 @@ void memory_failure(unsigned long pfn, int trapno) __memory_failure(pfn, trapno, 0); } -#define MEMORY_FAILURE_FIFO_ORDER 4 -#define MEMORY_FAILURE_FIFO_SIZE (1 << MEMORY_FAILURE_FIFO_ORDER) - -struct memory_failure_entry { - unsigned long pfn; - int trapno; - int flags; -}; - -struct memory_failure_cpu { - DECLARE_KFIFO(fifo, struct memory_failure_entry, - MEMORY_FAILURE_FIFO_SIZE); - spinlock_t lock; - struct work_struct work; -}; - -static DEFINE_PER_CPU(struct memory_failure_cpu, memory_failure_cpu); - -/** - * memory_failure_queue - Schedule handling memory failure of a page. - * @pfn: Page Number of the corrupted page - * @trapno: Trap number reported in the signal to user space. - * @flags: Flags for memory failure handling - * - * This function is called by the low level hardware error handler - * when it detects hardware memory corruption of a page. It schedules - * the recovering of error page, including dropping pages, killing - * processes etc. - * - * The function is primarily of use for corruptions that - * happen outside the current execution context (e.g. when - * detected by a background scrubber) - * - * Can run in IRQ context. - */ -void memory_failure_queue(unsigned long pfn, int trapno, int flags) -{ - struct memory_failure_cpu *mf_cpu; - unsigned long proc_flags; - struct memory_failure_entry entry = { - .pfn = pfn, - .trapno = trapno, - .flags = flags, - }; - - mf_cpu = &get_cpu_var(memory_failure_cpu); - spin_lock_irqsave(&mf_cpu->lock, proc_flags); - if (kfifo_put(&mf_cpu->fifo, &entry)) - schedule_work_on(smp_processor_id(), &mf_cpu->work); - else - pr_err("Memory failure: buffer overflow when queuing memory failure at 0x%#lx\n", - pfn); - spin_unlock_irqrestore(&mf_cpu->lock, proc_flags); - put_cpu_var(memory_failure_cpu); -} -EXPORT_SYMBOL_GPL(memory_failure_queue); - -static void memory_failure_work_func(struct work_struct *work) -{ - struct memory_failure_cpu *mf_cpu; - struct memory_failure_entry entry = { 0, }; - unsigned long proc_flags; - int gotten; - - mf_cpu = &__get_cpu_var(memory_failure_cpu); - for (;;) { - spin_lock_irqsave(&mf_cpu->lock, proc_flags); - gotten = kfifo_get(&mf_cpu->fifo, &entry); - spin_unlock_irqrestore(&mf_cpu->lock, proc_flags); - if (!gotten) - break; - __memory_failure(entry.pfn, entry.trapno, entry.flags); - } -} - -static int __init memory_failure_init(void) -{ - struct memory_failure_cpu *mf_cpu; - int cpu; - - for_each_possible_cpu(cpu) { - mf_cpu = &per_cpu(memory_failure_cpu, cpu); - spin_lock_init(&mf_cpu->lock); - INIT_KFIFO(mf_cpu->fifo); - INIT_WORK(&mf_cpu->work, memory_failure_work_func); - } - - return 0; -} -core_initcall(memory_failure_init); - /** * unpoison_memory - Unpoison a previously poisoned page * @pfn: Page number of the to be unpoisoned page diff --git a/trunk/mm/mincore.c b/trunk/mm/mincore.c index 636a86876ff2..a4e6b9d75c76 100644 --- a/trunk/mm/mincore.c +++ b/trunk/mm/mincore.c @@ -69,15 +69,12 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff) * file will not get a swp_entry_t in its pte, but rather it is like * any other file mapping (ie. marked !present and faulted in with * tmpfs's .fault). So swapped out tmpfs mappings are tested here. + * + * However when tmpfs moves the page from pagecache and into swapcache, + * it is still in core, but the find_get_page below won't find it. + * No big deal, but make a note of it. */ page = find_get_page(mapping, pgoff); -#ifdef CONFIG_SWAP - /* shmem/tmpfs may return swap: account for swapcache page too. */ - if (radix_tree_exceptional_entry(page)) { - swp_entry_t swap = radix_to_swp_entry(page); - page = find_get_page(&swapper_space, swap.val); - } -#endif if (page) { present = PageUptodate(page); page_cache_release(page); diff --git a/trunk/mm/oom_kill.c b/trunk/mm/oom_kill.c index 626303b52f3c..eafff89b3dd6 100644 --- a/trunk/mm/oom_kill.c +++ b/trunk/mm/oom_kill.c @@ -303,7 +303,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, do_each_thread(g, p) { unsigned int points; - if (p->exit_state) + if (!p->mm) continue; if (oom_unkillable_task(p, mem, nodemask)) continue; @@ -319,8 +319,6 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, */ if (test_tsk_thread_flag(p, TIF_MEMDIE)) return ERR_PTR(-1UL); - if (!p->mm) - continue; if (p->flags & PF_EXITING) { /* diff --git a/trunk/mm/page_alloc.c b/trunk/mm/page_alloc.c index 6e8ecb6e021c..1dbcf8888f14 100644 --- a/trunk/mm/page_alloc.c +++ b/trunk/mm/page_alloc.c @@ -1409,11 +1409,14 @@ static int __init fail_page_alloc_debugfs(void) { mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; struct dentry *dir; + int err; - dir = fault_create_debugfs_attr("fail_page_alloc", NULL, - &fail_page_alloc.attr); - if (IS_ERR(dir)) - return PTR_ERR(dir); + err = init_fault_attr_dentries(&fail_page_alloc.attr, + "fail_page_alloc"); + if (err) + return err; + + dir = fail_page_alloc.attr.dir; if (!debugfs_create_bool("ignore-gfp-wait", mode, dir, &fail_page_alloc.ignore_gfp_wait)) @@ -1427,7 +1430,7 @@ static int __init fail_page_alloc_debugfs(void) return 0; fail: - debugfs_remove_recursive(dir); + cleanup_fault_attr_dentries(&fail_page_alloc.attr); return -ENOMEM; } diff --git a/trunk/mm/shmem.c b/trunk/mm/shmem.c index 32f6763f16fb..5cc21f8b4cd3 100644 --- a/trunk/mm/shmem.c +++ b/trunk/mm/shmem.c @@ -6,8 +6,7 @@ * 2000-2001 Christoph Rohland * 2000-2001 SAP AG * 2002 Red Hat Inc. - * Copyright (C) 2002-2011 Hugh Dickins. - * Copyright (C) 2011 Google Inc. + * Copyright (C) 2002-2005 Hugh Dickins. * Copyright (C) 2002-2005 VERITAS Software Corporation. * Copyright (C) 2004 Andi Kleen, SuSE Labs * @@ -29,6 +28,7 @@ #include #include #include +#include #include static struct vfsmount *shm_mnt; @@ -51,8 +51,6 @@ static struct vfsmount *shm_mnt; #include #include #include -#include -#include #include #include #include @@ -65,17 +63,43 @@ static struct vfsmount *shm_mnt; #include #include +#include #include +/* + * The maximum size of a shmem/tmpfs file is limited by the maximum size of + * its triple-indirect swap vector - see illustration at shmem_swp_entry(). + * + * With 4kB page size, maximum file size is just over 2TB on a 32-bit kernel, + * but one eighth of that on a 64-bit kernel. With 8kB page size, maximum + * file size is just over 4TB on a 64-bit kernel, but 16TB on a 32-bit kernel, + * MAX_LFS_FILESIZE being then more restrictive than swap vector layout. + * + * We use / and * instead of shifts in the definitions below, so that the swap + * vector can be tested with small even values (e.g. 20) for ENTRIES_PER_PAGE. + */ +#define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long)) +#define ENTRIES_PER_PAGEPAGE ((unsigned long long)ENTRIES_PER_PAGE*ENTRIES_PER_PAGE) + +#define SHMSWP_MAX_INDEX (SHMEM_NR_DIRECT + (ENTRIES_PER_PAGEPAGE/2) * (ENTRIES_PER_PAGE+1)) +#define SHMSWP_MAX_BYTES (SHMSWP_MAX_INDEX << PAGE_CACHE_SHIFT) + +#define SHMEM_MAX_BYTES min_t(unsigned long long, SHMSWP_MAX_BYTES, MAX_LFS_FILESIZE) +#define SHMEM_MAX_INDEX ((unsigned long)((SHMEM_MAX_BYTES+1) >> PAGE_CACHE_SHIFT)) + #define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512) #define VM_ACCT(size) (PAGE_CACHE_ALIGN(size) >> PAGE_SHIFT) +/* info->flags needs VM_flags to handle pagein/truncate races efficiently */ +#define SHMEM_PAGEIN VM_READ +#define SHMEM_TRUNCATE VM_WRITE + +/* Definition to limit shmem_truncate's steps between cond_rescheds */ +#define LATENCY_LIMIT 64 + /* Pretend that each entry is of this size in directory's i_size */ #define BOGO_DIRENT_SIZE 20 -/* Symlink up to this size is kmalloc'ed instead of using a swappable page */ -#define SHORT_SYMLINK_LEN 128 - struct shmem_xattr { struct list_head list; /* anchored by shmem_inode_info->xattr_list */ char *name; /* xattr name */ @@ -83,7 +107,7 @@ struct shmem_xattr { char value[0]; }; -/* Flag allocation requirements to shmem_getpage */ +/* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */ enum sgp_type { SGP_READ, /* don't exceed i_size, don't allocate page */ SGP_CACHE, /* don't exceed i_size, may allocate page */ @@ -113,6 +137,56 @@ static inline int shmem_getpage(struct inode *inode, pgoff_t index, mapping_gfp_mask(inode->i_mapping), fault_type); } +static inline struct page *shmem_dir_alloc(gfp_t gfp_mask) +{ + /* + * The above definition of ENTRIES_PER_PAGE, and the use of + * BLOCKS_PER_PAGE on indirect pages, assume PAGE_CACHE_SIZE: + * might be reconsidered if it ever diverges from PAGE_SIZE. + * + * Mobility flags are masked out as swap vectors cannot move + */ + return alloc_pages((gfp_mask & ~GFP_MOVABLE_MASK) | __GFP_ZERO, + PAGE_CACHE_SHIFT-PAGE_SHIFT); +} + +static inline void shmem_dir_free(struct page *page) +{ + __free_pages(page, PAGE_CACHE_SHIFT-PAGE_SHIFT); +} + +static struct page **shmem_dir_map(struct page *page) +{ + return (struct page **)kmap_atomic(page, KM_USER0); +} + +static inline void shmem_dir_unmap(struct page **dir) +{ + kunmap_atomic(dir, KM_USER0); +} + +static swp_entry_t *shmem_swp_map(struct page *page) +{ + return (swp_entry_t *)kmap_atomic(page, KM_USER1); +} + +static inline void shmem_swp_balance_unmap(void) +{ + /* + * When passing a pointer to an i_direct entry, to code which + * also handles indirect entries and so will shmem_swp_unmap, + * we must arrange for the preempt count to remain in balance. + * What kmap_atomic of a lowmem page does depends on config + * and architecture, so pretend to kmap_atomic some lowmem page. + */ + (void) kmap_atomic(ZERO_PAGE(0), KM_USER1); +} + +static inline void shmem_swp_unmap(swp_entry_t *entry) +{ + kunmap_atomic(entry, KM_USER1); +} + static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb) { return sb->s_fs_info; @@ -170,6 +244,15 @@ static struct backing_dev_info shmem_backing_dev_info __read_mostly = { static LIST_HEAD(shmem_swaplist); static DEFINE_MUTEX(shmem_swaplist_mutex); +static void shmem_free_blocks(struct inode *inode, long pages) +{ + struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); + if (sbinfo->max_blocks) { + percpu_counter_add(&sbinfo->used_blocks, -pages); + inode->i_blocks -= pages*BLOCKS_PER_PAGE; + } +} + static int shmem_reserve_inode(struct super_block *sb) { struct shmem_sb_info *sbinfo = SHMEM_SB(sb); @@ -196,7 +279,7 @@ static void shmem_free_inode(struct super_block *sb) } /** - * shmem_recalc_inode - recalculate the block usage of an inode + * shmem_recalc_inode - recalculate the size of an inode * @inode: inode to recalc * * We have to calculate the free blocks since the mm can drop @@ -214,297 +297,474 @@ static void shmem_recalc_inode(struct inode *inode) freed = info->alloced - info->swapped - inode->i_mapping->nrpages; if (freed > 0) { - struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - if (sbinfo->max_blocks) - percpu_counter_add(&sbinfo->used_blocks, -freed); info->alloced -= freed; - inode->i_blocks -= freed * BLOCKS_PER_PAGE; shmem_unacct_blocks(info->flags, freed); + shmem_free_blocks(inode, freed); } } -/* - * Replace item expected in radix tree by a new item, while holding tree lock. +/** + * shmem_swp_entry - find the swap vector position in the info structure + * @info: info structure for the inode + * @index: index of the page to find + * @page: optional page to add to the structure. Has to be preset to + * all zeros + * + * If there is no space allocated yet it will return NULL when + * page is NULL, else it will use the page for the needed block, + * setting it to NULL on return to indicate that it has been used. + * + * The swap vector is organized the following way: + * + * There are SHMEM_NR_DIRECT entries directly stored in the + * shmem_inode_info structure. So small files do not need an addional + * allocation. + * + * For pages with index > SHMEM_NR_DIRECT there is the pointer + * i_indirect which points to a page which holds in the first half + * doubly indirect blocks, in the second half triple indirect blocks: + * + * For an artificial ENTRIES_PER_PAGE = 4 this would lead to the + * following layout (for SHMEM_NR_DIRECT == 16): + * + * i_indirect -> dir --> 16-19 + * | +-> 20-23 + * | + * +-->dir2 --> 24-27 + * | +-> 28-31 + * | +-> 32-35 + * | +-> 36-39 + * | + * +-->dir3 --> 40-43 + * +-> 44-47 + * +-> 48-51 + * +-> 52-55 */ -static int shmem_radix_tree_replace(struct address_space *mapping, - pgoff_t index, void *expected, void *replacement) -{ - void **pslot; - void *item = NULL; - - VM_BUG_ON(!expected); - pslot = radix_tree_lookup_slot(&mapping->page_tree, index); - if (pslot) - item = radix_tree_deref_slot_protected(pslot, - &mapping->tree_lock); - if (item != expected) - return -ENOENT; - if (replacement) - radix_tree_replace_slot(pslot, replacement); - else - radix_tree_delete(&mapping->page_tree, index); - return 0; -} +static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, struct page **page) +{ + unsigned long offset; + struct page **dir; + struct page *subdir; -/* - * Like add_to_page_cache_locked, but error if expected item has gone. - */ -static int shmem_add_to_page_cache(struct page *page, - struct address_space *mapping, - pgoff_t index, gfp_t gfp, void *expected) -{ - int error = 0; - - VM_BUG_ON(!PageLocked(page)); - VM_BUG_ON(!PageSwapBacked(page)); - - if (!expected) - error = radix_tree_preload(gfp & GFP_RECLAIM_MASK); - if (!error) { - page_cache_get(page); - page->mapping = mapping; - page->index = index; - - spin_lock_irq(&mapping->tree_lock); - if (!expected) - error = radix_tree_insert(&mapping->page_tree, - index, page); - else - error = shmem_radix_tree_replace(mapping, index, - expected, page); - if (!error) { - mapping->nrpages++; - __inc_zone_page_state(page, NR_FILE_PAGES); - __inc_zone_page_state(page, NR_SHMEM); - spin_unlock_irq(&mapping->tree_lock); - } else { - page->mapping = NULL; - spin_unlock_irq(&mapping->tree_lock); - page_cache_release(page); + if (index < SHMEM_NR_DIRECT) { + shmem_swp_balance_unmap(); + return info->i_direct+index; + } + if (!info->i_indirect) { + if (page) { + info->i_indirect = *page; + *page = NULL; } - if (!expected) - radix_tree_preload_end(); + return NULL; /* need another page */ } - if (error) - mem_cgroup_uncharge_cache_page(page); - return error; + + index -= SHMEM_NR_DIRECT; + offset = index % ENTRIES_PER_PAGE; + index /= ENTRIES_PER_PAGE; + dir = shmem_dir_map(info->i_indirect); + + if (index >= ENTRIES_PER_PAGE/2) { + index -= ENTRIES_PER_PAGE/2; + dir += ENTRIES_PER_PAGE/2 + index/ENTRIES_PER_PAGE; + index %= ENTRIES_PER_PAGE; + subdir = *dir; + if (!subdir) { + if (page) { + *dir = *page; + *page = NULL; + } + shmem_dir_unmap(dir); + return NULL; /* need another page */ + } + shmem_dir_unmap(dir); + dir = shmem_dir_map(subdir); + } + + dir += index; + subdir = *dir; + if (!subdir) { + if (!page || !(subdir = *page)) { + shmem_dir_unmap(dir); + return NULL; /* need a page */ + } + *dir = subdir; + *page = NULL; + } + shmem_dir_unmap(dir); + return shmem_swp_map(subdir) + offset; } -/* - * Like delete_from_page_cache, but substitutes swap for page. - */ -static void shmem_delete_from_page_cache(struct page *page, void *radswap) +static void shmem_swp_set(struct shmem_inode_info *info, swp_entry_t *entry, unsigned long value) { - struct address_space *mapping = page->mapping; - int error; + long incdec = value? 1: -1; - spin_lock_irq(&mapping->tree_lock); - error = shmem_radix_tree_replace(mapping, page->index, page, radswap); - page->mapping = NULL; - mapping->nrpages--; - __dec_zone_page_state(page, NR_FILE_PAGES); - __dec_zone_page_state(page, NR_SHMEM); - spin_unlock_irq(&mapping->tree_lock); - page_cache_release(page); - BUG_ON(error); + entry->val = value; + info->swapped += incdec; + if ((unsigned long)(entry - info->i_direct) >= SHMEM_NR_DIRECT) { + struct page *page = kmap_atomic_to_page(entry); + set_page_private(page, page_private(page) + incdec); + } } -/* - * Like find_get_pages, but collecting swap entries as well as pages. +/** + * shmem_swp_alloc - get the position of the swap entry for the page. + * @info: info structure for the inode + * @index: index of the page to find + * @sgp: check and recheck i_size? skip allocation? + * @gfp: gfp mask to use for any page allocation + * + * If the entry does not exist, allocate it. */ -static unsigned shmem_find_get_pages_and_swap(struct address_space *mapping, - pgoff_t start, unsigned int nr_pages, - struct page **pages, pgoff_t *indices) -{ - unsigned int i; - unsigned int ret; - unsigned int nr_found; - - rcu_read_lock(); -restart: - nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree, - (void ***)pages, indices, start, nr_pages); - ret = 0; - for (i = 0; i < nr_found; i++) { - struct page *page; -repeat: - page = radix_tree_deref_slot((void **)pages[i]); - if (unlikely(!page)) - continue; - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) - goto restart; - /* - * Otherwise, we must be storing a swap entry - * here as an exceptional entry: so return it - * without attempting to raise page count. - */ - goto export; +static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, + unsigned long index, enum sgp_type sgp, gfp_t gfp) +{ + struct inode *inode = &info->vfs_inode; + struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); + struct page *page = NULL; + swp_entry_t *entry; + + if (sgp != SGP_WRITE && + ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) + return ERR_PTR(-EINVAL); + + while (!(entry = shmem_swp_entry(info, index, &page))) { + if (sgp == SGP_READ) + return shmem_swp_map(ZERO_PAGE(0)); + /* + * Test used_blocks against 1 less max_blocks, since we have 1 data + * page (and perhaps indirect index pages) yet to allocate: + * a waste to allocate index if we cannot allocate data. + */ + if (sbinfo->max_blocks) { + if (percpu_counter_compare(&sbinfo->used_blocks, + sbinfo->max_blocks - 1) >= 0) + return ERR_PTR(-ENOSPC); + percpu_counter_inc(&sbinfo->used_blocks); + inode->i_blocks += BLOCKS_PER_PAGE; } - if (!page_cache_get_speculative(page)) - goto repeat; - /* Has the page moved? */ - if (unlikely(page != *((void **)pages[i]))) { - page_cache_release(page); - goto repeat; + spin_unlock(&info->lock); + page = shmem_dir_alloc(gfp); + spin_lock(&info->lock); + + if (!page) { + shmem_free_blocks(inode, 1); + return ERR_PTR(-ENOMEM); } -export: - indices[ret] = indices[i]; - pages[ret] = page; - ret++; - } - if (unlikely(!ret && nr_found)) - goto restart; - rcu_read_unlock(); - return ret; + if (sgp != SGP_WRITE && + ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) { + entry = ERR_PTR(-EINVAL); + break; + } + if (info->next_index <= index) + info->next_index = index + 1; + } + if (page) { + /* another task gave its page, or truncated the file */ + shmem_free_blocks(inode, 1); + shmem_dir_free(page); + } + if (info->next_index <= index && !IS_ERR(entry)) + info->next_index = index + 1; + return entry; } -/* - * Remove swap entry from radix tree, free the swap and its page cache. +/** + * shmem_free_swp - free some swap entries in a directory + * @dir: pointer to the directory + * @edir: pointer after last entry of the directory + * @punch_lock: pointer to spinlock when needed for the holepunch case */ -static int shmem_free_swap(struct address_space *mapping, - pgoff_t index, void *radswap) -{ - int error; - - spin_lock_irq(&mapping->tree_lock); - error = shmem_radix_tree_replace(mapping, index, radswap, NULL); - spin_unlock_irq(&mapping->tree_lock); - if (!error) - free_swap_and_cache(radix_to_swp_entry(radswap)); - return error; +static int shmem_free_swp(swp_entry_t *dir, swp_entry_t *edir, + spinlock_t *punch_lock) +{ + spinlock_t *punch_unlock = NULL; + swp_entry_t *ptr; + int freed = 0; + + for (ptr = dir; ptr < edir; ptr++) { + if (ptr->val) { + if (unlikely(punch_lock)) { + punch_unlock = punch_lock; + punch_lock = NULL; + spin_lock(punch_unlock); + if (!ptr->val) + continue; + } + free_swap_and_cache(*ptr); + *ptr = (swp_entry_t){0}; + freed++; + } + } + if (punch_unlock) + spin_unlock(punch_unlock); + return freed; +} + +static int shmem_map_and_free_swp(struct page *subdir, int offset, + int limit, struct page ***dir, spinlock_t *punch_lock) +{ + swp_entry_t *ptr; + int freed = 0; + + ptr = shmem_swp_map(subdir); + for (; offset < limit; offset += LATENCY_LIMIT) { + int size = limit - offset; + if (size > LATENCY_LIMIT) + size = LATENCY_LIMIT; + freed += shmem_free_swp(ptr+offset, ptr+offset+size, + punch_lock); + if (need_resched()) { + shmem_swp_unmap(ptr); + if (*dir) { + shmem_dir_unmap(*dir); + *dir = NULL; + } + cond_resched(); + ptr = shmem_swp_map(subdir); + } + } + shmem_swp_unmap(ptr); + return freed; } -/* - * Pagevec may contain swap entries, so shuffle up pages before releasing. - */ -static void shmem_pagevec_release(struct pagevec *pvec) +static void shmem_free_pages(struct list_head *next) { - int i, j; - - for (i = 0, j = 0; i < pagevec_count(pvec); i++) { - struct page *page = pvec->pages[i]; - if (!radix_tree_exceptional_entry(page)) - pvec->pages[j++] = page; - } - pvec->nr = j; - pagevec_release(pvec); + struct page *page; + int freed = 0; + + do { + page = container_of(next, struct page, lru); + next = next->next; + shmem_dir_free(page); + freed++; + if (freed >= LATENCY_LIMIT) { + cond_resched(); + freed = 0; + } + } while (next); } -/* - * Remove range of pages and swap entries from radix tree, and free them. - */ -void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) +void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end) { - struct address_space *mapping = inode->i_mapping; struct shmem_inode_info *info = SHMEM_I(inode); - pgoff_t start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - unsigned partial = lstart & (PAGE_CACHE_SIZE - 1); - pgoff_t end = (lend >> PAGE_CACHE_SHIFT); - struct pagevec pvec; - pgoff_t indices[PAGEVEC_SIZE]; + unsigned long idx; + unsigned long size; + unsigned long limit; + unsigned long stage; + unsigned long diroff; + struct page **dir; + struct page *topdir; + struct page *middir; + struct page *subdir; + swp_entry_t *ptr; + LIST_HEAD(pages_to_free); + long nr_pages_to_free = 0; long nr_swaps_freed = 0; - pgoff_t index; - int i; - - BUG_ON((lend & (PAGE_CACHE_SIZE - 1)) != (PAGE_CACHE_SIZE - 1)); - - pagevec_init(&pvec, 0); - index = start; - while (index <= end) { - pvec.nr = shmem_find_get_pages_and_swap(mapping, index, - min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1, - pvec.pages, indices); - if (!pvec.nr) - break; - mem_cgroup_uncharge_start(); - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; + int offset; + int freed; + int punch_hole; + spinlock_t *needs_lock; + spinlock_t *punch_lock; + unsigned long upper_limit; - index = indices[i]; - if (index > end) - break; + truncate_inode_pages_range(inode->i_mapping, start, end); - if (radix_tree_exceptional_entry(page)) { - nr_swaps_freed += !shmem_free_swap(mapping, - index, page); - continue; - } + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + idx = (start + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + if (idx >= info->next_index) + return; - if (!trylock_page(page)) - continue; - if (page->mapping == mapping) { - VM_BUG_ON(PageWriteback(page)); - truncate_inode_page(mapping, page); - } - unlock_page(page); + spin_lock(&info->lock); + info->flags |= SHMEM_TRUNCATE; + if (likely(end == (loff_t) -1)) { + limit = info->next_index; + upper_limit = SHMEM_MAX_INDEX; + info->next_index = idx; + needs_lock = NULL; + punch_hole = 0; + } else { + if (end + 1 >= inode->i_size) { /* we may free a little more */ + limit = (inode->i_size + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT; + upper_limit = SHMEM_MAX_INDEX; + } else { + limit = (end + 1) >> PAGE_CACHE_SHIFT; + upper_limit = limit; } - shmem_pagevec_release(&pvec); - mem_cgroup_uncharge_end(); - cond_resched(); - index++; + needs_lock = &info->lock; + punch_hole = 1; } - if (partial) { - struct page *page = NULL; - shmem_getpage(inode, start - 1, &page, SGP_READ, NULL); - if (page) { - zero_user_segment(page, partial, PAGE_CACHE_SIZE); - set_page_dirty(page); - unlock_page(page); - page_cache_release(page); - } + topdir = info->i_indirect; + if (topdir && idx <= SHMEM_NR_DIRECT && !punch_hole) { + info->i_indirect = NULL; + nr_pages_to_free++; + list_add(&topdir->lru, &pages_to_free); } + spin_unlock(&info->lock); - index = start; - for ( ; ; ) { - cond_resched(); - pvec.nr = shmem_find_get_pages_and_swap(mapping, index, - min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1, - pvec.pages, indices); - if (!pvec.nr) { - if (index == start) - break; - index = start; - continue; - } - if (index == start && indices[0] > end) { - shmem_pagevec_release(&pvec); - break; - } - mem_cgroup_uncharge_start(); - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; + if (info->swapped && idx < SHMEM_NR_DIRECT) { + ptr = info->i_direct; + size = limit; + if (size > SHMEM_NR_DIRECT) + size = SHMEM_NR_DIRECT; + nr_swaps_freed = shmem_free_swp(ptr+idx, ptr+size, needs_lock); + } - index = indices[i]; - if (index > end) - break; + /* + * If there are no indirect blocks or we are punching a hole + * below indirect blocks, nothing to be done. + */ + if (!topdir || limit <= SHMEM_NR_DIRECT) + goto done2; - if (radix_tree_exceptional_entry(page)) { - nr_swaps_freed += !shmem_free_swap(mapping, - index, page); - continue; + /* + * The truncation case has already dropped info->lock, and we're safe + * because i_size and next_index have already been lowered, preventing + * access beyond. But in the punch_hole case, we still need to take + * the lock when updating the swap directory, because there might be + * racing accesses by shmem_getpage(SGP_CACHE), shmem_unuse_inode or + * shmem_writepage. However, whenever we find we can remove a whole + * directory page (not at the misaligned start or end of the range), + * we first NULLify its pointer in the level above, and then have no + * need to take the lock when updating its contents: needs_lock and + * punch_lock (either pointing to info->lock or NULL) manage this. + */ + + upper_limit -= SHMEM_NR_DIRECT; + limit -= SHMEM_NR_DIRECT; + idx = (idx > SHMEM_NR_DIRECT)? (idx - SHMEM_NR_DIRECT): 0; + offset = idx % ENTRIES_PER_PAGE; + idx -= offset; + + dir = shmem_dir_map(topdir); + stage = ENTRIES_PER_PAGEPAGE/2; + if (idx < ENTRIES_PER_PAGEPAGE/2) { + middir = topdir; + diroff = idx/ENTRIES_PER_PAGE; + } else { + dir += ENTRIES_PER_PAGE/2; + dir += (idx - ENTRIES_PER_PAGEPAGE/2)/ENTRIES_PER_PAGEPAGE; + while (stage <= idx) + stage += ENTRIES_PER_PAGEPAGE; + middir = *dir; + if (*dir) { + diroff = ((idx - ENTRIES_PER_PAGEPAGE/2) % + ENTRIES_PER_PAGEPAGE) / ENTRIES_PER_PAGE; + if (!diroff && !offset && upper_limit >= stage) { + if (needs_lock) { + spin_lock(needs_lock); + *dir = NULL; + spin_unlock(needs_lock); + needs_lock = NULL; + } else + *dir = NULL; + nr_pages_to_free++; + list_add(&middir->lru, &pages_to_free); } + shmem_dir_unmap(dir); + dir = shmem_dir_map(middir); + } else { + diroff = 0; + offset = 0; + idx = stage; + } + } - lock_page(page); - if (page->mapping == mapping) { - VM_BUG_ON(PageWriteback(page)); - truncate_inode_page(mapping, page); + for (; idx < limit; idx += ENTRIES_PER_PAGE, diroff++) { + if (unlikely(idx == stage)) { + shmem_dir_unmap(dir); + dir = shmem_dir_map(topdir) + + ENTRIES_PER_PAGE/2 + idx/ENTRIES_PER_PAGEPAGE; + while (!*dir) { + dir++; + idx += ENTRIES_PER_PAGEPAGE; + if (idx >= limit) + goto done1; } - unlock_page(page); + stage = idx + ENTRIES_PER_PAGEPAGE; + middir = *dir; + if (punch_hole) + needs_lock = &info->lock; + if (upper_limit >= stage) { + if (needs_lock) { + spin_lock(needs_lock); + *dir = NULL; + spin_unlock(needs_lock); + needs_lock = NULL; + } else + *dir = NULL; + nr_pages_to_free++; + list_add(&middir->lru, &pages_to_free); + } + shmem_dir_unmap(dir); + cond_resched(); + dir = shmem_dir_map(middir); + diroff = 0; } - shmem_pagevec_release(&pvec); - mem_cgroup_uncharge_end(); - index++; + punch_lock = needs_lock; + subdir = dir[diroff]; + if (subdir && !offset && upper_limit-idx >= ENTRIES_PER_PAGE) { + if (needs_lock) { + spin_lock(needs_lock); + dir[diroff] = NULL; + spin_unlock(needs_lock); + punch_lock = NULL; + } else + dir[diroff] = NULL; + nr_pages_to_free++; + list_add(&subdir->lru, &pages_to_free); + } + if (subdir && page_private(subdir) /* has swap entries */) { + size = limit - idx; + if (size > ENTRIES_PER_PAGE) + size = ENTRIES_PER_PAGE; + freed = shmem_map_and_free_swp(subdir, + offset, size, &dir, punch_lock); + if (!dir) + dir = shmem_dir_map(middir); + nr_swaps_freed += freed; + if (offset || punch_lock) { + spin_lock(&info->lock); + set_page_private(subdir, + page_private(subdir) - freed); + spin_unlock(&info->lock); + } else + BUG_ON(page_private(subdir) != freed); + } + offset = 0; + } +done1: + shmem_dir_unmap(dir); +done2: + if (inode->i_mapping->nrpages && (info->flags & SHMEM_PAGEIN)) { + /* + * Call truncate_inode_pages again: racing shmem_unuse_inode + * may have swizzled a page in from swap since + * truncate_pagecache or generic_delete_inode did it, before we + * lowered next_index. Also, though shmem_getpage checks + * i_size before adding to cache, no recheck after: so fix the + * narrow window there too. + */ + truncate_inode_pages_range(inode->i_mapping, start, end); } spin_lock(&info->lock); + info->flags &= ~SHMEM_TRUNCATE; info->swapped -= nr_swaps_freed; + if (nr_pages_to_free) + shmem_free_blocks(inode, nr_pages_to_free); shmem_recalc_inode(inode); spin_unlock(&info->lock); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; + /* + * Empty swap vector directory pages to be freed? + */ + if (!list_empty(&pages_to_free)) { + pages_to_free.prev->next = NULL; + shmem_free_pages(pages_to_free.next); + } } EXPORT_SYMBOL_GPL(shmem_truncate_range); @@ -520,7 +780,37 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr) if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { loff_t oldsize = inode->i_size; loff_t newsize = attr->ia_size; + struct page *page = NULL; + if (newsize < oldsize) { + /* + * If truncating down to a partial page, then + * if that page is already allocated, hold it + * in memory until the truncation is over, so + * truncate_partial_page cannot miss it were + * it assigned to swap. + */ + if (newsize & (PAGE_CACHE_SIZE-1)) { + (void) shmem_getpage(inode, + newsize >> PAGE_CACHE_SHIFT, + &page, SGP_READ, NULL); + if (page) + unlock_page(page); + } + /* + * Reset SHMEM_PAGEIN flag so that shmem_truncate can + * detect if any pages might have been added to cache + * after truncate_inode_pages. But we needn't bother + * if it's being fully truncated to zero-length: the + * nrpages check is efficient enough in that case. + */ + if (newsize) { + struct shmem_inode_info *info = SHMEM_I(inode); + spin_lock(&info->lock); + info->flags &= ~SHMEM_PAGEIN; + spin_unlock(&info->lock); + } + } if (newsize != oldsize) { i_size_write(inode, newsize); inode->i_ctime = inode->i_mtime = CURRENT_TIME; @@ -532,6 +822,8 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr) /* unmap again to remove racily COWed private pages */ unmap_mapping_range(inode->i_mapping, holebegin, 0, 1); } + if (page) + page_cache_release(page); } setattr_copy(inode, attr); @@ -556,8 +848,7 @@ static void shmem_evict_inode(struct inode *inode) list_del_init(&info->swaplist); mutex_unlock(&shmem_swaplist_mutex); } - } else - kfree(info->symlink); + } list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) { kfree(xattr->name); @@ -568,27 +859,106 @@ static void shmem_evict_inode(struct inode *inode) end_writeback(inode); } -/* - * If swap found in inode, free it and move page from swapcache to filecache. - */ -static int shmem_unuse_inode(struct shmem_inode_info *info, - swp_entry_t swap, struct page *page) +static inline int shmem_find_swp(swp_entry_t entry, swp_entry_t *dir, swp_entry_t *edir) { - struct address_space *mapping = info->vfs_inode.i_mapping; - void *radswap; - pgoff_t index; + swp_entry_t *ptr; + + for (ptr = dir; ptr < edir; ptr++) { + if (ptr->val == entry.val) + return ptr - dir; + } + return -1; +} + +static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, struct page *page) +{ + struct address_space *mapping; + unsigned long idx; + unsigned long size; + unsigned long limit; + unsigned long stage; + struct page **dir; + struct page *subdir; + swp_entry_t *ptr; + int offset; int error; - radswap = swp_to_radix_entry(swap); - index = radix_tree_locate_item(&mapping->page_tree, radswap); - if (index == -1) - return 0; + idx = 0; + ptr = info->i_direct; + spin_lock(&info->lock); + if (!info->swapped) { + list_del_init(&info->swaplist); + goto lost2; + } + limit = info->next_index; + size = limit; + if (size > SHMEM_NR_DIRECT) + size = SHMEM_NR_DIRECT; + offset = shmem_find_swp(entry, ptr, ptr+size); + if (offset >= 0) { + shmem_swp_balance_unmap(); + goto found; + } + if (!info->i_indirect) + goto lost2; + + dir = shmem_dir_map(info->i_indirect); + stage = SHMEM_NR_DIRECT + ENTRIES_PER_PAGEPAGE/2; + + for (idx = SHMEM_NR_DIRECT; idx < limit; idx += ENTRIES_PER_PAGE, dir++) { + if (unlikely(idx == stage)) { + shmem_dir_unmap(dir-1); + if (cond_resched_lock(&info->lock)) { + /* check it has not been truncated */ + if (limit > info->next_index) { + limit = info->next_index; + if (idx >= limit) + goto lost2; + } + } + dir = shmem_dir_map(info->i_indirect) + + ENTRIES_PER_PAGE/2 + idx/ENTRIES_PER_PAGEPAGE; + while (!*dir) { + dir++; + idx += ENTRIES_PER_PAGEPAGE; + if (idx >= limit) + goto lost1; + } + stage = idx + ENTRIES_PER_PAGEPAGE; + subdir = *dir; + shmem_dir_unmap(dir); + dir = shmem_dir_map(subdir); + } + subdir = *dir; + if (subdir && page_private(subdir)) { + ptr = shmem_swp_map(subdir); + size = limit - idx; + if (size > ENTRIES_PER_PAGE) + size = ENTRIES_PER_PAGE; + offset = shmem_find_swp(entry, ptr, ptr+size); + shmem_swp_unmap(ptr); + if (offset >= 0) { + shmem_dir_unmap(dir); + ptr = shmem_swp_map(subdir); + goto found; + } + } + } +lost1: + shmem_dir_unmap(dir-1); +lost2: + spin_unlock(&info->lock); + return 0; +found: + idx += offset; + ptr += offset; /* * Move _head_ to start search for next from here. * But be careful: shmem_evict_inode checks list_empty without taking * mutex, and there's an instant in list_move_tail when info->swaplist - * would appear empty, if it were the only one on shmem_swaplist. + * would appear empty, if it were the only one on shmem_swaplist. We + * could avoid doing it if inode NULL; or use this minor optimization. */ if (shmem_swaplist.next != &info->swaplist) list_move_tail(&shmem_swaplist, &info->swaplist); @@ -598,34 +968,29 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, * but also to hold up shmem_evict_inode(): so inode cannot be freed * beneath us (pagelock doesn't help until the page is in pagecache). */ - error = shmem_add_to_page_cache(page, mapping, index, - GFP_NOWAIT, radswap); + mapping = info->vfs_inode.i_mapping; + error = add_to_page_cache_locked(page, mapping, idx, GFP_NOWAIT); /* which does mem_cgroup_uncharge_cache_page on error */ if (error != -ENOMEM) { - /* - * Truncation and eviction use free_swap_and_cache(), which - * only does trylock page: if we raced, best clean up here. - */ delete_from_swap_cache(page); set_page_dirty(page); - if (!error) { - spin_lock(&info->lock); - info->swapped--; - spin_unlock(&info->lock); - swap_free(swap); - } + info->flags |= SHMEM_PAGEIN; + shmem_swp_set(info, ptr, 0); + swap_free(entry); error = 1; /* not an error, but entry was found */ } + shmem_swp_unmap(ptr); + spin_unlock(&info->lock); return error; } /* - * Search through swapped inodes to find and replace swap by page. + * shmem_unuse() search for an eventually swapped out shmem page. */ -int shmem_unuse(swp_entry_t swap, struct page *page) +int shmem_unuse(swp_entry_t entry, struct page *page) { - struct list_head *this, *next; + struct list_head *p, *next; struct shmem_inode_info *info; int found = 0; int error; @@ -634,25 +999,32 @@ int shmem_unuse(swp_entry_t swap, struct page *page) * Charge page using GFP_KERNEL while we can wait, before taking * the shmem_swaplist_mutex which might hold up shmem_writepage(). * Charged back to the user (not to caller) when swap account is used. + * add_to_page_cache() will be called with GFP_NOWAIT. */ error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL); if (error) goto out; - /* No radix_tree_preload: swap entry keeps a place for page in tree */ + /* + * Try to preload while we can wait, to not make a habit of + * draining atomic reserves; but don't latch on to this cpu, + * it's okay if sometimes we get rescheduled after this. + */ + error = radix_tree_preload(GFP_KERNEL); + if (error) + goto uncharge; + radix_tree_preload_end(); mutex_lock(&shmem_swaplist_mutex); - list_for_each_safe(this, next, &shmem_swaplist) { - info = list_entry(this, struct shmem_inode_info, swaplist); - if (info->swapped) - found = shmem_unuse_inode(info, swap, page); - else - list_del_init(&info->swaplist); + list_for_each_safe(p, next, &shmem_swaplist) { + info = list_entry(p, struct shmem_inode_info, swaplist); + found = shmem_unuse_inode(info, entry, page); cond_resched(); if (found) break; } mutex_unlock(&shmem_swaplist_mutex); +uncharge: if (!found) mem_cgroup_uncharge_cache_page(page); if (found < 0) @@ -669,10 +1041,10 @@ int shmem_unuse(swp_entry_t swap, struct page *page) static int shmem_writepage(struct page *page, struct writeback_control *wbc) { struct shmem_inode_info *info; + swp_entry_t *entry, swap; struct address_space *mapping; + unsigned long index; struct inode *inode; - swp_entry_t swap; - pgoff_t index; BUG_ON(!PageLocked(page)); mapping = page->mapping; @@ -701,32 +1073,50 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) /* * Add inode to shmem_unuse()'s list of swapped-out inodes, - * if it's not already there. Do it now before the page is - * moved to swap cache, when its pagelock no longer protects + * if it's not already there. Do it now because we cannot take + * mutex while holding spinlock, and must do so before the page + * is moved to swap cache, when its pagelock no longer protects * the inode from eviction. But don't unlock the mutex until - * we've incremented swapped, because shmem_unuse_inode() will - * prune a !swapped inode from the swaplist under this mutex. + * we've taken the spinlock, because shmem_unuse_inode() will + * prune a !swapped inode from the swaplist under both locks. */ mutex_lock(&shmem_swaplist_mutex); if (list_empty(&info->swaplist)) list_add_tail(&info->swaplist, &shmem_swaplist); + spin_lock(&info->lock); + mutex_unlock(&shmem_swaplist_mutex); + + if (index >= info->next_index) { + BUG_ON(!(info->flags & SHMEM_TRUNCATE)); + goto unlock; + } + entry = shmem_swp_entry(info, index, NULL); + if (entry->val) { + WARN_ON_ONCE(1); /* Still happens? Tell us about it! */ + free_swap_and_cache(*entry); + shmem_swp_set(info, entry, 0); + } + shmem_recalc_inode(inode); + if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) { + delete_from_page_cache(page); + shmem_swp_set(info, entry, swap.val); + shmem_swp_unmap(entry); swap_shmem_alloc(swap); - shmem_delete_from_page_cache(page, swp_to_radix_entry(swap)); - - spin_lock(&info->lock); - info->swapped++; - shmem_recalc_inode(inode); spin_unlock(&info->lock); - - mutex_unlock(&shmem_swaplist_mutex); BUG_ON(page_mapped(page)); swap_writepage(page, wbc); return 0; } - mutex_unlock(&shmem_swaplist_mutex); + shmem_swp_unmap(entry); +unlock: + spin_unlock(&info->lock); + /* + * add_to_swap_cache() doesn't return -EEXIST, so we can safely + * clear SWAP_HAS_CACHE flag. + */ swapcache_free(swap, NULL); redirty: set_page_dirty(page); @@ -763,33 +1153,35 @@ static struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo) } #endif /* CONFIG_TMPFS */ -static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp, - struct shmem_inode_info *info, pgoff_t index) +static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp, + struct shmem_inode_info *info, unsigned long idx) { struct mempolicy mpol, *spol; struct vm_area_struct pvma; + struct page *page; spol = mpol_cond_copy(&mpol, - mpol_shared_policy_lookup(&info->policy, index)); + mpol_shared_policy_lookup(&info->policy, idx)); /* Create a pseudo vma that just contains the policy */ pvma.vm_start = 0; - pvma.vm_pgoff = index; + pvma.vm_pgoff = idx; pvma.vm_ops = NULL; pvma.vm_policy = spol; - return swapin_readahead(swap, gfp, &pvma, 0); + page = swapin_readahead(entry, gfp, &pvma, 0); + return page; } static struct page *shmem_alloc_page(gfp_t gfp, - struct shmem_inode_info *info, pgoff_t index) + struct shmem_inode_info *info, unsigned long idx) { struct vm_area_struct pvma; /* Create a pseudo vma that just contains the policy */ pvma.vm_start = 0; - pvma.vm_pgoff = index; + pvma.vm_pgoff = idx; pvma.vm_ops = NULL; - pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index); + pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx); /* * alloc_page_vma() will drop the shared policy reference @@ -798,19 +1190,19 @@ static struct page *shmem_alloc_page(gfp_t gfp, } #else /* !CONFIG_NUMA */ #ifdef CONFIG_TMPFS -static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol) +static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *p) { } #endif /* CONFIG_TMPFS */ -static inline struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp, - struct shmem_inode_info *info, pgoff_t index) +static inline struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp, + struct shmem_inode_info *info, unsigned long idx) { - return swapin_readahead(swap, gfp, NULL, 0); + return swapin_readahead(entry, gfp, NULL, 0); } static inline struct page *shmem_alloc_page(gfp_t gfp, - struct shmem_inode_info *info, pgoff_t index) + struct shmem_inode_info *info, unsigned long idx) { return alloc_page(gfp); } @@ -830,190 +1222,243 @@ static inline struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo) * vm. If we swap it in we mark it dirty since we also free the swap * entry since a page cannot live in both the swap and page cache */ -static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, +static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx, struct page **pagep, enum sgp_type sgp, gfp_t gfp, int *fault_type) { struct address_space *mapping = inode->i_mapping; - struct shmem_inode_info *info; + struct shmem_inode_info *info = SHMEM_I(inode); struct shmem_sb_info *sbinfo; struct page *page; + struct page *prealloc_page = NULL; + swp_entry_t *entry; swp_entry_t swap; int error; - int once = 0; + int ret; - if (index > (MAX_LFS_FILESIZE >> PAGE_CACHE_SHIFT)) + if (idx >= SHMEM_MAX_INDEX) return -EFBIG; repeat: - swap.val = 0; - page = find_lock_page(mapping, index); - if (radix_tree_exceptional_entry(page)) { - swap = radix_to_swp_entry(page); - page = NULL; - } - - if (sgp != SGP_WRITE && - ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) { - error = -EINVAL; - goto failed; - } - - if (page || (sgp == SGP_READ && !swap.val)) { + page = find_lock_page(mapping, idx); + if (page) { /* * Once we can get the page lock, it must be uptodate: * if there were an error in reading back from swap, * the page would not be inserted into the filecache. */ - BUG_ON(page && !PageUptodate(page)); - *pagep = page; - return 0; + BUG_ON(!PageUptodate(page)); + goto done; } /* - * Fast cache lookup did not find it: - * bring it back from swap or allocate. + * Try to preload while we can wait, to not make a habit of + * draining atomic reserves; but don't latch on to this cpu. */ - info = SHMEM_I(inode); - sbinfo = SHMEM_SB(inode->i_sb); + error = radix_tree_preload(gfp & GFP_RECLAIM_MASK); + if (error) + goto out; + radix_tree_preload_end(); + + if (sgp != SGP_READ && !prealloc_page) { + prealloc_page = shmem_alloc_page(gfp, info, idx); + if (prealloc_page) { + SetPageSwapBacked(prealloc_page); + if (mem_cgroup_cache_charge(prealloc_page, + current->mm, GFP_KERNEL)) { + page_cache_release(prealloc_page); + prealloc_page = NULL; + } + } + } + + spin_lock(&info->lock); + shmem_recalc_inode(inode); + entry = shmem_swp_alloc(info, idx, sgp, gfp); + if (IS_ERR(entry)) { + spin_unlock(&info->lock); + error = PTR_ERR(entry); + goto out; + } + swap = *entry; if (swap.val) { /* Look it up and read it in.. */ page = lookup_swap_cache(swap); if (!page) { + shmem_swp_unmap(entry); + spin_unlock(&info->lock); /* here we actually do the io */ if (fault_type) *fault_type |= VM_FAULT_MAJOR; - page = shmem_swapin(swap, gfp, info, index); + page = shmem_swapin(swap, gfp, info, idx); if (!page) { - error = -ENOMEM; - goto failed; + spin_lock(&info->lock); + entry = shmem_swp_alloc(info, idx, sgp, gfp); + if (IS_ERR(entry)) + error = PTR_ERR(entry); + else { + if (entry->val == swap.val) + error = -ENOMEM; + shmem_swp_unmap(entry); + } + spin_unlock(&info->lock); + if (error) + goto out; + goto repeat; } + wait_on_page_locked(page); + page_cache_release(page); + goto repeat; } /* We have to do this with page locked to prevent races */ - lock_page(page); + if (!trylock_page(page)) { + shmem_swp_unmap(entry); + spin_unlock(&info->lock); + wait_on_page_locked(page); + page_cache_release(page); + goto repeat; + } + if (PageWriteback(page)) { + shmem_swp_unmap(entry); + spin_unlock(&info->lock); + wait_on_page_writeback(page); + unlock_page(page); + page_cache_release(page); + goto repeat; + } if (!PageUptodate(page)) { + shmem_swp_unmap(entry); + spin_unlock(&info->lock); + unlock_page(page); + page_cache_release(page); error = -EIO; - goto failed; - } - wait_on_page_writeback(page); - - /* Someone may have already done it for us */ - if (page->mapping) { - if (page->mapping == mapping && - page->index == index) - goto done; - error = -EEXIST; - goto failed; + goto out; } - error = mem_cgroup_cache_charge(page, current->mm, - gfp & GFP_RECLAIM_MASK); - if (!error) - error = shmem_add_to_page_cache(page, mapping, index, - gfp, swp_to_radix_entry(swap)); - if (error) - goto failed; - - spin_lock(&info->lock); - info->swapped--; - shmem_recalc_inode(inode); - spin_unlock(&info->lock); + error = add_to_page_cache_locked(page, mapping, + idx, GFP_NOWAIT); + if (error) { + shmem_swp_unmap(entry); + spin_unlock(&info->lock); + if (error == -ENOMEM) { + /* + * reclaim from proper memory cgroup and + * call memcg's OOM if needed. + */ + error = mem_cgroup_shmem_charge_fallback( + page, current->mm, gfp); + if (error) { + unlock_page(page); + page_cache_release(page); + goto out; + } + } + unlock_page(page); + page_cache_release(page); + goto repeat; + } + info->flags |= SHMEM_PAGEIN; + shmem_swp_set(info, entry, 0); + shmem_swp_unmap(entry); delete_from_swap_cache(page); + spin_unlock(&info->lock); set_page_dirty(page); swap_free(swap); - } else { - if (shmem_acct_block(info->flags)) { - error = -ENOSPC; - goto failed; + } else if (sgp == SGP_READ) { + shmem_swp_unmap(entry); + page = find_get_page(mapping, idx); + if (page && !trylock_page(page)) { + spin_unlock(&info->lock); + wait_on_page_locked(page); + page_cache_release(page); + goto repeat; } + spin_unlock(&info->lock); + + } else if (prealloc_page) { + shmem_swp_unmap(entry); + sbinfo = SHMEM_SB(inode->i_sb); if (sbinfo->max_blocks) { if (percpu_counter_compare(&sbinfo->used_blocks, - sbinfo->max_blocks) >= 0) { - error = -ENOSPC; - goto unacct; - } + sbinfo->max_blocks) >= 0 || + shmem_acct_block(info->flags)) + goto nospace; percpu_counter_inc(&sbinfo->used_blocks); + inode->i_blocks += BLOCKS_PER_PAGE; + } else if (shmem_acct_block(info->flags)) + goto nospace; + + page = prealloc_page; + prealloc_page = NULL; + + entry = shmem_swp_alloc(info, idx, sgp, gfp); + if (IS_ERR(entry)) + error = PTR_ERR(entry); + else { + swap = *entry; + shmem_swp_unmap(entry); } - - page = shmem_alloc_page(gfp, info, index); - if (!page) { - error = -ENOMEM; - goto decused; + ret = error || swap.val; + if (ret) + mem_cgroup_uncharge_cache_page(page); + else + ret = add_to_page_cache_lru(page, mapping, + idx, GFP_NOWAIT); + /* + * At add_to_page_cache_lru() failure, + * uncharge will be done automatically. + */ + if (ret) { + shmem_unacct_blocks(info->flags, 1); + shmem_free_blocks(inode, 1); + spin_unlock(&info->lock); + page_cache_release(page); + if (error) + goto out; + goto repeat; } - SetPageSwapBacked(page); - __set_page_locked(page); - error = mem_cgroup_cache_charge(page, current->mm, - gfp & GFP_RECLAIM_MASK); - if (!error) - error = shmem_add_to_page_cache(page, mapping, index, - gfp, NULL); - if (error) - goto decused; - lru_cache_add_anon(page); - - spin_lock(&info->lock); + info->flags |= SHMEM_PAGEIN; info->alloced++; - inode->i_blocks += BLOCKS_PER_PAGE; - shmem_recalc_inode(inode); spin_unlock(&info->lock); - clear_highpage(page); flush_dcache_page(page); SetPageUptodate(page); if (sgp == SGP_DIRTY) set_page_dirty(page); + + } else { + spin_unlock(&info->lock); + error = -ENOMEM; + goto out; } done: - /* Perhaps the file has been truncated since we checked */ - if (sgp != SGP_WRITE && - ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) { - error = -EINVAL; - goto trunc; - } *pagep = page; - return 0; + error = 0; +out: + if (prealloc_page) { + mem_cgroup_uncharge_cache_page(prealloc_page); + page_cache_release(prealloc_page); + } + return error; +nospace: /* - * Error recovery. + * Perhaps the page was brought in from swap between find_lock_page + * and taking info->lock? We allow for that at add_to_page_cache_lru, + * but must also avoid reporting a spurious ENOSPC while working on a + * full tmpfs. */ -trunc: - ClearPageDirty(page); - delete_from_page_cache(page); - spin_lock(&info->lock); - info->alloced--; - inode->i_blocks -= BLOCKS_PER_PAGE; + page = find_get_page(mapping, idx); spin_unlock(&info->lock); -decused: - if (sbinfo->max_blocks) - percpu_counter_add(&sbinfo->used_blocks, -1); -unacct: - shmem_unacct_blocks(info->flags, 1); -failed: - if (swap.val && error != -EINVAL) { - struct page *test = find_get_page(mapping, index); - if (test && !radix_tree_exceptional_entry(test)) - page_cache_release(test); - /* Have another try if the entry has changed */ - if (test != swp_to_radix_entry(swap)) - error = -EEXIST; - } if (page) { - unlock_page(page); page_cache_release(page); - } - if (error == -ENOSPC && !once++) { - info = SHMEM_I(inode); - spin_lock(&info->lock); - shmem_recalc_inode(inode); - spin_unlock(&info->lock); goto repeat; } - if (error == -EEXIST) - goto repeat; - return error; + error = -ENOSPC; + goto out; } static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -1022,6 +1467,9 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) int error; int ret = VM_FAULT_LOCKED; + if (((loff_t)vmf->pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode)) + return VM_FAULT_SIGBUS; + error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret); if (error) return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS); @@ -1034,20 +1482,20 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } #ifdef CONFIG_NUMA -static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol) +static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new) { - struct inode *inode = vma->vm_file->f_path.dentry->d_inode; - return mpol_set_shared_policy(&SHMEM_I(inode)->policy, vma, mpol); + struct inode *i = vma->vm_file->f_path.dentry->d_inode; + return mpol_set_shared_policy(&SHMEM_I(i)->policy, vma, new); } static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma, unsigned long addr) { - struct inode *inode = vma->vm_file->f_path.dentry->d_inode; - pgoff_t index; + struct inode *i = vma->vm_file->f_path.dentry->d_inode; + unsigned long idx; - index = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - return mpol_shared_policy_lookup(&SHMEM_I(inode)->policy, index); + idx = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + return mpol_shared_policy_lookup(&SHMEM_I(i)->policy, idx); } #endif @@ -1145,7 +1593,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode #ifdef CONFIG_TMPFS static const struct inode_operations shmem_symlink_inode_operations; -static const struct inode_operations shmem_short_symlink_operations; +static const struct inode_operations shmem_symlink_inline_operations; static int shmem_write_begin(struct file *file, struct address_space *mapping, @@ -1178,8 +1626,7 @@ static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_ { struct inode *inode = filp->f_path.dentry->d_inode; struct address_space *mapping = inode->i_mapping; - pgoff_t index; - unsigned long offset; + unsigned long index, offset; enum sgp_type sgp = SGP_READ; /* @@ -1195,8 +1642,7 @@ static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_ for (;;) { struct page *page = NULL; - pgoff_t end_index; - unsigned long nr, ret; + unsigned long end_index, nr, ret; loff_t i_size = i_size_read(inode); end_index = i_size >> PAGE_CACHE_SHIFT; @@ -1434,9 +1880,8 @@ static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_namelen = NAME_MAX; if (sbinfo->max_blocks) { buf->f_blocks = sbinfo->max_blocks; - buf->f_bavail = - buf->f_bfree = sbinfo->max_blocks - - percpu_counter_sum(&sbinfo->used_blocks); + buf->f_bavail = buf->f_bfree = + sbinfo->max_blocks - percpu_counter_sum(&sbinfo->used_blocks); } if (sbinfo->max_inodes) { buf->f_files = sbinfo->max_inodes; @@ -1610,13 +2055,10 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s info = SHMEM_I(inode); inode->i_size = len-1; - if (len <= SHORT_SYMLINK_LEN) { - info->symlink = kmemdup(symname, len, GFP_KERNEL); - if (!info->symlink) { - iput(inode); - return -ENOMEM; - } - inode->i_op = &shmem_short_symlink_operations; + if (len <= SHMEM_SYMLINK_INLINE_LEN) { + /* do it inline */ + memcpy(info->inline_symlink, symname, len); + inode->i_op = &shmem_symlink_inline_operations; } else { error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL); if (error) { @@ -1639,17 +2081,17 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s return 0; } -static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd) +static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd) { - nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink); + nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink); return NULL; } static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *page = NULL; - int error = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL); - nd_set_link(nd, error ? ERR_PTR(error) : kmap(page)); + int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL); + nd_set_link(nd, res ? ERR_PTR(res) : kmap(page)); if (page) unlock_page(page); return page; @@ -1760,6 +2202,7 @@ static int shmem_xattr_set(struct dentry *dentry, const char *name, return err; } + static const struct xattr_handler *shmem_xattr_handlers[] = { #ifdef CONFIG_TMPFS_POSIX_ACL &generic_acl_access_handler, @@ -1889,9 +2332,9 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) } #endif /* CONFIG_TMPFS_XATTR */ -static const struct inode_operations shmem_short_symlink_operations = { +static const struct inode_operations shmem_symlink_inline_operations = { .readlink = generic_readlink, - .follow_link = shmem_follow_short_symlink, + .follow_link = shmem_follow_link_inline, #ifdef CONFIG_TMPFS_XATTR .setxattr = shmem_setxattr, .getxattr = shmem_getxattr, @@ -2091,7 +2534,8 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) if (config.max_inodes < inodes) goto out; /* - * Those tests disallow limited->unlimited while any are in use; + * Those tests also disallow limited->unlimited while any are in + * use, so i_blocks will always be zero when max_blocks is zero; * but we must separately disallow unlimited->limited, because * in that case we have no record of how much is already in use. */ @@ -2183,7 +2627,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) goto failed; sbinfo->free_inodes = sbinfo->max_inodes; - sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_maxbytes = SHMEM_MAX_BYTES; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = TMPFS_MAGIC; @@ -2218,14 +2662,14 @@ static struct kmem_cache *shmem_inode_cachep; static struct inode *shmem_alloc_inode(struct super_block *sb) { - struct shmem_inode_info *info; - info = kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL); - if (!info) + struct shmem_inode_info *p; + p = (struct shmem_inode_info *)kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL); + if (!p) return NULL; - return &info->vfs_inode; + return &p->vfs_inode; } -static void shmem_destroy_callback(struct rcu_head *head) +static void shmem_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); INIT_LIST_HEAD(&inode->i_dentry); @@ -2234,26 +2678,29 @@ static void shmem_destroy_callback(struct rcu_head *head) static void shmem_destroy_inode(struct inode *inode) { - if ((inode->i_mode & S_IFMT) == S_IFREG) + if ((inode->i_mode & S_IFMT) == S_IFREG) { + /* only struct inode is valid if it's an inline symlink */ mpol_free_shared_policy(&SHMEM_I(inode)->policy); - call_rcu(&inode->i_rcu, shmem_destroy_callback); + } + call_rcu(&inode->i_rcu, shmem_i_callback); } -static void shmem_init_inode(void *foo) +static void init_once(void *foo) { - struct shmem_inode_info *info = foo; - inode_init_once(&info->vfs_inode); + struct shmem_inode_info *p = (struct shmem_inode_info *) foo; + + inode_init_once(&p->vfs_inode); } -static int shmem_init_inodecache(void) +static int init_inodecache(void) { shmem_inode_cachep = kmem_cache_create("shmem_inode_cache", sizeof(struct shmem_inode_info), - 0, SLAB_PANIC, shmem_init_inode); + 0, SLAB_PANIC, init_once); return 0; } -static void shmem_destroy_inodecache(void) +static void destroy_inodecache(void) { kmem_cache_destroy(shmem_inode_cachep); } @@ -2350,20 +2797,21 @@ static const struct vm_operations_struct shmem_vm_ops = { #endif }; + static struct dentry *shmem_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_nodev(fs_type, flags, data, shmem_fill_super); } -static struct file_system_type shmem_fs_type = { +static struct file_system_type tmpfs_fs_type = { .owner = THIS_MODULE, .name = "tmpfs", .mount = shmem_mount, .kill_sb = kill_litter_super, }; -int __init shmem_init(void) +int __init init_tmpfs(void) { int error; @@ -2371,18 +2819,18 @@ int __init shmem_init(void) if (error) goto out4; - error = shmem_init_inodecache(); + error = init_inodecache(); if (error) goto out3; - error = register_filesystem(&shmem_fs_type); + error = register_filesystem(&tmpfs_fs_type); if (error) { printk(KERN_ERR "Could not register tmpfs\n"); goto out2; } - shm_mnt = vfs_kern_mount(&shmem_fs_type, MS_NOUSER, - shmem_fs_type.name, NULL); + shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER, + tmpfs_fs_type.name, NULL); if (IS_ERR(shm_mnt)) { error = PTR_ERR(shm_mnt); printk(KERN_ERR "Could not kern_mount tmpfs\n"); @@ -2391,9 +2839,9 @@ int __init shmem_init(void) return 0; out1: - unregister_filesystem(&shmem_fs_type); + unregister_filesystem(&tmpfs_fs_type); out2: - shmem_destroy_inodecache(); + destroy_inodecache(); out3: bdi_destroy(&shmem_backing_dev_info); out4: @@ -2401,6 +2849,45 @@ int __init shmem_init(void) return error; } +#ifdef CONFIG_CGROUP_MEM_RES_CTLR +/** + * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file + * @inode: the inode to be searched + * @pgoff: the offset to be searched + * @pagep: the pointer for the found page to be stored + * @ent: the pointer for the found swap entry to be stored + * + * If a page is found, refcount of it is incremented. Callers should handle + * these refcount. + */ +void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff, + struct page **pagep, swp_entry_t *ent) +{ + swp_entry_t entry = { .val = 0 }, *ptr; + struct page *page = NULL; + struct shmem_inode_info *info = SHMEM_I(inode); + + if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode)) + goto out; + + spin_lock(&info->lock); + ptr = shmem_swp_entry(info, pgoff, NULL); +#ifdef CONFIG_SWAP + if (ptr && ptr->val) { + entry.val = ptr->val; + page = find_get_page(&swapper_space, entry.val); + } else +#endif + page = find_get_page(inode->i_mapping, pgoff); + if (ptr) + shmem_swp_unmap(ptr); + spin_unlock(&info->lock); +out: + *pagep = page; + *ent = entry; +} +#endif + #else /* !CONFIG_SHMEM */ /* @@ -2414,23 +2901,23 @@ int __init shmem_init(void) #include -static struct file_system_type shmem_fs_type = { +static struct file_system_type tmpfs_fs_type = { .name = "tmpfs", .mount = ramfs_mount, .kill_sb = kill_litter_super, }; -int __init shmem_init(void) +int __init init_tmpfs(void) { - BUG_ON(register_filesystem(&shmem_fs_type) != 0); + BUG_ON(register_filesystem(&tmpfs_fs_type) != 0); - shm_mnt = kern_mount(&shmem_fs_type); + shm_mnt = kern_mount(&tmpfs_fs_type); BUG_ON(IS_ERR(shm_mnt)); return 0; } -int shmem_unuse(swp_entry_t swap, struct page *page) +int shmem_unuse(swp_entry_t entry, struct page *page) { return 0; } @@ -2440,17 +2927,43 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user) return 0; } -void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) +void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end) { - truncate_inode_pages_range(inode->i_mapping, lstart, lend); + truncate_inode_pages_range(inode->i_mapping, start, end); } EXPORT_SYMBOL_GPL(shmem_truncate_range); +#ifdef CONFIG_CGROUP_MEM_RES_CTLR +/** + * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file + * @inode: the inode to be searched + * @pgoff: the offset to be searched + * @pagep: the pointer for the found page to be stored + * @ent: the pointer for the found swap entry to be stored + * + * If a page is found, refcount of it is incremented. Callers should handle + * these refcount. + */ +void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff, + struct page **pagep, swp_entry_t *ent) +{ + struct page *page = NULL; + + if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode)) + goto out; + page = find_get_page(inode->i_mapping, pgoff); +out: + *pagep = page; + *ent = (swp_entry_t){ .val = 0 }; +} +#endif + #define shmem_vm_ops generic_file_vm_ops #define shmem_file_operations ramfs_file_operations #define shmem_get_inode(sb, dir, mode, dev, flags) ramfs_get_inode(sb, dir, mode, dev) #define shmem_acct_size(flags, size) 0 #define shmem_unacct_size(flags, size) do {} while (0) +#define SHMEM_MAX_BYTES MAX_LFS_FILESIZE #endif /* CONFIG_SHMEM */ @@ -2474,7 +2987,7 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags if (IS_ERR(shm_mnt)) return (void *)shm_mnt; - if (size < 0 || size > MAX_LFS_FILESIZE) + if (size < 0 || size > SHMEM_MAX_BYTES) return ERR_PTR(-EINVAL); if (shmem_acct_size(flags, size)) diff --git a/trunk/mm/slab.c b/trunk/mm/slab.c index 6d90a091fdca..95947400702b 100644 --- a/trunk/mm/slab.c +++ b/trunk/mm/slab.c @@ -622,51 +622,6 @@ int slab_is_available(void) static struct lock_class_key on_slab_l3_key; static struct lock_class_key on_slab_alc_key; -static struct lock_class_key debugobj_l3_key; -static struct lock_class_key debugobj_alc_key; - -static void slab_set_lock_classes(struct kmem_cache *cachep, - struct lock_class_key *l3_key, struct lock_class_key *alc_key, - int q) -{ - struct array_cache **alc; - struct kmem_list3 *l3; - int r; - - l3 = cachep->nodelists[q]; - if (!l3) - return; - - lockdep_set_class(&l3->list_lock, l3_key); - alc = l3->alien; - /* - * FIXME: This check for BAD_ALIEN_MAGIC - * should go away when common slab code is taught to - * work even without alien caches. - * Currently, non NUMA code returns BAD_ALIEN_MAGIC - * for alloc_alien_cache, - */ - if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC) - return; - for_each_node(r) { - if (alc[r]) - lockdep_set_class(&alc[r]->lock, alc_key); - } -} - -static void slab_set_debugobj_lock_classes_node(struct kmem_cache *cachep, int node) -{ - slab_set_lock_classes(cachep, &debugobj_l3_key, &debugobj_alc_key, node); -} - -static void slab_set_debugobj_lock_classes(struct kmem_cache *cachep) -{ - int node; - - for_each_online_node(node) - slab_set_debugobj_lock_classes_node(cachep, node); -} - static void init_node_lock_keys(int q) { struct cache_sizes *s = malloc_sizes; @@ -675,14 +630,29 @@ static void init_node_lock_keys(int q) return; for (s = malloc_sizes; s->cs_size != ULONG_MAX; s++) { + struct array_cache **alc; struct kmem_list3 *l3; + int r; l3 = s->cs_cachep->nodelists[q]; if (!l3 || OFF_SLAB(s->cs_cachep)) continue; - - slab_set_lock_classes(s->cs_cachep, &on_slab_l3_key, - &on_slab_alc_key, q); + lockdep_set_class(&l3->list_lock, &on_slab_l3_key); + alc = l3->alien; + /* + * FIXME: This check for BAD_ALIEN_MAGIC + * should go away when common slab code is taught to + * work even without alien caches. + * Currently, non NUMA code returns BAD_ALIEN_MAGIC + * for alloc_alien_cache, + */ + if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC) + continue; + for_each_node(r) { + if (alc[r]) + lockdep_set_class(&alc[r]->lock, + &on_slab_alc_key); + } } } @@ -701,14 +671,6 @@ static void init_node_lock_keys(int q) static inline void init_lock_keys(void) { } - -static void slab_set_debugobj_lock_classes_node(struct kmem_cache *cachep, int node) -{ -} - -static void slab_set_debugobj_lock_classes(struct kmem_cache *cachep) -{ -} #endif /* @@ -1302,8 +1264,6 @@ static int __cpuinit cpuup_prepare(long cpu) spin_unlock_irq(&l3->list_lock); kfree(shared); free_alien_cache(alien); - if (cachep->flags & SLAB_DEBUG_OBJECTS) - slab_set_debugobj_lock_classes_node(cachep, node); } init_node_lock_keys(node); @@ -1666,9 +1626,6 @@ void __init kmem_cache_init_late(void) { struct kmem_cache *cachep; - /* Annotate slab for lockdep -- annotate the malloc caches */ - init_lock_keys(); - /* 6) resize the head arrays to their final sizes */ mutex_lock(&cache_chain_mutex); list_for_each_entry(cachep, &cache_chain, next) @@ -1679,6 +1636,9 @@ void __init kmem_cache_init_late(void) /* Done! */ g_cpucache_up = FULL; + /* Annotate slab for lockdep -- annotate the malloc caches */ + init_lock_keys(); + /* * Register a cpu startup notifier callback that initializes * cpu_cache_get for all new cpus @@ -2466,16 +2426,6 @@ kmem_cache_create (const char *name, size_t size, size_t align, goto oops; } - if (flags & SLAB_DEBUG_OBJECTS) { - /* - * Would deadlock through slab_destroy()->call_rcu()-> - * debug_object_activate()->kmem_cache_alloc(). - */ - WARN_ON_ONCE(flags & SLAB_DESTROY_BY_RCU); - - slab_set_debugobj_lock_classes(cachep); - } - /* cache setup completed, link it into the list */ list_add(&cachep->next, &cache_chain); oops: diff --git a/trunk/mm/swapfile.c b/trunk/mm/swapfile.c index 17bc224bce68..1b8c33907242 100644 --- a/trunk/mm/swapfile.c +++ b/trunk/mm/swapfile.c @@ -1924,24 +1924,20 @@ static unsigned long read_swap_header(struct swap_info_struct *p, /* * Find out how many pages are allowed for a single swap - * device. There are three limiting factors: 1) the number - * of bits for the swap offset in the swp_entry_t type, and - * 2) the number of bits in the swap pte as defined by the - * the different architectures, and 3) the number of free bits - * in an exceptional radix_tree entry. In order to find the - * largest possible bit mask, a swap entry with swap type 0 + * device. There are two limiting factors: 1) the number of + * bits for the swap offset in the swp_entry_t type and + * 2) the number of bits in the a swap pte as defined by + * the different architectures. In order to find the + * largest possible bit mask a swap entry with swap type 0 * and swap offset ~0UL is created, encoded to a swap pte, - * decoded to a swp_entry_t again, and finally the swap + * decoded to a swp_entry_t again and finally the swap * offset is extracted. This will mask all the bits from * the initial ~0UL mask that can't be encoded in either * the swp_entry_t or the architecture definition of a - * swap pte. Then the same is done for a radix_tree entry. + * swap pte. */ maxpages = swp_offset(pte_to_swp_entry( - swp_entry_to_pte(swp_entry(0, ~0UL)))); - maxpages = swp_offset(radix_to_swp_entry( - swp_to_radix_entry(swp_entry(0, maxpages)))) + 1; - + swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1; if (maxpages > swap_header->info.last_page) { maxpages = swap_header->info.last_page + 1; /* p->max is an unsigned int: don't overflow it */ diff --git a/trunk/mm/truncate.c b/trunk/mm/truncate.c index b40ac6d4e86e..232eb2736a79 100644 --- a/trunk/mm/truncate.c +++ b/trunk/mm/truncate.c @@ -336,14 +336,6 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping, unsigned long count = 0; int i; - /* - * Note: this function may get called on a shmem/tmpfs mapping: - * pagevec_lookup() might then return 0 prematurely (because it - * got a gangful of swap entries); but it's hardly worth worrying - * about - it can rarely have anything to free from such a mapping - * (most pages are dirty), and already skips over any difficulties. - */ - pagevec_init(&pvec, 0); while (index <= end && pagevec_lookup(&pvec, mapping, index, min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) { diff --git a/trunk/net/atm/br2684.c b/trunk/net/atm/br2684.c index 52cfd0c3ea71..2252c2085dac 100644 --- a/trunk/net/atm/br2684.c +++ b/trunk/net/atm/br2684.c @@ -242,6 +242,8 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev, if (brdev->payload == p_bridged) { skb_push(skb, 2); memset(skb->data, 0, 2); + } else { /* p_routed */ + skb_pull(skb, ETH_HLEN); } } skb_debug(skb); diff --git a/trunk/net/core/skbuff.c b/trunk/net/core/skbuff.c index 27002dffe7ed..2beda824636e 100644 --- a/trunk/net/core/skbuff.c +++ b/trunk/net/core/skbuff.c @@ -1369,21 +1369,8 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta) } EXPORT_SYMBOL(__pskb_pull_tail); -/** - * skb_copy_bits - copy bits from skb to kernel buffer - * @skb: source skb - * @offset: offset in source - * @to: destination buffer - * @len: number of bytes to copy - * - * Copy the specified number of bytes from the source skb to the - * destination buffer. - * - * CAUTION ! : - * If its prototype is ever changed, - * check arch/{*}/net/{*}.S files, - * since it is called from BPF assembly code. - */ +/* Copy some data bits from skb to kernel buffer. */ + int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len) { int start = skb_headlen(skb); diff --git a/trunk/net/ipv4/igmp.c b/trunk/net/ipv4/igmp.c index 283c0a26e03f..f1d27f6c9351 100644 --- a/trunk/net/ipv4/igmp.c +++ b/trunk/net/ipv4/igmp.c @@ -1718,7 +1718,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, pmc->sfcount[sfmode]--; for (j=0; jsfcount[MCAST_EXCLUDE] != 0)) { #ifdef CONFIG_IP_MULTICAST struct ip_sf_list *psf; diff --git a/trunk/net/ipv4/ip_output.c b/trunk/net/ipv4/ip_output.c index 77d3eded665a..ccaaa851ab42 100644 --- a/trunk/net/ipv4/ip_output.c +++ b/trunk/net/ipv4/ip_output.c @@ -204,15 +204,9 @@ static inline int ip_finish_output2(struct sk_buff *skb) skb = skb2; } - rcu_read_lock(); neigh = dst_get_neighbour(dst); - if (neigh) { - int res = neigh_output(neigh, skb); - - rcu_read_unlock(); - return res; - } - rcu_read_unlock(); + if (neigh) + return neigh_output(neigh, skb); if (net_ratelimit()) printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n"); diff --git a/trunk/net/ipv4/route.c b/trunk/net/ipv4/route.c index 6afc4eb50591..1730689f560e 100644 --- a/trunk/net/ipv4/route.c +++ b/trunk/net/ipv4/route.c @@ -1628,18 +1628,16 @@ static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) { struct rtable *rt = (struct rtable *) dst; __be32 orig_gw = rt->rt_gateway; - struct neighbour *n, *old_n; + struct neighbour *n; dst_confirm(&rt->dst); - rt->rt_gateway = peer->redirect_learned.a4; + neigh_release(dst_get_neighbour(&rt->dst)); + dst_set_neighbour(&rt->dst, NULL); - n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); - if (IS_ERR(n)) - return PTR_ERR(n); - old_n = xchg(&rt->dst._neighbour, n); - if (old_n) - neigh_release(old_n); + rt->rt_gateway = peer->redirect_learned.a4; + rt_bind_neighbour(rt); + n = dst_get_neighbour(&rt->dst); if (!n || !(n->nud_state & NUD_VALID)) { if (n) neigh_event_send(n, NULL); diff --git a/trunk/net/ipv6/addrconf.c b/trunk/net/ipv6/addrconf.c index f012ebd87b43..a55500cc0b29 100644 --- a/trunk/net/ipv6/addrconf.c +++ b/trunk/net/ipv6/addrconf.c @@ -656,7 +656,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, * layer address of our nexhop router */ - if (dst_get_neighbour_raw(&rt->dst) == NULL) + if (dst_get_neighbour(&rt->dst) == NULL) ifa->flags &= ~IFA_F_OPTIMISTIC; ifa->idev = idev; diff --git a/trunk/net/ipv6/datagram.c b/trunk/net/ipv6/datagram.c index 9ef1831746ef..16560336eb72 100644 --- a/trunk/net/ipv6/datagram.c +++ b/trunk/net/ipv6/datagram.c @@ -33,11 +33,6 @@ #include #include -static inline int ipv6_mapped_addr_any(const struct in6_addr *a) -{ - return (ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0)); -} - int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; @@ -107,12 +102,10 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ipv6_addr_set_v4mapped(inet->inet_daddr, &np->daddr); - if (ipv6_addr_any(&np->saddr) || - ipv6_mapped_addr_any(&np->saddr)) + if (ipv6_addr_any(&np->saddr)) ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); - if (ipv6_addr_any(&np->rcv_saddr) || - ipv6_mapped_addr_any(&np->rcv_saddr)) { + if (ipv6_addr_any(&np->rcv_saddr)) { ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, &np->rcv_saddr); if (sk->sk_prot->rehash) diff --git a/trunk/net/ipv6/ip6_fib.c b/trunk/net/ipv6/ip6_fib.c index 320d91d20ad7..54a4678955bf 100644 --- a/trunk/net/ipv6/ip6_fib.c +++ b/trunk/net/ipv6/ip6_fib.c @@ -1455,7 +1455,7 @@ static int fib6_age(struct rt6_info *rt, void *arg) RT6_TRACE("aging clone %p\n", rt); return -1; } else if ((rt->rt6i_flags & RTF_GATEWAY) && - (!(dst_get_neighbour_raw(&rt->dst)->flags & NTF_ROUTER))) { + (!(dst_get_neighbour(&rt->dst)->flags & NTF_ROUTER))) { RT6_TRACE("purging route %p via non-router but gateway\n", rt); return -1; diff --git a/trunk/net/ipv6/ip6_output.c b/trunk/net/ipv6/ip6_output.c index 4c882cf4e8a1..32e5339db0c8 100644 --- a/trunk/net/ipv6/ip6_output.c +++ b/trunk/net/ipv6/ip6_output.c @@ -135,15 +135,10 @@ static int ip6_finish_output2(struct sk_buff *skb) skb->len); } - rcu_read_lock(); neigh = dst_get_neighbour(dst); - if (neigh) { - int res = neigh_output(neigh, skb); + if (neigh) + return neigh_output(neigh, skb); - rcu_read_unlock(); - return res; - } - rcu_read_unlock(); IP6_INC_STATS_BH(dev_net(dst->dev), ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); kfree_skb(skb); @@ -980,14 +975,12 @@ static int ip6_dst_lookup_tail(struct sock *sk, * dst entry and replace it instead with the * dst entry of the nexthop router */ - rcu_read_lock(); n = dst_get_neighbour(*dst); if (n && !(n->nud_state & NUD_VALID)) { struct inet6_ifaddr *ifp; struct flowi6 fl_gw6; int redirect; - rcu_read_unlock(); ifp = ipv6_get_ifaddr(net, &fl6->saddr, (*dst)->dev, 1); @@ -1007,8 +1000,6 @@ static int ip6_dst_lookup_tail(struct sock *sk, if ((err = (*dst)->error)) goto out_err_release; } - } else { - rcu_read_unlock(); } #endif diff --git a/trunk/net/ipv6/route.c b/trunk/net/ipv6/route.c index 9e69eb0ec6dd..e8987da06667 100644 --- a/trunk/net/ipv6/route.c +++ b/trunk/net/ipv6/route.c @@ -364,7 +364,7 @@ static inline struct rt6_info *rt6_device_match(struct net *net, #ifdef CONFIG_IPV6_ROUTER_PREF static void rt6_probe(struct rt6_info *rt) { - struct neighbour *neigh; + struct neighbour *neigh = rt ? dst_get_neighbour(&rt->dst) : NULL; /* * Okay, this does not seem to be appropriate * for now, however, we need to check if it @@ -373,10 +373,8 @@ static void rt6_probe(struct rt6_info *rt) * Router Reachability Probe MUST be rate-limited * to no more than one per minute. */ - rcu_read_lock(); - neigh = rt ? dst_get_neighbour(&rt->dst) : NULL; if (!neigh || (neigh->nud_state & NUD_VALID)) - goto out; + return; read_lock_bh(&neigh->lock); if (!(neigh->nud_state & NUD_VALID) && time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { @@ -389,11 +387,8 @@ static void rt6_probe(struct rt6_info *rt) target = (struct in6_addr *)&neigh->primary_key; addrconf_addr_solict_mult(target, &mcaddr); ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); - } else { + } else read_unlock_bh(&neigh->lock); - } -out: - rcu_read_unlock(); } #else static inline void rt6_probe(struct rt6_info *rt) @@ -417,11 +412,8 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) static inline int rt6_check_neigh(struct rt6_info *rt) { - struct neighbour *neigh; + struct neighbour *neigh = dst_get_neighbour(&rt->dst); int m; - - rcu_read_lock(); - neigh = dst_get_neighbour(&rt->dst); if (rt->rt6i_flags & RTF_NONEXTHOP || !(rt->rt6i_flags & RTF_GATEWAY)) m = 1; @@ -438,7 +430,6 @@ static inline int rt6_check_neigh(struct rt6_info *rt) read_unlock_bh(&neigh->lock); } else m = 0; - rcu_read_unlock(); return m; } @@ -778,7 +769,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, rt->rt6i_dst.plen = 128; rt->rt6i_flags |= RTF_CACHE; rt->dst.flags |= DST_HOST; - dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst))); + dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour(&ort->dst))); } return rt; } @@ -812,7 +803,7 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, dst_hold(&rt->dst); read_unlock_bh(&table->tb6_lock); - if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) + if (!dst_get_neighbour(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); else if (!(rt->dst.flags & DST_HOST)) nrt = rt6_alloc_clone(rt, &fl6->daddr); @@ -1596,7 +1587,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, dst_confirm(&rt->dst); /* Duplicate redirect: silently ignore. */ - if (neigh == dst_get_neighbour_raw(&rt->dst)) + if (neigh == dst_get_neighbour(&rt->dst)) goto out; nrt = ip6_rt_copy(rt, dest); @@ -1691,7 +1682,7 @@ static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr 1. It is connected route. Action: COW 2. It is gatewayed route or NONEXTHOP route. Action: clone it. */ - if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) + if (!dst_get_neighbour(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) nrt = rt6_alloc_cow(rt, daddr, saddr); else nrt = rt6_alloc_clone(rt, daddr); @@ -2335,7 +2326,6 @@ static int rt6_fill_node(struct net *net, struct nlmsghdr *nlh; long expires; u32 table; - struct neighbour *n; if (prefix) { /* user wants prefix routes only */ if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { @@ -2424,11 +2414,8 @@ static int rt6_fill_node(struct net *net, if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) goto nla_put_failure; - rcu_read_lock(); - n = dst_get_neighbour(&rt->dst); - if (n) - NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key); - rcu_read_unlock(); + if (dst_get_neighbour(&rt->dst)) + NLA_PUT(skb, RTA_GATEWAY, 16, &dst_get_neighbour(&rt->dst)->primary_key); if (rt->dst.dev) NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); @@ -2621,14 +2608,12 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) #else seq_puts(m, "00000000000000000000000000000000 00 "); #endif - rcu_read_lock(); n = dst_get_neighbour(&rt->dst); if (n) { seq_printf(m, "%pi6", n->primary_key); } else { seq_puts(m, "00000000000000000000000000000000"); } - rcu_read_unlock(); seq_printf(m, " %08x %08x %08x %08x %8s\n", rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), rt->dst.__use, rt->rt6i_flags, diff --git a/trunk/net/netfilter/ipvs/ip_vs_ctl.c b/trunk/net/netfilter/ipvs/ip_vs_ctl.c index 2b771dc708a3..be43fd805bd0 100644 --- a/trunk/net/netfilter/ipvs/ip_vs_ctl.c +++ b/trunk/net/netfilter/ipvs/ip_vs_ctl.c @@ -3771,7 +3771,6 @@ int __init ip_vs_control_init(void) void ip_vs_control_cleanup(void) { EnterFunction(2); - unregister_netdevice_notifier(&ip_vs_dst_notifier); ip_vs_genl_unregister(); nf_unregister_sockopt(&ip_vs_sockopts); LeaveFunction(2); diff --git a/trunk/net/netlabel/Makefile b/trunk/net/netlabel/Makefile index d2732fc952e2..ea750e9df65f 100644 --- a/trunk/net/netlabel/Makefile +++ b/trunk/net/netlabel/Makefile @@ -1,6 +1,8 @@ # # Makefile for the NetLabel subsystem. # +# Feb 9, 2006, Paul Moore +# # base objects obj-y := netlabel_user.o netlabel_kapi.o diff --git a/trunk/net/netlabel/netlabel_addrlist.c b/trunk/net/netlabel/netlabel_addrlist.c index 96b749dacc34..c0519139679e 100644 --- a/trunk/net/netlabel/netlabel_addrlist.c +++ b/trunk/net/netlabel/netlabel_addrlist.c @@ -6,7 +6,7 @@ * system manages static and dynamic label mappings for network protocols such * as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_addrlist.h b/trunk/net/netlabel/netlabel_addrlist.h index fdbc1d2c7352..2b9644e19de0 100644 --- a/trunk/net/netlabel/netlabel_addrlist.h +++ b/trunk/net/netlabel/netlabel_addrlist.h @@ -6,7 +6,7 @@ * system manages static and dynamic label mappings for network protocols such * as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_cipso_v4.c b/trunk/net/netlabel/netlabel_cipso_v4.c index 6bf878335d94..dd53a36d89af 100644 --- a/trunk/net/netlabel/netlabel_cipso_v4.c +++ b/trunk/net/netlabel/netlabel_cipso_v4.c @@ -5,7 +5,7 @@ * NetLabel system manages static and dynamic label mappings for network * protocols such as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_cipso_v4.h b/trunk/net/netlabel/netlabel_cipso_v4.h index d24d774bfd62..af7f3355103e 100644 --- a/trunk/net/netlabel/netlabel_cipso_v4.h +++ b/trunk/net/netlabel/netlabel_cipso_v4.h @@ -5,7 +5,7 @@ * NetLabel system manages static and dynamic label mappings for network * protocols such as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_domainhash.c b/trunk/net/netlabel/netlabel_domainhash.c index 7d8083cde34f..2aa975e5452d 100644 --- a/trunk/net/netlabel/netlabel_domainhash.c +++ b/trunk/net/netlabel/netlabel_domainhash.c @@ -6,7 +6,7 @@ * system manages static and dynamic label mappings for network protocols such * as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_domainhash.h b/trunk/net/netlabel/netlabel_domainhash.h index bfcc0f7024c5..0261dda3f2d2 100644 --- a/trunk/net/netlabel/netlabel_domainhash.h +++ b/trunk/net/netlabel/netlabel_domainhash.h @@ -6,7 +6,7 @@ * system manages static and dynamic label mappings for network protocols such * as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_kapi.c b/trunk/net/netlabel/netlabel_kapi.c index 58107d060846..b528dd928d3c 100644 --- a/trunk/net/netlabel/netlabel_kapi.c +++ b/trunk/net/netlabel/netlabel_kapi.c @@ -5,7 +5,7 @@ * system manages static and dynamic label mappings for network protocols such * as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_mgmt.c b/trunk/net/netlabel/netlabel_mgmt.c index bfa555869775..dff8a0809245 100644 --- a/trunk/net/netlabel/netlabel_mgmt.c +++ b/trunk/net/netlabel/netlabel_mgmt.c @@ -5,7 +5,7 @@ * NetLabel system manages static and dynamic label mappings for network * protocols such as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_mgmt.h b/trunk/net/netlabel/netlabel_mgmt.h index 5a9f31ce5799..8db37f4c10f7 100644 --- a/trunk/net/netlabel/netlabel_mgmt.h +++ b/trunk/net/netlabel/netlabel_mgmt.h @@ -5,7 +5,7 @@ * NetLabel system manages static and dynamic label mappings for network * protocols such as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_unlabeled.c b/trunk/net/netlabel/netlabel_unlabeled.c index e6e823656f9d..f1ecf848e3ac 100644 --- a/trunk/net/netlabel/netlabel_unlabeled.c +++ b/trunk/net/netlabel/netlabel_unlabeled.c @@ -5,7 +5,7 @@ * NetLabel system. The NetLabel system manages static and dynamic label * mappings for network protocols such as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_unlabeled.h b/trunk/net/netlabel/netlabel_unlabeled.h index 700af49022a0..0bc8dc3f9e3c 100644 --- a/trunk/net/netlabel/netlabel_unlabeled.h +++ b/trunk/net/netlabel/netlabel_unlabeled.h @@ -5,7 +5,7 @@ * NetLabel system. The NetLabel system manages static and dynamic label * mappings for network protocols such as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_user.c b/trunk/net/netlabel/netlabel_user.c index 9fae63f10298..a3fd75ac3fa5 100644 --- a/trunk/net/netlabel/netlabel_user.c +++ b/trunk/net/netlabel/netlabel_user.c @@ -5,7 +5,7 @@ * NetLabel system manages static and dynamic label mappings for network * protocols such as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/netlabel/netlabel_user.h b/trunk/net/netlabel/netlabel_user.h index 81969785e279..f4fc4c9ad567 100644 --- a/trunk/net/netlabel/netlabel_user.h +++ b/trunk/net/netlabel/netlabel_user.h @@ -5,7 +5,7 @@ * NetLabel system manages static and dynamic label mappings for network * protocols such as CIPSO and RIPSO. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/net/sched/sch_sfq.c b/trunk/net/sched/sch_sfq.c index 4f5510e2bd6f..4536ee64383e 100644 --- a/trunk/net/sched/sch_sfq.c +++ b/trunk/net/sched/sch_sfq.c @@ -410,12 +410,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) /* Return Congestion Notification only if we dropped a packet * from this flow. */ - if (qlen != slot->qlen) - return NET_XMIT_CN; - - /* As we dropped a packet, better let upper stack know this */ - qdisc_tree_decrease_qlen(sch, 1); - return NET_XMIT_SUCCESS; + return (qlen != slot->qlen) ? NET_XMIT_CN : NET_XMIT_SUCCESS; } static struct sk_buff * diff --git a/trunk/net/socket.c b/trunk/net/socket.c index 24a77400b65e..b1cbbcd92558 100644 --- a/trunk/net/socket.c +++ b/trunk/net/socket.c @@ -1871,14 +1871,8 @@ SYSCALL_DEFINE2(shutdown, int, fd, int, how) #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) -struct used_address { - struct sockaddr_storage name; - unsigned int name_len; -}; - static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg, - struct msghdr *msg_sys, unsigned flags, - struct used_address *used_address) + struct msghdr *msg_sys, unsigned flags, int nosec) { struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; @@ -1959,28 +1953,8 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg, if (sock->file->f_flags & O_NONBLOCK) msg_sys->msg_flags |= MSG_DONTWAIT; - /* - * If this is sendmmsg() and current destination address is same as - * previously succeeded address, omit asking LSM's decision. - * used_address->name_len is initialized to UINT_MAX so that the first - * destination address never matches. - */ - if (used_address && used_address->name_len == msg_sys->msg_namelen && - !memcmp(&used_address->name, msg->msg_name, - used_address->name_len)) { - err = sock_sendmsg_nosec(sock, msg_sys, total_len); - goto out_freectl; - } - err = sock_sendmsg(sock, msg_sys, total_len); - /* - * If this is sendmmsg() and sending to current destination address was - * successful, remember it. - */ - if (used_address && err >= 0) { - used_address->name_len = msg_sys->msg_namelen; - memcpy(&used_address->name, msg->msg_name, - used_address->name_len); - } + err = (nosec ? sock_sendmsg_nosec : sock_sendmsg)(sock, msg_sys, + total_len); out_freectl: if (ctl_buf != ctl) @@ -2005,7 +1979,7 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags) if (!sock) goto out; - err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL); + err = __sys_sendmsg(sock, msg, &msg_sys, flags, 0); fput_light(sock->file, fput_needed); out: @@ -2024,10 +1998,6 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, struct mmsghdr __user *entry; struct compat_mmsghdr __user *compat_entry; struct msghdr msg_sys; - struct used_address used_address; - - if (vlen > UIO_MAXIOV) - vlen = UIO_MAXIOV; datagrams = 0; @@ -2035,22 +2005,27 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, if (!sock) return err; - used_address.name_len = UINT_MAX; + err = sock_error(sock->sk); + if (err) + goto out_put; + entry = mmsg; compat_entry = (struct compat_mmsghdr __user *)mmsg; - err = 0; while (datagrams < vlen) { + /* + * No need to ask LSM for more than the first datagram. + */ if (MSG_CMSG_COMPAT & flags) { err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry, - &msg_sys, flags, &used_address); + &msg_sys, flags, datagrams); if (err < 0) break; err = __put_user(err, &compat_entry->msg_len); ++compat_entry; } else { err = __sys_sendmsg(sock, (struct msghdr __user *)entry, - &msg_sys, flags, &used_address); + &msg_sys, flags, datagrams); if (err < 0) break; err = put_user(err, &entry->msg_len); @@ -2062,11 +2037,29 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, ++datagrams; } +out_put: fput_light(sock->file, fput_needed); - /* We only return an error if no datagrams were able to be sent */ - if (datagrams != 0) + if (err == 0) + return datagrams; + + if (datagrams != 0) { + /* + * We may send less entries than requested (vlen) if the + * sock is non blocking... + */ + if (err != -EAGAIN) { + /* + * ... or if sendmsg returns an error after we + * send some datagrams, where we record the + * error to return on the next call or if the + * app asks about it using getsockopt(SO_ERROR). + */ + sock->sk->sk_err = -err; + } + return datagrams; + } return err; } diff --git a/trunk/net/sunrpc/xprt.c b/trunk/net/sunrpc/xprt.c index f4385e45a5fc..9b6a4d1ea8f8 100644 --- a/trunk/net/sunrpc/xprt.c +++ b/trunk/net/sunrpc/xprt.c @@ -187,7 +187,6 @@ EXPORT_SYMBOL_GPL(xprt_load_transport); /** * xprt_reserve_xprt - serialize write access to transports * @task: task that is requesting access to the transport - * @xprt: pointer to the target transport * * This prevents mixing the payload of separate requests, and prevents * transport connects from colliding with writes. No congestion control diff --git a/trunk/net/wireless/nl80211.c b/trunk/net/wireless/nl80211.c index e83e7fee3bc0..28d2aa109bee 100644 --- a/trunk/net/wireless/nl80211.c +++ b/trunk/net/wireless/nl80211.c @@ -3464,7 +3464,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) tmp) { enum ieee80211_band band = nla_type(attr); - if (band < 0 || band >= IEEE80211_NUM_BANDS) { + if (band < 0 || band > IEEE80211_NUM_BANDS) { err = -EINVAL; goto out_free; } diff --git a/trunk/net/xfrm/xfrm_algo.c b/trunk/net/xfrm/xfrm_algo.c index 791ab2e77f3f..58064d9e565d 100644 --- a/trunk/net/xfrm/xfrm_algo.c +++ b/trunk/net/xfrm/xfrm_algo.c @@ -462,8 +462,8 @@ static struct xfrm_algo_desc ealg_list[] = { .desc = { .sadb_alg_id = SADB_X_EALG_AESCTR, .sadb_alg_ivlen = 8, - .sadb_alg_minbits = 160, - .sadb_alg_maxbits = 288 + .sadb_alg_minbits = 128, + .sadb_alg_maxbits = 256 } }, }; diff --git a/trunk/security/selinux/hooks.c b/trunk/security/selinux/hooks.c index 266a2292451d..a38316b2e3f6 100644 --- a/trunk/security/selinux/hooks.c +++ b/trunk/security/selinux/hooks.c @@ -14,7 +14,7 @@ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * * Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P. - * Paul Moore + * Paul Moore * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. * Yuichi Nakamura * diff --git a/trunk/security/selinux/include/netif.h b/trunk/security/selinux/include/netif.h index 43d507242b42..ce23edd128b3 100644 --- a/trunk/security/selinux/include/netif.h +++ b/trunk/security/selinux/include/netif.h @@ -8,7 +8,7 @@ * * Copyright (C) 2003 Red Hat, Inc., James Morris * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. - * Paul Moore + * Paul Moore, * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, diff --git a/trunk/security/selinux/include/netlabel.h b/trunk/security/selinux/include/netlabel.h index 8c59b8f150e8..cf2f628e6e28 100644 --- a/trunk/security/selinux/include/netlabel.h +++ b/trunk/security/selinux/include/netlabel.h @@ -1,7 +1,7 @@ /* * SELinux interface to the NetLabel subsystem * - * Author: Paul Moore + * Author : Paul Moore * */ diff --git a/trunk/security/selinux/include/netnode.h b/trunk/security/selinux/include/netnode.h index df7a5ed6c694..1b94450d11d2 100644 --- a/trunk/security/selinux/include/netnode.h +++ b/trunk/security/selinux/include/netnode.h @@ -6,7 +6,7 @@ * needed to reduce the lookup overhead since most of these queries happen on * a per-packet basis. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/security/selinux/include/netport.h b/trunk/security/selinux/include/netport.h index 4d965b83d735..8991752eaf93 100644 --- a/trunk/security/selinux/include/netport.h +++ b/trunk/security/selinux/include/netport.h @@ -5,7 +5,7 @@ * mapping is maintained as part of the normal policy but a fast cache is * needed to reduce the lookup overhead. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/security/selinux/netif.c b/trunk/security/selinux/netif.c index 326f22cbe405..58cc481c93d5 100644 --- a/trunk/security/selinux/netif.c +++ b/trunk/security/selinux/netif.c @@ -8,7 +8,7 @@ * * Copyright (C) 2003 Red Hat, Inc., James Morris * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. - * Paul Moore + * Paul Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, diff --git a/trunk/security/selinux/netlabel.c b/trunk/security/selinux/netlabel.c index da4b8b233280..c3bf3ed07b06 100644 --- a/trunk/security/selinux/netlabel.c +++ b/trunk/security/selinux/netlabel.c @@ -4,7 +4,7 @@ * This file provides the necessary glue to tie NetLabel into the SELinux * subsystem. * - * Author: Paul Moore + * Author: Paul Moore * */ diff --git a/trunk/security/selinux/netnode.c b/trunk/security/selinux/netnode.c index 3bf46abaa688..8b691a863186 100644 --- a/trunk/security/selinux/netnode.c +++ b/trunk/security/selinux/netnode.c @@ -6,7 +6,7 @@ * needed to reduce the lookup overhead since most of these queries happen on * a per-packet basis. * - * Author: Paul Moore + * Author: Paul Moore * * This code is heavily based on the "netif" concept originally developed by * James Morris diff --git a/trunk/security/selinux/netport.c b/trunk/security/selinux/netport.c index 0b62bd112461..ae76e298de7d 100644 --- a/trunk/security/selinux/netport.c +++ b/trunk/security/selinux/netport.c @@ -5,7 +5,7 @@ * mapping is maintained as part of the normal policy but a fast cache is * needed to reduce the lookup overhead. * - * Author: Paul Moore + * Author: Paul Moore * * This code is heavily based on the "netif" concept originally developed by * James Morris diff --git a/trunk/security/selinux/selinuxfs.c b/trunk/security/selinux/selinuxfs.c index 55d92cbb177a..de7900ef53da 100644 --- a/trunk/security/selinux/selinuxfs.c +++ b/trunk/security/selinux/selinuxfs.c @@ -2,7 +2,7 @@ * * Added conditional policy language extensions * - * Updated: Hewlett-Packard + * Updated: Hewlett-Packard * * Added support for the policy capability bitmap * diff --git a/trunk/security/selinux/ss/ebitmap.c b/trunk/security/selinux/ss/ebitmap.c index 30f119b1d1ec..d42951fcbe87 100644 --- a/trunk/security/selinux/ss/ebitmap.c +++ b/trunk/security/selinux/ss/ebitmap.c @@ -4,7 +4,7 @@ * Author : Stephen Smalley, */ /* - * Updated: Hewlett-Packard + * Updated: Hewlett-Packard * * Added support to import/export the NetLabel category bitmap * diff --git a/trunk/security/selinux/ss/mls.c b/trunk/security/selinux/ss/mls.c index fbf9c5816c71..e96174216bc9 100644 --- a/trunk/security/selinux/ss/mls.c +++ b/trunk/security/selinux/ss/mls.c @@ -11,7 +11,7 @@ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. */ /* - * Updated: Hewlett-Packard + * Updated: Hewlett-Packard * * Added support to import/export the MLS label from NetLabel * diff --git a/trunk/security/selinux/ss/mls.h b/trunk/security/selinux/ss/mls.h index e4369e3e6366..037bf9d82d41 100644 --- a/trunk/security/selinux/ss/mls.h +++ b/trunk/security/selinux/ss/mls.h @@ -11,7 +11,7 @@ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. */ /* - * Updated: Hewlett-Packard + * Updated: Hewlett-Packard * * Added support to import/export the MLS label from NetLabel * diff --git a/trunk/security/selinux/ss/policydb.c b/trunk/security/selinux/ss/policydb.c index 2381d0ded228..d246aca3f4fb 100644 --- a/trunk/security/selinux/ss/policydb.c +++ b/trunk/security/selinux/ss/policydb.c @@ -13,7 +13,7 @@ * * Added conditional policy language extensions * - * Updated: Hewlett-Packard + * Updated: Hewlett-Packard * * Added support for the policy capability bitmap * diff --git a/trunk/security/selinux/ss/services.c b/trunk/security/selinux/ss/services.c index f6917bc0aa05..973e00e34fa9 100644 --- a/trunk/security/selinux/ss/services.c +++ b/trunk/security/selinux/ss/services.c @@ -13,7 +13,7 @@ * * Added conditional policy language extensions * - * Updated: Hewlett-Packard + * Updated: Hewlett-Packard * * Added support for NetLabel * Added support for the policy capability bitmap diff --git a/trunk/security/smack/smack_lsm.c b/trunk/security/smack/smack_lsm.c index b9c5e149903b..f375eb2e1957 100644 --- a/trunk/security/smack/smack_lsm.c +++ b/trunk/security/smack/smack_lsm.c @@ -9,7 +9,7 @@ * * Copyright (C) 2007 Casey Schaufler * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * Paul Moore + * Paul Moore * Copyright (C) 2010 Nokia Corporation * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/core/pcm_compat.c b/trunk/sound/core/pcm_compat.c index 91cdf9435fec..5fb2e28e796f 100644 --- a/trunk/sound/core/pcm_compat.c +++ b/trunk/sound/core/pcm_compat.c @@ -342,7 +342,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, kfree(bufs); return -EFAULT; } - bufs[i] = compat_ptr(ptr); + bufs[ch] = compat_ptr(ptr); bufptr++; } if (dir == SNDRV_PCM_STREAM_PLAYBACK) diff --git a/trunk/sound/core/rtctimer.c b/trunk/sound/core/rtctimer.c index e85e72baff9e..0851cd13e303 100644 --- a/trunk/sound/core/rtctimer.c +++ b/trunk/sound/core/rtctimer.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/trunk/sound/pci/asihpi/hpidspcd.c b/trunk/sound/pci/asihpi/hpidspcd.c index 71d32c868c92..3a7afa31c1d8 100644 --- a/trunk/sound/pci/asihpi/hpidspcd.c +++ b/trunk/sound/pci/asihpi/hpidspcd.c @@ -43,7 +43,6 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, struct pci_dev *dev = os_data; struct code_header header; char fw_name[20]; - short err_ret = HPI_ERROR_DSP_FILE_NOT_FOUND; int err; sprintf(fw_name, "asihpi/dsp%04x.bin", adapter); @@ -86,10 +85,8 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name); dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL); - if (!dsp_code->pvt) { - err_ret = HPI_ERROR_MEMORY_ALLOC; - goto error2; - } + if (!dsp_code->pvt) + return HPI_ERROR_MEMORY_ALLOC; dsp_code->pvt->dev = dev; dsp_code->pvt->firmware = firmware; @@ -102,7 +99,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, release_firmware(firmware); error1: dsp_code->block_length = 0; - return err_ret; + return HPI_ERROR_DSP_FILE_NOT_FOUND; } /*-------------------------------------------------------------------*/ diff --git a/trunk/sound/pci/asihpi/hpioctl.c b/trunk/sound/pci/asihpi/hpioctl.c index a32502e796de..9683f84ecdc8 100644 --- a/trunk/sound/pci/asihpi/hpioctl.c +++ b/trunk/sound/pci/asihpi/hpioctl.c @@ -177,21 +177,16 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } else { u16 __user *ptr = NULL; u32 size = 0; - u32 adapter_present; + /* -1=no data 0=read from user mem, 1=write to user mem */ int wrflag = -1; - struct hpi_adapter *pa; - - if (hm->h.adapter_index < HPI_MAX_ADAPTERS) { - pa = &adapters[hm->h.adapter_index]; - adapter_present = pa->type; - } else { - adapter_present = 0; - } + u32 adapter = hm->h.adapter_index; + struct hpi_adapter *pa = &adapters[adapter]; - if (!adapter_present) { - hpi_init_response(&hr->r0, hm->h.object, - hm->h.function, HPI_ERROR_BAD_ADAPTER_NUMBER); + if ((adapter >= HPI_MAX_ADAPTERS) || (!pa->type)) { + hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER, + HPI_ADAPTER_OPEN, + HPI_ERROR_BAD_ADAPTER_NUMBER); uncopied_bytes = copy_to_user(puhr, hr, sizeof(hr->h)); diff --git a/trunk/sound/pci/rme9652/hdspm.c b/trunk/sound/pci/rme9652/hdspm.c index 6edc67ced905..af130ee0c45d 100644 --- a/trunk/sound/pci/rme9652/hdspm.c +++ b/trunk/sound/pci/rme9652/hdspm.c @@ -521,7 +521,6 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) /* revisions >= 230 indicate AES32 card */ -#define HDSPM_MADI_ANCIENT_REV 204 #define HDSPM_MADI_OLD_REV 207 #define HDSPM_MADI_REV 210 #define HDSPM_RAYDAT_REV 211 @@ -1218,22 +1217,6 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) rate = 0; break; } - - /* QS and DS rates normally can not be detected - * automatically by the card. Only exception is MADI - * in 96k frame mode. - * - * So if we read SS values (32 .. 48k), check for - * user-provided DS/QS bits in the control register - * and multiply the base frequency accordingly. - */ - if (rate <= 48000) { - if (hdspm->control_register & HDSPM_QuadSpeed) - rate *= 4; - else if (hdspm->control_register & - HDSPM_DoubleSpeed) - rate *= 2; - } } break; } @@ -3432,91 +3415,6 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, return change; } -#define HDSPM_MADI_SPEEDMODE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_madi_speedmode, \ - .get = snd_hdspm_get_madi_speedmode, \ - .put = snd_hdspm_put_madi_speedmode \ -} - -static int hdspm_madi_speedmode(struct hdspm *hdspm) -{ - if (hdspm->control_register & HDSPM_QuadSpeed) - return 2; - if (hdspm->control_register & HDSPM_DoubleSpeed) - return 1; - return 0; -} - -static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode) -{ - hdspm->control_register &= ~(HDSPM_DoubleSpeed | HDSPM_QuadSpeed); - switch (mode) { - case 0: - break; - case 1: - hdspm->control_register |= HDSPM_DoubleSpeed; - break; - case 2: - hdspm->control_register |= HDSPM_QuadSpeed; - break; - } - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - - return 0; -} - -static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { "Single", "Double", "Quad" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - -static int snd_hdspm_get_madi_speedmode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.enumerated.item[0] = hdspm_madi_speedmode(hdspm); - spin_unlock_irq(&hdspm->lock); - return 0; -} - -static int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0]; - if (val < 0) - val = 0; - if (val > 2) - val = 2; - spin_lock_irq(&hdspm->lock); - change = val != hdspm_madi_speedmode(hdspm); - hdspm_set_madi_speedmode(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} #define HDSPM_MIXER(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ @@ -4391,8 +4289,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { HDSPM_TX_64("TX 64 channels mode", 0), HDSPM_C_TMS("Clear Track Marker", 0), HDSPM_SAFE_MODE("Safe Mode", 0), - HDSPM_INPUT_SELECT("Input Select", 0), - HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) + HDSPM_INPUT_SELECT("Input Select", 0) }; @@ -4405,8 +4302,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_madiface[] = { HDSPM_SYNC_CHECK("MADI SyncCheck", 0), HDSPM_TX_64("TX 64 channels mode", 0), HDSPM_C_TMS("Clear Track Marker", 0), - HDSPM_SAFE_MODE("Safe Mode", 0), - HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) + HDSPM_SAFE_MODE("Safe Mode", 0) }; static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { @@ -6485,7 +6381,6 @@ static int __devinit snd_hdspm_create(struct snd_card *card, switch (hdspm->firmware_rev) { case HDSPM_MADI_REV: case HDSPM_MADI_OLD_REV: - case HDSPM_MADI_ANCIENT_REV: hdspm->io_type = MADI; hdspm->card_name = "RME MADI"; hdspm->midiPorts = 3; diff --git a/trunk/sound/soc/txx9/txx9aclc.c b/trunk/sound/soc/txx9/txx9aclc.c index 3de99af8cb82..34aa972669ed 100644 --- a/trunk/sound/soc/txx9/txx9aclc.c +++ b/trunk/sound/soc/txx9/txx9aclc.c @@ -290,7 +290,6 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm) static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd) { - struct snd_card *card = rtd->card->snd_card; struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_pcm *pcm = rtd->pcm; struct platform_device *pdev = to_platform_device(dai->platform->dev); diff --git a/trunk/tools/power/x86/turbostat/turbostat.c b/trunk/tools/power/x86/turbostat/turbostat.c index 8b2d37b59c9e..6d8ef4a3a9b5 100644 --- a/trunk/tools/power/x86/turbostat/turbostat.c +++ b/trunk/tools/power/x86/turbostat/turbostat.c @@ -128,34 +128,34 @@ unsigned long long get_msr(int cpu, off_t offset) void print_header(void) { if (show_pkg) - fprintf(stderr, "pk"); + fprintf(stderr, "pkg "); if (show_core) - fprintf(stderr, " cr"); + fprintf(stderr, "core"); if (show_cpu) fprintf(stderr, " CPU"); if (do_nhm_cstates) - fprintf(stderr, " %%c0 "); + fprintf(stderr, " %%c0 "); if (has_aperf) - fprintf(stderr, " GHz"); + fprintf(stderr, " GHz"); fprintf(stderr, " TSC"); if (do_nhm_cstates) - fprintf(stderr, " %%c1"); + fprintf(stderr, " %%c1 "); if (do_nhm_cstates) - fprintf(stderr, " %%c3"); + fprintf(stderr, " %%c3 "); if (do_nhm_cstates) - fprintf(stderr, " %%c6"); + fprintf(stderr, " %%c6 "); if (do_snb_cstates) - fprintf(stderr, " %%c7"); + fprintf(stderr, " %%c7 "); if (do_snb_cstates) - fprintf(stderr, " %%pc2"); + fprintf(stderr, " %%pc2 "); if (do_nhm_cstates) - fprintf(stderr, " %%pc3"); + fprintf(stderr, " %%pc3 "); if (do_nhm_cstates) - fprintf(stderr, " %%pc6"); + fprintf(stderr, " %%pc6 "); if (do_snb_cstates) - fprintf(stderr, " %%pc7"); + fprintf(stderr, " %%pc7 "); if (extra_msr_offset) - fprintf(stderr, " MSR 0x%x ", extra_msr_offset); + fprintf(stderr, " MSR 0x%x ", extra_msr_offset); putc('\n', stderr); } @@ -194,14 +194,14 @@ void print_cnt(struct counters *p) /* topology columns, print blanks on 1st (average) line */ if (p == cnt_average) { if (show_pkg) - fprintf(stderr, " "); + fprintf(stderr, " "); if (show_core) fprintf(stderr, " "); if (show_cpu) fprintf(stderr, " "); } else { if (show_pkg) - fprintf(stderr, "%d", p->pkg); + fprintf(stderr, "%4d", p->pkg); if (show_core) fprintf(stderr, "%4d", p->core); if (show_cpu) @@ -241,22 +241,22 @@ void print_cnt(struct counters *p) if (!skip_c1) fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc); else - fprintf(stderr, " ****"); + fprintf(stderr, " ****"); } if (do_nhm_cstates) - fprintf(stderr, " %6.2f", 100.0 * p->c3/p->tsc); + fprintf(stderr, "%7.2f", 100.0 * p->c3/p->tsc); if (do_nhm_cstates) - fprintf(stderr, " %6.2f", 100.0 * p->c6/p->tsc); + fprintf(stderr, "%7.2f", 100.0 * p->c6/p->tsc); if (do_snb_cstates) - fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc); + fprintf(stderr, "%7.2f", 100.0 * p->c7/p->tsc); if (do_snb_cstates) - fprintf(stderr, " %5.2f", 100.0 * p->pc2/p->tsc); + fprintf(stderr, "%7.2f", 100.0 * p->pc2/p->tsc); if (do_nhm_cstates) - fprintf(stderr, " %5.2f", 100.0 * p->pc3/p->tsc); + fprintf(stderr, "%7.2f", 100.0 * p->pc3/p->tsc); if (do_nhm_cstates) - fprintf(stderr, " %5.2f", 100.0 * p->pc6/p->tsc); + fprintf(stderr, "%7.2f", 100.0 * p->pc6/p->tsc); if (do_snb_cstates) - fprintf(stderr, " %5.2f", 100.0 * p->pc7/p->tsc); + fprintf(stderr, "%7.2f", 100.0 * p->pc7/p->tsc); if (extra_msr_offset) fprintf(stderr, " 0x%016llx", p->extra_msr); putc('\n', stderr); diff --git a/trunk/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/trunk/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index 33c5c7ee148f..2618ef2ba31f 100644 --- a/trunk/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/trunk/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c @@ -137,6 +137,7 @@ void cmdline(int argc, char **argv) void validate_cpuid(void) { unsigned int eax, ebx, ecx, edx, max_level; + char brand[16]; unsigned int fms, family, model, stepping; eax = ebx = ecx = edx = 0; @@ -159,8 +160,8 @@ void validate_cpuid(void) model += ((fms >> 16) & 0xf) << 4; if (verbose > 1) - printf("CPUID %d levels family:model:stepping " - "0x%x:%x:%x (%d:%d:%d)\n", max_level, + printf("CPUID %s %d levels family:model:stepping " + "0x%x:%x:%x (%d:%d:%d)\n", brand, max_level, family, model, stepping, family, model, stepping); if (!(edx & (1 << 5))) {