diff options
458 files changed, 5522 insertions, 3772 deletions
diff --git a/Documentation/Changes b/Documentation/Changes index 5f4828a034e..b1758088527 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -2,13 +2,7 @@ Intro ===== This document is designed to provide a list of the minimum levels of -software necessary to run the 2.6 kernels, as well as provide brief -instructions regarding any other "Gotchas" users may encounter when -trying life on the Bleeding Edge. If upgrading from a pre-2.4.x -kernel, please consult the Changes file included with 2.4.x kernels for -additional information; most of that information will not be repeated -here. Basically, this document assumes that your system is already -functional and running at least 2.4.x kernels. +software necessary to run the 3.0 kernels. This document is originally based on my "Changes" file for 2.0.x kernels and therefore owes credit to the same people as that file (Jared Mauch, @@ -22,11 +16,10 @@ Upgrade to at *least* these software revisions before thinking you've encountered a bug! If you're unsure what version you're currently running, the suggested command should tell you. -Again, keep in mind that this list assumes you are already -functionally running a Linux 2.4 kernel. Also, not all tools are -necessary on all systems; obviously, if you don't have any ISDN -hardware, for example, you probably needn't concern yourself with -isdn4k-utils. +Again, keep in mind that this list assumes you are already functionally +running a Linux kernel. Also, not all tools are necessary on all +systems; obviously, if you don't have any ISDN hardware, for example, +you probably needn't concern yourself with isdn4k-utils. o Gnu C 3.2 # gcc --version o Gnu make 3.80 # make --version @@ -114,12 +107,12 @@ Ksymoops If the unthinkable happens and your kernel oopses, you may need the ksymoops tool to decode it, but in most cases you don't. -In the 2.6 kernel it is generally preferred to build the kernel with -CONFIG_KALLSYMS so that it produces readable dumps that can be used as-is -(this also produces better output than ksymoops). -If for some reason your kernel is not build with CONFIG_KALLSYMS and -you have no way to rebuild and reproduce the Oops with that option, then -you can still decode that Oops with ksymoops. +It is generally preferred to build the kernel with CONFIG_KALLSYMS so +that it produces readable dumps that can be used as-is (this also +produces better output than ksymoops). If for some reason your kernel +is not build with CONFIG_KALLSYMS and you have no way to rebuild and +reproduce the Oops with that option, then you can still decode that Oops +with ksymoops. Module-Init-Tools ----------------- @@ -261,8 +254,8 @@ needs to be recompiled or (preferably) upgraded. NFS-utils --------- -In 2.4 and earlier kernels, the nfs server needed to know about any -client that expected to be able to access files via NFS. This +In ancient (2.4 and earlier) kernels, the nfs server needed to know +about any client that expected to be able to access files via NFS. This information would be given to the kernel by "mountd" when the client mounted the filesystem, or by "exportfs" at system startup. exportfs would take information about active clients from /var/lib/nfs/rmtab. @@ -272,11 +265,11 @@ which is not always easy, particularly when trying to implement fail-over. Even when the system is working well, rmtab suffers from getting lots of old entries that never get removed. -With 2.6 we have the option of having the kernel tell mountd when it -gets a request from an unknown host, and mountd can give appropriate -export information to the kernel. This removes the dependency on -rmtab and means that the kernel only needs to know about currently -active clients. +With modern kernels we have the option of having the kernel tell mountd +when it gets a request from an unknown host, and mountd can give +appropriate export information to the kernel. This removes the +dependency on rmtab and means that the kernel only needs to know about +currently active clients. To enable this new functionality, you need to: diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 58b0bf91783..fa6e25b94a5 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -680,8 +680,8 @@ ones already enabled by DEBUG. Chapter 14: Allocating memory The kernel provides the following general purpose memory allocators: -kmalloc(), kzalloc(), kcalloc(), and vmalloc(). Please refer to the API -documentation for further information about them. +kmalloc(), kzalloc(), kcalloc(), vmalloc(), and vzalloc(). Please refer to +the API documentation for further information about them. The preferred form for passing a size of a struct is the following: diff --git a/Documentation/arm/Booting b/Documentation/arm/Booting index 4e686a2ed91..a341d87d276 100644 --- a/Documentation/arm/Booting +++ b/Documentation/arm/Booting @@ -164,3 +164,8 @@ In either case, the following conditions must be met: - The boot loader is expected to call the kernel image by jumping directly to the first instruction of the kernel image. + On CPUs supporting the ARM instruction set, the entry must be + made in ARM state, even for a Thumb-2 kernel. + + On CPUs supporting only the Thumb instruction set such as + Cortex-M class CPUs, the entry must be made in Thumb state. diff --git a/Documentation/arm/SH-Mobile/zboot-rom-sdhi.txt b/Documentation/arm/SH-Mobile/zboot-rom-sdhi.txt new file mode 100644 index 00000000000..441959846e1 --- /dev/null +++ b/Documentation/arm/SH-Mobile/zboot-rom-sdhi.txt @@ -0,0 +1,42 @@ +ROM-able zImage boot from eSD +----------------------------- + +An ROM-able zImage compiled with ZBOOT_ROM_SDHI may be written to eSD and +SuperH Mobile ARM will to boot directly from the SDHI hardware block. + +This is achieved by the mask ROM loading the first portion of the image into +MERAM and then jumping to it. This portion contains loader code which +copies the entire image to SDRAM and jumps to it. From there the zImage +boot code proceeds as normal, uncompressing the image into its final +location and then jumping to it. + +This code has been tested on an mackerel board using the developer 1A eSD +boot mode which is configured using the following jumper settings. + + 8 7 6 5 4 3 2 1 + x|x|x|x| |x|x| +S4 -+-+-+-+-+-+-+- + | | | |x| | |x on + +The eSD card needs to be present in SDHI slot 1 (CN7). +As such S1 and S33 also need to be configured as per +the notes in arch/arm/mach-shmobile/board-mackerel.c. + +A partial zImage must be written to physical partition #1 (boot) +of the eSD at sector 0 in vrl4 format. A utility vrl4 is supplied to +accomplish this. + +e.g. + vrl4 < zImage | dd of=/dev/sdX bs=512 count=17 + +A full copy of _the same_ zImage should be written to physical partition #1 +(boot) of the eSD at sector 0. This should _not_ be in vrl4 format. + + vrl4 < zImage | dd of=/dev/sdX bs=512 + +Note: The commands above assume that the physical partition has been +switched. No such facility currently exists in the Linux Kernel. + +Physical partitions are described in the eSD specification. At the time of +writing they are not the same as partitions that are typically configured +using fdisk and visible through /proc/partitions diff --git a/Documentation/cgroups/blkio-controller.txt b/Documentation/cgroups/blkio-controller.txt index cd45c8ea746..84f0a15fc21 100644 --- a/Documentation/cgroups/blkio-controller.txt +++ b/Documentation/cgroups/blkio-controller.txt @@ -77,7 +77,7 @@ Throttling/Upper Limit policy - Specify a bandwidth rate on particular device for root group. The format for policy is "<major>:<minor> <byes_per_second>". - echo "8:16 1048576" > /sys/fs/cgroup/blkio/blkio.read_bps_device + echo "8:16 1048576" > /sys/fs/cgroup/blkio/blkio.throttle.read_bps_device Above will put a limit of 1MB/second on reads happening for root group on device having major/minor number 8:16. @@ -90,7 +90,7 @@ Throttling/Upper Limit policy 1024+0 records out 4194304 bytes (4.2 MB) copied, 4.0001 s, 1.0 MB/s - Limits for writes can be put using blkio.write_bps_device file. + Limits for writes can be put using blkio.throttle.write_bps_device file. Hierarchical Cgroups ==================== @@ -286,28 +286,28 @@ Throttling/Upper limit policy files specified in bytes per second. Rules are per deivce. Following is the format. - echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.read_bps_device + echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.read_bps_device - blkio.throttle.write_bps_device - Specifies upper limit on WRITE rate to the device. IO rate is specified in bytes per second. Rules are per deivce. Following is the format. - echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.write_bps_device + echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.write_bps_device - blkio.throttle.read_iops_device - Specifies upper limit on READ rate from the device. IO rate is specified in IO per second. Rules are per deivce. Following is the format. - echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.read_iops_device + echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.read_iops_device - blkio.throttle.write_iops_device - Specifies upper limit on WRITE rate to the device. IO rate is specified in io per second. Rules are per deivce. Following is the format. - echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.write_iops_device + echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.write_iops_device Note: If both BW and IOPS rules are specified for a device, then IO is subjectd to both the constraints. diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt new file mode 100644 index 00000000000..1c044eb320c --- /dev/null +++ b/Documentation/devicetree/bindings/arm/pmu.txt @@ -0,0 +1,21 @@ +* ARM Performance Monitor Units + +ARM cores often have a PMU for counting cpu and cache events like cache misses +and hits. The interface to the PMU is part of the ARM ARM. The ARM PMU +representation in the device tree should be done as under:- + +Required properties: + +- compatible : should be one of + "arm,cortex-a9-pmu" + "arm,cortex-a8-pmu" + "arm,arm1176-pmu" + "arm,arm1136-pmu" +- interrupts : 1 combined interrupt or 1 per core. + +Example: + +pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <100 101>; +}; diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 72e238465b0..b1c921c2751 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -583,3 +583,25 @@ Why: Superseded by the UVCIOC_CTRL_QUERY ioctl. Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com> ---------------------------- + +What: For VIDIOC_S_FREQUENCY the type field must match the device node's type. + If not, return -EINVAL. +When: 3.2 +Why: It makes no sense to switch the tuner to radio mode by calling + VIDIOC_S_FREQUENCY on a video node, or to switch the tuner to tv mode by + calling VIDIOC_S_FREQUENCY on a radio node. This is the first step of a + move to more consistent handling of tv and radio tuners. +Who: Hans Verkuil <hans.verkuil@cisco.com> + +---------------------------- + +What: Opening a radio device node will no longer automatically switch the + tuner mode from tv to radio. +When: 3.3 +Why: Just opening a V4L device should not change the state of the hardware + like that. It's very unexpected and against the V4L spec. Instead, you + switch to radio mode by calling VIDIOC_S_FREQUENCY. This is the second + and last step of the move to consistent handling of tv and radio tuners. +Who: Hans Verkuil <hans.verkuil@cisco.com> + +---------------------------- diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt index a167ab876c3..7cc6bf2871e 100644 --- a/Documentation/filesystems/caching/netfs-api.txt +++ b/Documentation/filesystems/caching/netfs-api.txt @@ -673,6 +673,22 @@ storage request to complete, or it may attempt to cancel the storage request - in which case the page will not be stored in the cache this time. +BULK INODE PAGE UNCACHE +----------------------- + +A convenience routine is provided to perform an uncache on all the pages +attached to an inode. This assumes that the pages on the inode correspond on a +1:1 basis with the pages in the cache. + + void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, + struct inode *inode); + +This takes the netfs cookie that the pages were cached with and the inode that +the pages are attached to. This function will wait for pages to finish being +written to the cache and for the cache to finish with the page generally. No +error is returned. + + ========================== INDEX AND DATA FILE UPDATE ========================== diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt index d5c0cef38a7..873a2ab2e9f 100644 --- a/Documentation/filesystems/nilfs2.txt +++ b/Documentation/filesystems/nilfs2.txt @@ -40,7 +40,6 @@ Features which NILFS2 does not support yet: - POSIX ACLs - quotas - fsck - - resize - defragmentation Mount options diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index fd248a31821..aa47be71df4 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2015,6 +2015,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. the default. off: Turn ECRC off on: Turn ECRC on. + realloc reallocate PCI resources if allocations done by BIOS + are erroneous. pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power Management. diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 1565eefd6fd..61815483efa 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -534,6 +534,8 @@ Events that are never propagated by the driver: 0x2404 System is waking up from hibernation to undock 0x2405 System is waking up from hibernation to eject bay 0x5010 Brightness level changed/control event +0x6000 KEYBOARD: Numlock key pressed +0x6005 KEYBOARD: Fn key pressed (TO BE VERIFIED) Events that are propagated by the driver to userspace: @@ -545,6 +547,8 @@ Events that are propagated by the driver to userspace: 0x3006 Bay hotplug request (hint to power up SATA link when the optical drive tray is ejected) 0x4003 Undocked (see 0x2x04), can sleep again +0x4010 Docked into hotplug port replicator (non-ACPI dock) +0x4011 Undocked from hotplug port replicator (non-ACPI dock) 0x500B Tablet pen inserted into its storage bay 0x500C Tablet pen removed from its storage bay 0x6011 ALARM: battery is too hot @@ -552,6 +556,7 @@ Events that are propagated by the driver to userspace: 0x6021 ALARM: a sensor is too hot 0x6022 ALARM: a sensor is extremely hot 0x6030 System thermal table changed +0x6040 Nvidia Optimus/AC adapter related (TO BE VERIFIED) Battery nearly empty alarms are a last resort attempt to get the operating system to hibernate or shutdown cleanly (0x2313), or shutdown diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index d3d653a5f9b..bfe924217f2 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -346,7 +346,7 @@ tcp_orphan_retries - INTEGER when RTO retransmissions remain unacknowledged. See tcp_retries2 for more details. - The default value is 7. + The default value is 8. If your machine is a loaded WEB server, you should think about lowering this value, such sockets may consume significant resources. Cf. tcp_max_orphans. diff --git a/Documentation/spinlocks.txt b/Documentation/spinlocks.txt index 2e3c64b1a6a..9dbe885ecd8 100644 --- a/Documentation/spinlocks.txt +++ b/Documentation/spinlocks.txt @@ -13,18 +13,8 @@ static DEFINE_SPINLOCK(xxx_lock); The above is always safe. It will disable interrupts _locally_, but the spinlock itself will guarantee the global lock, so it will guarantee that there is only one thread-of-control within the region(s) protected by that -lock. This works well even under UP. The above sequence under UP -essentially is just the same as doing - - unsigned long flags; - - save_flags(flags); cli(); - ... critical section ... - restore_flags(flags); - -so the code does _not_ need to worry about UP vs SMP issues: the spinlocks -work correctly under both (and spinlocks are actually more efficient on -architectures that allow doing the "save_flags + cli" in one operation). +lock. This works well even under UP also, so the code does _not_ need to +worry about UP vs SMP issues: the spinlocks work correctly under both. NOTE! Implications of spin_locks for memory are further described in: @@ -36,27 +26,7 @@ The above is usually pretty simple (you usually need and want only one spinlock for most things - using more than one spinlock can make things a lot more complex and even slower and is usually worth it only for sequences that you _know_ need to be split up: avoid it at all cost if you -aren't sure). HOWEVER, it _does_ mean that if you have some code that does - - cli(); - .. critical section .. - sti(); - -and another sequence that does - - spin_lock_irqsave(flags); - .. critical section .. - spin_unlock_irqrestore(flags); - -then they are NOT mutually exclusive, and the critical regions can happen -at the same time on two different CPU's. That's fine per se, but the -critical regions had better be critical for different things (ie they -can't stomp on each other). - -The above is a problem mainly if you end up mixing code - for example the -routines in ll_rw_block() tend to use cli/sti to protect the atomicity of -their actions, and if a driver uses spinlocks instead then you should -think about issues like the above. +aren't sure). This is really the only really hard part about spinlocks: once you start using spinlocks they tend to expand to areas you might not have noticed @@ -120,11 +90,10 @@ Lesson 3: spinlocks revisited. The single spin-lock primitives above are by no means the only ones. They are the most safe ones, and the ones that work under all circumstances, -but partly _because_ they are safe they are also fairly slow. They are -much faster than a generic global cli/sti pair, but slower than they'd -need to be, because they do have to disable interrupts (which is just a -single instruction on a x86, but it's an expensive one - and on other -architectures it can be worse). +but partly _because_ they are safe they are also fairly slow. They are slower +than they'd need to be, because they do have to disable interrupts +(which is just a single instruction on a x86, but it's an expensive one - +and on other architectures it can be worse). If you have a case where you have to protect a data structure across several CPU's and you want to use spinlocks you can potentially use diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index 9b7221a86df..7c3a8801b7c 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -674,7 +674,7 @@ Protocol: 2.10+ Field name: init_size Type: read -Offset/size: 0x25c/4 +Offset/size: 0x260/4 This field indicates the amount of linear contiguous memory starting at the kernel runtime start address that the kernel needs before it diff --git a/MAINTAINERS b/MAINTAINERS index ae563fad227..187282da921 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -594,6 +594,16 @@ S: Maintained F: arch/arm/lib/floppydma.S F: arch/arm/include/asm/floppy.h +ARM PMU PROFILING AND DEBUGGING +M: Will Deacon <will.deacon@arm.com> +S: Maintained +F: arch/arm/kernel/perf_event* +F: arch/arm/oprofile/common.c +F: arch/arm/kernel/pmu.c +F: arch/arm/include/asm/pmu.h +F: arch/arm/kernel/hw_breakpoint.c +F: arch/arm/include/asm/hw_breakpoint.h + ARM PORT M: Russell King <linux@arm.linux.org.uk> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -2197,7 +2207,7 @@ F: drivers/acpi/dock.c DOCUMENTATION M: Randy Dunlap <rdunlap@xenotime.net> L: linux-doc@vger.kernel.org -T: quilt oss.oracle.com/~rdunlap/kernel-doc-patches/current/ +T: quilt http://userweb.kernel.org/~rdunlap/kernel-doc-patches/current/ S: Maintained F: Documentation/ @@ -4982,7 +4992,7 @@ F: drivers/power/power_supply* PNP SUPPORT M: Adam Belay <abelay@mit.edu> -M: Bjorn Helgaas <bjorn.helgaas@hp.com> +M: Bjorn Helgaas <bhelgaas@google.com> S: Maintained F: drivers/pnp/ @@ -6733,6 +6743,7 @@ F: fs/fat/ VIDEOBUF2 FRAMEWORK M: Pawel Osciak <pawel@osciak.com> M: Marek Szyprowski <m.szyprowski@samsung.com> +M: Kyungmin Park <kyungmin.park@samsung.com> L: linux-media@vger.kernel.org S: Maintained F: drivers/media/video/videobuf2-* @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 0 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Sneaky Weasel # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9adc278a22a..84fda2bebd7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -37,6 +37,9 @@ config ARM Europe. There is an ARM Linux project with a web page at <http://www.arm.linux.org.uk/>. +config ARM_HAS_SG_CHAIN + bool + config HAVE_PWM bool @@ -1346,7 +1349,6 @@ config SMP_ON_UP config HAVE_ARM_SCU bool - depends on SMP help This option enables support for the ARM system coherency unit @@ -1715,17 +1717,34 @@ config ZBOOT_ROM Say Y here if you intend to execute your compressed kernel image (zImage) directly from ROM or flash. If unsure, say N. +choice + prompt "Include SD/MMC loader in zImage (EXPERIMENTAL)" + depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL + default ZBOOT_ROM_NONE + help + Include experimental SD/MMC loading code in the ROM-able zImage. + With this enabled it is possible to write the the ROM-able zImage + kernel image to an MMC or SD card and boot the kernel straight + from the reset vector. At reset the processor Mask ROM will load + the first part of the the ROM-able zImage which in turn loads the + rest the kernel image to RAM. + +config ZBOOT_ROM_NONE + bool "No SD/MMC loader in zImage (EXPERIMENTAL)" + help + Do not load image from SD or MMC + config ZBOOT_ROM_MMCIF bool "Include MMCIF loader in zImage (EXPERIMENTAL)" - depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL help - Say Y here to include experimental MMCIF loading code in the - ROM-able zImage. With this enabled it is possible to write the - the ROM-able zImage kernel image to an MMC card and boot the - kernel straight from the reset vector. At reset the processor - Mask ROM will load the first part of the the ROM-able zImage - which in turn loads the rest the kernel image to RAM using the - MMCIF hardware block. + Load image from MMCIF hardware block. + +config ZBOOT_ROM_SH_MOBILE_SDHI + bool "Include SuperH Mobile SDHI loader in zImage (EXPERIMENTAL)" + help + Load image from SDHI hardware block + +endchoice config CMDLINE string "Default kernel command string" diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 23aad072230..0c74a6fab95 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -6,13 +6,19 @@ OBJS = -# Ensure that mmcif loader code appears early in the image +# Ensure that MMCIF loader code appears early in the image # to minimise that number of bocks that have to be read in # order to load it. ifeq ($(CONFIG_ZBOOT_ROM_MMCIF),y) -ifeq ($(CONFIG_ARCH_SH7372),y) OBJS += mmcif-sh7372.o endif + +# Ensure that SDHI loader code appears early in the image +# to minimise that number of bocks that have to be read in +# order to load it. +ifeq ($(CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI),y) +OBJS += sdhi-shmobile.o +OBJS += sdhi-sh7372.o endif AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET) diff --git a/arch/arm/boot/compressed/head-shmobile.S b/arch/arm/boot/compressed/head-shmobile.S index c943d2e7da9..fe3719b516f 100644 --- a/arch/arm/boot/compressed/head-shmobile.S +++ b/arch/arm/boot/compressed/head-shmobile.S @@ -25,14 +25,14 @@ /* load board-specific initialization code */ #include <mach/zboot.h> -#ifdef CONFIG_ZBOOT_ROM_MMCIF - /* Load image from MMC */ - adr sp, __tmp_stack + 128 +#if defined(CONFIG_ZBOOT_ROM_MMCIF) || defined(CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI) + /* Load image from MMC/SD */ + adr sp, __tmp_stack + 256 ldr r0, __image_start ldr r1, __image_end subs r1, r1, r0 ldr r0, __load_base - bl mmcif_loader + bl mmc_loader /* Jump to loaded code */ ldr r0, __loaded @@ -51,9 +51,9 @@ __loaded: .long __continue .align __tmp_stack: - .space 128 + .space 256 __continue: -#endif /* CONFIG_ZBOOT_ROM_MMCIF */ +#endif /* CONFIG_ZBOOT_ROM_MMC || CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI */ b 1f __atags:@ tag #1 diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 940b2017810..e95a5989602 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -353,7 +353,8 @@ not_relocated: mov r0, #0 mov r0, #0 @ must be zero mov r1, r7 @ restore architecture number mov r2, r8 @ restore atags pointer - mov pc, r4 @ call kernel + ARM( mov pc, r4 ) @ call kernel + THUMB( bx r4 ) @ entry point is always ARM .align 2 .type LC0, #object diff --git a/arch/arm/boot/compressed/mmcif-sh7372.c b/arch/arm/boot/compressed/mmcif-sh7372.c index 7453c8337b8..b6f61d9a5a1 100644 --- a/arch/arm/boot/compressed/mmcif-sh7372.c +++ b/arch/arm/boot/compressed/mmcif-sh7372.c @@ -40,7 +40,7 @@ * to an MMC card * # dd if=vrl4.out of=/dev/sdx bs=512 seek=1 */ -asmlinkage void mmcif_loader(unsigned char *buf, unsigned long len) +asmlinkage void mmc_loader(unsigned char *buf, unsigned long len) { mmc_init_progress(); mmc_update_progress(MMC_PROGRESS_ENTER); diff --git a/arch/arm/boot/compressed/sdhi-sh7372.c b/arch/arm/boot/compressed/sdhi-sh7372.c new file mode 100644 index 00000000000..d403a8b24d7 --- /dev/null +++ b/arch/arm/boot/compressed/sdhi-sh7372.c @@ -0,0 +1,95 @@ +/* + * SuperH Mobile SDHI + * + * Copyright (C) 2010 Magnus Damm + * Copyright (C) 2010 Kuninori Morimoto + * Copyright (C) 2010 Simon Horman + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Parts inspired by u-boot + */ + +#include <linux/io.h> +#include <mach/mmc.h> +#include <linux/mmc/boot.h> +#include <linux/mmc/tmio.h> + +#include "sdhi-shmobile.h" + +#define PORT179CR 0xe60520b3 +#define PORT180CR 0xe60520b4 +#define PORT181CR 0xe60520b5 +#define PORT182CR 0xe60520b6 +#define PORT183CR 0xe60520b7 +#define PORT184CR 0xe60520b8 + +#define SMSTPCR3 0xe615013c + +#define CR_INPUT_ENABLE 0x10 +#define CR_FUNCTION1 0x01 + +#define SDHI1_BASE (void __iomem *)0xe6860000 +#define SDHI_BASE SDHI1_BASE + +/* SuperH Mobile SDHI loader + * + * loads the zImage from an SD card starting from block 0 + * on physical partition 1 + * + * The image must be start with a vrl4 header and + * the zImage must start at offset 512 of the image. That is, + * at block 1 (=byte 512) of physical partition 1 + * + * Use the following line to write the vrl4 formated zImage + * to an SD card + * # dd if=vrl4.out of=/dev/sdx bs=512 + */ +asmlinkage void mmc_loader(unsigned short *buf, unsigned long len) +{ + int high_capacity; + + mmc_init_progress(); + + mmc_update_progress(MMC_PROGRESS_ENTER); + /* Initialise SDHI1 */ + /* PORT184CR: GPIO_FN_SDHICMD1 Control */ + __raw_writeb(CR_FUNCTION1, PORT184CR); + /* PORT179CR: GPIO_FN_SDHICLK1 Control */ + __raw_writeb(CR_INPUT_ENABLE|CR_FUNCTION1, PORT179CR); + /* PORT181CR: GPIO_FN_SDHID1_3 Control */ + __raw_writeb(CR_FUNCTION1, PORT183CR); + /* PORT182CR: GPIO_FN_SDHID1_2 Control */ + __raw_writeb(CR_FUNCTION1, PORT182CR); + /* PORT183CR: GPIO_FN_SDHID1_1 Control */ + __raw_writeb(CR_FUNCTION1, PORT181CR); + /* PORT180CR: GPIO_FN_SDHID1_0 Control */ + __raw_writeb(CR_FUNCTION1, PORT180CR); + + /* Enable clock to SDHI1 hardware block */ + __raw_writel(__raw_readl(SMSTPCR3) & ~(1 << 13), SMSTPCR3); + + /* setup SDHI hardware */ + mmc_update_progress(MMC_PROGRESS_INIT); + high_capacity = sdhi_boot_init(SDHI_BASE); + if (high_capacity < 0) + goto err; + + mmc_update_progress(MMC_PROGRESS_LOAD); + /* load kernel */ + if (sdhi_boot_do_read(SDHI_BASE, high_capacity, + 0, /* Kernel is at block 1 */ + (len + TMIO_BBS - 1) / TMIO_BBS, buf)) + goto err; + + /* Disable clock to SDHI1 hardware block */ + __raw_writel(__raw_readl(SMSTPCR3) & (1 << 13), SMSTPCR3); + + mmc_update_progress(MMC_PROGRESS_DONE); + + return; +err: + for(;;); +} diff --git a/arch/arm/boot/compressed/sdhi-shmobile.c b/arch/arm/boot/compressed/sdhi-shmobile.c new file mode 100644 index 00000000000..bd3d4698095 --- /dev/null +++ b/arch/arm/boot/compressed/sdhi-shmobile.c @@ -0,0 +1,449 @@ +/* + * SuperH Mobile SDHI + * + * Copyright (C) 2010 Magnus Damm + * Copyright (C) 2010 Kuninori Morimoto + * Copyright (C) 2010 Simon Horman + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Parts inspired by u-boot + */ + +#include <linux/io.h> +#include <linux/mmc/host.h> +#include <linux/mmc/core.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/sd.h> +#include <linux/mmc/tmio.h> +#include <mach/sdhi.h> + +#define OCR_FASTBOOT (1<<29) +#define OCR_HCS (1<<30) +#define OCR_BUSY (1<<31) + +#define RESP_CMD12 0x00000030 + +static inline u16 sd_ctrl_read16(void __iomem *base, int addr) +{ + return __raw_readw(base + addr); +} + +static inline u32 sd_ctrl_read32(void __iomem *base, int addr) +{ + return __raw_readw(base + addr) | + __raw_readw(base + addr + 2) << 16; +} + +static inline void sd_ctrl_write16(void __iomem *base, int addr, u16 val) +{ + __raw_writew(val, base + addr); +} + +static inline void sd_ctrl_write32(void __iomem *base, int addr, u32 val) +{ + __raw_writew(val, base + addr); + __raw_writew(val >> 16, base + addr + 2); +} + +#define ALL_ERROR (TMIO_STAT_CMD_IDX_ERR | TMIO_STAT_CRCFAIL | \ + TMIO_STAT_STOPBIT_ERR | TMIO_STAT_DATATIMEOUT | \ + TMIO_STAT_RXOVERFLOW | TMIO_STAT_TXUNDERRUN | \ + TMIO_STAT_CMDTIMEOUT | TMIO_STAT_ILL_ACCESS | \ + TMIO_STAT_ILL_FUNC) + +static int sdhi_intr(void __iomem *base) +{ + unsigned long state = sd_ctrl_read32(base, CTL_STATUS); + + if (state & ALL_ERROR) { + sd_ctrl_write32(base, CTL_STATUS, ~ALL_ERROR); + sd_ctrl_write32(base, CTL_IRQ_MASK, + ALL_ERROR | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + return -EINVAL; + } + if (state & TMIO_STAT_CMDRESPEND) { + sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_CMDRESPEND); + sd_ctrl_write32(base, CTL_IRQ_MASK, + TMIO_STAT_CMDRESPEND | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + return 0; + } + if (state & TMIO_STAT_RXRDY) { + sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_RXRDY); + sd_ctrl_write32(base, CTL_IRQ_MASK, + TMIO_STAT_RXRDY | TMIO_STAT_TXUNDERRUN | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + return 0; + } + if (state & TMIO_STAT_DATAEND) { + sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_DATAEND); + sd_ctrl_write32(base, CTL_IRQ_MASK, + TMIO_STAT_DATAEND | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + return 0; + } + + return -EAGAIN; +} + +static int sdhi_boot_wait_resp_end(void __iomem *base) +{ + int err = -EAGAIN, timeout = 10000000; + + while (timeout--) { + err = sdhi_intr(base); + if (err != -EAGAIN) + break; + udelay(1); + } + + return err; +} + +/* SDHI_CLK_CTRL */ +#define CLK_MMC_ENABLE (1 << 8) +#define CLK_MMC_INIT (1 << 6) /* clk / 256 */ + +static void sdhi_boot_mmc_clk_stop(void __iomem *base) +{ + sd_ctrl_write16(base, CTL_CLK_AND_WAIT_CTL, 0x0000); + msleep(10); + sd_ctrl_write16(base, CTL_SD_CARD_CLK_CTL, ~CLK_MMC_ENABLE & + sd_ctrl_read16(base, CTL_SD_CARD_CLK_CTL)); + msleep(10); +} + +static void sdhi_boot_mmc_clk_start(void __iomem *base) +{ + sd_ctrl_write16(base, CTL_SD_CARD_CLK_CTL, CLK_MMC_ENABLE | + sd_ctrl_read16(base, CTL_SD_CARD_CLK_CTL)); + msleep(10); + sd_ctrl_write16(base, CTL_CLK_AND_WAIT_CTL, CLK_MMC_ENABLE); + msleep(10); +} + +static void sdhi_boot_reset(void __iomem *base) +{ + sd_ctrl_write16(base, CTL_RESET_SD, 0x0000); + msleep(10); + sd_ctrl_write16(base, CTL_RESET_SD, 0x0001); + msleep(10); +} + +/* Set MMC clock / power. + * Note: This controller uses a simple divider scheme therefore it cannot + * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as + * MMC wont run that fast, it has to be clocked at 12MHz which is the next + * slowest setting. + */ +static int sdhi_boot_mmc_set_ios(void __iomem *base, struct mmc_ios *ios) +{ + if (sd_ctrl_read32(base, CTL_STATUS) & TMIO_STAT_CMD_BUSY) + return -EBUSY; + + if (ios->clock) + sd_ctrl_write16(base, CTL_SD_CARD_CLK_CTL, + ios->clock | CLK_MMC_ENABLE); + + /* Power sequence - OFF -> ON -> UP */ + switch (ios->power_mode) { + case MMC_POWER_OFF: /* power down SD bus */ + sdhi_boot_mmc_clk_stop(base); + break; + case MMC_POWER_ON: /* power up SD bus */ + break; + case MMC_POWER_UP: /* start bus clock */ + sdhi_boot_mmc_clk_start(base); + break; + } + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + sd_ctrl_write16(base, CTL_SD_MEM_CARD_OPT, 0x80e0); + break; + case MMC_BUS_WIDTH_4: + sd_ctrl_write16(base, CTL_SD_MEM_CARD_OPT, 0x00e0); + break; + } + + /* Let things settle. delay taken from winCE driver */ + udelay(140); + + return 0; +} + +/* These are the bitmasks the tmio chip requires to implement the MMC response + * types. Note that R1 and R6 are the same in this scheme. */ +#define RESP_NONE 0x0300 +#define RESP_R1 0x0400 +#define RESP_R1B 0x0500 +#define RESP_R2 0x0600 +#define RESP_R3 0x0700 +#define DATA_PRESENT 0x0800 +#define TRANSFER_READ 0x1000 + +static int sdhi_boot_request(void __iomem *base, struct mmc_command *cmd) +{ + int err, c = cmd->opcode; + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: c |= RESP_NONE; break; + case MMC_RSP_R1: c |= RESP_R1; break; + case MMC_RSP_R1B: c |= RESP_R1B; break; + case MMC_RSP_R2: c |= RESP_R2; break; + case MMC_RSP_R3: c |= RESP_R3; break; + default: + return -EINVAL; + } + + /* No interrupts so this may not be cleared */ + sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_CMDRESPEND); + + sd_ctrl_write32(base, CTL_IRQ_MASK, TMIO_STAT_CMDRESPEND | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + sd_ctrl_write32(base, CTL_ARG_REG, cmd->arg); + sd_ctrl_write16(base, CTL_SD_CMD, c); + + + sd_ctrl_write32(base, CTL_IRQ_MASK, + ~(TMIO_STAT_CMDRESPEND | ALL_ERROR) & + sd_ctrl_read32(base, CTL_IRQ_MASK)); + + err = sdhi_boot_wait_resp_end(base); + if (err) + return err; + + cmd->resp[0] = sd_ctrl_read32(base, CTL_RESPONSE); + + return 0; +} + +static int sdhi_boot_do_read_single(void __iomem *base, int high_capacity, + unsigned long block, unsigned short *buf) +{ + int err, i; + + /* CMD17 - Read */ + { + struct mmc_command cmd; + + cmd.opcode = MMC_READ_SINGLE_BLOCK | \ + TRANSFER_READ | DATA_PRESENT; + if (high_capacity) + cmd.arg = block; + else + cmd.arg = block * TMIO_BBS; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + sd_ctrl_write32(base, CTL_IRQ_MASK, + ~(TMIO_STAT_DATAEND | TMIO_STAT_RXRDY | + TMIO_STAT_TXUNDERRUN) & + sd_ctrl_read32(base, CTL_IRQ_MASK)); + err = sdhi_boot_wait_resp_end(base); + if (err) + return err; + + sd_ctrl_write16(base, CTL_SD_XFER_LEN, TMIO_BBS); + for (i = 0; i < TMIO_BBS / sizeof(*buf); i++) + *buf++ = sd_ctrl_read16(base, RESP_CMD12); + + err = sdhi_boot_wait_resp_end(base); + if (err) + return err; + + return 0; +} + +int sdhi_boot_do_read(void __iomem *base, int high_capacity, + unsigned long offset, unsigned short count, + unsigned short *buf) +{ + unsigned long i; + int err = 0; + + for (i = 0; i < count; i++) { + err = sdhi_boot_do_read_single(base, high_capacity, offset + i, + buf + (i * TMIO_BBS / + sizeof(*buf))); + if (err) + return err; + } + + return 0; +} + +#define VOLTAGES (MMC_VDD_32_33 | MMC_VDD_33_34) + +int sdhi_boot_init(void __iomem *base) +{ + bool sd_v2 = false, sd_v1_0 = false; + unsigned short cid; + int err, high_capacity = 0; + + sdhi_boot_mmc_clk_stop(base); + sdhi_boot_reset(base); + + /* mmc0: clock 400000Hz busmode 1 powermode 2 cs 0 Vdd 21 width 0 timing 0 */ + { + struct mmc_ios ios; + ios.power_mode = MMC_POWER_ON; + ios.bus_width = MMC_BUS_WIDTH_1; + ios.clock = CLK_MMC_INIT; + err = sdhi_boot_mmc_set_ios(base, &ios); + if (err) + return err; + } + + /* CMD0 */ + { + struct mmc_command cmd; + msleep(1); + cmd.opcode = MMC_GO_IDLE_STATE; + cmd.arg = 0; + cmd.flags = MMC_RSP_NONE; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + msleep(2); + } + + /* CMD8 - Test for SD version 2 */ + { + struct mmc_command cmd; + cmd.opcode = SD_SEND_IF_COND; + cmd.arg = (VOLTAGES != 0) << 8 | 0xaa; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); /* Ignore error */ + if ((cmd.resp[0] & 0xff) == 0xaa) + sd_v2 = true; + } + + /* CMD55 - Get OCR (SD) */ + { + int timeout = 1000; + struct mmc_command cmd; + + cmd.arg = 0; + + do { + cmd.opcode = MMC_APP_CMD; + cmd.flags = MMC_RSP_R1; + cmd.arg = 0; + err = sdhi_boot_request(base, &cmd); + if (err) + break; + + cmd.opcode = SD_APP_OP_COND; + cmd.flags = MMC_RSP_R3; + cmd.arg = (VOLTAGES & 0xff8000); + if (sd_v2) + cmd.arg |= OCR_HCS; + cmd.arg |= OCR_FASTBOOT; + err = sdhi_boot_request(base, &cmd); + if (err) + break; + + msleep(1); + } while((!(cmd.resp[0] & OCR_BUSY)) && --timeout); + + if (!err && timeout) { + if (!sd_v2) + sd_v1_0 = true; + high_capacity = (cmd.resp[0] & OCR_HCS) == OCR_HCS; + } + } + + /* CMD1 - Get OCR (MMC) */ + if (!sd_v2 && !sd_v1_0) { + int timeout = 1000; + struct mmc_command cmd; + + do { + cmd.opcode = MMC_SEND_OP_COND; + cmd.arg = VOLTAGES | OCR_HCS; + cmd.flags = MMC_RSP_R3; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + + msleep(1); + } while((!(cmd.resp[0] & OCR_BUSY)) && --timeout); + + if (!timeout) + return -EAGAIN; + + high_capacity = (cmd.resp[0] & OCR_HCS) == OCR_HCS; + } + + /* CMD2 - Get CID */ + { + struct mmc_command cmd; + cmd.opcode = MMC_ALL_SEND_CID; + cmd.arg = 0; + cmd.flags = MMC_RSP_R2; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + /* CMD3 + * MMC: Set the relative address + * SD: Get the relative address + * Also puts the card into the standby state + */ + { + struct mmc_command cmd; + cmd.opcode = MMC_SET_RELATIVE_ADDR; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + cid = cmd.resp[0] >> 16; + } + + /* CMD9 - Get CSD */ + { + struct mmc_command cmd; + cmd.opcode = MMC_SEND_CSD; + cmd.arg = cid << 16; + cmd.flags = MMC_RSP_R2; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + /* CMD7 - Select the card */ + { + struct mmc_command cmd; + cmd.opcode = MMC_SELECT_CARD; + //cmd.arg = rca << 16; + cmd.arg = cid << 16; + //cmd.flags = MMC_RSP_R1B; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + /* CMD16 - Set the block size */ + { + struct mmc_command cmd; + cmd.opcode = MMC_SET_BLOCKLEN; + cmd.arg = TMIO_BBS; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + return high_capacity; +} diff --git a/arch/arm/boot/compressed/sdhi-shmobile.h b/arch/arm/boot/compressed/sdhi-shmobile.h new file mode 100644 index 00000000000..92eaa09f985 --- /dev/null +++ b/arch/arm/boot/compressed/sdhi-shmobile.h @@ -0,0 +1,11 @@ +#ifndef SDHI_MOBILE_H +#define SDHI_MOBILE_H + +#include <linux/compiler.h> + +int sdhi_boot_do_read(void __iomem *base, int high_capacity, + unsigned long offset, unsigned short count, + unsigned short *buf); +int sdhi_boot_init(void __iomem *base); + +#endif diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index e5681636626..595ecd290eb 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -79,6 +79,8 @@ struct dmabounce_device_info { struct dmabounce_pool large; rwlock_t lock; + + int (*needs_bounce)(struct device *, dma_addr_t, size_t); }; #ifdef STATS @@ -210,114 +212,91 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev, if (!dev || !dev->archdata.dmabounce) return NULL; if (dma_mapping_error(dev, dma_addr)) { - if (dev) - dev_err(dev, "Trying to %s invalid mapping\n", where); - else - pr_err("unknown device: Trying to %s invalid mapping\n", where); + dev_err(dev, "Trying to %s invalid mapping\n", where); return NULL; } return find_safe_buffer(dev->archdata.dmabounce, dma_addr); } -static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction dir) +static int needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) { - struct dmabounce_device_info *device_info = dev->archdata.dmabounce; - dma_addr_t dma_addr; - int needs_bounce = 0; - - if (device_info) - DO_STATS ( device_info->map_op_count++ ); - - dma_addr = virt_to_dma(dev, ptr); + if (!dev || !dev->archdata.dmabounce) + return 0; if (dev->dma_mask) { - unsigned long mask = *dev->dma_mask; - unsigned long limit; + unsigned long limit, mask = *dev->dma_mask; limit = (mask + 1) & ~mask; if (limit && size > limit) { dev_err(dev, "DMA mapping too big (requested %#x " "mask %#Lx)\n", size, *dev->dma_mask); - return ~0; + return -E2BIG; } - /* - * Figure out if we need to bounce from the DMA mask. - */ - needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask; + /* Figure out if we need to bounce from the DMA mask. */ + if ((dma_addr | (dma_addr + size - 1)) & ~mask) + return 1; } - if (device_info && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) { - struct safe_buffer *buf; + return !!dev->archdata.dmabounce->needs_bounce(dev, dma_addr, size); +} - buf = alloc_safe_buffer(device_info, ptr, size, dir); - if (buf == 0) { - dev_err(dev, "%s: unable to map unsafe buffer %p!\n", - __func__, ptr); - return 0; - } +static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction dir) +{ + struct dmabounce_device_info *device_info = dev->archdata.dmabounce; + struct safe_buffer *buf; - dev_dbg(dev, - "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", - __func__, buf->ptr, virt_to_dma(dev, buf->ptr), - buf->safe, buf->safe_dma_addr); + if (device_info) + DO_STATS ( device_info->map_op_count++ ); - if ((dir == DMA_TO_DEVICE) || - (dir == DMA_BIDIRECTIONAL)) { - dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", - __func__, ptr, buf->safe, size); - memcpy(buf->safe, ptr, size); - } - ptr = buf->safe; + buf = alloc_safe_buffer(device_info, ptr, size, dir); + if (buf == NULL) { + dev_err(dev, "%s: unable to map unsafe buffer %p!\n", + __func__, ptr); + return ~0; + } - dma_addr = buf->safe_dma_addr; - } else { - /* - * We don't need to sync the DMA buffer since - * it was allocated via the coherent allocators. - */ - __dma_single_cpu_to_dev(ptr, size, dir); + dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", + __func__, buf->ptr, virt_to_dma(dev, buf->ptr), + buf->safe, buf->safe_dma_addr); + + if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) { + dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", + __func__, ptr, buf->safe, size); + memcpy(buf->safe, ptr, size); } - return dma_addr; + return buf->safe_dma_addr; } -static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, +static inline void unmap_single(struct device *dev, struct safe_buffer *buf, size_t size, enum dma_data_direction dir) { - struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap"); - - if (buf) { - BUG_ON(buf->size != size); - BUG_ON(buf->direction != dir); + BUG_ON(buf->size != size); + BUG_ON(buf->direction != dir); - dev_dbg(dev, - "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", - __func__, buf->ptr, virt_to_dma(dev, buf->ptr), - buf->safe, buf->safe_dma_addr); + dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", + __func__, buf->ptr, virt_to_dma(dev, buf->ptr), + buf->safe, buf->safe_dma_addr); - DO_STATS(dev->archdata.dmabounce->bounce_count++); + DO_STATS(dev->archdata.dmabounce->bounce_count++); - if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { - void *ptr = buf->ptr; + if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { + void *ptr = buf->ptr; - dev_dbg(dev, - "%s: copy back safe %p to unsafe %p size %d\n", - __func__, buf->safe, ptr, size); - memcpy(ptr, buf->safe, size); + dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", + __func__, buf->safe, ptr, size); + memcpy(ptr, buf->safe, size); - /* - * Since we may have written to a page cache page, - * we need to ensure that the data will be coherent - * with user mappings. - */ - __cpuc_flush_dcache_area(ptr, size); - } - free_safe_buffer(dev->archdata.dmabounce, buf); - } else { - __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir); + /* + * Since we may have written to a page cache page, + * we need to ensure that the data will be coherent + * with user mappings. + */ + __cpuc_flush_dcache_area(ptr, size); } + free_safe_buffer(dev->archdata.dmabounce, buf); } /* ************************************************** */ @@ -328,45 +307,28 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) */ -dma_addr_t __dma_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction dir) -{ - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", - __func__, ptr, size, dir); - - BUG_ON(!valid_dma_direction(dir)); - - return map_single(dev, ptr, size, dir); -} -EXPORT_SYMBOL(__dma_map_single); - -/* - * see if a mapped address was really a "safe" buffer and if so, copy - * the data from the safe buffer back to the unsafe buffer and free up - * the safe buffer. (basically return things back to the way they - * should be) - */ -void __dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction dir) -{ - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", - __func__, (void *) dma_addr, size, dir); - - unmap_single(dev, dma_addr, size, dir); -} -EXPORT_SYMBOL(__dma_unmap_single); - dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { + dma_addr_t dma_addr; + int ret; + dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", __func__, page, offset, size, dir); - BUG_ON(!valid_dma_direction(dir)); + dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset; + + ret = needs_bounce(dev, dma_addr, size); + if (ret < 0) + return ~0; + + if (ret == 0) { + __dma_page_cpu_to_dev(page, offset, size, dir); + return dma_addr; + } if (PageHighMem(page)) { - dev_err(dev, "DMA buffer bouncing of HIGHMEM pages " - "is not supported\n"); + dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n"); return ~0; } @@ -383,10 +345,19 @@ EXPORT_SYMBOL(__dma_map_page); void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", - __func__, (void *) dma_addr, size, dir); + struct safe_buffer *buf; + + dev_dbg(dev, "%s(dma=%#x,size=%d,dir=%x)\n", + __func__, dma_addr, size, dir); + + buf = find_safe_buffer_dev(dev, dma_addr, __func__); + if (!buf) { + __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)), + dma_addr & ~PAGE_MASK, size, dir); + return; + } - unmap_single(dev, dma_addr, size, dir); + unmap_single(dev, buf, size, dir); } EXPORT_SYMBOL(__dma_unmap_page); @@ -461,7 +432,8 @@ static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, } int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, - unsigned long large_buffer_size) + unsigned long large_buffer_size, + int (*needs_bounce_fn)(struct device *, dma_addr_t, size_t)) { struct dmabounce_device_info *device_info; int ret; @@ -497,6 +469,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, device_info->dev = dev; INIT_LIST_HEAD(&device_info->safe_buffers); rwlock_init(&device_info->lock); + device_info->needs_bounce = needs_bounce_fn; #ifdef STATS device_info->total_allocs = 0; diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 4ddd0a6ac7f..7bdd91766d6 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -179,22 +179,21 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, { void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); unsigned int shift = (d->irq % 4) * 8; - unsigned int cpu = cpumask_first(mask_val); + unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); u32 val, mask, bit; - if (cpu >= 8) + if (cpu >= 8 || cpu >= nr_cpu_ids) return -EINVAL; mask = 0xff << shift; bit = 1 << (cpu + shift); spin_lock(&irq_controller_lock); - d->node = cpu; val = readl_relaxed(reg) & ~mask; writel_relaxed(val | bit, reg); spin_unlock(&irq_controller_lock); - return 0; + return IRQ_SET_MASK_OK; } #endif diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c index 7a21927c52e..14ad62e16dd 100644 --- a/arch/arm/common/it8152.c +++ b/arch/arm/common/it8152.c @@ -243,6 +243,12 @@ static struct resource it8152_mem = { * ITE8152 chip can address up to 64MByte, so all the devices * connected to ITE8152 (PCI and USB) should have limited DMA window */ +static int it8152_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) +{ + dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", + __func__, dma_addr, size); + return (dma_addr + size - PHYS_OFFSET) >= SZ_64M; +} /* * Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all @@ -254,7 +260,7 @@ static int it8152_pci_platform_notify(struct device *dev) if (dev->dma_mask) *dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET; dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET; - dmabounce_register_dev(dev, 2048, 4096); + dmabounce_register_dev(dev, 2048, 4096, it8152_needs_bounce); } return 0; } @@ -267,14 +273,6 @@ static int it8152_pci_platform_notify_remove(struct device *dev) return 0; } -int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) -{ - dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", - __func__, dma_addr, size); - return (dev->bus == &pci_bus_type) && - ((dma_addr + size - PHYS_OFFSET) >= SZ_64M); -} - int dma_set_coherent_mask(struct device *dev, u64 mask) { if (mask >= PHYS_OFFSET + SZ_64M - 1) diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 9c49a46a2b7..0569de6acfb 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -579,7 +579,36 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2]; } +#endif +#ifdef CONFIG_DMABOUNCE +/* + * According to the "Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update" (June 2000), erratum #7, there is a + * significant bug in the SA1111 SDRAM shared memory controller. If + * an access to a region of memory above 1MB relative to the bank base, + * it is important that address bit 10 _NOT_ be asserted. Depending + * on the configuration of the RAM, bit 10 may correspond to one + * of several different (processor-relative) address bits. + * + * This routine only identifies whether or not a given DMA address + * is susceptible to the bug. + * + * This should only get called for sa1111_device types due to the + * way we configure our device dma_masks. + */ +static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) +{ + /* + * Section 4.6 of the "Intel StrongARM SA-1111 Development Module + * User's Guide" mentions that jumpers R51 and R52 control the + * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or + * SDRAM bank 1 on Neponset). The default configuration selects + * Assabet, so any address in bank 1 is necessarily invalid. + */ + return (machine_is_assabet() || machine_is_pfs168()) && + (addr >= 0xc8000000 || (addr + size) >= 0xc8000000); +} #endif static void sa1111_dev_release(struct device *_dev) @@ -644,7 +673,8 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->dev.dma_mask = &dev->dma_mask; if (dev->dma_mask != 0xffffffffUL) { - ret = dmabounce_register_dev(&dev->dev, 1024, 4096); + ret = dmabounce_register_dev(&dev->dev, 1024, 4096, + sa1111_needs_bounce); if (ret) { dev_err(&dev->dev, "SA1111: Failed to register" " with dmabounce\n"); @@ -818,34 +848,6 @@ static void __sa1111_remove(struct sa1111 *sachip) kfree(sachip); } -/* - * According to the "Intel StrongARM SA-1111 Microprocessor Companion - * Chip Specification Update" (June 2000), erratum #7, there is a - * significant bug in the SA1111 SDRAM shared memory controller. If - * an access to a region of memory above 1MB relative to the bank base, - * it is important that address bit 10 _NOT_ be asserted. Depending - * on the configuration of the RAM, bit 10 may correspond to one - * of several different (processor-relative) address bits. - * - * This routine only identifies whether or not a given DMA address - * is susceptible to the bug. - * - * This should only get called for sa1111_device types due to the - * way we configure our device dma_masks. - */ -int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) -{ - /* - * Section 4.6 of the "Intel StrongARM SA-1111 Development Module - * User's Guide" mentions that jumpers R51 and R52 control the - * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or - * SDRAM bank 1 on Neponset). The default configuration selects - * Assabet, so any address in bank 1 is necessarily invalid. - */ - return ((machine_is_assabet() || machine_is_pfs168()) && - (addr >= 0xc8000000 || (addr + size) >= 0xc8000000)); -} - struct sa1111_save_data { unsigned int skcr; unsigned int skpcr; diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h index b4892a06442..f4280593dfa 100644 --- a/arch/arm/include/asm/bitops.h +++ b/arch/arm/include/asm/bitops.h @@ -26,8 +26,8 @@ #include <linux/compiler.h> #include <asm/system.h> -#define smp_mb__before_clear_bit() mb() -#define smp_mb__after_clear_bit() mb() +#define smp_mb__before_clear_bit() smp_mb() +#define smp_mb__after_clear_bit() smp_mb() /* * These functions are the basis of our bit ops. diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 4fff837363e..7a21d0bf713 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -115,39 +115,8 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, ___dma_page_dev_to_cpu(page, off, size, dir); } -/* - * Return whether the given device DMA address mask can be supported - * properly. For example, if your device can only drive the low 24-bits - * during bus mastering, then you would pass 0x00ffffff as the mask - * to this function. - * - * FIXME: This should really be a platform specific issue - we should - * return false if GFP_DMA allocations may not satisfy the supplied 'mask'. - */ -static inline int dma_supported(struct device *dev, u64 mask) -{ - if (mask < ISA_DMA_THRESHOLD) - return 0; - return 1; -} - -static inline int dma_set_mask(struct device *dev, u64 dma_mask) -{ -#ifdef CONFIG_DMABOUNCE - if (dev->archdata.dmabounce) { - if (dma_mask >= ISA_DMA_THRESHOLD) - return 0; - else - return -EIO; - } -#endif - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) - return -EIO; - - *dev->dma_mask = dma_mask; - - return 0; -} +extern int dma_supported(struct device *, u64); +extern int dma_set_mask(struct device *, u64); /* * DMA errors are defined by all-bits-set in the DMA address. @@ -256,14 +225,14 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *, * @dev: valid struct device pointer * @small_buf_size: size of buffers to use with small buffer pool * @large_buf_size: size of buffers to use with large buffer pool (can be 0) + * @needs_bounce_fn: called to determine whether buffer needs bouncing * * This function should be called by low-level platform code to register * a device as requireing DMA buffer bouncing. The function will allocate * appropriate DMA pools for the device. - * */ extern int dmabounce_register_dev(struct device *, unsigned long, - unsigned long); + unsigned long, int (*)(struct device *, dma_addr_t, size_t)); /** * dmabounce_unregister_dev @@ -277,31 +246,9 @@ extern int dmabounce_register_dev(struct device *, unsigned long, */ extern void dmabounce_unregister_dev(struct device *); -/** - * dma_needs_bounce - * - * @dev: valid struct device pointer - * @dma_handle: dma_handle of unbounced buffer - * @size: size of region being mapped - * - * Platforms that utilize the dmabounce mechanism must implement - * this function. - * - * The dmabounce routines call this function whenever a dma-mapping - * is requested to determine whether a given buffer needs to be bounced - * or not. The function must return 0 if the buffer is OK for - * DMA access and 1 if the buffer needs to be bounced. - * - */ -extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); - /* * The DMA API, implemented by dmabounce.c. See below for descriptions. */ -extern dma_addr_t __dma_map_single(struct device *, void *, size_t, - enum dma_data_direction); -extern void __dma_unmap_single(struct device *, dma_addr_t, size_t, - enum dma_data_direction); extern dma_addr_t __dma_map_page(struct device *, struct page *, unsigned long, size_t, enum dma_data_direction); extern void __dma_unmap_page(struct device *, dma_addr_t, size_t, @@ -328,13 +275,6 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr, } -static inline dma_addr_t __dma_map_single(struct device *dev, void *cpu_addr, - size_t size, enum dma_data_direction dir) -{ - __dma_single_cpu_to_dev(cpu_addr, size, dir); - return virt_to_dma(dev, cpu_addr); -} - static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { @@ -342,12 +282,6 @@ static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, return pfn_to_dma(dev, page_to_pfn(page)) + offset; } -static inline void __dma_unmap_single(struct device *dev, dma_addr_t handle, - size_t size, enum dma_data_direction dir) -{ - __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir); -} - static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { @@ -373,14 +307,18 @@ static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir) { + unsigned long offset; + struct page *page; dma_addr_t addr; + BUG_ON(!virt_addr_valid(cpu_addr)); + BUG_ON(!virt_addr_valid(cpu_addr + size - 1)); BUG_ON(!valid_dma_direction(dir)); - addr = __dma_map_single(dev, cpu_addr, size, dir); - debug_dma_map_page(dev, virt_to_page(cpu_addr), - (unsigned long)cpu_addr & ~PAGE_MASK, size, - dir, addr, true); + page = virt_to_page(cpu_addr); + offset = (unsigned long)cpu_addr & ~PAGE_MASK; + addr = __dma_map_page(dev, page, offset, size, dir); + debug_dma_map_page(dev, page, offset, size, dir, addr, true); return addr; } @@ -430,7 +368,7 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { debug_dma_unmap_page(dev, handle, size, dir, true); - __dma_unmap_single(dev, handle, size, dir); + __dma_unmap_page(dev, handle, size, dir); } /** diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S index 2da8547de6d..2f1e2098dfe 100644 --- a/arch/arm/include/asm/entry-macro-multi.S +++ b/arch/arm/include/asm/entry-macro-multi.S @@ -4,8 +4,8 @@ * Interrupt handling. Preserves r7, r8, r9 */ .macro arch_irq_handler_default - get_irqnr_preamble r5, lr -1: get_irqnr_and_base r0, r6, r5, lr + get_irqnr_preamble r6, lr +1: get_irqnr_and_base r0, r2, r6, lr movne r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @@ -17,17 +17,17 @@ /* * XXX * - * this macro assumes that irqstat (r6) and base (r5) are + * this macro assumes that irqstat (r2) and base (r6) are * preserved from get_irqnr_and_base above */ - ALT_SMP(test_for_ipi r0, r6, r5, lr) + ALT_SMP(test_for_ipi r0, r2, r6, lr) ALT_UP_B(9997f) movne r1, sp adrne lr, BSYM(1b) bne do_IPI #ifdef CONFIG_LOCAL_TIMERS - test_for_ltirq r0, r6, r5, lr + test_for_ltirq r0, r2, r6, lr movne r0, sp adrne lr, BSYM(1b) bne do_local_timer @@ -40,7 +40,7 @@ .align 5 .global \symbol_name \symbol_name: - mov r4, lr + mov r8, lr arch_irq_handler_default - mov pc, r4 + mov pc, r8 .endm diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index af44a8fb348..b8de516e600 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -204,18 +204,6 @@ static inline unsigned long __phys_to_virt(unsigned long x) #endif /* - * The DMA mask corresponding to the maximum bus address allocatable - * using GFP_DMA. The default here places no restriction on DMA - * allocations. This must be the smallest DMA mask in the system, - * so a successful GFP_DMA allocation will always satisfy this. - */ -#ifndef ARM_DMA_ZONE_SIZE -#define ISA_DMA_THRESHOLD (0xffffffffULL) -#else -#define ISA_DMA_THRESHOLD (PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1) -#endif - -/* * PFNs are used to describe any physical page; this means * PFN 0 == physical address 0. * diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 7544ce6b481..67c70a31a1b 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -52,7 +52,7 @@ reserve_pmu(enum arm_pmu_type device); * a cookie. */ extern int -release_pmu(struct platform_device *pdev); +release_pmu(enum arm_pmu_type type); /** * init_pmu() - Initialise the PMU. diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index 8ec535e11fd..633d1cb84d8 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h @@ -82,13 +82,13 @@ extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext); extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); #else -#define cpu_proc_init() processor._proc_init() -#define cpu_proc_fin() processor._proc_fin() -#define cpu_reset(addr) processor.reset(addr) -#define cpu_do_idle() processor._do_idle() -#define cpu_dcache_clean_area(addr,sz) processor.dcache_clean_area(addr,sz) -#define cpu_set_pte_ext(ptep,pte,ext) processor.set_pte_ext(ptep,pte,ext) -#define cpu_do_switch_mm(pgd,mm) processor.switch_mm(pgd,mm) +#define cpu_proc_init processor._proc_init +#define cpu_proc_fin processor._proc_fin +#define cpu_reset processor.reset +#define cpu_do_idle processor._do_idle +#define cpu_dcache_clean_area processor.dcache_clean_area +#define cpu_set_pte_ext processor.set_pte_ext +#define cpu_do_switch_mm processor.switch_mm #endif extern void cpu_resume(void); diff --git a/arch/arm/include/asm/scatterlist.h b/arch/arm/include/asm/scatterlist.h index 2f87870d934..cefdb8f898a 100644 --- a/arch/arm/include/asm/scatterlist.h +++ b/arch/arm/include/asm/scatterlist.h @@ -1,6 +1,10 @@ #ifndef _ASMARM_SCATTERLIST_H #define _ASMARM_SCATTERLIST_H +#ifdef CONFIG_ARM_HAS_SG_CHAIN +#define ARCH_HAS_SG_CHAIN +#endif + #include <asm/memory.h> #include <asm/types.h> #include <asm-generic/scatterlist.h> diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h index c3b5c796d81..915696dd9c7 100644 --- a/arch/arm/include/asm/setup.h +++ b/arch/arm/include/asm/setup.h @@ -192,7 +192,11 @@ static const struct tagtable __tagtable_##fn __tag = { tag, fn } /* * Memory map description */ -#define NR_BANKS 8 +#ifdef CONFIG_ARCH_EP93XX +# define NR_BANKS 16 +#else +# define NR_BANKS 8 +#endif struct membank { phys_addr_t start; diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h new file mode 100644 index 00000000000..b0e4e1a0231 --- /dev/null +++ b/arch/arm/include/asm/suspend.h @@ -0,0 +1,22 @@ +#ifndef __ASM_ARM_SUSPEND_H +#define __ASM_ARM_SUSPEND_H + +#include <asm/memory.h> +#include <asm/tlbflush.h> + +extern void cpu_resume(void); + +/* + * Hide the first two arguments to __cpu_suspend - these are an implementation + * detail which platform code shouldn't have to know about. + */ +static inline int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) +{ + extern int __cpu_suspend(int, long, unsigned long, + int (*)(unsigned long)); + int ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn); + flush_tlb_all(); + return ret; +} + +#endif diff --git a/arch/arm/include/asm/tcm.h b/arch/arm/include/asm/tcm.h index 5929ef5d927..8578d726ad7 100644 --- a/arch/arm/include/asm/tcm.h +++ b/arch/arm/include/asm/tcm.h @@ -27,5 +27,7 @@ void *tcm_alloc(size_t len); void tcm_free(void *addr, size_t len); +bool tcm_dtcm_present(void); +bool tcm_itcm_present(void); #endif diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index d2005de383b..8077145698f 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -34,16 +34,12 @@ #define TLB_V6_D_ASID (1 << 17) #define TLB_V6_I_ASID (1 << 18) -#define TLB_BTB (1 << 28) - /* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */ #define TLB_V7_UIS_PAGE (1 << 19) #define TLB_V7_UIS_FULL (1 << 20) #define TLB_V7_UIS_ASID (1 << 21) -/* Inner Shareable BTB operation (ARMv7 MP extensions) */ -#define TLB_V7_IS_BTB (1 << 22) - +#define TLB_BARRIER (1 << 28) #define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */ #define TLB_DCLEAN (1 << 30) #define TLB_WB (1 << 31) @@ -58,7 +54,7 @@ * v4wb - ARMv4 with write buffer without I TLB flush entry instruction * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction * fr - Feroceon (v4wbi with non-outer-cacheable page table walks) - * fa - Faraday (v4 with write buffer with UTLB and branch target buffer (BTB)) + * fa - Faraday (v4 with write buffer with UTLB) * v6wbi - ARMv6 with write buffer with I TLB flush entry instruction * v7wbi - identical to v6wbi */ @@ -99,7 +95,7 @@ # define v4_always_flags (-1UL) #endif -#define fa_tlb_flags (TLB_WB | TLB_BTB | TLB_DCLEAN | \ +#define fa_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ TLB_V4_U_FULL | TLB_V4_U_PAGE) #ifdef CONFIG_CPU_TLB_FA @@ -166,7 +162,7 @@ # define v4wb_always_flags (-1UL) #endif -#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \ +#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ TLB_V6_I_FULL | TLB_V6_D_FULL | \ TLB_V6_I_PAGE | TLB_V6_D_PAGE | \ TLB_V6_I_ASID | TLB_V6_D_ASID) @@ -184,9 +180,9 @@ # define v6wbi_always_flags (-1UL) #endif -#define v7wbi_tlb_flags_smp (TLB_WB | TLB_DCLEAN | TLB_V7_IS_BTB | \ +#define v7wbi_tlb_flags_smp (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID) -#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BTB | \ +#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID) #ifdef CONFIG_CPU_TLB_V7 @@ -341,15 +337,7 @@ static inline void local_flush_tlb_all(void) if (tlb_flag(TLB_V7_UIS_FULL)) asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc"); - if (tlb_flag(TLB_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); - dsb(); - isb(); - } - if (tlb_flag(TLB_V7_IS_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_BARRIER)) { dsb(); isb(); } @@ -389,17 +377,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc"); #endif - if (tlb_flag(TLB_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); - dsb(); - } - if (tlb_flag(TLB_V7_IS_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_BARRIER)) dsb(); - isb(); - } } static inline void @@ -439,17 +418,8 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc"); #endif - if (tlb_flag(TLB_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); - dsb(); - } - if (tlb_flag(TLB_V7_IS_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_BARRIER)) dsb(); - isb(); - } } static inline void local_flush_tlb_kernel_page(unsigned long kaddr) @@ -482,15 +452,7 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr) if (tlb_flag(TLB_V7_UIS_PAGE)) asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc"); - if (tlb_flag(TLB_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); - dsb(); - isb(); - } - if (tlb_flag(TLB_V7_IS_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_BARRIER)) { dsb(); isb(); } diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h index f90756dc16d..5b29a667362 100644 --- a/arch/arm/include/asm/traps.h +++ b/arch/arm/include/asm/traps.h @@ -3,6 +3,9 @@ #include <linux/list.h> +struct pt_regs; +struct task_struct; + struct undef_hook { struct list_head node; u32 instr_mask; diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 927522cfc12..16baba2e436 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -59,6 +59,9 @@ int main(void) DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate)); DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); +#ifdef CONFIG_SMP + DEFINE(VFP_CPU, offsetof(union vfp_state, hard.cpu)); +#endif #ifdef CONFIG_ARM_THUMBEE DEFINE(TI_THUMBEE_STATE, offsetof(struct thread_info, thumbee_state)); #endif diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 90c62cd51ca..fa02a22a4c4 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -29,21 +29,53 @@ #include <asm/entry-macro-multi.S> /* - * Interrupt handling. Preserves r7, r8, r9 + * Interrupt handling. */ .macro irq_handler #ifdef CONFIG_MULTI_IRQ_HANDLER - ldr r5, =handle_arch_irq + ldr r1, =handle_arch_irq mov r0, sp - ldr r5, [r5] + ldr r1, [r1] adr lr, BSYM(9997f) - teq r5, #0 - movne pc, r5 + teq r1, #0 + movne pc, r1 #endif arch_irq_handler_default 9997: .endm + .macro pabt_helper + @ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5 +#ifdef MULTI_PABORT + ldr ip, .LCprocfns + mov lr, pc + ldr pc, [ip, #PROCESSOR_PABT_FUNC] +#else + bl CPU_PABORT_HANDLER +#endif + .endm + + .macro dabt_helper + + @ + @ Call the processor-specific abort handler: + @ + @ r2 - pt_regs + @ r4 - aborted context pc + @ r5 - aborted context psr + @ + @ The abort handler must return the aborted address in r0, and + @ the fault status register in r1. r9 must be preserved. + @ +#ifdef MULTI_DABORT + ldr ip, .LCprocfns + mov lr, pc + ldr pc, [ip, #PROCESSOR_DABT_FUNC] +#else + bl CPU_DABORT_HANDLER +#endif + .endm + #ifdef CONFIG_KPROBES .section .kprobes.text,"ax",%progbits #else @@ -126,106 +158,74 @@ ENDPROC(__und_invalid) SPFIX( subeq sp, sp, #4 ) stmia sp, {r1 - r12} - ldmia r0, {r1 - r3} - add r5, sp, #S_SP - 4 @ here for interlock avoidance - mov r4, #-1 @ "" "" "" "" - add r0, sp, #(S_FRAME_SIZE + \stack_hole - 4) - SPFIX( addeq r0, r0, #4 ) - str r1, [sp, #-4]! @ save the "real" r0 copied + ldmia r0, {r3 - r5} + add r7, sp, #S_SP - 4 @ here for interlock avoidance + mov r6, #-1 @ "" "" "" "" + add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4) + SPFIX( addeq r2, r2, #4 ) + str r3, [sp, #-4]! @ save the "real" r0 copied @ from the exception stack - mov r1, lr + mov r3, lr @ @ We are now ready to fill in the remaining blanks on the stack: @ - @ r0 - sp_svc - @ r1 - lr_svc - @ r2 - lr_<exception>, already fixed up for correct return/restart - @ r3 - spsr_<exception> - @ r4 - orig_r0 (see pt_regs definition in ptrace.h) + @ r2 - sp_svc + @ r3 - lr_svc + @ r4 - lr_<exception>, already fixed up for correct return/restart + @ r5 - spsr_<exception> + @ r6 - orig_r0 (see pt_regs definition in ptrace.h) @ - stmia r5, {r0 - r4} + stmia r7, {r2 - r6} + +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif .endm .align 5 __dabt_svc: svc_entry - - @ - @ get ready to re-enable interrupts if appropriate - @ - mrs r9, cpsr - tst r3, #PSR_I_BIT - biceq r9, r9, #PSR_I_BIT - - @ - @ Call the processor-specific abort handler: - @ - @ r2 - aborted context pc - @ r3 - aborted context cpsr - @ - @ The abort handler must return the aborted address in r0, and - @ the fault status register in r1. r9 must be preserved. - @ -#ifdef MULTI_DABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_DABT_FUNC] -#else - bl CPU_DABORT_HANDLER -#endif - - @ - @ set desired IRQ state, then call main handler - @ - debug_entry r1 - msr cpsr_c, r9 mov r2, sp - bl do_DataAbort + dabt_helper @ @ IRQs off again before pulling preserved data off the stack @ disable_irq_notrace - @ - @ restore SPSR and restart the instruction - @ - ldr r2, [sp, #S_PSR] - svc_exit r2 @ return from exception +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__dabt_svc) .align 5 __irq_svc: svc_entry + irq_handler -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off -#endif #ifdef CONFIG_PREEMPT get_thread_info tsk ldr r8, [tsk, #TI_PREEMPT] @ get preempt count - add r7, r8, #1 @ increment it - str r7, [tsk, #TI_PREEMPT] -#endif - - irq_handler -#ifdef CONFIG_PREEMPT - str r8, [tsk, #TI_PREEMPT] @ restore preempt count ldr r0, [tsk, #TI_FLAGS] @ get flags teq r8, #0 @ if preempt count != 0 movne r0, #0 @ force flags to 0 tst r0, #_TIF_NEED_RESCHED blne svc_preempt #endif - ldr r4, [sp, #S_PSR] @ irqs are already disabled + #ifdef CONFIG_TRACE_IRQFLAGS - tst r4, #PSR_I_BIT - bleq trace_hardirqs_on + @ The parent context IRQs must have been enabled to get here in + @ the first place, so there's no point checking the PSR I bit. + bl trace_hardirqs_on #endif - svc_exit r4 @ return from exception + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__irq_svc) @@ -251,7 +251,6 @@ __und_svc: #else svc_entry #endif - @ @ call emulation code, which returns using r9 if it has emulated @ the instruction, or the more conventional lr if we are to treat @@ -260,15 +259,16 @@ __und_svc: @ r0 - instruction @ #ifndef CONFIG_THUMB2_KERNEL - ldr r0, [r2, #-4] + ldr r0, [r4, #-4] #else - ldrh r0, [r2, #-2] @ Thumb instruction at LR - 2 + ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2 and r9, r0, #0xf800 cmp r9, #0xe800 @ 32-bit instruction if xx >= 0 - ldrhhs r9, [r2] @ bottom 16 bits + ldrhhs r9, [r4] @ bottom 16 bits orrhs r0, r9, r0, lsl #16 #endif adr r9, BSYM(1f) + mov r2, r4 bl call_fpe mov r0, sp @ struct pt_regs *regs @@ -282,45 +282,35 @@ __und_svc: @ @ restore SPSR and restart the instruction @ - ldr r2, [sp, #S_PSR] @ Get SVC cpsr - svc_exit r2 @ return from exception + ldr r5, [sp, #S_PSR] @ Get SVC cpsr +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__und_svc) .align 5 __pabt_svc: svc_entry - - @ - @ re-enable interrupts if appropriate - @ - mrs r9, cpsr - tst r3, #PSR_I_BIT - biceq r9, r9, #PSR_I_BIT - - mov r0, r2 @ pass address of aborted instruction. -#ifdef MULTI_PABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_PABT_FUNC] -#else - bl CPU_PABORT_HANDLER -#endif - debug_entry r1 - msr cpsr_c, r9 @ Maybe enable interrupts mov r2, sp @ regs - bl do_PrefetchAbort @ call abort handler + pabt_helper @ @ IRQs off again before pulling preserved data off the stack @ disable_irq_notrace - @ - @ restore SPSR and restart the instruction - @ - ldr r2, [sp, #S_PSR] - svc_exit r2 @ return from exception +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__pabt_svc) @@ -351,23 +341,23 @@ ENDPROC(__pabt_svc) ARM( stmib sp, {r1 - r12} ) THUMB( stmia sp, {r0 - r12} ) - ldmia r0, {r1 - r3} + ldmia r0, {r3 - r5} add r0, sp, #S_PC @ here for interlock avoidance - mov r4, #-1 @ "" "" "" "" + mov r6, #-1 @ "" "" "" "" - str r1, [sp] @ save the "real" r0 copied + str r3, [sp] @ save the "real" r0 copied @ from the exception stack @ @ We are now ready to fill in the remaining blanks on the stack: @ - @ r2 - lr_<exception>, already fixed up for correct return/restart - @ r3 - spsr_<exception> - @ r4 - orig_r0 (see pt_regs definition in ptrace.h) + @ r4 - lr_<exception>, already fixed up for correct return/restart + @ r5 - spsr_<exception> + @ r6 - orig_r0 (see pt_regs definition in ptrace.h) @ @ Also, separately save sp_usr and lr_usr @ - stmia r0, {r2 - r4} + stmia r0, {r4 - r6} ARM( stmdb r0, {sp, lr}^ ) THUMB( store_user_sp_lr r0, r1, S_SP - S_PC ) @@ -380,6 +370,10 @@ ENDPROC(__pabt_svc) @ Clear FP to mark the first stack frame @ zero_fp + +#ifdef CONFIG_IRQSOFF_TRACER + bl trace_hardirqs_off +#endif .endm .macro kuser_cmpxchg_check @@ -391,7 +385,7 @@ ENDPROC(__pabt_svc) @ if it was interrupted in a critical region. Here we @ perform a quick test inline since it should be false @ 99.9999% of the time. The rest is done out of line. - cmp r2, #TASK_SIZE + cmp r4, #TASK_SIZE blhs kuser_cmpxchg_fixup #endif #endif @@ -401,32 +395,9 @@ ENDPROC(__pabt_svc) __dabt_usr: usr_entry kuser_cmpxchg_check - - @ - @ Call the processor-specific abort handler: - @ - @ r2 - aborted context pc - @ r3 - aborted context cpsr - @ - @ The abort handler must return the aborted address in r0, and - @ the fault status register in r1. - @ -#ifdef MULTI_DABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_DABT_FUNC] -#else - bl CPU_DABORT_HANDLER -#endif - - @ - @ IRQs on, then call the main handler - @ - debug_entry r1 - enable_irq mov r2, sp - adr lr, BSYM(ret_from_exception) - b do_DataAbort + dabt_helper + b ret_from_exception UNWIND(.fnend ) ENDPROC(__dabt_usr) @@ -434,28 +405,8 @@ ENDPROC(__dabt_usr) __irq_usr: usr_entry kuser_cmpxchg_check - -#ifdef CONFIG_IRQSOFF_TRACER - bl trace_hardirqs_off -#endif - - get_thread_info tsk -#ifdef CONFIG_PREEMPT - ldr r8, [tsk, #TI_PREEMPT] @ get preempt count - add r7, r8, #1 @ increment it - str r7, [tsk, #TI_PREEMPT] -#endif - irq_handler -#ifdef CONFIG_PREEMPT - ldr r0, [tsk, #TI_PREEMPT] - str r8, [tsk, #TI_PREEMPT] - teq r0, r7 - ARM( strne r0, [r0, -r0] ) - THUMB( movne r0, #0 ) - THUMB( strne r0, [r0] ) -#endif - + get_thread_info tsk mov why, #0 b ret_to_user_from_irq UNWIND(.fnend ) @@ -467,6 +418,9 @@ ENDPROC(__irq_usr) __und_usr: usr_entry + mov r2, r4 + mov r3, r5 + @ @ fall through to the emulation code, which returns using r9 if @ it has emulated the instruction, or the more conventional lr @@ -682,19 +636,8 @@ ENDPROC(__und_usr_unknown) .align 5 __pabt_usr: usr_entry - - mov r0, r2 @ pass address of aborted instruction. -#ifdef MULTI_PABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_PABT_FUNC] -#else - bl CPU_PABORT_HANDLER -#endif - debug_entry r1 - enable_irq @ Enable interrupts mov r2, sp @ regs - bl do_PrefetchAbort @ call abort handler + pabt_helper UNWIND(.fnend ) /* fall through */ /* @@ -927,13 +870,13 @@ __kuser_cmpxchg: @ 0xffff0fc0 .text kuser_cmpxchg_fixup: @ Called from kuser_cmpxchg_check macro. - @ r2 = address of interrupted insn (must be preserved). + @ r4 = address of interrupted insn (must be preserved). @ sp = saved regs. r7 and r8 are clobbered. @ 1b = first critical insn, 2b = last critical insn. - @ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b. + @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b. mov r7, #0xffff0fff sub r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg))) - subs r8, r2, r7 + subs r8, r4, r7 rsbcss r8, r8, #(2b - 1b) strcs r7, [sp, #S_PC] mov pc, lr diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 051166c2a93..4d6ad8348e8 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -165,25 +165,6 @@ .endm #endif /* !CONFIG_THUMB2_KERNEL */ - @ - @ Debug exceptions are taken as prefetch or data aborts. - @ We must disable preemption during the handler so that - @ we can access the debug registers safely. - @ - .macro debug_entry, fsr -#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT) - ldr r4, =0x40f @ mask out fsr.fs - and r5, r4, \fsr - cmp r5, #2 @ debug exception - bne 1f - get_thread_info r10 - ldr r6, [r10, #TI_PREEMPT] @ get preempt count - add r11, r6, #1 @ increment it - str r11, [r10, #TI_PREEMPT] -1: -#endif - .endm - /* * These are the registers used in the syscall handler, and allow us to * have in theory up to 7 arguments to a function - r0 to r6. diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 6b1e0ad9ec3..d46f25968be 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -32,8 +32,16 @@ * numbers for r1. * */ + .arm + __HEAD ENTRY(stext) + + THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. + THUMB( bx r9 ) @ If this is a Thumb-2 kernel, + THUMB( .thumb ) @ switch to Thumb now. + THUMB(1: ) + setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled #ifndef CONFIG_CPU_CP15 diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 278c1b0ebb2..742b6108a00 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -71,8 +71,16 @@ * crap here - that's what the boot loader (or in extreme, well justified * circumstances, zImage) is for. */ + .arm + __HEAD ENTRY(stext) + + THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. + THUMB( bx r9 ) @ If this is a Thumb-2 kernel, + THUMB( .thumb ) @ switch to Thumb now. + THUMB(1: ) + setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled mrc p15, 0, r9, c0, c0 @ get processor id diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 87acc25d7a3..a927ca1f556 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -796,7 +796,7 @@ unlock: /* * Called from either the Data Abort Handler [watchpoint] or the - * Prefetch Abort Handler [breakpoint] with preemption disabled. + * Prefetch Abort Handler [breakpoint] with interrupts disabled. */ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, struct pt_regs *regs) @@ -804,8 +804,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, int ret = 0; u32 dscr; - /* We must be called with preemption disabled. */ - WARN_ON(preemptible()); + preempt_disable(); + + if (interrupts_enabled(regs)) + local_irq_enable(); /* We only handle watchpoints and hardware breakpoints. */ ARM_DBG_READ(c1, 0, dscr); @@ -824,10 +826,6 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, ret = 1; /* Unhandled fault. */ } - /* - * Re-enable preemption after it was disabled in the - * low-level exception handling code. - */ preempt_enable(); return ret; diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 83bbad03fcc..0f928a131af 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -131,54 +131,63 @@ int __init arch_probe_nr_irqs(void) #ifdef CONFIG_HOTPLUG_CPU -static bool migrate_one_irq(struct irq_data *d) +static bool migrate_one_irq(struct irq_desc *desc) { - unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask); + struct irq_data *d = irq_desc_get_irq_data(desc); + const struct cpumask *affinity = d->affinity; + struct irq_chip *c; bool ret = false; - if (cpu >= nr_cpu_ids) { - cpu = cpumask_any(cpu_online_mask); + /* + * If this is a per-CPU interrupt, or the affinity does not + * include this CPU, then we have nothing to do. + */ + if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity)) + return false; + + if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { + affinity = cpu_online_mask; ret = true; } - pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu); - - d->chip->irq_set_affinity(d, cpumask_of(cpu), true); + c = irq_data_get_irq_chip(d); + if (c->irq_set_affinity) + c->irq_set_affinity(d, affinity, true); + else + pr_debug("IRQ%u: unable to set affinity\n", d->irq); return ret; } /* - * The CPU has been marked offline. Migrate IRQs off this CPU. If - * the affinity settings do not allow other CPUs, force them onto any + * The current CPU has been marked offline. Migrate IRQs off this CPU. + * If the affinity settings do not allow other CPUs, force them onto any * available CPU. + * + * Note: we must iterate over all IRQs, whether they have an attached + * action structure or not, as we need to get chained interrupts too. */ void migrate_irqs(void) { - unsigned int i, cpu = smp_processor_id(); + unsigned int i; struct irq_desc *desc; unsigned long flags; local_irq_save(flags); for_each_irq_desc(i, desc) { - struct irq_data *d = &desc->irq_data; bool affinity_broken = false; - raw_spin_lock(&desc->lock); - do { - if (desc->action == NULL) - break; - - if (d->node != cpu) - break; + if (!desc) + continue; - affinity_broken = migrate_one_irq(d); - } while (0); + raw_spin_lock(&desc->lock); + affinity_broken = migrate_one_irq(desc); raw_spin_unlock(&desc->lock); if (affinity_broken && printk_ratelimit()) - pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu); + pr_warning("IRQ%u no longer affine to CPU%u\n", i, + smp_processor_id()); } local_irq_restore(flags); diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index d53c0abc4dd..8d8507858e5 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -435,7 +435,7 @@ armpmu_reserve_hardware(void) if (irq >= 0) free_irq(irq, NULL); } - release_pmu(pmu_device); + release_pmu(ARM_PMU_DEVICE_CPU); pmu_device = NULL; } @@ -454,7 +454,7 @@ armpmu_release_hardware(void) } armpmu->stop(); - release_pmu(pmu_device); + release_pmu(ARM_PMU_DEVICE_CPU); pmu_device = NULL; } @@ -583,7 +583,7 @@ static int armpmu_event_init(struct perf_event *event) static void armpmu_enable(struct pmu *pmu) { /* Enable all of the perf events on hardware. */ - int idx; + int idx, enabled = 0; struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); if (!armpmu) @@ -596,9 +596,11 @@ static void armpmu_enable(struct pmu *pmu) continue; armpmu->enable(&event->hw, idx); + enabled = 1; } - armpmu->start(); + if (enabled) + armpmu->start(); } static void armpmu_disable(struct pmu *pmu) diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index 2c79eec1926..2b70709376c 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c @@ -17,6 +17,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <asm/pmu.h> @@ -25,36 +26,88 @@ static volatile long pmu_lock; static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES]; -static int __devinit pmu_device_probe(struct platform_device *pdev) +static int __devinit pmu_register(struct platform_device *pdev, + enum arm_pmu_type type) { - - if (pdev->id < 0 || pdev->id >= ARM_NUM_PMU_DEVICES) { + if (type < 0 || type >= ARM_NUM_PMU_DEVICES) { pr_warning("received registration request for unknown " - "device %d\n", pdev->id); + "device %d\n", type); return -EINVAL; } - if (pmu_devices[pdev->id]) - pr_warning("registering new PMU device type %d overwrites " - "previous registration!\n", pdev->id); - else - pr_info("registered new PMU device of type %d\n", - pdev->id); + if (pmu_devices[type]) { + pr_warning("rejecting duplicate registration of PMU device " + "type %d.", type); + return -ENOSPC; + } - pmu_devices[pdev->id] = pdev; + pr_info("registered new PMU device of type %d\n", type); + pmu_devices[type] = pdev; return 0; } -static struct platform_driver pmu_driver = { +#define OF_MATCH_PMU(_name, _type) { \ + .compatible = _name, \ + .data = (void *)_type, \ +} + +#define OF_MATCH_CPU(name) OF_MATCH_PMU(name, ARM_PMU_DEVICE_CPU) + +static struct of_device_id armpmu_of_device_ids[] = { + OF_MATCH_CPU("arm,cortex-a9-pmu"), + OF_MATCH_CPU("arm,cortex-a8-pmu"), + OF_MATCH_CPU("arm,arm1136-pmu"), + OF_MATCH_CPU("arm,arm1176-pmu"), + {}, +}; + +#define PLAT_MATCH_PMU(_name, _type) { \ + .name = _name, \ + .driver_data = _type, \ +} + +#define PLAT_MATCH_CPU(_name) PLAT_MATCH_PMU(_name, ARM_PMU_DEVICE_CPU) + +static struct platform_device_id armpmu_plat_device_ids[] = { + PLAT_MATCH_CPU("arm-pmu"), + {}, +}; + +enum arm_pmu_type armpmu_device_type(struct platform_device *pdev) +{ + const struct of_device_id *of_id; + const struct platform_device_id *pdev_id; + + /* provided by of_device_id table */ + if (pdev->dev.of_node) { + of_id = of_match_device(armpmu_of_device_ids, &pdev->dev); + BUG_ON(!of_id); + return (enum arm_pmu_type)of_id->data; + } + + /* Provided by platform_device_id table */ + pdev_id = platform_get_device_id(pdev); + BUG_ON(!pdev_id); + return pdev_id->driver_data; +} + +static int __devinit armpmu_device_probe(struct platform_device *pdev) +{ + return pmu_register(pdev, armpmu_device_type(pdev)); +} + +static struct platform_driver armpmu_driver = { .driver = { .name = "arm-pmu", + .of_match_table = armpmu_of_device_ids, }, - .probe = pmu_device_probe, + .probe = armpmu_device_probe, + .id_table = armpmu_plat_device_ids, }; static int __init register_pmu_driver(void) { - return platform_driver_register(&pmu_driver); + return platform_driver_register(&armpmu_driver); } device_initcall(register_pmu_driver); @@ -77,11 +130,11 @@ reserve_pmu(enum arm_pmu_type device) EXPORT_SYMBOL_GPL(reserve_pmu); int -release_pmu(struct platform_device *pdev) +release_pmu(enum arm_pmu_type device) { - if (WARN_ON(pdev != pmu_devices[pdev->id])) + if (WARN_ON(!pmu_devices[device])) return -EINVAL; - clear_bit_unlock(pdev->id, &pmu_lock); + clear_bit_unlock(device, &pmu_lock); return 0; } EXPORT_SYMBOL_GPL(release_pmu); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index ed11fb08b05..9c3278f3779 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -73,6 +73,7 @@ __setup("fpe=", fpe_setup); #endif extern void paging_init(struct machine_desc *desc); +extern void sanity_check_meminfo(void); extern void reboot_setup(char *str); unsigned int processor_id; @@ -342,54 +343,6 @@ static void __init feat_v6_fixup(void) elf_hwcap &= ~HWCAP_TLS; } -static void __init setup_processor(void) -{ - struct proc_info_list *list; - - /* - * locate processor in the list of supported processor - * types. The linker builds this table for us from the - * entries in arch/arm/mm/proc-*.S - */ - list = lookup_processor_type(read_cpuid_id()); - if (!list) { - printk("CPU configuration botched (ID %08x), unable " - "to continue.\n", read_cpuid_id()); - while (1); - } - - cpu_name = list->cpu_name; - -#ifdef MULTI_CPU - processor = *list->proc; -#endif -#ifdef MULTI_TLB - cpu_tlb = *list->tlb; -#endif -#ifdef MULTI_USER - cpu_user = *list->user; -#endif -#ifdef MULTI_CACHE - cpu_cache = *list->cache; -#endif - - printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", - cpu_name, read_cpuid_id(), read_cpuid_id() & 15, - proc_arch[cpu_architecture()], cr_alignment); - - sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); - sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); - elf_hwcap = list->elf_hwcap; -#ifndef CONFIG_ARM_THUMB - elf_hwcap &= ~HWCAP_THUMB; -#endif - - feat_v6_fixup(); - - cacheid_init(); - cpu_proc_init(); -} - /* * cpu_init - initialise one CPU. * @@ -405,6 +358,8 @@ void cpu_init(void) BUG(); } + cpu_proc_init(); + /* * Define the placement constraint for the inline asm directive below. * In Thumb-2, msr with an immediate value is not allowed. @@ -441,6 +396,54 @@ void cpu_init(void) : "r14"); } +static void __init setup_processor(void) +{ + struct proc_info_list *list; + + /* + * locate processor in the list of supported processor + * types. The linker builds this table for us from the + * entries in arch/arm/mm/proc-*.S + */ + list = lookup_processor_type(read_cpuid_id()); + if (!list) { + printk("CPU configuration botched (ID %08x), unable " + "to continue.\n", read_cpuid_id()); + while (1); + } + + cpu_name = list->cpu_name; + +#ifdef MULTI_CPU + processor = *list->proc; +#endif +#ifdef MULTI_TLB + cpu_tlb = *list->tlb; +#endif +#ifdef MULTI_USER + cpu_user = *list->user; +#endif +#ifdef MULTI_CACHE + cpu_cache = *list->cache; +#endif + + printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", + cpu_name, read_cpuid_id(), read_cpuid_id() & 15, + proc_arch[cpu_architecture()], cr_alignment); + + sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); + sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); + elf_hwcap = list->elf_hwcap; +#ifndef CONFIG_ARM_THUMB + elf_hwcap &= ~HWCAP_THUMB; +#endif + + feat_v6_fixup(); + + cacheid_init(); + cpu_init(); +} + void __init dump_machine_table(void) { struct machine_desc *p; @@ -900,6 +903,7 @@ void __init setup_arch(char **cmdline_p) parse_early_param(); + sanity_check_meminfo(); arm_memblock_init(&meminfo, mdesc); paging_init(mdesc); @@ -913,7 +917,6 @@ void __init setup_arch(char **cmdline_p) #endif reserve_crashkernel(); - cpu_init(); tcm_init(); #ifdef CONFIG_MULTI_IRQ_HANDLER diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 6398ead9d1c..dc902f2c684 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -10,64 +10,61 @@ /* * Save CPU state for a suspend * r1 = v:p offset - * r3 = virtual return function - * Note: sp is decremented to allocate space for CPU state on stack - * r0-r3,r9,r10,lr corrupted + * r2 = suspend function arg0 + * r3 = suspend function */ -ENTRY(cpu_suspend) - mov r9, lr +ENTRY(__cpu_suspend) + stmfd sp!, {r4 - r11, lr} #ifdef MULTI_CPU ldr r10, =processor - mov r2, sp @ current virtual SP - ldr r0, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state + ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function - sub sp, sp, r0 @ allocate CPU state on stack - mov r0, sp @ save pointer +#else + ldr r5, =cpu_suspend_size + ldr ip, =cpu_do_resume +#endif + mov r6, sp @ current virtual SP + sub sp, sp, r5 @ allocate CPU state on stack + mov r0, sp @ save pointer to CPU save block add ip, ip, r1 @ convert resume fn to phys - stmfd sp!, {r1, r2, r3, ip} @ save v:p, virt SP, retfn, phys resume fn - ldr r3, =sleep_save_sp - add r2, sp, r1 @ convert SP to phys + stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn + ldr r5, =sleep_save_sp + add r6, sp, r1 @ convert SP to phys + stmfd sp!, {r2, r3} @ save suspend func arg and pointer #ifdef CONFIG_SMP ALT_SMP(mrc p15, 0, lr, c0, c0, 5) ALT_UP(mov lr, #0) and lr, lr, #15 - str r2, [r3, lr, lsl #2] @ save phys SP + str r6, [r5, lr, lsl #2] @ save phys SP #else - str r2, [r3] @ save phys SP + str r6, [r5] @ save phys SP #endif +#ifdef MULTI_CPU mov lr, pc ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state #else - mov r2, sp @ current virtual SP - ldr r0, =cpu_suspend_size - sub sp, sp, r0 @ allocate CPU state on stack - mov r0, sp @ save pointer - stmfd sp!, {r1, r2, r3} @ save v:p, virt SP, return fn - ldr r3, =sleep_save_sp - add r2, sp, r1 @ convert SP to phys -#ifdef CONFIG_SMP - ALT_SMP(mrc p15, 0, lr, c0, c0, 5) - ALT_UP(mov lr, #0) - and lr, lr, #15 - str r2, [r3, lr, lsl #2] @ save phys SP -#else - str r2, [r3] @ save phys SP -#endif bl cpu_do_suspend #endif @ flush data cache #ifdef MULTI_CACHE ldr r10, =cpu_cache - mov lr, r9 + mov lr, pc ldr pc, [r10, #CACHE_FLUSH_KERN_ALL] #else - mov lr, r9 - b __cpuc_flush_kern_all + bl __cpuc_flush_kern_all #endif -ENDPROC(cpu_suspend) + adr lr, BSYM(cpu_suspend_abort) + ldmfd sp!, {r0, pc} @ call suspend fn +ENDPROC(__cpu_suspend) .ltorg +cpu_suspend_abort: + ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn + mov sp, r2 + ldmfd sp!, {r4 - r11, pc} +ENDPROC(cpu_suspend_abort) + /* * r0 = control register value * r1 = v:p offset (preserved by cpu_do_resume) @@ -97,7 +94,9 @@ ENDPROC(cpu_resume_turn_mmu_on) cpu_resume_after_mmu: str r5, [r2, r4, lsl #2] @ restore old mapping mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache - mov pc, lr + bl cpu_init @ restore the und/abt/irq banked regs + mov r0, #0 @ return zero on success + ldmfd sp!, {r4 - r11, pc} ENDPROC(cpu_resume_after_mmu) /* @@ -120,20 +119,11 @@ ENTRY(cpu_resume) ldr r0, sleep_save_sp @ stack phys addr #endif setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off -#ifdef MULTI_CPU - @ load v:p, stack, return fn, resume fn - ARM( ldmia r0!, {r1, sp, lr, pc} ) -THUMB( ldmia r0!, {r1, r2, r3, r4} ) + @ load v:p, stack, resume fn + ARM( ldmia r0!, {r1, sp, pc} ) +THUMB( ldmia r0!, {r1, r2, r3} ) THUMB( mov sp, r2 ) -THUMB( mov lr, r3 ) -THUMB( bx r4 ) -#else - @ load v:p, stack, return fn - ARM( ldmia r0!, {r1, sp, lr} ) -THUMB( ldmia r0!, {r1, r2, lr} ) -THUMB( mov sp, r2 ) - b cpu_do_resume -#endif +THUMB( bx r3 ) ENDPROC(cpu_resume) sleep_save_sp: diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index e7f92a4321f..167e3cbe1f2 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -365,8 +365,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) */ if (max_cpus > ncores) max_cpus = ncores; - - if (max_cpus > 1) { + if (ncores > 1 && max_cpus) { /* * Enable the local timer or broadcast device for the * boot CPU, but only if we have more than one CPU. @@ -374,6 +373,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus) percpu_timer_setup(); /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. A platform should + * re-initialize the map in platform_smp_prepare_cpus() if + * present != possible (e.g. physical hotplug). + */ + init_cpu_present(&cpu_possible_map); + + /* * Initialise the SCU if there are more than one CPU * and let them know where to start. */ diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c index a1e757c3439..79ed5e7f204 100644 --- a/arch/arm/kernel/smp_scu.c +++ b/arch/arm/kernel/smp_scu.c @@ -20,6 +20,7 @@ #define SCU_INVALIDATE 0x0c #define SCU_FPGA_REVISION 0x10 +#ifdef CONFIG_SMP /* * Get the number of CPU cores from the SCU configuration */ @@ -50,6 +51,7 @@ void __init scu_enable(void __iomem *scu_base) */ flush_cache_all(); } +#endif /* * Set the executing CPUs power mode as defined. This will be in diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 60636f499cb..2c277d40cee 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -115,7 +115,7 @@ static void __cpuinit twd_calibrate_rate(void) twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000, - (twd_timer_rate / 1000000) % 100); + (twd_timer_rate / 10000) % 100); } } diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c index f5cf660eefc..30e302d33e0 100644 --- a/arch/arm/kernel/tcm.c +++ b/arch/arm/kernel/tcm.c @@ -19,6 +19,8 @@ #include "tcm.h" static struct gen_pool *tcm_pool; +static bool dtcm_present; +static bool itcm_present; /* TCM section definitions from the linker */ extern char __itcm_start, __sitcm_text, __eitcm_text; @@ -90,6 +92,18 @@ void tcm_free(void *addr, size_t len) } EXPORT_SYMBOL(tcm_free); +bool tcm_dtcm_present(void) +{ + return dtcm_present; +} +EXPORT_SYMBOL(tcm_dtcm_present); + +bool tcm_itcm_present(void) +{ + return itcm_present; +} +EXPORT_SYMBOL(tcm_itcm_present); + static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, u32 *offset) { @@ -134,6 +148,10 @@ static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, (tcm_region & 1) ? "" : "not "); } + /* Not much fun you can do with a size 0 bank */ + if (tcm_size == 0) + return 0; + /* Force move the TCM bank to where we want it, enable */ tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1; @@ -165,12 +183,20 @@ void __init tcm_init(void) u32 tcm_status = read_cpuid_tcmstatus(); u8 dtcm_banks = (tcm_status >> 16) & 0x03; u8 itcm_banks = (tcm_status & 0x03); + size_t dtcm_code_sz = &__edtcm_data - &__sdtcm_data; + size_t itcm_code_sz = &__eitcm_text - &__sitcm_text; char *start; char *end; char *ram; int ret; int i; + /* Values greater than 2 for D/ITCM banks are "reserved" */ + if (dtcm_banks > 2) + dtcm_banks = 0; + if (itcm_banks > 2) + itcm_banks = 0; + /* Setup DTCM if present */ if (dtcm_banks > 0) { for (i = 0; i < dtcm_banks; i++) { @@ -178,6 +204,13 @@ void __init tcm_init(void) if (ret) return; } + /* This means you compiled more code than fits into DTCM */ + if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) { + pr_info("CPU DTCM: %u bytes of code compiled to " + "DTCM but only %lu bytes of DTCM present\n", + dtcm_code_sz, (dtcm_end - DTCM_OFFSET)); + goto no_dtcm; + } dtcm_res.end = dtcm_end - 1; request_resource(&iomem_resource, &dtcm_res); dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET; @@ -186,12 +219,16 @@ void __init tcm_init(void) start = &__sdtcm_data; end = &__edtcm_data; ram = &__dtcm_start; - /* This means you compiled more code than fits into DTCM */ - BUG_ON((end - start) > (dtcm_end - DTCM_OFFSET)); - memcpy(start, ram, (end-start)); - pr_debug("CPU DTCM: copied data from %p - %p\n", start, end); + memcpy(start, ram, dtcm_code_sz); + pr_debug("CPU DTCM: copied data from %p - %p\n", + start, end); + dtcm_present = true; + } else if (dtcm_code_sz) { + pr_info("CPU DTCM: %u bytes of code compiled to DTCM but no " + "DTCM banks present in CPU\n", dtcm_code_sz); } +no_dtcm: /* Setup ITCM if present */ if (itcm_banks > 0) { for (i = 0; i < itcm_banks; i++) { @@ -199,6 +236,13 @@ void __init tcm_init(void) if (ret) return; } + /* This means you compiled more code than fits into ITCM */ + if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) { + pr_info("CPU ITCM: %u bytes of code compiled to " + "ITCM but only %lu bytes of ITCM present\n", + itcm_code_sz, (itcm_end - ITCM_OFFSET)); + return; + } itcm_res.end = itcm_end - 1; request_resource(&iomem_resource, &itcm_res); itcm_iomap[0].length = itcm_end - ITCM_OFFSET; @@ -207,10 +251,13 @@ void __init tcm_init(void) start = &__sitcm_text; end = &__eitcm_text; ram = &__itcm_start; - /* This means you compiled more code than fits into ITCM */ - BUG_ON((end - start) > (itcm_end - ITCM_OFFSET)); - memcpy(start, ram, (end-start)); - pr_debug("CPU ITCM: copied code from %p - %p\n", start, end); + memcpy(start, ram, itcm_code_sz); + pr_debug("CPU ITCM: copied code from %p - %p\n", + start, end); + itcm_present = true; + } else if (itcm_code_sz) { + pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no " + "ITCM banks present in CPU\n", itcm_code_sz); } } @@ -221,7 +268,6 @@ void __init tcm_init(void) */ static int __init setup_tcm_pool(void) { - u32 tcm_status = read_cpuid_tcmstatus(); u32 dtcm_pool_start = (u32) &__edtcm_data; u32 itcm_pool_start = (u32) &__eitcm_text; int ret; @@ -236,7 +282,7 @@ static int __init setup_tcm_pool(void) pr_debug("Setting up TCM memory pool\n"); /* Add the rest of DTCM to the TCM pool */ - if (tcm_status & (0x03 << 16)) { + if (dtcm_present) { if (dtcm_pool_start < dtcm_end) { ret = gen_pool_add(tcm_pool, dtcm_pool_start, dtcm_end - dtcm_pool_start, -1); @@ -253,7 +299,7 @@ static int __init setup_tcm_pool(void) } /* Add the rest of ITCM to the TCM pool */ - if (tcm_status & 0x03) { + if (itcm_present) { if (itcm_pool_start < itcm_end) { ret = gen_pool_add(tcm_pool, itcm_pool_start, itcm_end - itcm_pool_start, -1); diff --git a/arch/arm/mach-bcmring/include/mach/entry-macro.S b/arch/arm/mach-bcmring/include/mach/entry-macro.S index 7d393ca010a..94c950d783b 100644 --- a/arch/arm/mach-bcmring/include/mach/entry-macro.S +++ b/arch/arm/mach-bcmring/include/mach/entry-macro.S @@ -80,7 +80,3 @@ .macro arch_ret_to_user, tmp1, tmp2 .endm - - .macro irq_prio_table - .endm - diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index c67f684ee3e..09a87e61ffc 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -520,7 +520,7 @@ fail: */ if (have_imager()) { label = "HD imager"; - mux |= 1; + mux |= 2; /* externally mux MMC1/ENET/AIC33 to imager */ mux |= BIT(6) | BIT(5) | BIT(3); @@ -540,7 +540,7 @@ fail: resets &= ~BIT(1); if (have_tvp7002()) { - mux |= 2; + mux |= 1; resets &= ~BIT(2); label = "tvp7002 HD"; } else { diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c index e7221398e5a..cafbe13a82a 100644 --- a/arch/arm/mach-davinci/gpio.c +++ b/arch/arm/mach-davinci/gpio.c @@ -254,8 +254,10 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc) { struct davinci_gpio_regs __iomem *g; u32 mask = 0xffff; + struct davinci_gpio_controller *d; - g = (__force struct davinci_gpio_regs __iomem *) irq_desc_get_handler_data(desc); + d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc); + g = (struct davinci_gpio_regs __iomem *)d->regs; /* we only care about one bank */ if (irq & 1) @@ -274,11 +276,14 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc) if (!status) break; __raw_writel(status, &g->intstat); - if (irq & 1) - status >>= 16; /* now demux them to the right lowlevel handler */ - n = (int)irq_get_handler_data(irq); + n = d->irq_base; + if (irq & 1) { + n += 16; + status >>= 16; + } + while (status) { res = ffs(status); n += res; @@ -424,7 +429,13 @@ static int __init davinci_gpio_irq_setup(void) /* set up all irqs in this bank */ irq_set_chained_handler(bank_irq, gpio_irq_handler); - irq_set_handler_data(bank_irq, (__force void *)g); + + /* + * Each chip handles 32 gpios, and each irq bank consists of 16 + * gpio irqs. Pass the irq bank's corresponding controller to + * the chained irq handler. + */ + irq_set_handler_data(bank_irq, &chips[gpio / 32]); for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) { irq_set_chip(irq, &gpio_irqchip); diff --git a/arch/arm/mach-davinci/include/mach/entry-macro.S b/arch/arm/mach-davinci/include/mach/entry-macro.S index fbdebc7cb40..e14c0dc0e12 100644 --- a/arch/arm/mach-davinci/include/mach/entry-macro.S +++ b/arch/arm/mach-davinci/include/mach/entry-macro.S @@ -46,6 +46,3 @@ #endif 1002: .endm - - .macro irq_prio_table - .endm diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c index bfe68ec4e1a..952dc126c39 100644 --- a/arch/arm/mach-davinci/irq.c +++ b/arch/arm/mach-davinci/irq.c @@ -52,8 +52,14 @@ davinci_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) struct irq_chip_type *ct; gc = irq_alloc_generic_chip("AINTC", 1, irq_start, base, handle_edge_irq); + if (!gc) { + pr_err("%s: irq_alloc_generic_chip for IRQ %u failed\n", + __func__, irq_start); + return; + } + ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 1d4b65fd673..6659a0d137a 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -251,9 +251,9 @@ static void ep93xx_uart_set_mctrl(struct amba_device *dev, unsigned int mcr; mcr = 0; - if (!(mctrl & TIOCM_RTS)) + if (mctrl & TIOCM_RTS) mcr |= 2; - if (!(mctrl & TIOCM_DTR)) + if (mctrl & TIOCM_DTR) mcr |= 1; __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET); diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c index 9babe4473e8..bfd621460ab 100644 --- a/arch/arm/mach-exynos4/cpu.c +++ b/arch/arm/mach-exynos4/cpu.c @@ -23,6 +23,7 @@ #include <plat/sdhci.h> #include <plat/devs.h> #include <plat/fimc-core.h> +#include <plat/iic-core.h> #include <mach/regs-irq.h> @@ -132,6 +133,11 @@ void __init exynos4_map_io(void) s3c_fimc_setname(1, "exynos4-fimc"); s3c_fimc_setname(2, "exynos4-fimc"); s3c_fimc_setname(3, "exynos4-fimc"); + + /* The I2C bus controllers are directly compatible with s3c2440 */ + s3c_i2c0_setname("s3c2440-i2c"); + s3c_i2c1_setname("s3c2440-i2c"); + s3c_i2c2_setname("s3c2440-i2c"); } void __init exynos4_init_clocks(int xtal) diff --git a/arch/arm/mach-exynos4/dev-audio.c b/arch/arm/mach-exynos4/dev-audio.c index 1eed5f9f7bd..983069a5323 100644 --- a/arch/arm/mach-exynos4/dev-audio.c +++ b/arch/arm/mach-exynos4/dev-audio.c @@ -330,7 +330,7 @@ struct platform_device exynos4_device_ac97 = { static int exynos4_spdif_cfg_gpio(struct platform_device *pdev) { - s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(3)); + s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(4)); return 0; } diff --git a/arch/arm/mach-exynos4/headsmp.S b/arch/arm/mach-exynos4/headsmp.S index 6c6cfc50c46..3cdeb364754 100644 --- a/arch/arm/mach-exynos4/headsmp.S +++ b/arch/arm/mach-exynos4/headsmp.S @@ -13,7 +13,7 @@ #include <linux/linkage.h> #include <linux/init.h> - __INIT + __CPUINIT /* * exynos4 specific entry point for secondary CPUs. This provides diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c index 152676471b6..edd814110da 100644 --- a/arch/arm/mach-exynos4/mach-smdkv310.c +++ b/arch/arm/mach-exynos4/mach-smdkv310.c @@ -78,9 +78,7 @@ static struct s3c2410_uartcfg smdkv310_uartcfgs[] __initdata = { }; static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = { - .cd_type = S3C_SDHCI_CD_GPIO, - .ext_cd_gpio = EXYNOS4_GPK0(2), - .ext_cd_gpio_invert = 1, + .cd_type = S3C_SDHCI_CD_INTERNAL, .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, #ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT .max_width = 8, @@ -96,9 +94,7 @@ static struct s3c_sdhci_platdata smdkv310_hsmmc1_pdata __initdata = { }; static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = { - .cd_type = S3C_SDHCI_CD_GPIO, - .ext_cd_gpio = EXYNOS4_GPK2(2), - .ext_cd_gpio_invert = 1, + .cd_type = S3C_SDHCI_CD_INTERNAL, .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, #ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT .max_width = 8, diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c index c5e65a02be8..b68d5bdf04c 100644 --- a/arch/arm/mach-exynos4/platsmp.c +++ b/arch/arm/mach-exynos4/platsmp.c @@ -154,14 +154,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); scu_enable(scu_base_addr()); diff --git a/arch/arm/mach-exynos4/pm.c b/arch/arm/mach-exynos4/pm.c index 8755ca8dd48..533c28f758c 100644 --- a/arch/arm/mach-exynos4/pm.c +++ b/arch/arm/mach-exynos4/pm.c @@ -280,7 +280,7 @@ static struct sleep_save exynos4_l2cc_save[] = { SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL), }; -void exynos4_cpu_suspend(void) +static int exynos4_cpu_suspend(unsigned long arg) { unsigned long tmp; unsigned long mask = 0xFFFFFFFF; diff --git a/arch/arm/mach-exynos4/sleep.S b/arch/arm/mach-exynos4/sleep.S index 6b62425417a..0984078f1eb 100644 --- a/arch/arm/mach-exynos4/sleep.S +++ b/arch/arm/mach-exynos4/sleep.S @@ -33,28 +33,6 @@ .text /* - * s3c_cpu_save - * - * entry: - * r1 = v:p offset - */ - -ENTRY(s3c_cpu_save) - - stmfd sp!, { r3 - r12, lr } - ldr r3, =resume_with_mmu - bl cpu_suspend - - ldr r0, =pm_cpu_sleep - ldr r0, [ r0 ] - mov pc, r0 - -resume_with_mmu: - ldmfd sp!, { r3 - r12, pc } - - .ltorg - - /* * sleep magic, to allow the bootloader to check for an valid * image to resume to. Must be the first word before the * s3c_cpu_resume entry. diff --git a/arch/arm/mach-h720x/include/mach/entry-macro.S b/arch/arm/mach-h720x/include/mach/entry-macro.S index 6d3b917c4a1..c3948e5ba4a 100644 --- a/arch/arm/mach-h720x/include/mach/entry-macro.S +++ b/arch/arm/mach-h720x/include/mach/entry-macro.S @@ -57,9 +57,6 @@ tst \irqstat, #1 @ bit 0 should be set .endm - .macro irq_prio_table - .endm - #else #error hynix processor selection missmatch #endif diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c index e9a58939572..e2e98bbb641 100644 --- a/arch/arm/mach-ixp4xx/common-pci.c +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -316,6 +316,11 @@ static int abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *r } +static int ixp4xx_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) +{ + return (dma_addr + size) >= SZ_64M; +} + /* * Setup DMA mask to 64MB on PCI devices. Ignore all other devices. */ @@ -324,7 +329,7 @@ static int ixp4xx_pci_platform_notify(struct device *dev) if(dev->bus == &pci_bus_type) { *dev->dma_mask = SZ_64M - 1; dev->coherent_dma_mask = SZ_64M - 1; - dmabounce_register_dev(dev, 2048, 4096); + dmabounce_register_dev(dev, 2048, 4096, ixp4xx_needs_bounce); } return 0; } @@ -337,11 +342,6 @@ static int ixp4xx_pci_platform_notify_remove(struct device *dev) return 0; } -int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) -{ - return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M); -} - void __init ixp4xx_pci_preinit(void) { unsigned long cpuid = read_cpuid_id(); diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 74ed81a3cb1..07772575d7a 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -419,14 +419,20 @@ static void notrace ixp4xx_update_sched_clock(void) /* * clocksource */ + +static cycle_t ixp4xx_clocksource_read(struct clocksource *c) +{ + return *IXP4XX_OSTS; +} + unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ; EXPORT_SYMBOL(ixp4xx_timer_freq); static void __init ixp4xx_clocksource_init(void) { init_sched_clock(&cd, ixp4xx_update_sched_clock, 32, ixp4xx_timer_freq); - clocksource_mmio_init(&IXP4XX_OSTS, "OSTS", ixp4xx_timer_freq, 200, 32, - clocksource_mmio_readl_up); + clocksource_mmio_init(NULL, "OSTS", ixp4xx_timer_freq, 200, 32, + ixp4xx_clocksource_read); } /* diff --git a/arch/arm/mach-lpc32xx/include/mach/entry-macro.S b/arch/arm/mach-lpc32xx/include/mach/entry-macro.S index 870227c9660..b725f6c9397 100644 --- a/arch/arm/mach-lpc32xx/include/mach/entry-macro.S +++ b/arch/arm/mach-lpc32xx/include/mach/entry-macro.S @@ -41,7 +41,3 @@ rsb \irqnr, \irqnr, #31 teq \irqstat, #0 .endm - - .macro irq_prio_table - .endm - diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c index 72b4e763158..ab9f999106c 100644 --- a/arch/arm/mach-mmp/pxa168.c +++ b/arch/arm/mach-mmp/pxa168.c @@ -79,7 +79,7 @@ static APBC_CLK(ssp4, PXA168_SSP4, 4, 0); static APBC_CLK(ssp5, PXA168_SSP5, 4, 0); static APBC_CLK(keypad, PXA168_KPC, 0, 32000); -static APMU_CLK(nand, NAND, 0x01db, 208000000); +static APMU_CLK(nand, NAND, 0x19b, 156000000); static APMU_CLK(lcd, LCD, 0x7f, 312000000); /* device and clock bindings */ diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c index 8f92ccd26ed..1464607aa60 100644 --- a/arch/arm/mach-mmp/pxa910.c +++ b/arch/arm/mach-mmp/pxa910.c @@ -110,7 +110,7 @@ static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000); static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000); static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000); -static APMU_CLK(nand, NAND, 0x01db, 208000000); +static APMU_CLK(nand, NAND, 0x19b, 156000000); static APMU_CLK(u2o, USB, 0x1b, 480000000); /* device and clock bindings */ diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c index 2034098cf01..315b9f36532 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-msm/platsmp.c @@ -157,12 +157,4 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); } diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index de88c9297b6..f49ce85d244 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -215,7 +215,7 @@ static struct omap_kp_platform_data ams_delta_kp_data __initdata = { .delay = 9, }; -static struct platform_device ams_delta_kp_device __initdata = { +static struct platform_device ams_delta_kp_device = { .name = "omap-keypad", .id = -1, .dev = { @@ -225,12 +225,12 @@ static struct platform_device ams_delta_kp_device __initdata = { .resource = ams_delta_kp_resources, }; -static struct platform_device ams_delta_lcd_device __initdata = { +static struct platform_device ams_delta_lcd_device = { .name = "lcd_ams_delta", .id = -1, }; -static struct platform_device ams_delta_led_device __initdata = { +static struct platform_device ams_delta_led_device = { .name = "ams-delta-led", .id = -1 }; @@ -267,7 +267,7 @@ static struct soc_camera_link ams_delta_iclink = { .power = ams_delta_camera_power, }; -static struct platform_device ams_delta_camera_device __initdata = { +static struct platform_device ams_delta_camera_device = { .name = "soc-camera-pdrv", .id = 0, .dev = { diff --git a/arch/arm/mach-omap1/gpio15xx.c b/arch/arm/mach-omap1/gpio15xx.c index 04c4b04cf54..364137c2042 100644 --- a/arch/arm/mach-omap1/gpio15xx.c +++ b/arch/arm/mach-omap1/gpio15xx.c @@ -41,7 +41,7 @@ static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = { .bank_stride = 1, }; -static struct __initdata platform_device omap15xx_mpu_gpio = { +static struct platform_device omap15xx_mpu_gpio = { .name = "omap_gpio", .id = 0, .dev = { @@ -70,7 +70,7 @@ static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = { .bank_width = 16, }; -static struct __initdata platform_device omap15xx_gpio = { +static struct platform_device omap15xx_gpio = { .name = "omap_gpio", .id = 1, .dev = { diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c index 5dd0d4c82b2..293a246e282 100644 --- a/arch/arm/mach-omap1/gpio16xx.c +++ b/arch/arm/mach-omap1/gpio16xx.c @@ -44,7 +44,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = { .bank_stride = 1, }; -static struct __initdata platform_device omap16xx_mpu_gpio = { +static struct platform_device omap16xx_mpu_gpio = { .name = "omap_gpio", .id = 0, .dev = { @@ -73,7 +73,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = { .bank_width = 16, }; -static struct __initdata platform_device omap16xx_gpio1 = { +static struct platform_device omap16xx_gpio1 = { .name = "omap_gpio", .id = 1, .dev = { @@ -102,7 +102,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = { .bank_width = 16, }; -static struct __initdata platform_device omap16xx_gpio2 = { +static struct platform_device omap16xx_gpio2 = { .name = "omap_gpio", .id = 2, .dev = { @@ -131,7 +131,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = { .bank_width = 16, }; -static struct __initdata platform_device omap16xx_gpio3 = { +static struct platform_device omap16xx_gpio3 = { .name = "omap_gpio", .id = 3, .dev = { @@ -160,7 +160,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = { .bank_width = 16, }; -static struct __initdata platform_device omap16xx_gpio4 = { +static struct platform_device omap16xx_gpio4 = { .name = "omap_gpio", .id = 4, .dev = { diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c index 1204c8b871a..c6ad248d63a 100644 --- a/arch/arm/mach-omap1/gpio7xx.c +++ b/arch/arm/mach-omap1/gpio7xx.c @@ -46,7 +46,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = { .bank_stride = 2, }; -static struct __initdata platform_device omap7xx_mpu_gpio = { +static struct platform_device omap7xx_mpu_gpio = { .name = "omap_gpio", .id = 0, .dev = { @@ -75,7 +75,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = { .bank_width = 32, }; -static struct __initdata platform_device omap7xx_gpio1 = { +static struct platform_device omap7xx_gpio1 = { .name = "omap_gpio", .id = 1, .dev = { @@ -104,7 +104,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = { .bank_width = 32, }; -static struct __initdata platform_device omap7xx_gpio2 = { +static struct platform_device omap7xx_gpio2 = { .name = "omap_gpio", .id = 2, .dev = { @@ -133,7 +133,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = { .bank_width = 32, }; -static struct __initdata platform_device omap7xx_gpio3 = { +static struct platform_device omap7xx_gpio3 = { .name = "omap_gpio", .id = 3, .dev = { @@ -162,7 +162,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = { .bank_width = 32, }; -static struct __initdata platform_device omap7xx_gpio4 = { +static struct platform_device omap7xx_gpio4 = { .name = "omap_gpio", .id = 4, .dev = { @@ -191,7 +191,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = { .bank_width = 32, }; -static struct __initdata platform_device omap7xx_gpio5 = { +static struct platform_device omap7xx_gpio5 = { .name = "omap_gpio", .id = 5, .dev = { @@ -220,7 +220,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = { .bank_width = 32, }; -static struct __initdata platform_device omap7xx_gpio6 = { +static struct platform_device omap7xx_gpio6 = { .name = "omap_gpio", .id = 6, .dev = { diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 990366726c5..88bd6f7705f 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -558,7 +558,7 @@ static struct radio_si4713_platform_data rx51_si4713_data __initdata_or_module = .subdev_board_info = &rx51_si4713_board_info, }; -static struct platform_device rx51_si4713_dev __initdata_or_module = { +static struct platform_device rx51_si4713_dev = { .name = "radio-si4713", .id = -1, .dev = { diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index da53ba3917c..aab884fecc5 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -286,14 +286,15 @@ void omap3_save_scratchpad_contents(void) scratchpad_contents.boot_config_ptr = 0x0; if (cpu_is_omap3630()) scratchpad_contents.public_restore_ptr = - virt_to_phys(get_omap3630_restore_pointer()); + virt_to_phys(omap3_restore_3630); else if (omap_rev() != OMAP3430_REV_ES3_0 && omap_rev() != OMAP3430_REV_ES3_1) scratchpad_contents.public_restore_ptr = - virt_to_phys(get_restore_pointer()); + virt_to_phys(omap3_restore); else scratchpad_contents.public_restore_ptr = - virt_to_phys(get_es3_restore_pointer()); + virt_to_phys(omap3_restore_es3); + if (omap_type() == OMAP2_DEVICE_TYPE_GP) scratchpad_contents.secure_ram_restore_ptr = 0x0; else diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h index a016c8b59e0..d4ef75d5a38 100644 --- a/arch/arm/mach-omap2/control.h +++ b/arch/arm/mach-omap2/control.h @@ -386,9 +386,9 @@ extern void omap4_ctrl_pad_writel(u32 val, u16 offset); extern void omap3_save_scratchpad_contents(void); extern void omap3_clear_scratchpad_contents(void); -extern u32 *get_restore_pointer(void); -extern u32 *get_es3_restore_pointer(void); -extern u32 *get_omap3630_restore_pointer(void); +extern void omap3_restore(void); +extern void omap3_restore_es3(void); +extern void omap3_restore_3630(void); extern u32 omap3_arm_context[128]; extern void omap3_control_save_context(void); extern void omap3_control_restore_context(void); diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S index a48690b9099..ceb8b7e593d 100644 --- a/arch/arm/mach-omap2/include/mach/entry-macro.S +++ b/arch/arm/mach-omap2/include/mach/entry-macro.S @@ -165,6 +165,3 @@ #endif #endif /* MULTI_OMAP2 */ - - .macro irq_prio_table - .endm diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index ecfe93c4b58..ce65e9329c7 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -125,14 +125,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); /* * Initialise the SCU and wake up the secondary core using diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 45bcfce7735..04ee5664612 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -88,18 +88,28 @@ extern int pm_dbg_regset_init(int reg_set); #define pm_dbg_regset_init(reg_set) do {} while (0); #endif /* CONFIG_PM_DEBUG */ +/* 24xx */ extern void omap24xx_idle_loop_suspend(void); +extern unsigned int omap24xx_idle_loop_suspend_sz; extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl, void __iomem *sdrc_power); -extern void omap34xx_cpu_suspend(u32 *addr, int save_state); -extern int save_secure_ram_context(u32 *addr); -extern void omap3_save_scratchpad_contents(void); +extern unsigned int omap24xx_cpu_suspend_sz; -extern unsigned int omap24xx_idle_loop_suspend_sz; +/* 3xxx */ +extern void omap34xx_cpu_suspend(int save_state); + +/* omap3_do_wfi function pointer and size, for copy to SRAM */ +extern void omap3_do_wfi(void); +extern unsigned int omap3_do_wfi_sz; +/* ... and its pointer from SRAM after copy */ +extern void (*omap3_do_wfi_sram)(void); + +/* save_secure_ram_context function pointer and size, for copy to SRAM */ +extern int save_secure_ram_context(u32 *addr); extern unsigned int save_secure_ram_context_sz; -extern unsigned int omap24xx_cpu_suspend_sz; -extern unsigned int omap34xx_cpu_suspend_sz; + +extern void omap3_save_scratchpad_contents(void); #define PM_RTA_ERRATUM_i608 (1 << 0) #define PM_SDRC_WAKEUP_ERRATUM_i583 (1 << 1) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index c155c9d1c82..b77d82665ab 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -31,6 +31,8 @@ #include <linux/console.h> #include <trace/events/power.h> +#include <asm/suspend.h> + #include <plat/sram.h> #include "clockdomain.h" #include "powerdomain.h" @@ -40,8 +42,6 @@ #include <plat/gpmc.h> #include <plat/dma.h> -#include <asm/tlbflush.h> - #include "cm2xxx_3xxx.h" #include "cm-regbits-34xx.h" #include "prm-regbits-34xx.h" @@ -64,11 +64,6 @@ static inline bool is_suspending(void) } #endif -/* Scratchpad offsets */ -#define OMAP343X_TABLE_ADDRESS_OFFSET 0xc4 -#define OMAP343X_TABLE_VALUE_OFFSET 0xc0 -#define OMAP343X_CONTROL_REG_VALUE_OFFSET 0xc8 - /* pm34xx errata defined in pm.h */ u16 pm34xx_errata; @@ -83,9 +78,8 @@ struct power_state { static LIST_HEAD(pwrst_list); -static void (*_omap_sram_idle)(u32 *addr, int save_state); - static int (*_omap_save_secure_sram)(u32 *addr); +void (*omap3_do_wfi_sram)(void); static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; @@ -312,28 +306,25 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) return IRQ_HANDLED; } -/* Function to restore the table entry that was modified for enabling MMU */ -static void restore_table_entry(void) +static void omap34xx_save_context(u32 *save) { - void __iomem *scratchpad_address; - u32 previous_value, control_reg_value; - u32 *address; + u32 val; - scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD); + /* Read Auxiliary Control Register */ + asm("mrc p15, 0, %0, c1, c0, 1" : "=r" (val)); + *save++ = 1; + *save++ = val; - /* Get address of entry that was modified */ - address = (u32 *)__raw_readl(scratchpad_address + - OMAP343X_TABLE_ADDRESS_OFFSET); - /* Get the previous value which needs to be restored */ - previous_value = __raw_readl(scratchpad_address + - OMAP343X_TABLE_VALUE_OFFSET); - address = __va(address); - *address = previous_value; - flush_tlb_all(); - control_reg_value = __raw_readl(scratchpad_address - + OMAP343X_CONTROL_REG_VALUE_OFFSET); - /* This will enable caches and prediction */ - set_cr(control_reg_value); + /* Read L2 AUX ctrl register */ + asm("mrc p15, 1, %0, c9, c0, 2" : "=r" (val)); + *save++ = 1; + *save++ = val; +} + +static int omap34xx_do_sram_idle(unsigned long save_state) +{ + omap34xx_cpu_suspend(save_state); + return 0; } void omap_sram_idle(void) @@ -352,9 +343,6 @@ void omap_sram_idle(void) int core_prev_state, per_prev_state; u32 sdrc_pwr = 0; - if (!_omap_sram_idle) - return; - pwrdm_clear_all_prev_pwrst(mpu_pwrdm); pwrdm_clear_all_prev_pwrst(neon_pwrdm); pwrdm_clear_all_prev_pwrst(core_pwrdm); @@ -432,12 +420,16 @@ void omap_sram_idle(void) sdrc_pwr = sdrc_read_reg(SDRC_POWER); /* - * omap3_arm_context is the location where ARM registers - * get saved. The restore path then reads from this - * location and restores them back. + * omap3_arm_context is the location where some ARM context + * get saved. The rest is placed on the stack, and restored + * from there before resuming. */ - _omap_sram_idle(omap3_arm_context, save_state); - cpu_init(); + if (save_state) + omap34xx_save_context(omap3_arm_context); + if (save_state == 1 || save_state == 3) + cpu_suspend(save_state, omap34xx_do_sram_idle); + else + omap34xx_do_sram_idle(save_state); /* Restore normal SDRC POWER settings */ if (omap_rev() >= OMAP3430_REV_ES3_0 && @@ -445,10 +437,6 @@ void omap_sram_idle(void) core_next_state == PWRDM_POWER_OFF) sdrc_write_reg(sdrc_pwr, SDRC_POWER); - /* Restore table entry modified during MMU restoration */ - if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) - restore_table_entry(); - /* CORE */ if (core_next_state < PWRDM_POWER_ON) { core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm); @@ -852,10 +840,17 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) return 0; } +/* + * Push functions to SRAM + * + * The minimum set of functions is pushed to SRAM for execution: + * - omap3_do_wfi for erratum i581 WA, + * - save_secure_ram_context for security extensions. + */ void omap_push_sram_idle(void) { - _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, - omap34xx_cpu_suspend_sz); + omap3_do_wfi_sram = omap_sram_push(omap3_do_wfi, omap3_do_wfi_sz); + if (omap_type() != OMAP2_DEVICE_TYPE_GP) _omap_save_secure_sram = omap_sram_push(save_secure_ram_context, save_secure_ram_context_sz); @@ -920,7 +915,6 @@ static int __init omap3_pm_init(void) per_clkdm = clkdm_lookup("per_clkdm"); core_clkdm = clkdm_lookup("core_clkdm"); - omap_push_sram_idle(); #ifdef CONFIG_SUSPEND suspend_set_ops(&omap_pm_ops); #endif /* CONFIG_SUSPEND */ diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index 63f10669571..f2ea1bd1c69 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -74,46 +74,6 @@ * API functions */ -/* - * The "get_*restore_pointer" functions are used to provide a - * physical restore address where the ROM code jumps while waking - * up from MPU OFF/OSWR state. - * The restore pointer is stored into the scratchpad. - */ - - .text -/* Function call to get the restore pointer for resume from OFF */ -ENTRY(get_restore_pointer) - stmfd sp!, {lr} @ save registers on stack - adr r0, restore - ldmfd sp!, {pc} @ restore regs and return -ENDPROC(get_restore_pointer) - .align -ENTRY(get_restore_pointer_sz) - .word . - get_restore_pointer - - .text -/* Function call to get the restore pointer for 3630 resume from OFF */ -ENTRY(get_omap3630_restore_pointer) - stmfd sp!, {lr} @ save registers on stack - adr r0, restore_3630 - ldmfd sp!, {pc} @ restore regs and return -ENDPROC(get_omap3630_restore_pointer) - .align -ENTRY(get_omap3630_restore_pointer_sz) - .word . - get_omap3630_restore_pointer - - .text -/* Function call to get the restore pointer for ES3 to resume from OFF */ -ENTRY(get_es3_restore_pointer) - stmfd sp!, {lr} @ save registers on stack - adr r0, restore_es3 - ldmfd sp!, {pc} @ restore regs and return -ENDPROC(get_es3_restore_pointer) - .align -ENTRY(get_es3_restore_pointer_sz) - .word . - get_es3_restore_pointer - .text /* * L2 cache needs to be toggled for stable OFF mode functionality on 3630. @@ -133,7 +93,7 @@ ENDPROC(enable_omap3630_toggle_l2_on_restore) /* Function to call rom code to save secure ram context */ .align 3 ENTRY(save_secure_ram_context) - stmfd sp!, {r1-r12, lr} @ save registers on stack + stmfd sp!, {r4 - r11, lr} @ save registers on stack adr r3, api_params @ r3 points to parameters str r0, [r3,#0x4] @ r0 has sdram address ldr r12, high_mask @@ -152,7 +112,7 @@ ENTRY(save_secure_ram_context) nop nop nop - ldmfd sp!, {r1-r12, pc} + ldmfd sp!, {r4 - r11, pc} .align sram_phy_addr_mask: .word SRAM_BASE_P @@ -179,69 +139,38 @@ ENTRY(save_secure_ram_context_sz) * * * Notes: - * - this code gets copied to internal SRAM at boot and after wake-up - * from OFF mode. The execution pointer in SRAM is _omap_sram_idle. + * - only the minimum set of functions gets copied to internal SRAM at boot + * and after wake-up from OFF mode, cf. omap_push_sram_idle. The function + * pointers in SDRAM or SRAM are called depending on the desired low power + * target state. * - when the OMAP wakes up it continues at different execution points * depending on the low power mode (non-OFF vs OFF modes), * cf. 'Resume path for xxx mode' comments. */ .align 3 ENTRY(omap34xx_cpu_suspend) - stmfd sp!, {r0-r12, lr} @ save registers on stack + stmfd sp!, {r4 - r11, lr} @ save registers on stack /* - * r0 contains CPU context save/restore pointer in sdram - * r1 contains information about saving context: + * r0 contains information about saving context: * 0 - No context lost * 1 - Only L1 and logic lost * 2 - Only L2 lost (Even L1 is retained we clean it along with L2) * 3 - Both L1 and L2 lost and logic lost */ - /* Directly jump to WFI is the context save is not required */ - cmp r1, #0x0 - beq omap3_do_wfi + /* + * For OFF mode: save context and jump to WFI in SDRAM (omap3_do_wfi) + * For non-OFF modes: jump to the WFI code in SRAM (omap3_do_wfi_sram) + */ + ldr r4, omap3_do_wfi_sram_addr + ldr r5, [r4] + cmp r0, #0x0 @ If no context save required, + bxeq r5 @ jump to the WFI code in SRAM + /* Otherwise fall through to the save context code */ save_context_wfi: - mov r8, r0 @ Store SDRAM address in r8 - mrc p15, 0, r5, c1, c0, 1 @ Read Auxiliary Control Register - mov r4, #0x1 @ Number of parameters for restore call - stmia r8!, {r4-r5} @ Push parameters for restore call - mrc p15, 1, r5, c9, c0, 2 @ Read L2 AUX ctrl register - stmia r8!, {r4-r5} @ Push parameters for restore call - - /* Check what that target sleep state is from r1 */ - cmp r1, #0x2 @ Only L2 lost, no need to save context - beq clean_caches - -l1_logic_lost: - mov r4, sp @ Store sp - mrs r5, spsr @ Store spsr - mov r6, lr @ Store lr - stmia r8!, {r4-r6} - - mrc p15, 0, r4, c1, c0, 2 @ Coprocessor access control register - mrc p15, 0, r5, c2, c0, 0 @ TTBR0 - mrc p15, 0, r6, c2, c0, 1 @ TTBR1 - mrc p15, 0, r7, c2, c0, 2 @ TTBCR - stmia r8!, {r4-r7} - - mrc p15, 0, r4, c3, c0, 0 @ Domain access Control Register - mrc p15, 0, r5, c10, c2, 0 @ PRRR - mrc p15, 0, r6, c10, c2, 1 @ NMRR - stmia r8!,{r4-r6} - - mrc p15, 0, r4, c13, c0, 1 @ Context ID - mrc p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID - mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address - mrs r7, cpsr @ Store current cpsr - stmia r8!, {r4-r7} - - mrc p15, 0, r4, c1, c0, 0 @ save control register - stmia r8!, {r4} - -clean_caches: /* * jump out to kernel flush routine * - reuse that code is better @@ -284,7 +213,32 @@ clean_caches: THUMB( nop ) .arm -omap3_do_wfi: + b omap3_do_wfi + +/* + * Local variables + */ +omap3_do_wfi_sram_addr: + .word omap3_do_wfi_sram +kernel_flush: + .word v7_flush_dcache_all + +/* =================================== + * == WFI instruction => Enter idle == + * =================================== + */ + +/* + * Do WFI instruction + * Includes the resume path for non-OFF modes + * + * This code gets copied to internal SRAM and is accessible + * from both SDRAM and SRAM: + * - executed from SRAM for non-off modes (omap3_do_wfi_sram), + * - executed from SDRAM for OFF mode (omap3_do_wfi). + */ + .align 3 +ENTRY(omap3_do_wfi) ldr r4, sdrc_power @ read the SDRC_POWER register ldr r5, [r4] @ read the contents of SDRC_POWER orr r5, r5, #0x40 @ enable self refresh on idle req @@ -316,8 +270,86 @@ omap3_do_wfi: nop nop nop - bl wait_sdrc_ok +/* + * This function implements the erratum ID i581 WA: + * SDRC state restore before accessing the SDRAM + * + * Only used at return from non-OFF mode. For OFF + * mode the ROM code configures the SDRC and + * the DPLL before calling the restore code directly + * from DDR. + */ + +/* Make sure SDRC accesses are ok */ +wait_sdrc_ok: + +/* DPLL3 must be locked before accessing the SDRC. Maybe the HW ensures this */ + ldr r4, cm_idlest_ckgen +wait_dpll3_lock: + ldr r5, [r4] + tst r5, #1 + beq wait_dpll3_lock + + ldr r4, cm_idlest1_core +wait_sdrc_ready: + ldr r5, [r4] + tst r5, #0x2 + bne wait_sdrc_ready + /* allow DLL powerdown upon hw idle req */ + ldr r4, sdrc_power + ldr r5, [r4] + bic r5, r5, #0x40 + str r5, [r4] + +/* + * PC-relative stores lead to undefined behaviour in Thumb-2: use a r7 as a + * base instead. + * Be careful not to clobber r7 when maintaing this code. + */ + +is_dll_in_lock_mode: + /* Is dll in lock mode? */ + ldr r4, sdrc_dlla_ctrl + ldr r5, [r4] + tst r5, #0x4 + bne exit_nonoff_modes @ Return if locked + /* wait till dll locks */ + adr r7, kick_counter +wait_dll_lock_timed: + ldr r4, wait_dll_lock_counter + add r4, r4, #1 + str r4, [r7, #wait_dll_lock_counter - kick_counter] + ldr r4, sdrc_dlla_status + /* Wait 20uS for lock */ + mov r6, #8 +wait_dll_lock: + subs r6, r6, #0x1 + beq kick_dll + ldr r5, [r4] + and r5, r5, #0x4 + cmp r5, #0x4 + bne wait_dll_lock + b exit_nonoff_modes @ Return when locked + + /* disable/reenable DLL if not locked */ +kick_dll: + ldr r4, sdrc_dlla_ctrl + ldr r5, [r4] + mov r6, r5 + bic r6, #(1<<3) @ disable dll + str r6, [r4] + dsb + orr r6, r6, #(1<<3) @ enable dll + str r6, [r4] + dsb + ldr r4, kick_counter + add r4, r4, #1 + str r4, [r7] @ kick_counter + b wait_dll_lock_timed + +exit_nonoff_modes: + /* Re-enable C-bit if needed */ mrc p15, 0, r0, c1, c0, 0 tst r0, #(1 << 2) @ Check C bit enabled? orreq r0, r0, #(1 << 2) @ Enable the C bit if cleared @@ -329,7 +361,32 @@ omap3_do_wfi: * == Exit point from non-OFF modes == * =================================== */ - ldmfd sp!, {r0-r12, pc} @ restore regs and return + ldmfd sp!, {r4 - r11, pc} @ restore regs and return + +/* + * Local variables + */ +sdrc_power: + .word SDRC_POWER_V +cm_idlest1_core: + .word CM_IDLEST1_CORE_V +cm_idlest_ckgen: + .word CM_IDLEST_CKGEN_V +sdrc_dlla_status: + .word SDRC_DLLA_STATUS_V +sdrc_dlla_ctrl: + .word SDRC_DLLA_CTRL_V + /* + * When exporting to userspace while the counters are in SRAM, + * these 2 words need to be at the end to facilitate retrival! + */ +kick_counter: + .word 0 +wait_dll_lock_counter: + .word 0 + +ENTRY(omap3_do_wfi_sz) + .word . - omap3_do_wfi /* @@ -346,13 +403,17 @@ omap3_do_wfi: * restore_es3: applies to 34xx >= ES3.0 * restore_3630: applies to 36xx * restore: common code for 3xxx + * + * Note: when back from CORE and MPU OFF mode we are running + * from SDRAM, without MMU, without the caches and prediction. + * Also the SRAM content has been cleared. */ -restore_es3: +ENTRY(omap3_restore_es3) ldr r5, pm_prepwstst_core_p ldr r4, [r5] and r4, r4, #0x3 cmp r4, #0x0 @ Check if previous power state of CORE is OFF - bne restore + bne omap3_restore @ Fall through to OMAP3 common code adr r0, es3_sdrc_fix ldr r1, sram_base ldr r2, es3_sdrc_fix_sz @@ -364,35 +425,32 @@ copy_to_sram: bne copy_to_sram ldr r1, sram_base blx r1 - b restore + b omap3_restore @ Fall through to OMAP3 common code +ENDPROC(omap3_restore_es3) -restore_3630: +ENTRY(omap3_restore_3630) ldr r1, pm_prepwstst_core_p ldr r2, [r1] and r2, r2, #0x3 cmp r2, #0x0 @ Check if previous power state of CORE is OFF - bne restore + bne omap3_restore @ Fall through to OMAP3 common code /* Disable RTA before giving control */ ldr r1, control_mem_rta mov r2, #OMAP36XX_RTA_DISABLE str r2, [r1] +ENDPROC(omap3_restore_3630) /* Fall through to common code for the remaining logic */ -restore: +ENTRY(omap3_restore) /* - * Check what was the reason for mpu reset and store the reason in r9: - * 0 - No context lost - * 1 - Only L1 and logic lost - * 2 - Only L2 lost - In this case, we wont be here - * 3 - Both L1 and L2 lost + * Read the pwstctrl register to check the reason for mpu reset. + * This tells us what was lost. */ ldr r1, pm_pwstctrl_mpu ldr r2, [r1] and r2, r2, #0x3 cmp r2, #0x0 @ Check if target power state was OFF or RET - moveq r9, #0x3 @ MPU OFF => L1 and L2 lost - movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation bne logic_l1_restore ldr r0, l2dis_3630 @@ -471,115 +529,39 @@ logic_l1_restore: orr r1, r1, #2 @ re-enable L2 cache mcr p15, 0, r1, c1, c0, 1 skipl2reen: - mov r1, #0 - /* - * Invalidate all instruction caches to PoU - * and flush branch target cache - */ - mcr p15, 0, r1, c7, c5, 0 - ldr r4, scratchpad_base - ldr r3, [r4,#0xBC] - adds r3, r3, #16 - - ldmia r3!, {r4-r6} - mov sp, r4 @ Restore sp - msr spsr_cxsf, r5 @ Restore spsr - mov lr, r6 @ Restore lr - - ldmia r3!, {r4-r7} - mcr p15, 0, r4, c1, c0, 2 @ Coprocessor access Control Register - mcr p15, 0, r5, c2, c0, 0 @ TTBR0 - mcr p15, 0, r6, c2, c0, 1 @ TTBR1 - mcr p15, 0, r7, c2, c0, 2 @ TTBCR - - ldmia r3!,{r4-r6} - mcr p15, 0, r4, c3, c0, 0 @ Domain access Control Register - mcr p15, 0, r5, c10, c2, 0 @ PRRR - mcr p15, 0, r6, c10, c2, 1 @ NMRR - - - ldmia r3!,{r4-r7} - mcr p15, 0, r4, c13, c0, 1 @ Context ID - mcr p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID - mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address - msr cpsr, r7 @ store cpsr - - /* Enabling MMU here */ - mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl - /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1 */ - and r7, #0x7 - cmp r7, #0x0 - beq usettbr0 -ttbr_error: - /* - * More work needs to be done to support N[0:2] value other than 0 - * So looping here so that the error can be detected - */ - b ttbr_error -usettbr0: - mrc p15, 0, r2, c2, c0, 0 - ldr r5, ttbrbit_mask - and r2, r5 - mov r4, pc - ldr r5, table_index_mask - and r4, r5 @ r4 = 31 to 20 bits of pc - /* Extract the value to be written to table entry */ - ldr r1, table_entry - /* r1 has the value to be written to table entry*/ - add r1, r1, r4 - /* Getting the address of table entry to modify */ - lsr r4, #18 - /* r2 has the location which needs to be modified */ - add r2, r4 - /* Storing previous entry of location being modified */ - ldr r5, scratchpad_base - ldr r4, [r2] - str r4, [r5, #0xC0] - /* Modify the table entry */ - str r1, [r2] - /* - * Storing address of entry being modified - * - will be restored after enabling MMU - */ - ldr r5, scratchpad_base - str r2, [r5, #0xC4] - - mov r0, #0 - mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer - mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array - mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB - mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB - /* - * Restore control register. This enables the MMU. - * The caches and prediction are not enabled here, they - * will be enabled after restoring the MMU table entry. - */ - ldmia r3!, {r4} - /* Store previous value of control register in scratchpad */ - str r4, [r5, #0xC8] - ldr r2, cache_pred_disable_mask - and r4, r2 - mcr p15, 0, r4, c1, c0, 0 - dsb - isb - ldr r0, =restoremmu_on - bx r0 + /* Now branch to the common CPU resume function */ + b cpu_resume +ENDPROC(omap3_restore) + + .ltorg /* - * ============================== - * == Exit point from OFF mode == - * ============================== + * Local variables */ -restoremmu_on: - ldmfd sp!, {r0-r12, pc} @ restore regs and return - +pm_prepwstst_core_p: + .word PM_PREPWSTST_CORE_P +pm_pwstctrl_mpu: + .word PM_PWSTCTRL_MPU_P +scratchpad_base: + .word SCRATCHPAD_BASE_P +sram_base: + .word SRAM_BASE_P + 0x8000 +control_stat: + .word CONTROL_STAT +control_mem_rta: + .word CONTROL_MEM_RTA_CTRL +l2dis_3630: + .word 0 /* * Internal functions */ -/* This function implements the erratum ID i443 WA, applies to 34xx >= ES3.0 */ +/* + * This function implements the erratum ID i443 WA, applies to 34xx >= ES3.0 + * Copied to and run from SRAM in order to reconfigure the SDRC parameters. + */ .text .align 3 ENTRY(es3_sdrc_fix) @@ -609,6 +591,9 @@ ENTRY(es3_sdrc_fix) str r5, [r4] @ kick off refreshes bx lr +/* + * Local variables + */ .align sdrc_syscfg: .word SDRC_SYSCONFIG_P @@ -627,128 +612,3 @@ sdrc_manual_1: ENDPROC(es3_sdrc_fix) ENTRY(es3_sdrc_fix_sz) .word . - es3_sdrc_fix - -/* - * This function implements the erratum ID i581 WA: - * SDRC state restore before accessing the SDRAM - * - * Only used at return from non-OFF mode. For OFF - * mode the ROM code configures the SDRC and - * the DPLL before calling the restore code directly - * from DDR. - */ - -/* Make sure SDRC accesses are ok */ -wait_sdrc_ok: - -/* DPLL3 must be locked before accessing the SDRC. Maybe the HW ensures this */ - ldr r4, cm_idlest_ckgen -wait_dpll3_lock: - ldr r5, [r4] - tst r5, #1 - beq wait_dpll3_lock - - ldr r4, cm_idlest1_core -wait_sdrc_ready: - ldr r5, [r4] - tst r5, #0x2 - bne wait_sdrc_ready - /* allow DLL powerdown upon hw idle req */ - ldr r4, sdrc_power - ldr r5, [r4] - bic r5, r5, #0x40 - str r5, [r4] - -/* - * PC-relative stores lead to undefined behaviour in Thumb-2: use a r7 as a - * base instead. - * Be careful not to clobber r7 when maintaing this code. - */ - -is_dll_in_lock_mode: - /* Is dll in lock mode? */ - ldr r4, sdrc_dlla_ctrl - ldr r5, [r4] - tst r5, #0x4 - bxne lr @ Return if locked - /* wait till dll locks */ - adr r7, kick_counter -wait_dll_lock_timed: - ldr r4, wait_dll_lock_counter - add r4, r4, #1 - str r4, [r7, #wait_dll_lock_counter - kick_counter] - ldr r4, sdrc_dlla_status - /* Wait 20uS for lock */ - mov r6, #8 -wait_dll_lock: - subs r6, r6, #0x1 - beq kick_dll - ldr r5, [r4] - and r5, r5, #0x4 - cmp r5, #0x4 - bne wait_dll_lock - bx lr @ Return when locked - - /* disable/reenable DLL if not locked */ -kick_dll: - ldr r4, sdrc_dlla_ctrl - ldr r5, [r4] - mov r6, r5 - bic r6, #(1<<3) @ disable dll - str r6, [r4] - dsb - orr r6, r6, #(1<<3) @ enable dll - str r6, [r4] - dsb - ldr r4, kick_counter - add r4, r4, #1 - str r4, [r7] @ kick_counter - b wait_dll_lock_timed - - .align -cm_idlest1_core: - .word CM_IDLEST1_CORE_V -cm_idlest_ckgen: - .word CM_IDLEST_CKGEN_V -sdrc_dlla_status: - .word SDRC_DLLA_STATUS_V -sdrc_dlla_ctrl: - .word SDRC_DLLA_CTRL_V -pm_prepwstst_core_p: - .word PM_PREPWSTST_CORE_P -pm_pwstctrl_mpu: - .word PM_PWSTCTRL_MPU_P -scratchpad_base: - .word SCRATCHPAD_BASE_P -sram_base: - .word SRAM_BASE_P + 0x8000 -sdrc_power: - .word SDRC_POWER_V -ttbrbit_mask: - .word 0xFFFFC000 -table_index_mask: - .word 0xFFF00000 -table_entry: - .word 0x00000C02 -cache_pred_disable_mask: - .word 0xFFFFE7FB -control_stat: - .word CONTROL_STAT -control_mem_rta: - .word CONTROL_MEM_RTA_CTRL -kernel_flush: - .word v7_flush_dcache_all -l2dis_3630: - .word 0 - /* - * When exporting to userspace while the counters are in SRAM, - * these 2 words need to be at the end to facilitate retrival! - */ -kick_counter: - .word 0 -wait_dll_lock_counter: - .word 0 -ENDPROC(omap34xx_cpu_suspend) - -ENTRY(omap34xx_cpu_suspend_sz) - .word . - omap34xx_cpu_suspend diff --git a/arch/arm/mach-pnx4008/include/mach/entry-macro.S b/arch/arm/mach-pnx4008/include/mach/entry-macro.S index 8003037578e..db7eeebf30d 100644 --- a/arch/arm/mach-pnx4008/include/mach/entry-macro.S +++ b/arch/arm/mach-pnx4008/include/mach/entry-macro.S @@ -120,8 +120,3 @@ 1003: .endm - - .macro irq_prio_table - .endm - - diff --git a/arch/arm/mach-pxa/include/mach/pm.h b/arch/arm/mach-pxa/include/mach/pm.h index f15afe01299..51558bcee99 100644 --- a/arch/arm/mach-pxa/include/mach/pm.h +++ b/arch/arm/mach-pxa/include/mach/pm.h @@ -22,8 +22,8 @@ struct pxa_cpu_pm_fns { extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns; /* sleep.S */ -extern void pxa25x_cpu_suspend(unsigned int, long); -extern void pxa27x_cpu_suspend(unsigned int, long); +extern int pxa25x_finish_suspend(unsigned long); +extern int pxa27x_finish_suspend(unsigned long); extern int pxa_pm_enter(suspend_state_t state); extern int pxa_pm_prepare(void); diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index 87ae3129f4f..b27544bcafc 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c @@ -347,9 +347,9 @@ static int pxa2xx_mfp_suspend(void) if ((gpio_desc[i].config & MFP_LPM_KEEP_OUTPUT) && (GPDR(i) & GPIO_bit(i))) { if (GPLR(i) & GPIO_bit(i)) - PGSR(i) |= GPIO_bit(i); + PGSR(gpio_to_bank(i)) |= GPIO_bit(i); else - PGSR(i) &= ~GPIO_bit(i); + PGSR(gpio_to_bank(i)) &= ~GPIO_bit(i); } } diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c index 65f24f0b77e..5a5329bc33f 100644 --- a/arch/arm/mach-pxa/palmz72.c +++ b/arch/arm/mach-pxa/palmz72.c @@ -33,6 +33,7 @@ #include <linux/i2c-gpio.h> #include <asm/mach-types.h> +#include <asm/suspend.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index 51e1583265b..37178a8559b 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c @@ -42,7 +42,6 @@ int pxa_pm_enter(suspend_state_t state) /* *** go zzz *** */ pxa_cpu_pm_fns->enter(state); - cpu_init(); if (state != PM_SUSPEND_STANDBY && pxa_cpu_pm_fns->restore) { /* after sleeping, validate the checksum */ diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index fed363cec9c..9c434d21a27 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -25,6 +25,7 @@ #include <linux/irq.h> #include <asm/mach/map.h> +#include <asm/suspend.h> #include <mach/hardware.h> #include <mach/irqs.h> #include <mach/gpio.h> @@ -244,7 +245,7 @@ static void pxa25x_cpu_pm_enter(suspend_state_t state) switch (state) { case PM_SUSPEND_MEM: - pxa25x_cpu_suspend(PWRMODE_SLEEP, PLAT_PHYS_OFFSET - PAGE_OFFSET); + cpu_suspend(PWRMODE_SLEEP, pxa25x_finish_suspend); break; } } diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 2fecbec58d8..9d2400b5f50 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -24,6 +24,7 @@ #include <asm/mach/map.h> #include <mach/hardware.h> #include <asm/irq.h> +#include <asm/suspend.h> #include <mach/irqs.h> #include <mach/gpio.h> #include <mach/pxa27x.h> @@ -284,6 +285,11 @@ void pxa27x_cpu_pm_restore(unsigned long *sleep_save) void pxa27x_cpu_pm_enter(suspend_state_t state) { extern void pxa_cpu_standby(void); +#ifndef CONFIG_IWMMXT + u64 acc0; + + asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0)); +#endif /* ensure voltage-change sequencer not initiated, which hangs */ PCFR &= ~PCFR_FVC; @@ -299,7 +305,10 @@ void pxa27x_cpu_pm_enter(suspend_state_t state) pxa_cpu_standby(); break; case PM_SUSPEND_MEM: - pxa27x_cpu_suspend(pwrmode, PLAT_PHYS_OFFSET - PAGE_OFFSET); + cpu_suspend(pwrmode, pxa27x_finish_suspend); +#ifndef CONFIG_IWMMXT + asm volatile("mar acc0, %Q0, %R0" : "=r" (acc0)); +#endif break; } } diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 8521d7d6f1d..ef1c56a67af 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -24,6 +24,7 @@ #include <linux/i2c/pxa-i2c.h> #include <asm/mach/map.h> +#include <asm/suspend.h> #include <mach/hardware.h> #include <mach/gpio.h> #include <mach/pxa3xx-regs.h> @@ -141,8 +142,13 @@ static void pxa3xx_cpu_pm_suspend(void) { volatile unsigned long *p = (volatile void *)0xc0000000; unsigned long saved_data = *p; +#ifndef CONFIG_IWMMXT + u64 acc0; - extern void pxa3xx_cpu_suspend(long); + asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0)); +#endif + + extern int pxa3xx_finish_suspend(unsigned long); /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */ CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM); @@ -162,11 +168,15 @@ static void pxa3xx_cpu_pm_suspend(void) /* overwrite with the resume address */ *p = virt_to_phys(cpu_resume); - pxa3xx_cpu_suspend(PLAT_PHYS_OFFSET - PAGE_OFFSET); + cpu_suspend(0, pxa3xx_finish_suspend); *p = saved_data; AD3ER = 0; + +#ifndef CONFIG_IWMMXT + asm volatile("mar acc0, %Q0, %R0" : "=r" (acc0)); +#endif } static void pxa3xx_cpu_pm_enter(suspend_state_t state) diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index d130f77b6d1..2f37d43f51b 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -573,10 +573,10 @@ static struct pxafb_mode_info sharp_lq043t3dx02_mode = { .xres = 480, .yres = 272, .bpp = 16, - .hsync_len = 4, + .hsync_len = 41, .left_margin = 2, .right_margin = 1, - .vsync_len = 1, + .vsync_len = 10, .upper_margin = 3, .lower_margin = 1, .sync = 0, @@ -596,29 +596,31 @@ static void __init raumfeld_lcd_init(void) { int ret; - pxa_set_fb_info(NULL, &raumfeld_sharp_lcd_info); - - /* Earlier devices had the backlight regulator controlled - * via PWM, later versions use another controller for that */ - if ((system_rev & 0xff) < 2) { - mfp_cfg_t raumfeld_pwm_pin_config = GPIO17_PWM0_OUT; - pxa3xx_mfp_config(&raumfeld_pwm_pin_config, 1); - platform_device_register(&raumfeld_pwm_backlight_device); - } else - platform_device_register(&raumfeld_lt3593_device); - ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable"); if (ret < 0) pr_warning("Unable to request GPIO_TFT_VA_EN\n"); else gpio_direction_output(GPIO_TFT_VA_EN, 1); + msleep(100); + ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable"); if (ret < 0) pr_warning("Unable to request GPIO_DISPLAY_ENABLE\n"); else gpio_direction_output(GPIO_DISPLAY_ENABLE, 1); + /* Hardware revision 2 has the backlight regulator controlled + * by an LT3593, earlier and later devices use PWM for that. */ + if ((system_rev & 0xff) == 2) { + platform_device_register(&raumfeld_lt3593_device); + } else { + mfp_cfg_t raumfeld_pwm_pin_config = GPIO17_PWM0_OUT; + pxa3xx_mfp_config(&raumfeld_pwm_pin_config, 1); + platform_device_register(&raumfeld_pwm_backlight_device); + } + + pxa_set_fb_info(NULL, &raumfeld_sharp_lcd_info); platform_device_register(&pxa3xx_device_gcu); } @@ -657,10 +659,10 @@ static struct lis3lv02d_platform_data lis3_pdata = { #define SPI_AK4104 \ { \ - .modalias = "ak4104", \ - .max_speed_hz = 10000, \ - .bus_num = 0, \ - .chip_select = 0, \ + .modalias = "ak4104-codec", \ + .max_speed_hz = 10000, \ + .bus_num = 0, \ + .chip_select = 0, \ .controller_data = (void *) GPIO_SPDIF_CS, \ } diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S index 6f5368899d8..1e544be9905 100644 --- a/arch/arm/mach-pxa/sleep.S +++ b/arch/arm/mach-pxa/sleep.S @@ -24,20 +24,9 @@ #ifdef CONFIG_PXA3xx /* - * pxa3xx_cpu_suspend() - forces CPU into sleep state (S2D3C4) - * - * r0 = v:p offset + * pxa3xx_finish_suspend() - forces CPU into sleep state (S2D3C4) */ -ENTRY(pxa3xx_cpu_suspend) - -#ifndef CONFIG_IWMMXT - mra r2, r3, acc0 -#endif - stmfd sp!, {r2 - r12, lr} @ save registers on stack - mov r1, r0 - ldr r3, =pxa_cpu_resume @ resume function - bl cpu_suspend - +ENTRY(pxa3xx_finish_suspend) mov r0, #0x06 @ S2D3C4 mode mcr p14, 0, r0, c7, c0, 0 @ enter sleep @@ -46,28 +35,18 @@ ENTRY(pxa3xx_cpu_suspend) #ifdef CONFIG_PXA27x /* - * pxa27x_cpu_suspend() + * pxa27x_finish_suspend() * * Forces CPU into sleep state. * * r0 = value for PWRMODE M field for desired sleep state - * r1 = v:p offset */ -ENTRY(pxa27x_cpu_suspend) - -#ifndef CONFIG_IWMMXT - mra r2, r3, acc0 -#endif - stmfd sp!, {r2 - r12, lr} @ save registers on stack - mov r4, r0 @ save sleep mode - ldr r3, =pxa_cpu_resume @ resume function - bl cpu_suspend - +ENTRY(pxa27x_finish_suspend) @ Put the processor to sleep @ (also workaround for sighting 28071) @ prepare value for sleep mode - mov r1, r4 @ sleep mode + mov r1, r0 @ sleep mode @ prepare pointer to physical address 0 (virtual mapping in generic.c) mov r2, #UNCACHED_PHYS_0 @@ -99,21 +78,16 @@ ENTRY(pxa27x_cpu_suspend) #ifdef CONFIG_PXA25x /* - * pxa25x_cpu_suspend() + * pxa25x_finish_suspend() * * Forces CPU into sleep state. * * r0 = value for PWRMODE M field for desired sleep state - * r1 = v:p offset */ -ENTRY(pxa25x_cpu_suspend) - stmfd sp!, {r2 - r12, lr} @ save registers on stack - mov r4, r0 @ save sleep mode - ldr r3, =pxa_cpu_resume @ resume function - bl cpu_suspend +ENTRY(pxa25x_finish_suspend) @ prepare value for sleep mode - mov r1, r4 @ sleep mode + mov r1, r0 @ sleep mode @ prepare pointer to physical address 0 (virtual mapping in generic.c) mov r2, #UNCACHED_PHYS_0 @@ -195,16 +169,3 @@ pxa_cpu_do_suspend: mcr p14, 0, r1, c7, c0, 0 @ PWRMODE 20: b 20b @ loop waiting for sleep - -/* - * pxa_cpu_resume() - * - * entry point from bootloader into kernel during resume - */ - .align 5 -pxa_cpu_resume: - ldmfd sp!, {r2, r3} -#ifndef CONFIG_IWMMXT - mar acc0, r2, r3 -#endif - ldmfd sp!, {r4 - r12, pc} @ return to caller diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index 00363c7ac18..9b99cc164de 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -31,6 +31,7 @@ #include <linux/can/platform/mcp251x.h> #include <asm/mach-types.h> +#include <asm/suspend.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -676,7 +677,7 @@ static struct pxa2xx_udc_mach_info zeus_udc_info = { static void zeus_power_off(void) { local_irq_disable(); - pxa27x_cpu_suspend(PWRMODE_DEEPSLEEP, PLAT_PHYS_OFFSET - PAGE_OFFSET); + cpu_suspend(PWRMODE_DEEPSLEEP, pxa27x_finish_suspend); } #else #define zeus_power_off NULL diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig index b9a9805e482..dba6d0c1fc1 100644 --- a/arch/arm/mach-realview/Kconfig +++ b/arch/arm/mach-realview/Kconfig @@ -50,6 +50,7 @@ config MACH_REALVIEW_PB1176 bool "Support RealView(R) Platform Baseboard for ARM1176JZF-S" select CPU_V6 select ARM_GIC + select HAVE_TCM help Include support for the ARM(R) RealView(R) Platform Baseboard for ARM1176JZF-S. diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 963bf0d8119..4ae943bafa9 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -68,14 +68,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); scu_enable(scu_base_addr()); diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c index 752b13a7b3d..f4077efa51f 100644 --- a/arch/arm/mach-s3c2412/pm.c +++ b/arch/arm/mach-s3c2412/pm.c @@ -37,12 +37,10 @@ extern void s3c2412_sleep_enter(void); -static void s3c2412_cpu_suspend(void) +static int s3c2412_cpu_suspend(unsigned long arg) { unsigned long tmp; - flush_cache_all(); - /* set our standby method to sleep */ tmp = __raw_readl(S3C2412_PWRCFG); @@ -50,6 +48,8 @@ static void s3c2412_cpu_suspend(void) __raw_writel(tmp, S3C2412_PWRCFG); s3c2412_sleep_enter(); + + panic("sleep resumed to originator?"); } static void s3c2412_pm_prepare(void) diff --git a/arch/arm/mach-s3c2416/pm.c b/arch/arm/mach-s3c2416/pm.c index 41db2b21e21..9ec54f1d8e7 100644 --- a/arch/arm/mach-s3c2416/pm.c +++ b/arch/arm/mach-s3c2416/pm.c @@ -24,10 +24,8 @@ extern void s3c2412_sleep_enter(void); -static void s3c2416_cpu_suspend(void) +static int s3c2416_cpu_suspend(unsigned long arg) { - flush_cache_all(); - /* enable wakeup sources regardless of battery state */ __raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG); @@ -35,6 +33,8 @@ static void s3c2416_cpu_suspend(void) __raw_writel(0x2BED, S3C2443_PWRMODE); s3c2412_sleep_enter(); + + panic("sleep resumed to originator?"); } static void s3c2416_pm_prepare(void) diff --git a/arch/arm/mach-s3c2440/mach-mini2440.c b/arch/arm/mach-s3c2440/mach-mini2440.c index dd3120df09f..fc2dc0b3d4f 100644 --- a/arch/arm/mach-s3c2440/mach-mini2440.c +++ b/arch/arm/mach-s3c2440/mach-mini2440.c @@ -552,7 +552,7 @@ struct mini2440_features_t { struct platform_device *optional[8]; }; -static void mini2440_parse_features( +static void __init mini2440_parse_features( struct mini2440_features_t * features, const char * features_str ) { diff --git a/arch/arm/mach-s3c64xx/dev-spi.c b/arch/arm/mach-s3c64xx/dev-spi.c index 82db072cb83..5e6b42089eb 100644 --- a/arch/arm/mach-s3c64xx/dev-spi.c +++ b/arch/arm/mach-s3c64xx/dev-spi.c @@ -88,6 +88,7 @@ static struct s3c64xx_spi_info s3c64xx_spi0_pdata = { .cfg_gpio = s3c64xx_spi_cfg_gpio, .fifo_lvl_mask = 0x7f, .rx_lvl_offset = 13, + .tx_st_done = 21, }; static u64 spi_dmamask = DMA_BIT_MASK(32); @@ -132,6 +133,7 @@ static struct s3c64xx_spi_info s3c64xx_spi1_pdata = { .cfg_gpio = s3c64xx_spi_cfg_gpio, .fifo_lvl_mask = 0x7f, .rx_lvl_offset = 13, + .tx_st_done = 21, }; struct platform_device s3c64xx_device_spi1 = { diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c index b197171e7d0..204bfafe4bf 100644 --- a/arch/arm/mach-s3c64xx/dma.c +++ b/arch/arm/mach-s3c64xx/dma.c @@ -113,7 +113,7 @@ found: return chan; } -int s3c2410_dma_config(unsigned int channel, int xferunit) +int s3c2410_dma_config(enum dma_ch channel, int xferunit) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -297,7 +297,7 @@ static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan) return 0; } -int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op) +int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -331,7 +331,7 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl); * */ -int s3c2410_dma_enqueue(unsigned int channel, void *id, +int s3c2410_dma_enqueue(enum dma_ch channel, void *id, dma_addr_t data, int size) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -415,7 +415,7 @@ err_buff: EXPORT_SYMBOL(s3c2410_dma_enqueue); -int s3c2410_dma_devconfig(unsigned int channel, +int s3c2410_dma_devconfig(enum dma_ch channel, enum s3c2410_dmasrc source, unsigned long devaddr) { @@ -463,7 +463,7 @@ int s3c2410_dma_devconfig(unsigned int channel, EXPORT_SYMBOL(s3c2410_dma_devconfig); -int s3c2410_dma_getposition(unsigned int channel, +int s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dst) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -487,7 +487,7 @@ EXPORT_SYMBOL(s3c2410_dma_getposition); * get control of an dma channel */ -int s3c2410_dma_request(unsigned int channel, +int s3c2410_dma_request(enum dma_ch channel, struct s3c2410_dma_client *client, void *dev) { @@ -533,7 +533,7 @@ EXPORT_SYMBOL(s3c2410_dma_request); * allowed to go through. */ -int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client) +int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); unsigned long flags; diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index bc1c470b7de..8bad6437068 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c @@ -112,7 +112,7 @@ void s3c_pm_save_core(void) * this. */ -static void s3c64xx_cpu_suspend(void) +static int s3c64xx_cpu_suspend(unsigned long arg) { unsigned long tmp; diff --git a/arch/arm/mach-s3c64xx/sleep.S b/arch/arm/mach-s3c64xx/sleep.S index 1f87732b232..34313f9c879 100644 --- a/arch/arm/mach-s3c64xx/sleep.S +++ b/arch/arm/mach-s3c64xx/sleep.S @@ -25,29 +25,6 @@ .text - /* s3c_cpu_save - * - * Save enough processor state to allow the restart of the pm.c - * code after resume. - * - * entry: - * r1 = v:p offset - */ - -ENTRY(s3c_cpu_save) - stmfd sp!, { r4 - r12, lr } - ldr r3, =resume_with_mmu - bl cpu_suspend - - @@ call final suspend code - ldr r0, =pm_cpu_sleep - ldr pc, [r0] - - @@ return to the caller, after the MMU is turned on. - @@ restore the last bits of the stack and return. -resume_with_mmu: - ldmfd sp!, { r4 - r12, pc } @ return, from sp from s3c_cpu_save - /* Sleep magic, the word before the resume entry point so that the * bootloader can check for a resumeable image. */ diff --git a/arch/arm/mach-s5p64x0/dev-spi.c b/arch/arm/mach-s5p64x0/dev-spi.c index e78ee18c76e..ac825e82632 100644 --- a/arch/arm/mach-s5p64x0/dev-spi.c +++ b/arch/arm/mach-s5p64x0/dev-spi.c @@ -112,12 +112,14 @@ static struct s3c64xx_spi_info s5p6440_spi0_pdata = { .cfg_gpio = s5p6440_spi_cfg_gpio, .fifo_lvl_mask = 0x1ff, .rx_lvl_offset = 15, + .tx_st_done = 25, }; static struct s3c64xx_spi_info s5p6450_spi0_pdata = { .cfg_gpio = s5p6450_spi_cfg_gpio, .fifo_lvl_mask = 0x1ff, .rx_lvl_offset = 15, + .tx_st_done = 25, }; static u64 spi_dmamask = DMA_BIT_MASK(32); @@ -160,12 +162,14 @@ static struct s3c64xx_spi_info s5p6440_spi1_pdata = { .cfg_gpio = s5p6440_spi_cfg_gpio, .fifo_lvl_mask = 0x7f, .rx_lvl_offset = 15, + .tx_st_done = 25, }; static struct s3c64xx_spi_info s5p6450_spi1_pdata = { .cfg_gpio = s5p6450_spi_cfg_gpio, .fifo_lvl_mask = 0x7f, .rx_lvl_offset = 15, + .tx_st_done = 25, }; struct platform_device s5p64x0_device_spi1 = { diff --git a/arch/arm/mach-s5pc100/dev-spi.c b/arch/arm/mach-s5pc100/dev-spi.c index 57b19794d9b..e5d6c4dceb5 100644 --- a/arch/arm/mach-s5pc100/dev-spi.c +++ b/arch/arm/mach-s5pc100/dev-spi.c @@ -15,6 +15,7 @@ #include <mach/dma.h> #include <mach/map.h> #include <mach/spi-clocks.h> +#include <mach/irqs.h> #include <plat/s3c64xx-spi.h> #include <plat/gpio-cfg.h> @@ -90,6 +91,7 @@ static struct s3c64xx_spi_info s5pc100_spi0_pdata = { .fifo_lvl_mask = 0x7f, .rx_lvl_offset = 13, .high_speed = 1, + .tx_st_done = 21, }; static u64 spi_dmamask = DMA_BIT_MASK(32); @@ -134,6 +136,7 @@ static struct s3c64xx_spi_info s5pc100_spi1_pdata = { .fifo_lvl_mask = 0x7f, .rx_lvl_offset = 13, .high_speed = 1, + .tx_st_done = 21, }; struct platform_device s5pc100_device_spi1 = { @@ -176,6 +179,7 @@ static struct s3c64xx_spi_info s5pc100_spi2_pdata = { .fifo_lvl_mask = 0x7f, .rx_lvl_offset = 13, .high_speed = 1, + .tx_st_done = 21, }; struct platform_device s5pc100_device_spi2 = { diff --git a/arch/arm/mach-s5pv210/dev-spi.c b/arch/arm/mach-s5pv210/dev-spi.c index e3249a47e3b..eaf9a7bff7a 100644 --- a/arch/arm/mach-s5pv210/dev-spi.c +++ b/arch/arm/mach-s5pv210/dev-spi.c @@ -85,6 +85,7 @@ static struct s3c64xx_spi_info s5pv210_spi0_pdata = { .fifo_lvl_mask = 0x1ff, .rx_lvl_offset = 15, .high_speed = 1, + .tx_st_done = 25, }; static u64 spi_dmamask = DMA_BIT_MASK(32); @@ -129,6 +130,7 @@ static struct s3c64xx_spi_info s5pv210_spi1_pdata = { .fifo_lvl_mask = 0x7f, .rx_lvl_offset = 15, .high_speed = 1, + .tx_st_done = 25, }; struct platform_device s5pv210_device_spi1 = { diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c index 24febae3d4c..309e388a8a8 100644 --- a/arch/arm/mach-s5pv210/pm.c +++ b/arch/arm/mach-s5pv210/pm.c @@ -88,7 +88,7 @@ static struct sleep_save s5pv210_core_save[] = { SAVE_ITEM(S3C2410_TCNTO(0)), }; -void s5pv210_cpu_suspend(void) +void s5pv210_cpu_suspend(unsigned long arg) { unsigned long tmp; diff --git a/arch/arm/mach-s5pv210/sleep.S b/arch/arm/mach-s5pv210/sleep.S index a3d649466fb..e3452ccd4b0 100644 --- a/arch/arm/mach-s5pv210/sleep.S +++ b/arch/arm/mach-s5pv210/sleep.S @@ -32,27 +32,6 @@ .text - /* s3c_cpu_save - * - * entry: - * r1 = v:p offset - */ - -ENTRY(s3c_cpu_save) - - stmfd sp!, { r3 - r12, lr } - ldr r3, =resume_with_mmu - bl cpu_suspend - - ldr r0, =pm_cpu_sleep - ldr r0, [ r0 ] - mov pc, r0 - -resume_with_mmu: - ldmfd sp!, { r3 - r12, pc } - - .ltorg - /* sleep magic, to allow the bootloader to check for an valid * image to resume to. Must be the first word before the * s3c_cpu_resume entry. diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index c4661aab22f..bf85b8b259d 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -29,10 +29,11 @@ #include <mach/hardware.h> #include <asm/memory.h> +#include <asm/suspend.h> #include <asm/system.h> #include <asm/mach/time.h> -extern void sa1100_cpu_suspend(long); +extern int sa1100_finish_suspend(unsigned long); #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] @@ -75,9 +76,7 @@ static int sa11x0_pm_enter(suspend_state_t state) PSPR = virt_to_phys(cpu_resume); /* go zzz */ - sa1100_cpu_suspend(PLAT_PHYS_OFFSET - PAGE_OFFSET); - - cpu_init(); + cpu_suspend(0, sa1100_finish_suspend); /* * Ensure not to come back here if it wasn't intended diff --git a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S index 04f2a618d4e..e8223315b44 100644 --- a/arch/arm/mach-sa1100/sleep.S +++ b/arch/arm/mach-sa1100/sleep.S @@ -22,18 +22,13 @@ .text /* - * sa1100_cpu_suspend() + * sa1100_finish_suspend() * * Causes sa11x0 to enter sleep state * */ -ENTRY(sa1100_cpu_suspend) - stmfd sp!, {r4 - r12, lr} @ save registers on stack - mov r1, r0 - ldr r3, =sa1100_cpu_resume @ return function - bl cpu_suspend - +ENTRY(sa1100_finish_suspend) @ disable clock switching mcr p15, 0, r1, c15, c2, 2 @@ -139,13 +134,3 @@ sa1110_sdram_controller_fix: str r13, [r12] 20: b 20b @ loop waiting for sleep - -/* - * cpu_sa1100_resume() - * - * entry point from bootloader into kernel during resume - */ - .align 5 -sa1100_cpu_resume: - mcr p15, 0, r1, c15, c1, 2 @ enable clock switching - ldmfd sp!, {r4 - r12, pc} @ return to caller diff --git a/arch/arm/mach-shark/include/mach/entry-macro.S b/arch/arm/mach-shark/include/mach/entry-macro.S index e2853c0a333..0bb6cc626eb 100644 --- a/arch/arm/mach-shark/include/mach/entry-macro.S +++ b/arch/arm/mach-shark/include/mach/entry-macro.S @@ -11,17 +11,17 @@ .endm .macro get_irqnr_preamble, base, tmp + mov \base, #0xe0000000 .endm .macro arch_ret_to_user, tmp1, tmp2 .endm .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - mov r4, #0xe0000000 mov \irqstat, #0x0C - strb \irqstat, [r4, #0x20] @outb(0x0C, 0x20) /* Poll command */ - ldrb \irqnr, [r4, #0x20] @irq = inb(0x20) & 7 + strb \irqstat, [\base, #0x20] @outb(0x0C, 0x20) /* Poll command */ + ldrb \irqnr, [\base, #0x20] @irq = inb(0x20) & 7 and \irqstat, \irqnr, #0x80 teq \irqstat, #0 beq 43f @@ -29,8 +29,8 @@ teq \irqnr, #2 bne 44f 43: mov \irqstat, #0x0C - strb \irqstat, [r4, #0xa0] @outb(0x0C, 0xA0) /* Poll command */ - ldrb \irqnr, [r4, #0xa0] @irq = (inb(0xA0) & 7) + 8 + strb \irqstat, [\base, #0xa0] @outb(0x0C, 0xA0) /* Poll command */ + ldrb \irqnr, [\base, #0xa0] @irq = (inb(0xA0) & 7) + 8 and \irqstat, \irqnr, #0x80 teq \irqstat, #0 beq 44f diff --git a/arch/arm/mach-shmobile/include/mach/sdhi-sh7372.h b/arch/arm/mach-shmobile/include/mach/sdhi-sh7372.h new file mode 100644 index 00000000000..4a81b01f1e8 --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/sdhi-sh7372.h @@ -0,0 +1,21 @@ +#ifndef SDHI_SH7372_H +#define SDHI_SH7372_H + +#define SDGENCNTA 0xfe40009c + +/* The countdown of SDGENCNTA is controlled by + * ZB3D2CLK which runs at 149.5MHz. + * That is 149.5ticks/us. Approximate this as 150ticks/us. + */ +static void udelay(int us) +{ + __raw_writel(us * 150, SDGENCNTA); + while(__raw_readl(SDGENCNTA)) ; +} + +static void msleep(int ms) +{ + udelay(ms * 1000); +} + +#endif diff --git a/arch/arm/mach-shmobile/include/mach/sdhi.h b/arch/arm/mach-shmobile/include/mach/sdhi.h new file mode 100644 index 00000000000..0ec9e69f2c3 --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/sdhi.h @@ -0,0 +1,16 @@ +#ifndef SDHI_H +#define SDHI_H + +/************************************************** + * + * CPU specific settings + * + **************************************************/ + +#ifdef CONFIG_ARCH_SH7372 +#include "mach/sdhi-sh7372.h" +#else +#error "unsupported CPU." +#endif + +#endif /* SDHI_H */ diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c index f3888feb1c6..66f980625a3 100644 --- a/arch/arm/mach-shmobile/platsmp.c +++ b/arch/arm/mach-shmobile/platsmp.c @@ -64,10 +64,5 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); - shmobile_smp_prepare_cpus(); } diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index b8ae3c978de..1a594dce8fb 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -129,14 +129,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); scu_enable(scu_base); } diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 0c527fe2ceb..a33df5f4c27 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -172,14 +172,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); scu_enable(scu_base_addr()); wakeup_secondary(); diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index 765a71ff7f3..bfd32f52c2d 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -229,10 +229,6 @@ static void ct_ca9x4_init_cpu_map(void) static void ct_ca9x4_smp_enable(unsigned int max_cpus) { - int i; - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); - scu_enable(MMIO_P2V(A9_MPCORE_SCU)); } #endif diff --git a/arch/arm/mach-vt8500/irq.c b/arch/arm/mach-vt8500/irq.c index 245140c0df1..642de0408f2 100644 --- a/arch/arm/mach-vt8500/irq.c +++ b/arch/arm/mach-vt8500/irq.c @@ -39,9 +39,10 @@ static void __iomem *ic_regbase; static void __iomem *sic_regbase; -static void vt8500_irq_mask(unsigned int irq) +static void vt8500_irq_mask(struct irq_data *d) { void __iomem *base = ic_regbase; + unsigned irq = d->irq; u8 edge; if (irq >= 64) { @@ -64,9 +65,10 @@ static void vt8500_irq_mask(unsigned int irq) } } -static void vt8500_irq_unmask(unsigned int irq) +static void vt8500_irq_unmask(struct irq_data *d) { void __iomem *base = ic_regbase; + unsigned irq = d->irq; u8 dctr; if (irq >= 64) { @@ -78,10 +80,11 @@ static void vt8500_irq_unmask(unsigned int irq) writeb(dctr, base + VT8500_IC_DCTR + irq); } -static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type) +static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type) { void __iomem *base = ic_regbase; - unsigned int orig_irq = irq; + unsigned irq = d->irq; + unsigned orig_irq = irq; u8 dctr; if (irq >= 64) { @@ -114,11 +117,11 @@ static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type) } static struct irq_chip vt8500_irq_chip = { - .name = "vt8500", - .ack = vt8500_irq_mask, - .mask = vt8500_irq_mask, - .unmask = vt8500_irq_unmask, - .set_type = vt8500_irq_set_type, + .name = "vt8500", + .irq_ack = vt8500_irq_mask, + .irq_mask = vt8500_irq_mask, + .irq_unmask = vt8500_irq_unmask, + .irq_set_type = vt8500_irq_set_type, }; void __init vt8500_init_irq(void) diff --git a/arch/arm/mm/abort-ev4.S b/arch/arm/mm/abort-ev4.S index 4f18f9e87ba..54473cd4aba 100644 --- a/arch/arm/mm/abort-ev4.S +++ b/arch/arm/mm/abort-ev4.S @@ -3,14 +3,11 @@ /* * Function: v4_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r2 = pt_regs + * : r4 = aborted context pc + * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -21,10 +18,8 @@ ENTRY(v4_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r3, [r2] @ read aborted ARM instruction + ldr r3, [r4] @ read aborted ARM instruction bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #1 << 20 @ L = 1 -> write? orreq r1, r1, #1 << 11 @ yes. - mov pc, lr - - + b do_DataAbort diff --git a/arch/arm/mm/abort-ev4t.S b/arch/arm/mm/abort-ev4t.S index b6282548f92..9da704e7b86 100644 --- a/arch/arm/mm/abort-ev4t.S +++ b/arch/arm/mm/abort-ev4t.S @@ -4,14 +4,11 @@ /* * Function: v4t_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r2 = pt_regs + * : r4 = aborted context pc + * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -22,9 +19,9 @@ ENTRY(v4t_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - do_thumb_abort - ldreq r3, [r2] @ read aborted ARM instruction + do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 + ldreq r3, [r4] @ read aborted ARM instruction bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #1 << 20 @ check write orreq r1, r1, #1 << 11 - mov pc, lr + b do_DataAbort diff --git a/arch/arm/mm/abort-ev5t.S b/arch/arm/mm/abort-ev5t.S index 02251b526c0..a0908d4653a 100644 --- a/arch/arm/mm/abort-ev5t.S +++ b/arch/arm/mm/abort-ev5t.S @@ -4,14 +4,11 @@ /* * Function: v5t_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r2 = pt_regs + * : r4 = aborted context pc + * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -22,10 +19,10 @@ ENTRY(v5t_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - do_thumb_abort - ldreq r3, [r2] @ read aborted ARM instruction + do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 + ldreq r3, [r4] @ read aborted ARM instruction bic r1, r1, #1 << 11 @ clear bits 11 of FSR - do_ldrd_abort + do_ldrd_abort tmp=ip, insn=r3 tst r3, #1 << 20 @ check write orreq r1, r1, #1 << 11 - mov pc, lr + b do_DataAbort diff --git a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S index bce68d601c8..4006b7a6126 100644 --- a/arch/arm/mm/abort-ev5tj.S +++ b/arch/arm/mm/abort-ev5tj.S @@ -4,14 +4,11 @@ /* * Function: v5tj_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r2 = pt_regs + * : r4 = aborted context pc + * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -23,13 +20,11 @@ ENTRY(v5tj_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR - tst r3, #PSR_J_BIT @ Java? - movne pc, lr - do_thumb_abort - ldreq r3, [r2] @ read aborted ARM instruction - do_ldrd_abort + tst r5, #PSR_J_BIT @ Java? + bne do_DataAbort + do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 + ldreq r3, [r4] @ read aborted ARM instruction + do_ldrd_abort tmp=ip, insn=r3 tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. - mov pc, lr - - + b do_DataAbort diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index 1478aa52214..ff1f7cc11f8 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S @@ -4,14 +4,11 @@ /* * Function: v6_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r2 = pt_regs + * : r4 = aborted context pc + * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -33,16 +30,14 @@ ENTRY(v6_early_abort) * The test below covers all the write situations, including Java bytecodes */ bic r1, r1, #1 << 11 @ clear bit 11 of FSR - tst r3, #PSR_J_BIT @ Java? - movne pc, lr - do_thumb_abort - ldreq r3, [r2] @ read aborted ARM instruction + tst r5, #PSR_J_BIT @ Java? + bne do_DataAbort + do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 + ldreq r3, [r4] @ read aborted ARM instruction #ifdef CONFIG_CPU_ENDIAN_BE8 reveq r3, r3 #endif - do_ldrd_abort + do_ldrd_abort tmp=ip, insn=r3 tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. - mov pc, lr - - + b do_DataAbort diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S index ec88b157d3b..703375277ba 100644 --- a/arch/arm/mm/abort-ev7.S +++ b/arch/arm/mm/abort-ev7.S @@ -3,14 +3,11 @@ /* * Function: v7_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r2 = pt_regs + * : r4 = aborted context pc + * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. */ @@ -37,18 +34,18 @@ ENTRY(v7_early_abort) ldr r3, =0x40d @ On permission fault and r3, r1, r3 cmp r3, #0x0d - movne pc, lr + bne do_DataAbort mcr p15, 0, r0, c7, c8, 0 @ Retranslate FAR isb - mrc p15, 0, r2, c7, c4, 0 @ Read the PAR - and r3, r2, #0x7b @ On translation fault + mrc p15, 0, ip, c7, c4, 0 @ Read the PAR + and r3, ip, #0x7b @ On translation fault cmp r3, #0x0b - movne pc, lr + bne do_DataAbort bic r1, r1, #0xf @ Fix up FSR FS[5:0] - and r2, r2, #0x7e - orr r1, r1, r2, LSR #1 + and ip, ip, #0x7e + orr r1, r1, ip, LSR #1 #endif - mov pc, lr + b do_DataAbort ENDPROC(v7_early_abort) diff --git a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S index 9fb7b0e25ea..f3982580c27 100644 --- a/arch/arm/mm/abort-lv4t.S +++ b/arch/arm/mm/abort-lv4t.S @@ -3,14 +3,11 @@ /* * Function: v4t_late_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r2 = pt_regs + * : r4 = aborted context pc + * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4-r5, r10-r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -18,7 +15,7 @@ * picture. Unfortunately, this does happen. We live with it. */ ENTRY(v4t_late_abort) - tst r3, #PSR_T_BIT @ check for thumb mode + tst r5, #PSR_T_BIT @ check for thumb mode #ifdef CONFIG_CPU_CP15_MMU mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR @@ -28,7 +25,7 @@ ENTRY(v4t_late_abort) mov r1, #0 #endif bne .data_thumb_abort - ldr r8, [r2] @ read arm instruction + ldr r8, [r4] @ read arm instruction tst r8, #1 << 20 @ L = 1 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #15 << 24 @@ -47,86 +44,84 @@ ENTRY(v4t_late_abort) /* 9 */ b .data_arm_ldmstm @ ldm*b rn, <rlist> /* a */ b .data_unknown /* b */ b .data_unknown -/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m -/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* c */ b do_DataAbort @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ b do_DataAbort @ ldc rd, [rn, #m] /* e */ b .data_unknown /* f */ .data_unknown: @ Part of jumptable - mov r0, r2 + mov r0, r4 mov r1, r8 - mov r2, sp - bl baddataabort - b ret_from_exception + b baddataabort .data_arm_ldmstm: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup mov r7, #0x11 orr r7, r7, #0x1100 and r6, r8, r7 - and r2, r8, r7, lsl #1 - add r6, r6, r2, lsr #1 - and r2, r8, r7, lsl #2 - add r6, r6, r2, lsr #2 - and r2, r8, r7, lsl #3 - add r6, r6, r2, lsr #3 + and r9, r8, r7, lsl #1 + add r6, r6, r9, lsr #1 + and r9, r8, r7, lsl #2 + add r6, r6, r9, lsr #2 + and r9, r8, r7, lsl #3 + add r6, r6, r9, lsr #3 add r6, r6, r6, lsr #8 add r6, r6, r6, lsr #4 and r6, r6, #15 @ r6 = no. of registers to transfer. - and r5, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + and r9, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r6, lsl #2 @ Undo increment addeq r7, r7, r6, lsl #2 @ Undo decrement - str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + str r7, [r2, r9, lsr #14] @ Put register 'Rn' + b do_DataAbort .data_arm_lateldrhpre: tst r8, #1 << 21 @ Check writeback bit - moveq pc, lr @ No writeback -> no fixup + beq do_DataAbort @ No writeback -> no fixup .data_arm_lateldrhpost: - and r5, r8, #0x00f @ get Rm / low nibble of immediate value + and r9, r8, #0x00f @ get Rm / low nibble of immediate value tst r8, #1 << 22 @ if (immediate offset) andne r6, r8, #0xf00 @ { immediate high nibble - orrne r6, r5, r6, lsr #4 @ combine nibbles } else - ldreq r6, [sp, r5, lsl #2] @ { load Rm value } + orrne r6, r9, r6, lsr #4 @ combine nibbles } else + ldreq r6, [r2, r9, lsl #2] @ { load Rm value } .data_arm_apply_r6_and_rn: - and r5, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + and r9, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r6 @ Undo incrmenet addeq r7, r7, r6 @ Undo decrement - str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + str r7, [r2, r9, lsr #14] @ Put register 'Rn' + b do_DataAbort .data_arm_lateldrpreconst: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup .data_arm_lateldrpostconst: - movs r2, r8, lsl #20 @ Get offset - moveq pc, lr @ zero -> no fixup - and r5, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + movs r6, r8, lsl #20 @ Get offset + beq do_DataAbort @ zero -> no fixup + and r9, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit - subne r7, r7, r2, lsr #20 @ Undo increment - addeq r7, r7, r2, lsr #20 @ Undo decrement - str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + subne r7, r7, r6, lsr #20 @ Undo increment + addeq r7, r7, r6, lsr #20 @ Undo decrement + str r7, [r2, r9, lsr #14] @ Put register 'Rn' + b do_DataAbort .data_arm_lateldrprereg: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup .data_arm_lateldrpostreg: and r7, r8, #15 @ Extract 'm' from instruction - ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' - mov r5, r8, lsr #7 @ get shift count - ands r5, r5, #31 + ldr r6, [r2, r7, lsl #2] @ Get register 'Rm' + mov r9, r8, lsr #7 @ get shift count + ands r9, r9, #31 and r7, r8, #0x70 @ get shift type orreq r7, r7, #8 @ shift count = 0 add pc, pc, r7 nop - mov r6, r6, lsl r5 @ 0: LSL #!0 + mov r6, r6, lsl r9 @ 0: LSL #!0 b .data_arm_apply_r6_and_rn b .data_arm_apply_r6_and_rn @ 1: LSL #0 nop @@ -134,7 +129,7 @@ ENTRY(v4t_late_abort) nop b .data_unknown @ 3: MUL? nop - mov r6, r6, lsr r5 @ 4: LSR #!0 + mov r6, r6, lsr r9 @ 4: LSR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, lsr #32 @ 5: LSR #32 b .data_arm_apply_r6_and_rn @@ -142,7 +137,7 @@ ENTRY(v4t_late_abort) nop b .data_unknown @ 7: MUL? nop - mov r6, r6, asr r5 @ 8: ASR #!0 + mov r6, r6, asr r9 @ 8: ASR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, asr #32 @ 9: ASR #32 b .data_arm_apply_r6_and_rn @@ -150,7 +145,7 @@ ENTRY(v4t_late_abort) nop b .data_unknown @ B: MUL? nop - mov r6, r6, ror r5 @ C: ROR #!0 + mov r6, r6, ror r9 @ C: ROR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, rrx @ D: RRX b .data_arm_apply_r6_and_rn @@ -159,7 +154,7 @@ ENTRY(v4t_late_abort) b .data_unknown @ F: MUL? .data_thumb_abort: - ldrh r8, [r2] @ read instruction + ldrh r8, [r4] @ read instruction tst r8, #1 << 11 @ L = 1 -> write? orreq r1, r1, #1 << 8 @ yes and r7, r8, #15 << 12 @@ -172,10 +167,10 @@ ENTRY(v4t_late_abort) /* 3 */ b .data_unknown /* 4 */ b .data_unknown /* 5 */ b .data_thumb_reg -/* 6 */ mov pc, lr -/* 7 */ mov pc, lr -/* 8 */ mov pc, lr -/* 9 */ mov pc, lr +/* 6 */ b do_DataAbort +/* 7 */ b do_DataAbort +/* 8 */ b do_DataAbort +/* 9 */ b do_DataAbort /* A */ b .data_unknown /* B */ b .data_thumb_pushpop /* C */ b .data_thumb_ldmstm @@ -185,41 +180,41 @@ ENTRY(v4t_late_abort) .data_thumb_reg: tst r8, #1 << 9 - moveq pc, lr + beq do_DataAbort tst r8, #1 << 10 @ If 'S' (signed) bit is set movne r1, #0 @ it must be a load instr - mov pc, lr + b do_DataAbort .data_thumb_pushpop: tst r8, #1 << 10 beq .data_unknown and r6, r8, #0x55 @ hweight8(r8) + R bit - and r2, r8, #0xaa - add r6, r6, r2, lsr #1 - and r2, r6, #0xcc + and r9, r8, #0xaa + add r6, r6, r9, lsr #1 + and r9, r6, #0xcc and r6, r6, #0x33 - add r6, r6, r2, lsr #2 + add r6, r6, r9, lsr #2 movs r7, r8, lsr #9 @ C = r8 bit 8 (R bit) adc r6, r6, r6, lsr #4 @ high + low nibble + R bit and r6, r6, #15 @ number of regs to transfer - ldr r7, [sp, #13 << 2] + ldr r7, [r2, #13 << 2] tst r8, #1 << 11 addeq r7, r7, r6, lsl #2 @ increment SP if PUSH subne r7, r7, r6, lsl #2 @ decrement SP if POP - str r7, [sp, #13 << 2] - mov pc, lr + str r7, [r2, #13 << 2] + b do_DataAbort .data_thumb_ldmstm: and r6, r8, #0x55 @ hweight8(r8) - and r2, r8, #0xaa - add r6, r6, r2, lsr #1 - and r2, r6, #0xcc + and r9, r8, #0xaa + add r6, r6, r9, lsr #1 + and r9, r6, #0xcc and r6, r6, #0x33 - add r6, r6, r2, lsr #2 + add r6, r6, r9, lsr #2 add r6, r6, r6, lsr #4 - and r5, r8, #7 << 8 - ldr r7, [sp, r5, lsr #6] + and r9, r8, #7 << 8 + ldr r7, [r2, r9, lsr #6] and r6, r6, #15 @ number of regs to transfer sub r7, r7, r6, lsl #2 @ always decrement - str r7, [sp, r5, lsr #6] - mov pc, lr + str r7, [r2, r9, lsr #6] + b do_DataAbort diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S index d7cb1bfa51a..52162d59407 100644 --- a/arch/arm/mm/abort-macro.S +++ b/arch/arm/mm/abort-macro.S @@ -9,34 +9,32 @@ * */ - .macro do_thumb_abort - tst r3, #PSR_T_BIT + .macro do_thumb_abort, fsr, pc, psr, tmp + tst \psr, #PSR_T_BIT beq not_thumb - ldrh r3, [r2] @ Read aborted Thumb instruction - and r3, r3, # 0xfe00 @ Mask opcode field - cmp r3, # 0x5600 @ Is it ldrsb? - orreq r3, r3, #1 << 11 @ Set L-bit if yes - tst r3, #1 << 11 @ L = 0 -> write - orreq r1, r1, #1 << 11 @ yes. - mov pc, lr + ldrh \tmp, [\pc] @ Read aborted Thumb instruction + and \tmp, \tmp, # 0xfe00 @ Mask opcode field + cmp \tmp, # 0x5600 @ Is it ldrsb? + orreq \tmp, \tmp, #1 << 11 @ Set L-bit if yes + tst \tmp, #1 << 11 @ L = 0 -> write + orreq \psr, \psr, #1 << 11 @ yes. + b do_DataAbort not_thumb: .endm /* - * We check for the following insturction encoding for LDRD. + * We check for the following instruction encoding for LDRD. * - * [27:25] == 0 + * [27:25] == 000 * [7:4] == 1101 * [20] == 0 */ - .macro do_ldrd_abort - tst r3, #0x0e000000 @ [27:25] == 0 + .macro do_ldrd_abort, tmp, insn + tst \insn, #0x0e100000 @ [27:25,20] == 0 bne not_ldrd - and r2, r3, #0x000000f0 @ [7:4] == 1101 - cmp r2, #0x000000d0 - bne not_ldrd - tst r3, #1 << 20 @ [20] == 0 - moveq pc, lr + and \tmp, \insn, #0x000000f0 @ [7:4] == 1101 + cmp \tmp, #0x000000d0 + beq do_DataAbort not_ldrd: .endm diff --git a/arch/arm/mm/abort-nommu.S b/arch/arm/mm/abort-nommu.S index 625e580945b..119cb479c2a 100644 --- a/arch/arm/mm/abort-nommu.S +++ b/arch/arm/mm/abort-nommu.S @@ -3,11 +3,11 @@ /* * Function: nommu_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r2 = pt_regs + * : r4 = aborted context pc + * : r5 = aborted context psr * - * Returns : r0 = 0 (abort address) - * : r1 = 0 (FSR) + * Returns : r4 - r11, r13 preserved * * Note: There is no FSR/FAR on !CPU_CP15_MMU cores. * Just fill zero into the registers. @@ -16,5 +16,5 @@ ENTRY(nommu_early_abort) mov r0, #0 @ clear r0, r1 (no FSR/FAR) mov r1, #0 - mov pc, lr + b do_DataAbort ENDPROC(nommu_early_abort) diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 724ba3bce72..be7c638b648 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -727,6 +727,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) int isize = 4; int thumb2_32b = 0; + if (interrupts_enabled(regs)) + local_irq_enable(); + instrptr = instruction_pointer(regs); fs = get_fs(); diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index ef59099a546..44c086710d2 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -120,17 +120,22 @@ static void l2x0_cache_sync(void) spin_unlock_irqrestore(&l2x0_lock, flags); } -static void l2x0_flush_all(void) +static void __l2x0_flush_all(void) { - unsigned long flags; - - /* clean all ways */ - spin_lock_irqsave(&l2x0_lock, flags); debug_writel(0x03); writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); cache_sync(); debug_writel(0x00); +} + +static void l2x0_flush_all(void) +{ + unsigned long flags; + + /* clean all ways */ + spin_lock_irqsave(&l2x0_lock, flags); + __l2x0_flush_all(); spin_unlock_irqrestore(&l2x0_lock, flags); } @@ -266,7 +271,9 @@ static void l2x0_disable(void) unsigned long flags; spin_lock_irqsave(&l2x0_lock, flags); - writel(0, l2x0_base + L2X0_CTRL); + __l2x0_flush_all(); + writel_relaxed(0, l2x0_base + L2X0_CTRL); + dsb(); spin_unlock_irqrestore(&l2x0_lock, flags); } diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index bdba6c65c90..63cca009713 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -41,7 +41,6 @@ static void v6_copy_user_highpage_nonaliasing(struct page *to, kfrom = kmap_atomic(from, KM_USER0); kto = kmap_atomic(to, KM_USER1); copy_page(kto, kfrom); - __cpuc_flush_dcache_area(kto, PAGE_SIZE); kunmap_atomic(kto, KM_USER1); kunmap_atomic(kfrom, KM_USER0); } diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 82a093cee09..0a0a1e7c20d 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -25,9 +25,11 @@ #include <asm/tlbflush.h> #include <asm/sizes.h> +#include "mm.h" + static u64 get_coherent_dma_mask(struct device *dev) { - u64 mask = ISA_DMA_THRESHOLD; + u64 mask = (u64)arm_dma_limit; if (dev) { mask = dev->coherent_dma_mask; @@ -41,10 +43,10 @@ static u64 get_coherent_dma_mask(struct device *dev) return 0; } - if ((~mask) & ISA_DMA_THRESHOLD) { + if ((~mask) & (u64)arm_dma_limit) { dev_warn(dev, "coherent DMA mask %#llx is smaller " "than system GFP_DMA mask %#llx\n", - mask, (unsigned long long)ISA_DMA_THRESHOLD); + mask, (u64)arm_dma_limit); return 0; } } @@ -657,6 +659,33 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, } EXPORT_SYMBOL(dma_sync_sg_for_device); +/* + * Return whether the given device DMA address mask can be supported + * properly. For example, if your device can only drive the low 24-bits + * during bus mastering, then you would pass 0x00ffffff as the mask + * to this function. + */ +int dma_supported(struct device *dev, u64 mask) +{ + if (mask < (u64)arm_dma_limit) + return 0; + return 1; +} +EXPORT_SYMBOL(dma_supported); + +int dma_set_mask(struct device *dev, u64 dma_mask) +{ + if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + return -EIO; + +#ifndef CONFIG_DMABOUNCE + *dev->dma_mask = dma_mask; +#endif + + return 0; +} +EXPORT_SYMBOL(dma_set_mask); + #define PREALLOC_DMA_DEBUG_ENTRIES 4096 static int __init dma_debug_do_init(void) diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index bc0e1d88fd3..55657c222d7 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -94,7 +94,7 @@ void show_pte(struct mm_struct *mm, unsigned long addr) pud = pud_offset(pgd, addr); if (PTRS_PER_PUD != 1) - printk(", *pud=%08lx", pud_val(*pud)); + printk(", *pud=%08llx", (long long)pud_val(*pud)); if (pud_none(*pud)) break; @@ -285,6 +285,10 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) tsk = current; mm = tsk->mm; + /* Enable interrupts if they were enabled in the parent context. */ + if (interrupts_enabled(regs)) + local_irq_enable(); + /* * If we're in an interrupt or have no user * context, we must not take the fault.. diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index b8e89124315..e5ab4362322 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -212,6 +212,14 @@ static void __init arm_bootmem_init(unsigned long start_pfn, } #ifdef CONFIG_ZONE_DMA +/* + * The DMA mask corresponding to the maximum bus address allocatable + * using GFP_DMA. The default here places no restriction on DMA + * allocations. This must be the smallest DMA mask in the system, + * so a successful GFP_DMA allocation will always satisfy this. + */ +u32 arm_dma_limit; + static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole, unsigned long dma_size) { @@ -278,6 +286,8 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, */ arm_adjust_dma_zone(zone_size, zhole_size, ARM_DMA_ZONE_SIZE >> PAGE_SHIFT); + + arm_dma_limit = PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1; #endif free_area_init_node(0, zone_size, min, zhole_size); @@ -422,6 +432,17 @@ static inline int free_area(unsigned long pfn, unsigned long end, char *s) return pages; } +/* + * Poison init memory with an undefined instruction (ARM) or a branch to an + * undefined instruction (Thumb). + */ +static inline void poison_init_mem(void *s, size_t count) +{ + u32 *p = (u32 *)s; + while ((count = count - 4)) + *p++ = 0xe7fddef0; +} + static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn) { @@ -704,11 +725,13 @@ void free_initmem(void) #ifdef CONFIG_HAVE_TCM extern char __tcm_start, __tcm_end; + poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start); totalram_pages += free_area(__phys_to_pfn(__pa(&__tcm_start)), __phys_to_pfn(__pa(&__tcm_end)), "TCM link"); #endif + poison_init_mem(__init_begin, __init_end - __init_begin); if (!machine_is_integrator() && !machine_is_cintegrator()) totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)), __phys_to_pfn(__pa(__init_end)), @@ -721,10 +744,12 @@ static int keep_initrd; void free_initrd_mem(unsigned long start, unsigned long end) { - if (!keep_initrd) + if (!keep_initrd) { + poison_init_mem((void *)start, PAGE_ALIGN(end) - start); totalram_pages += free_area(__phys_to_pfn(__pa(start)), __phys_to_pfn(__pa(end)), "initrd"); + } } static int __init keepinitrd_setup(char *__unused) diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 5b3d7d54365..010566799c8 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -23,5 +23,11 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page #endif +#ifdef CONFIG_ZONE_DMA +extern u32 arm_dma_limit; +#else +#define arm_dma_limit ((u32)~0) +#endif + void __init bootmem_init(void); void arm_mm_memblock_reserve(void); diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 9d9e736c2b4..594d677b92c 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -759,7 +759,7 @@ early_param("vmalloc", early_vmalloc); static phys_addr_t lowmem_limit __initdata = 0; -static void __init sanity_check_meminfo(void) +void __init sanity_check_meminfo(void) { int i, j, highmem = 0; @@ -1032,8 +1032,9 @@ void __init paging_init(struct machine_desc *mdesc) { void *zero_page; + memblock_set_current_limit(lowmem_limit); + build_mem_type_table(); - sanity_check_meminfo(); prepare_page_table(); map_lowmem(); devicemaps_init(mdesc); diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index 687d02319a4..941a98c9e8a 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c @@ -27,6 +27,10 @@ void __init arm_mm_memblock_reserve(void) memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE); } +void __init sanity_check_meminfo(void) +{ +} + /* * paging_init() sets up the page tables, initialises the zone memory * maps, and sets up the zero page, bad page and bad page tables. diff --git a/arch/arm/mm/pabort-legacy.S b/arch/arm/mm/pabort-legacy.S index 87970eba88e..8bbff025269 100644 --- a/arch/arm/mm/pabort-legacy.S +++ b/arch/arm/mm/pabort-legacy.S @@ -4,16 +4,18 @@ /* * Function: legacy_pabort * - * Params : r0 = address of aborted instruction + * Params : r2 = pt_regs + * : r4 = address of aborted instruction + * : r5 = psr for parent context * - * Returns : r0 = address of abort - * : r1 = Simulated IFSR with section translation fault status + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current prefetch abort. */ .align 5 ENTRY(legacy_pabort) + mov r0, r4 mov r1, #5 - mov pc, lr + b do_PrefetchAbort ENDPROC(legacy_pabort) diff --git a/arch/arm/mm/pabort-v6.S b/arch/arm/mm/pabort-v6.S index 06e3d1ef211..9627646ce78 100644 --- a/arch/arm/mm/pabort-v6.S +++ b/arch/arm/mm/pabort-v6.S @@ -4,16 +4,18 @@ /* * Function: v6_pabort * - * Params : r0 = address of aborted instruction + * Params : r2 = pt_regs + * : r4 = address of aborted instruction + * : r5 = psr for parent context * - * Returns : r0 = address of abort - * : r1 = IFSR + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current prefetch abort. */ .align 5 ENTRY(v6_pabort) + mov r0, r4 mrc p15, 0, r1, c5, c0, 1 @ get IFSR - mov pc, lr + b do_PrefetchAbort ENDPROC(v6_pabort) diff --git a/arch/arm/mm/pabort-v7.S b/arch/arm/mm/pabort-v7.S index a8b3b300a18..875761f44f3 100644 --- a/arch/arm/mm/pabort-v7.S +++ b/arch/arm/mm/pabort-v7.S @@ -2,12 +2,13 @@ #include <asm/assembler.h> /* - * Function: v6_pabort + * Function: v7_pabort * - * Params : r0 = address of aborted instruction + * Params : r2 = pt_regs + * : r4 = address of aborted instruction + * : r5 = psr for parent context * - * Returns : r0 = address of abort - * : r1 = IFSR + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current prefetch abort. */ @@ -16,5 +17,5 @@ ENTRY(v7_pabort) mrc p15, 0, r0, c6, c0, 2 @ get IFAR mrc p15, 0, r1, c5, c0, 1 @ get IFSR - mov pc, lr + b do_PrefetchAbort ENDPROC(v7_pabort) diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S index 5f79dc4ce3f..50e3543d03b 100644 --- a/arch/arm/mm/proc-arm6_7.S +++ b/arch/arm/mm/proc-arm6_7.S @@ -29,19 +29,19 @@ ENTRY(cpu_arm7_dcache_clean_area) /* * Function: arm6_7_data_abort () * - * Params : r2 = address of aborted instruction - * : sp = pointer to registers + * Params : r2 = pt_regs + * : r4 = aborted context pc + * : r5 = aborted context psr * * Purpose : obtain information about current aborted instruction * - * Returns : r0 = address of abort - * : r1 = FSR + * Returns : r4-r5, r10-r11, r13 preserved */ ENTRY(cpu_arm7_data_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r8, [r2] @ read arm instruction + ldr r8, [r4] @ read arm instruction tst r8, #1 << 20 @ L = 0 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #15 << 24 @@ -49,7 +49,7 @@ ENTRY(cpu_arm7_data_abort) nop /* 0 */ b .data_unknown -/* 1 */ mov pc, lr @ swp +/* 1 */ b do_DataAbort @ swp /* 2 */ b .data_unknown /* 3 */ b .data_unknown /* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m @@ -60,87 +60,85 @@ ENTRY(cpu_arm7_data_abort) /* 9 */ b .data_arm_ldmstm @ ldm*b rn, <rlist> /* a */ b .data_unknown /* b */ b .data_unknown -/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m -/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* c */ b do_DataAbort @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ b do_DataAbort @ ldc rd, [rn, #m] /* e */ b .data_unknown /* f */ .data_unknown: @ Part of jumptable - mov r0, r2 + mov r0, r4 mov r1, r8 - mov r2, sp - bl baddataabort - b ret_from_exception + b baddataabort ENTRY(cpu_arm6_data_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r8, [r2] @ read arm instruction + ldr r8, [r4] @ read arm instruction tst r8, #1 << 20 @ L = 0 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #14 << 24 teq r7, #8 << 24 @ was it ldm/stm - movne pc, lr + bne do_DataAbort .data_arm_ldmstm: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup mov r7, #0x11 orr r7, r7, #0x1100 and r6, r8, r7 - and r2, r8, r7, lsl #1 - add r6, r6, r2, lsr #1 - and r2, r8, r7, lsl #2 - add r6, r6, r2, lsr #2 - and r2, r8, r7, lsl #3 - add r6, r6, r2, lsr #3 + and r9, r8, r7, lsl #1 + add r6, r6, r9, lsr #1 + and r9, r8, r7, lsl #2 + add r6, r6, r9, lsr #2 + and r9, r8, r7, lsl #3 + add r6, r6, r9, lsr #3 add r6, r6, r6, lsr #8 add r6, r6, r6, lsr #4 and r6, r6, #15 @ r6 = no. of registers to transfer. - and r5, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + and r9, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r6, lsl #2 @ Undo increment addeq r7, r7, r6, lsl #2 @ Undo decrement - str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + str r7, [r2, r9, lsr #14] @ Put register 'Rn' + b do_DataAbort .data_arm_apply_r6_and_rn: - and r5, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + and r9, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r6 @ Undo incrmenet addeq r7, r7, r6 @ Undo decrement - str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + str r7, [r2, r9, lsr #14] @ Put register 'Rn' + b do_DataAbort .data_arm_lateldrpreconst: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup .data_arm_lateldrpostconst: - movs r2, r8, lsl #20 @ Get offset - moveq pc, lr @ zero -> no fixup - and r5, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + movs r6, r8, lsl #20 @ Get offset + beq do_DataAbort @ zero -> no fixup + and r9, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit - subne r7, r7, r2, lsr #20 @ Undo increment - addeq r7, r7, r2, lsr #20 @ Undo decrement - str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + subne r7, r7, r6, lsr #20 @ Undo increment + addeq r7, r7, r6, lsr #20 @ Undo decrement + str r7, [r2, r9, lsr #14] @ Put register 'Rn' + b do_DataAbort .data_arm_lateldrprereg: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup .data_arm_lateldrpostreg: and r7, r8, #15 @ Extract 'm' from instruction - ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' - mov r5, r8, lsr #7 @ get shift count - ands r5, r5, #31 + ldr r6, [r2, r7, lsl #2] @ Get register 'Rm' + mov r9, r8, lsr #7 @ get shift count + ands r9, r9, #31 and r7, r8, #0x70 @ get shift type orreq r7, r7, #8 @ shift count = 0 add pc, pc, r7 nop - mov r6, r6, lsl r5 @ 0: LSL #!0 + mov r6, r6, lsl r9 @ 0: LSL #!0 b .data_arm_apply_r6_and_rn b .data_arm_apply_r6_and_rn @ 1: LSL #0 nop @@ -148,7 +146,7 @@ ENTRY(cpu_arm6_data_abort) nop b .data_unknown @ 3: MUL? nop - mov r6, r6, lsr r5 @ 4: LSR #!0 + mov r6, r6, lsr r9 @ 4: LSR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, lsr #32 @ 5: LSR #32 b .data_arm_apply_r6_and_rn @@ -156,7 +154,7 @@ ENTRY(cpu_arm6_data_abort) nop b .data_unknown @ 7: MUL? nop - mov r6, r6, asr r5 @ 8: ASR #!0 + mov r6, r6, asr r9 @ 8: ASR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, asr #32 @ 9: ASR #32 b .data_arm_apply_r6_and_rn @@ -164,7 +162,7 @@ ENTRY(cpu_arm6_data_abort) nop b .data_unknown @ B: MUL? nop - mov r6, r6, ror r5 @ C: ROR #!0 + mov r6, r6, ror r9 @ C: ROR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, rrx @ D: RRX b .data_arm_apply_r6_and_rn diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S index 184a9c997e3..e9c47271732 100644 --- a/arch/arm/mm/proc-sa1100.S +++ b/arch/arm/mm/proc-sa1100.S @@ -34,7 +34,7 @@ */ #define DCACHELINESIZE 32 - __INIT + .section .text /* * cpu_sa1100_proc_init() @@ -45,8 +45,6 @@ ENTRY(cpu_sa1100_proc_init) mcr p15, 0, r0, c9, c0, 5 @ Allow read-buffer operations from userland mov pc, lr - .section .text - /* * cpu_sa1100_proc_fin() * diff --git a/arch/arm/mm/tlb-fa.S b/arch/arm/mm/tlb-fa.S index 9694f1f6f48..d887a31faaa 100644 --- a/arch/arm/mm/tlb-fa.S +++ b/arch/arm/mm/tlb-fa.S @@ -46,7 +46,6 @@ ENTRY(fa_flush_user_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b - mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB mcr p15, 0, r3, c7, c10, 4 @ data write barrier mov pc, lr @@ -60,9 +59,8 @@ ENTRY(fa_flush_kern_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b - mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB mcr p15, 0, r3, c7, c10, 4 @ data write barrier - mcr p15, 0, r3, c7, c5, 4 @ prefetch flush + mcr p15, 0, r3, c7, c5, 4 @ prefetch flush (isb) mov pc, lr __INITDATA diff --git a/arch/arm/mm/tlb-v6.S b/arch/arm/mm/tlb-v6.S index 73d7d89b04c..ffe06a69a6e 100644 --- a/arch/arm/mm/tlb-v6.S +++ b/arch/arm/mm/tlb-v6.S @@ -54,7 +54,6 @@ ENTRY(v6wbi_flush_user_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b - mcr p15, 0, ip, c7, c5, 6 @ flush BTAC/BTB mcr p15, 0, ip, c7, c10, 4 @ data synchronization barrier mov pc, lr @@ -83,9 +82,8 @@ ENTRY(v6wbi_flush_kern_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b - mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB mcr p15, 0, r2, c7, c10, 4 @ data synchronization barrier - mcr p15, 0, r2, c7, c5, 4 @ prefetch flush + mcr p15, 0, r2, c7, c5, 4 @ prefetch flush (isb) mov pc, lr __INIT diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S index 53cd5b45467..86bb7166450 100644 --- a/arch/arm/mm/tlb-v7.S +++ b/arch/arm/mm/tlb-v7.S @@ -48,9 +48,6 @@ ENTRY(v7wbi_flush_user_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b - mov ip, #0 - ALT_SMP(mcr p15, 0, ip, c7, c1, 6) @ flush BTAC/BTB Inner Shareable - ALT_UP(mcr p15, 0, ip, c7, c5, 6) @ flush BTAC/BTB dsb mov pc, lr ENDPROC(v7wbi_flush_user_tlb_range) @@ -75,9 +72,6 @@ ENTRY(v7wbi_flush_kern_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b - mov r2, #0 - ALT_SMP(mcr p15, 0, r2, c7, c1, 6) @ flush BTAC/BTB Inner Shareable - ALT_UP(mcr p15, 0, r2, c7, c5, 6) @ flush BTAC/BTB dsb isb mov pc, lr diff --git a/arch/arm/plat-mxc/include/mach/entry-macro.S b/arch/arm/plat-mxc/include/mach/entry-macro.S index 2e49e71b1b9..066d464d322 100644 --- a/arch/arm/plat-mxc/include/mach/entry-macro.S +++ b/arch/arm/plat-mxc/include/mach/entry-macro.S @@ -78,7 +78,3 @@ movs \irqnr, \irqnr #endif .endm - - @ irq priority table (not used) - .macro irq_prio_table - .endm diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index 6af3d0b1f8d..363c91e44ef 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -394,20 +394,15 @@ void omap3_sram_restore_context(void) } #endif /* CONFIG_PM */ -static int __init omap34xx_sram_init(void) -{ - _omap3_sram_configure_core_dpll = - omap_sram_push(omap3_sram_configure_core_dpll, - omap3_sram_configure_core_dpll_sz); - omap_push_sram_idle(); - return 0; -} -#else +#endif /* CONFIG_ARCH_OMAP3 */ + static inline int omap34xx_sram_init(void) { +#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) + omap3_sram_restore_context(); +#endif return 0; } -#endif int __init omap_sram_init(void) { diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index 5b4fffab1eb..41ab97ebe4c 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c @@ -432,7 +432,7 @@ void __init orion_gpio_init(int gpio_base, int ngpio, ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF; ct->regs.ack = GPIO_EDGE_CAUSE_OFF; ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_clr_bit; ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->chip.irq_set_type = gpio_irq_set_type; diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c index 48ebb9479b6..a11dc367050 100644 --- a/arch/arm/plat-pxa/gpio.c +++ b/arch/arm/plat-pxa/gpio.c @@ -50,7 +50,7 @@ static inline void __iomem *gpio_chip_base(struct gpio_chip *c) return container_of(c, struct pxa_gpio_chip, chip)->regbase; } -static inline struct pxa_gpio_chip *gpio_to_chip(unsigned gpio) +static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio) { return &pxa_gpio_chips[gpio_to_bank(gpio)]; } @@ -161,7 +161,7 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) int gpio = irq_to_gpio(d->irq); unsigned long gpdr, mask = GPIO_bit(gpio); - c = gpio_to_chip(gpio); + c = gpio_to_pxachip(gpio); if (type == IRQ_TYPE_PROBE) { /* Don't mess with enabled GPIOs using preconfigured edges or @@ -230,7 +230,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) static void pxa_ack_muxed_gpio(struct irq_data *d) { int gpio = irq_to_gpio(d->irq); - struct pxa_gpio_chip *c = gpio_to_chip(gpio); + struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET); } @@ -238,7 +238,7 @@ static void pxa_ack_muxed_gpio(struct irq_data *d) static void pxa_mask_muxed_gpio(struct irq_data *d) { int gpio = irq_to_gpio(d->irq); - struct pxa_gpio_chip *c = gpio_to_chip(gpio); + struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); uint32_t grer, gfer; c->irq_mask &= ~GPIO_bit(gpio); @@ -252,7 +252,7 @@ static void pxa_mask_muxed_gpio(struct irq_data *d) static void pxa_unmask_muxed_gpio(struct irq_data *d) { int gpio = irq_to_gpio(d->irq); - struct pxa_gpio_chip *c = gpio_to_chip(gpio); + struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); c->irq_mask |= GPIO_bit(gpio); update_edge_detect(c); diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 2abf9660bc6..539bd0e3def 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -712,7 +712,7 @@ static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel); * get control of an dma channel */ -int s3c2410_dma_request(unsigned int channel, +int s3c2410_dma_request(enum dma_ch channel, struct s3c2410_dma_client *client, void *dev) { @@ -783,7 +783,7 @@ EXPORT_SYMBOL(s3c2410_dma_request); * allowed to go through. */ -int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client) +int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); unsigned long flags; @@ -974,7 +974,7 @@ static int s3c2410_dma_started(struct s3c2410_dma_chan *chan) } int -s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op) +s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -1021,23 +1021,19 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl); * xfersize: size of unit in bytes (1,2,4) */ -int s3c2410_dma_config(unsigned int channel, +int s3c2410_dma_config(enum dma_ch channel, int xferunit) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); unsigned int dcon; - pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", - __func__, channel, xferunit, dcon); + pr_debug("%s: chan=%d, xfer_unit=%d\n", __func__, channel, xferunit); if (chan == NULL) return -EINVAL; - pr_debug("%s: Initial dcon is %08x\n", __func__, dcon); - dcon = chan->dcon & dma_sel.dcon_mask; - - pr_debug("%s: New dcon is %08x\n", __func__, dcon); + pr_debug("%s: dcon is %08x\n", __func__, dcon); switch (chan->req_ch) { case DMACH_I2S_IN: @@ -1104,7 +1100,7 @@ EXPORT_SYMBOL(s3c2410_dma_config); * devaddr: physical address of the source */ -int s3c2410_dma_devconfig(unsigned int channel, +int s3c2410_dma_devconfig(enum dma_ch channel, enum s3c2410_dmasrc source, unsigned long devaddr) { @@ -1177,7 +1173,7 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig); * returns the current transfer points for the dma source and destination */ -int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *dst) +int s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dst) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -1235,7 +1231,7 @@ static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp) /* restore channel's hardware configuration */ if (!cp->in_use) - return 0; + return; printk(KERN_INFO "dma%d: restoring configuration\n", cp->number); @@ -1246,8 +1242,6 @@ static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp) if (cp->map != NULL) dma_sel.select(cp, cp->map); - - return 0; } static void s3c2410_dma_resume(void) diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/plat-s3c24xx/sleep.S index fd7032f84ae..c56612569b4 100644 --- a/arch/arm/plat-s3c24xx/sleep.S +++ b/arch/arm/plat-s3c24xx/sleep.S @@ -41,31 +41,6 @@ .text - /* s3c_cpu_save - * - * entry: - * r1 = v:p offset - */ - -ENTRY(s3c_cpu_save) - stmfd sp!, { r4 - r12, lr } - ldr r3, =resume_with_mmu - bl cpu_suspend - - @@ jump to final code to send system to sleep - ldr r0, =pm_cpu_sleep - @@ldr pc, [ r0 ] - ldr r0, [ r0 ] - mov pc, r0 - - @@ return to the caller, after having the MMU - @@ turned on, this restores the last bits from the - @@ stack -resume_with_mmu: - ldmfd sp!, { r4 - r12, pc } - - .ltorg - /* sleep magic, to allow the bootloader to check for an valid * image to resume to. Must be the first word before the * s3c_cpu_resume entry. diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c index 135abda31c9..327ab9f662e 100644 --- a/arch/arm/plat-s5p/irq-gpioint.c +++ b/arch/arm/plat-s5p/irq-gpioint.c @@ -152,7 +152,7 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) if (!gc) return -ENOMEM; ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_mask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_mask_clr_bit; ct->chip.irq_set_type = s5p_gpioint_set_type, diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-s5p/s5p-time.c index 899a8cc011f..612934c48b0 100644 --- a/arch/arm/plat-s5p/s5p-time.c +++ b/arch/arm/plat-s5p/s5p-time.c @@ -370,11 +370,11 @@ static void __init s5p_clocksource_init(void) clock_rate = clk_get_rate(tin_source); - init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate); - s5p_time_setup(timer_source.source_id, TCNT_MAX); s5p_time_start(timer_source.source_id, PERIODIC); + init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate); + if (clocksource_register_hz(&time_clocksource, clock_rate)) panic("%s: can't register clocksource\n", time_clocksource.name); } diff --git a/arch/arm/plat-samsung/dma.c b/arch/arm/plat-samsung/dma.c index cb459dd9545..6143aa14768 100644 --- a/arch/arm/plat-samsung/dma.c +++ b/arch/arm/plat-samsung/dma.c @@ -41,7 +41,7 @@ struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel) * irq? */ -int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn) +int s3c2410_dma_set_opfn(enum dma_ch channel, s3c2410_dma_opfn_t rtn) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -56,7 +56,7 @@ int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn) } EXPORT_SYMBOL(s3c2410_dma_set_opfn); -int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn) +int s3c2410_dma_set_buffdone_fn(enum dma_ch channel, s3c2410_dma_cbfn_t rtn) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -71,7 +71,7 @@ int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn) } EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); -int s3c2410_dma_setflags(unsigned int channel, unsigned int flags) +int s3c2410_dma_setflags(enum dma_ch channel, unsigned int flags) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h index 4af108ff411..e3b31c26ac3 100644 --- a/arch/arm/plat-samsung/include/plat/devs.h +++ b/arch/arm/plat-samsung/include/plat/devs.h @@ -12,6 +12,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#ifndef __PLAT_DEVS_H +#define __PLAT_DEVS_H __FILE__ + #include <linux/platform_device.h> struct s3c24xx_uart_resources { @@ -159,3 +163,5 @@ extern struct platform_device s3c_device_ac97; */ extern void *s3c_set_platdata(void *pd, size_t pdsize, struct platform_device *pdev); + +#endif /* __PLAT_DEVS_H */ diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h index 2e8f8c6560d..8c273b7a6f5 100644 --- a/arch/arm/plat-samsung/include/plat/dma.h +++ b/arch/arm/plat-samsung/include/plat/dma.h @@ -42,6 +42,7 @@ struct s3c2410_dma_client { }; struct s3c2410_dma_chan; +enum dma_ch; /* s3c2410_dma_cbfn_t * @@ -62,7 +63,7 @@ typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *, * request a dma channel exclusivley */ -extern int s3c2410_dma_request(unsigned int channel, +extern int s3c2410_dma_request(enum dma_ch channel, struct s3c2410_dma_client *, void *dev); @@ -71,14 +72,14 @@ extern int s3c2410_dma_request(unsigned int channel, * change the state of the dma channel */ -extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op); +extern int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op); /* s3c2410_dma_setflags * * set the channel's flags to a given state */ -extern int s3c2410_dma_setflags(unsigned int channel, +extern int s3c2410_dma_setflags(enum dma_ch channel, unsigned int flags); /* s3c2410_dma_free @@ -86,7 +87,7 @@ extern int s3c2410_dma_setflags(unsigned int channel, * free the dma channel (will also abort any outstanding operations) */ -extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *); +extern int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *); /* s3c2410_dma_enqueue * @@ -95,7 +96,7 @@ extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *); * drained before the buffer is given to the DMA system. */ -extern int s3c2410_dma_enqueue(unsigned int channel, void *id, +extern int s3c2410_dma_enqueue(enum dma_ch channel, void *id, dma_addr_t data, int size); /* s3c2410_dma_config @@ -103,14 +104,14 @@ extern int s3c2410_dma_enqueue(unsigned int channel, void *id, * configure the dma channel */ -extern int s3c2410_dma_config(unsigned int channel, int xferunit); +extern int s3c2410_dma_config(enum dma_ch channel, int xferunit); /* s3c2410_dma_devconfig * * configure the device we're talking to */ -extern int s3c2410_dma_devconfig(unsigned int channel, +extern int s3c2410_dma_devconfig(enum dma_ch channel, enum s3c2410_dmasrc source, unsigned long devaddr); /* s3c2410_dma_getposition @@ -118,10 +119,10 @@ extern int s3c2410_dma_devconfig(unsigned int channel, * get the position that the dma transfer is currently at */ -extern int s3c2410_dma_getposition(unsigned int channel, +extern int s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dest); -extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn); -extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn); +extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn); +extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn); diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index 7fb6f6be8c8..f6749916d19 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -42,7 +42,7 @@ extern unsigned long s3c_irqwake_eintallow; /* per-cpu sleep functions */ extern void (*pm_cpu_prep)(void); -extern void (*pm_cpu_sleep)(void); +extern int (*pm_cpu_sleep)(unsigned long); /* Flags for PM Control */ @@ -52,10 +52,9 @@ extern unsigned char pm_uart_udivslot; /* true to save UART UDIVSLOT */ /* from sleep.S */ -extern int s3c_cpu_save(unsigned long *saveblk, long); extern void s3c_cpu_resume(void); -extern void s3c2410_cpu_suspend(void); +extern int s3c2410_cpu_suspend(unsigned long); /* sleep save info */ diff --git a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h index 0ffe34a2155..4c16fa3621b 100644 --- a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h +++ b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h @@ -39,6 +39,7 @@ struct s3c64xx_spi_csinfo { * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6 * @rx_lvl_offset: Depends on tx fifo_lvl field and bus number * @high_speed: If the controller supports HIGH_SPEED_EN bit + * @tx_st_done: Depends on tx fifo_lvl field */ struct s3c64xx_spi_info { int src_clk_nr; @@ -53,6 +54,7 @@ struct s3c64xx_spi_info { int fifo_lvl_mask; int rx_lvl_offset; int high_speed; + int tx_st_done; }; /** diff --git a/arch/arm/plat-samsung/irq-uart.c b/arch/arm/plat-samsung/irq-uart.c index 32582c0958e..657405c481d 100644 --- a/arch/arm/plat-samsung/irq-uart.c +++ b/arch/arm/plat-samsung/irq-uart.c @@ -54,8 +54,15 @@ static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq) gc = irq_alloc_generic_chip("s3c-uart", 1, uirq->base_irq, reg_base, handle_level_irq); + + if (!gc) { + pr_err("%s: irq_alloc_generic_chip for IRQ %u failed\n", + __func__, uirq->base_irq); + return; + } + ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_mask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_mask_clr_bit; ct->regs.ack = S3C64XX_UINTP; diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c index a607546ddbd..f714d060370 100644 --- a/arch/arm/plat-samsung/irq-vic-timer.c +++ b/arch/arm/plat-samsung/irq-vic-timer.c @@ -54,6 +54,13 @@ void __init s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq) s3c_tgc = irq_alloc_generic_chip("s3c-timer", 1, timer_irq, S3C64XX_TINT_CSTAT, handle_level_irq); + + if (!s3c_tgc) { + pr_err("%s: irq_alloc_generic_chip for IRQ %d failed\n", + __func__, timer_irq); + return; + } + ct = s3c_tgc->chip_types; ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index 5c0a440d6e1..5fa1742d019 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -20,6 +20,7 @@ #include <linux/io.h> #include <asm/cacheflush.h> +#include <asm/suspend.h> #include <mach/hardware.h> #include <mach/map.h> @@ -231,7 +232,7 @@ static void __maybe_unused s3c_pm_show_resume_irqs(int start, void (*pm_cpu_prep)(void); -void (*pm_cpu_sleep)(void); +int (*pm_cpu_sleep)(unsigned long); #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) @@ -294,15 +295,11 @@ static int s3c_pm_enter(suspend_state_t state) s3c_pm_arch_stop_clocks(); - /* s3c_cpu_save will also act as our return point from when + /* this will also act as our return point from when * we resume as it saves its own register state and restores it * during the resume. */ - s3c_cpu_save(0, PLAT_PHYS_OFFSET - PAGE_OFFSET); - - /* restore the cpu state using the kernel's cpu init code. */ - - cpu_init(); + cpu_suspend(0, pm_cpu_sleep); /* restore the system state */ diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 9897dcfc16d..2d30c7f6edd 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -77,27 +77,27 @@ ENTRY(vfp_support_entry) bne look_for_VFP_exceptions @ VFP is already enabled DBGSTR1 "enable %x", r10 - ldr r3, last_VFP_context_address + ldr r3, vfp_current_hw_state_address orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set - ldr r4, [r3, r11, lsl #2] @ last_VFP_context pointer + ldr r4, [r3, r11, lsl #2] @ vfp_current_hw_state pointer bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled - cmp r4, r10 - beq check_for_exception @ we are returning to the same - @ process, so the registers are - @ still there. In this case, we do - @ not want to drop a pending exception. + cmp r4, r10 @ this thread owns the hw context? +#ifndef CONFIG_SMP + @ For UP, checking that this thread owns the hw context is + @ sufficient to determine that the hardware state is valid. + beq vfp_hw_state_valid + + @ On UP, we lazily save the VFP context. As a different + @ thread wants ownership of the VFP hardware, save the old + @ state if there was a previous (valid) owner. VFPFMXR FPEXC, r5 @ enable VFP, disable any pending @ exceptions, so we can get at the @ rest of it -#ifndef CONFIG_SMP - @ Save out the current registers to the old thread state - @ No need for SMP since this is not done lazily - DBGSTR1 "save old state %p", r4 - cmp r4, #0 - beq no_old_VFP_process + cmp r4, #0 @ if the vfp_current_hw_state is NULL + beq vfp_reload_hw @ then the hw state needs reloading VFPFSTMIA r4, r5 @ save the working registers VFPFMRX r5, FPSCR @ current status #ifndef CONFIG_CPU_FEROCEON @@ -110,13 +110,35 @@ ENTRY(vfp_support_entry) 1: #endif stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2 - @ and point r4 at the word at the - @ start of the register dump +vfp_reload_hw: + +#else + @ For SMP, if this thread does not own the hw context, then we + @ need to reload it. No need to save the old state as on SMP, + @ we always save the state when we switch away from a thread. + bne vfp_reload_hw + + @ This thread has ownership of the current hardware context. + @ However, it may have been migrated to another CPU, in which + @ case the saved state is newer than the hardware context. + @ Check this by looking at the CPU number which the state was + @ last loaded onto. + ldr ip, [r10, #VFP_CPU] + teq ip, r11 + beq vfp_hw_state_valid + +vfp_reload_hw: + @ We're loading this threads state into the VFP hardware. Update + @ the CPU number which contains the most up to date VFP context. + str r11, [r10, #VFP_CPU] + + VFPFMXR FPEXC, r5 @ enable VFP, disable any pending + @ exceptions, so we can get at the + @ rest of it #endif -no_old_VFP_process: DBGSTR1 "load state %p", r10 - str r10, [r3, r11, lsl #2] @ update the last_VFP_context pointer + str r10, [r3, r11, lsl #2] @ update the vfp_current_hw_state pointer @ Load the saved state back into the VFP VFPFLDMIA r10, r5 @ reload the working registers while @ FPEXC is in a safe state @@ -132,7 +154,8 @@ no_old_VFP_process: #endif VFPFMXR FPSCR, r5 @ restore status -check_for_exception: +@ The context stored in the VFP hardware is up to date with this thread +vfp_hw_state_valid: tst r1, #FPEXC_EX bne process_exception @ might as well handle the pending @ exception before retrying branch @@ -207,8 +230,8 @@ ENTRY(vfp_save_state) ENDPROC(vfp_save_state) .align -last_VFP_context_address: - .word last_VFP_context +vfp_current_hw_state_address: + .word vfp_current_hw_state .macro tbl_branch, base, tmp, shift #ifdef CONFIG_THUMB2_KERNEL diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index f25e7ec8941..0a96f71f0ab 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -33,7 +33,6 @@ void vfp_support_entry(void); void vfp_null_entry(void); void (*vfp_vector)(void) = vfp_null_entry; -union vfp_state *last_VFP_context[NR_CPUS]; /* * Dual-use variable. @@ -43,6 +42,46 @@ union vfp_state *last_VFP_context[NR_CPUS]; unsigned int VFP_arch; /* + * The pointer to the vfpstate structure of the thread which currently + * owns the context held in the VFP hardware, or NULL if the hardware + * context is invalid. + * + * For UP, this is sufficient to tell which thread owns the VFP context. + * However, for SMP, we also need to check the CPU number stored in the + * saved state too to catch migrations. + */ +union vfp_state *vfp_current_hw_state[NR_CPUS]; + +/* + * Is 'thread's most up to date state stored in this CPUs hardware? + * Must be called from non-preemptible context. + */ +static bool vfp_state_in_hw(unsigned int cpu, struct thread_info *thread) +{ +#ifdef CONFIG_SMP + if (thread->vfpstate.hard.cpu != cpu) + return false; +#endif + return vfp_current_hw_state[cpu] == &thread->vfpstate; +} + +/* + * Force a reload of the VFP context from the thread structure. We do + * this by ensuring that access to the VFP hardware is disabled, and + * clear last_VFP_context. Must be called from non-preemptible context. + */ +static void vfp_force_reload(unsigned int cpu, struct thread_info *thread) +{ + if (vfp_state_in_hw(cpu, thread)) { + fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); + vfp_current_hw_state[cpu] = NULL; + } +#ifdef CONFIG_SMP + thread->vfpstate.hard.cpu = NR_CPUS; +#endif +} + +/* * Per-thread VFP initialization. */ static void vfp_thread_flush(struct thread_info *thread) @@ -50,21 +89,27 @@ static void vfp_thread_flush(struct thread_info *thread) union vfp_state *vfp = &thread->vfpstate; unsigned int cpu; - memset(vfp, 0, sizeof(union vfp_state)); - - vfp->hard.fpexc = FPEXC_EN; - vfp->hard.fpscr = FPSCR_ROUND_NEAREST; - /* * Disable VFP to ensure we initialize it first. We must ensure - * that the modification of last_VFP_context[] and hardware disable - * are done for the same CPU and without preemption. + * that the modification of vfp_current_hw_state[] and hardware + * disable are done for the same CPU and without preemption. + * + * Do this first to ensure that preemption won't overwrite our + * state saving should access to the VFP be enabled at this point. */ cpu = get_cpu(); - if (last_VFP_context[cpu] == vfp) - last_VFP_context[cpu] = NULL; + if (vfp_current_hw_state[cpu] == vfp) + vfp_current_hw_state[cpu] = NULL; fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); put_cpu(); + + memset(vfp, 0, sizeof(union vfp_state)); + + vfp->hard.fpexc = FPEXC_EN; + vfp->hard.fpscr = FPSCR_ROUND_NEAREST; +#ifdef CONFIG_SMP + vfp->hard.cpu = NR_CPUS; +#endif } static void vfp_thread_exit(struct thread_info *thread) @@ -73,8 +118,8 @@ static void vfp_thread_exit(struct thread_info *thread) union vfp_state *vfp = &thread->vfpstate; unsigned int cpu = get_cpu(); - if (last_VFP_context[cpu] == vfp) - last_VFP_context[cpu] = NULL; + if (vfp_current_hw_state[cpu] == vfp) + vfp_current_hw_state[cpu] = NULL; put_cpu(); } @@ -84,6 +129,9 @@ static void vfp_thread_copy(struct thread_info *thread) vfp_sync_hwstate(parent); thread->vfpstate = parent->vfpstate; +#ifdef CONFIG_SMP + thread->vfpstate.hard.cpu = NR_CPUS; +#endif } /* @@ -129,17 +177,8 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) * case the thread migrates to a different CPU. The * restoring is done lazily. */ - if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) { - vfp_save_state(last_VFP_context[cpu], fpexc); - last_VFP_context[cpu]->hard.cpu = cpu; - } - /* - * Thread migration, just force the reloading of the - * state on the new CPU in case the VFP registers - * contain stale data. - */ - if (thread->vfpstate.hard.cpu != cpu) - last_VFP_context[cpu] = NULL; + if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) + vfp_save_state(vfp_current_hw_state[cpu], fpexc); #endif /* @@ -415,7 +454,7 @@ static int vfp_pm_suspend(void) } /* clear any information we had about last context state */ - memset(last_VFP_context, 0, sizeof(last_VFP_context)); + memset(vfp_current_hw_state, 0, sizeof(vfp_current_hw_state)); return 0; } @@ -443,15 +482,15 @@ static void vfp_pm_init(void) static inline void vfp_pm_init(void) { } #endif /* CONFIG_PM */ +/* + * Ensure that the VFP state stored in 'thread->vfpstate' is up to date + * with the hardware state. + */ void vfp_sync_hwstate(struct thread_info *thread) { unsigned int cpu = get_cpu(); - /* - * If the thread we're interested in is the current owner of the - * hardware VFP state, then we need to save its state. - */ - if (last_VFP_context[cpu] == &thread->vfpstate) { + if (vfp_state_in_hw(cpu, thread)) { u32 fpexc = fmrx(FPEXC); /* @@ -465,36 +504,13 @@ void vfp_sync_hwstate(struct thread_info *thread) put_cpu(); } +/* Ensure that the thread reloads the hardware VFP state on the next use. */ void vfp_flush_hwstate(struct thread_info *thread) { unsigned int cpu = get_cpu(); - /* - * If the thread we're interested in is the current owner of the - * hardware VFP state, then we need to save its state. - */ - if (last_VFP_context[cpu] == &thread->vfpstate) { - u32 fpexc = fmrx(FPEXC); - - fmxr(FPEXC, fpexc & ~FPEXC_EN); - - /* - * Set the context to NULL to force a reload the next time - * the thread uses the VFP. - */ - last_VFP_context[cpu] = NULL; - } + vfp_force_reload(cpu, thread); -#ifdef CONFIG_SMP - /* - * For SMP we still have to take care of the case where the thread - * migrates to another CPU and then back to the original CPU on which - * the last VFP user is still the same thread. Mark the thread VFP - * state as belonging to a non-existent CPU so that the saved one will - * be reloaded in the above case. - */ - thread->vfpstate.hard.cpu = NR_CPUS; -#endif put_cpu(); } @@ -513,8 +529,7 @@ static int vfp_hotplug(struct notifier_block *b, unsigned long action, void *hcpu) { if (action == CPU_DYING || action == CPU_DYING_FROZEN) { - unsigned int cpu = (long)hcpu; - last_VFP_context[cpu] = NULL; + vfp_force_reload((long)hcpu, current_thread_info()); } else if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) vfp_enable(NULL); return NOTIFY_OK; diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index c018696765d..5c74eb797f0 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -14,7 +14,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spinlock.h> -#include <linux/sysdev.h> +#include <linux/syscore_ops.h> #include <linux/irq.h> #include <asm/i8259.h> @@ -215,14 +215,13 @@ spurious_8259A_irq: } } -static int i8259A_resume(struct sys_device *dev) +static void i8259A_resume(void) { if (i8259A_auto_eoi >= 0) init_8259A(i8259A_auto_eoi); - return 0; } -static int i8259A_shutdown(struct sys_device *dev) +static void i8259A_shutdown(void) { /* Put the i8259A into a quiescent state that * the kernel initialization code can get it @@ -232,26 +231,17 @@ static int i8259A_shutdown(struct sys_device *dev) outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */ } - return 0; } -static struct sysdev_class i8259_sysdev_class = { - .name = "i8259", +static struct syscore_ops i8259_syscore_ops = { .resume = i8259A_resume, .shutdown = i8259A_shutdown, }; -static struct sys_device device_i8259A = { - .id = 0, - .cls = &i8259_sysdev_class, -}; - static int __init i8259A_init_sysfs(void) { - int error = sysdev_class_register(&i8259_sysdev_class); - if (!error) - error = sysdev_register(&device_i8259A); - return error; + register_syscore_ops(&i8259_syscore_ops); + return 0; } device_initcall(i8259A_init_sysfs); diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 33867ec4a23..9d6a8effeda 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -12,6 +12,8 @@ #include <linux/of.h> #include <linux/memblock.h> #include <linux/vmalloc.h> +#include <linux/memory.h> + #include <asm/firmware.h> #include <asm/machdep.h> #include <asm/pSeries_reconfig.h> @@ -20,24 +22,25 @@ static unsigned long get_memblock_size(void) { struct device_node *np; - unsigned int memblock_size = 0; + unsigned int memblock_size = MIN_MEMORY_BLOCK_SIZE; + struct resource r; np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); if (np) { - const unsigned long *size; + const __be64 *size; size = of_get_property(np, "ibm,lmb-size", NULL); - memblock_size = size ? *size : 0; - + if (size) + memblock_size = be64_to_cpup(size); of_node_put(np); - } else { + } else if (machine_is(pseries)) { + /* This fallback really only applies to pseries */ unsigned int memzero_size = 0; - const unsigned int *regs; np = of_find_node_by_path("/memory@0"); if (np) { - regs = of_get_property(np, "reg", NULL); - memzero_size = regs ? regs[3] : 0; + if (!of_address_to_resource(np, 0, &r)) + memzero_size = resource_size(&r); of_node_put(np); } @@ -50,16 +53,21 @@ static unsigned long get_memblock_size(void) sprintf(buf, "/memory@%x", memzero_size); np = of_find_node_by_path(buf); if (np) { - regs = of_get_property(np, "reg", NULL); - memblock_size = regs ? regs[3] : 0; + if (!of_address_to_resource(np, 0, &r)) + memblock_size = resource_size(&r); of_node_put(np); } } } - return memblock_size; } +/* WARNING: This is going to override the generic definition whenever + * pseries is built-in regardless of what platform is active at boot + * time. This is fine for now as this is the only "option" and it + * should work everywhere. If not, we'll have to turn this into a + * ppc_md. callback + */ unsigned long memory_block_size_bytes(void) { return get_memblock_size(); diff --git a/arch/sparc/include/asm/irqflags_32.h b/arch/sparc/include/asm/irqflags_32.h index d4d0711de0f..14848909e0d 100644 --- a/arch/sparc/include/asm/irqflags_32.h +++ b/arch/sparc/include/asm/irqflags_32.h @@ -18,7 +18,7 @@ extern void arch_local_irq_restore(unsigned long); extern unsigned long arch_local_irq_save(void); extern void arch_local_irq_enable(void); -static inline unsigned long arch_local_save_flags(void) +static inline notrace unsigned long arch_local_save_flags(void) { unsigned long flags; @@ -26,17 +26,17 @@ static inline unsigned long arch_local_save_flags(void) return flags; } -static inline void arch_local_irq_disable(void) +static inline notrace void arch_local_irq_disable(void) { arch_local_irq_save(); } -static inline bool arch_irqs_disabled_flags(unsigned long flags) +static inline notrace bool arch_irqs_disabled_flags(unsigned long flags) { return (flags & PSR_PIL) != 0; } -static inline bool arch_irqs_disabled(void) +static inline notrace bool arch_irqs_disabled(void) { return arch_irqs_disabled_flags(arch_local_save_flags()); } diff --git a/arch/sparc/include/asm/irqflags_64.h b/arch/sparc/include/asm/irqflags_64.h index aab969c82c2..23cd27f6beb 100644 --- a/arch/sparc/include/asm/irqflags_64.h +++ b/arch/sparc/include/asm/irqflags_64.h @@ -14,7 +14,7 @@ #ifndef __ASSEMBLY__ -static inline unsigned long arch_local_save_flags(void) +static inline notrace unsigned long arch_local_save_flags(void) { unsigned long flags; @@ -26,7 +26,7 @@ static inline unsigned long arch_local_save_flags(void) return flags; } -static inline void arch_local_irq_restore(unsigned long flags) +static inline notrace void arch_local_irq_restore(unsigned long flags) { __asm__ __volatile__( "wrpr %0, %%pil" @@ -36,7 +36,7 @@ static inline void arch_local_irq_restore(unsigned long flags) ); } -static inline void arch_local_irq_disable(void) +static inline notrace void arch_local_irq_disable(void) { __asm__ __volatile__( "wrpr %0, %%pil" @@ -46,7 +46,7 @@ static inline void arch_local_irq_disable(void) ); } -static inline void arch_local_irq_enable(void) +static inline notrace void arch_local_irq_enable(void) { __asm__ __volatile__( "wrpr 0, %%pil" @@ -56,17 +56,17 @@ static inline void arch_local_irq_enable(void) ); } -static inline int arch_irqs_disabled_flags(unsigned long flags) +static inline notrace int arch_irqs_disabled_flags(unsigned long flags) { return (flags > 0); } -static inline int arch_irqs_disabled(void) +static inline notrace int arch_irqs_disabled(void) { return arch_irqs_disabled_flags(arch_local_save_flags()); } -static inline unsigned long arch_local_irq_save(void) +static inline notrace unsigned long arch_local_irq_save(void) { unsigned long flags, tmp; diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 9fe08a1ea6c..f445e98463e 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -293,7 +293,7 @@ maybe_smp4m_msg: WRITE_PAUSE wr %l4, PSR_ET, %psr WRITE_PAUSE - sll %o3, 28, %o2 ! shift for simpler checks below + srl %o3, 28, %o2 ! shift for simpler checks below maybe_smp4m_msg_check_single: andcc %o2, 0x1, %g0 beq,a maybe_smp4m_msg_check_mask diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c index c0e01297e64..e485a680499 100644 --- a/arch/sparc/mm/leon_mm.c +++ b/arch/sparc/mm/leon_mm.c @@ -226,7 +226,7 @@ void leon3_getCacheRegs(struct leon3_cacheregs *regs) * Leon2 and Leon3 differ in their way of telling cache information * */ -int leon_flush_needed(void) +int __init leon_flush_needed(void) { int flush_needed = -1; unsigned int ssize, sets; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index da349723d41..37357a599dc 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1170,7 +1170,7 @@ comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI" config AMD_NUMA def_bool y prompt "Old style AMD Opteron NUMA detection" - depends on NUMA && PCI + depends on X86_64 && NUMA && PCI ---help--- Enable AMD NUMA node topology detection. You should say Y here if you have a multi processor AMD system. This uses an old method to diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h index 224e8c5eb30..ffa037f28d3 100644 --- a/arch/x86/include/asm/mmzone_32.h +++ b/arch/x86/include/asm/mmzone_32.h @@ -57,6 +57,8 @@ static inline int pfn_valid(int pfn) return 0; } +#define early_pfn_valid(pfn) pfn_valid((pfn)) + #endif /* CONFIG_DISCONTIGMEM */ #ifdef CONFIG_NEED_MULTIPLE_NODES diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S index ead21b66311..b4fd836e405 100644 --- a/arch/x86/kernel/acpi/realmode/wakeup.S +++ b/arch/x86/kernel/acpi/realmode/wakeup.S @@ -28,6 +28,8 @@ pmode_cr3: .long 0 /* Saved %cr3 */ pmode_cr4: .long 0 /* Saved %cr4 */ pmode_efer: .quad 0 /* Saved EFER */ pmode_gdt: .quad 0 +pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ +pmode_behavior: .long 0 /* Wakeup behavior flags */ realmode_flags: .long 0 real_magic: .long 0 trampoline_segment: .word 0 @@ -91,6 +93,18 @@ wakeup_code: /* Call the C code */ calll main + /* Restore MISC_ENABLE before entering protected mode, in case + BIOS decided to clear XD_DISABLE during S3. */ + movl pmode_behavior, %eax + btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax + jnc 1f + + movl pmode_misc_en, %eax + movl pmode_misc_en + 4, %edx + movl $MSR_IA32_MISC_ENABLE, %ecx + wrmsr +1: + /* Do any other stuff... */ #ifndef CONFIG_64BIT diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h index e1828c07e79..97a29e1430e 100644 --- a/arch/x86/kernel/acpi/realmode/wakeup.h +++ b/arch/x86/kernel/acpi/realmode/wakeup.h @@ -21,6 +21,9 @@ struct wakeup_header { u32 pmode_efer_low; /* Protected mode EFER */ u32 pmode_efer_high; u64 pmode_gdt; + u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */ + u32 pmode_misc_en_high; + u32 pmode_behavior; /* Wakeup routine behavior flags */ u32 realmode_flags; u32 real_magic; u16 trampoline_segment; /* segment with trampoline code, 64-bit only */ @@ -39,4 +42,7 @@ extern struct wakeup_header wakeup_header; #define WAKEUP_HEADER_SIGNATURE 0x51ee1111 #define WAKEUP_END_SIGNATURE 0x65a22c82 +/* Wakeup behavior bits */ +#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0 + #endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */ diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 18a857ba7a2..103b6ab368d 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -77,6 +77,12 @@ int acpi_suspend_lowlevel(void) header->pmode_cr0 = read_cr0(); header->pmode_cr4 = read_cr4_safe(); + header->pmode_behavior = 0; + if (!rdmsr_safe(MSR_IA32_MISC_ENABLE, + &header->pmode_misc_en_low, + &header->pmode_misc_en_high)) + header->pmode_behavior |= + (1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE); header->realmode_flags = acpi_realmode_flags; header->real_magic = 0x12345678; diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 0c016f72769..14eed214b58 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -294,6 +294,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "VersaLogic Menlow board"), }, }, + { /* Handle reboot issue on Acer Aspire one */ + .callback = set_bios_reboot, + .ident = "Acer Aspire One A110", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), + }, + }, { } }; @@ -411,6 +419,14 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), }, }, + { /* Handle problems with rebooting on the Latitude E6320. */ + .callback = set_pci_reboot, + .ident = "Dell Latitude E6320", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), + }, + }, { } }; diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index d865c4aeec5..bbaaa005bf0 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -28,6 +28,7 @@ #include <linux/poison.h> #include <linux/dma-mapping.h> #include <linux/module.h> +#include <linux/memory.h> #include <linux/memory_hotplug.h> #include <linux/nmi.h> #include <linux/gfp.h> @@ -895,8 +896,6 @@ const char *arch_vma_name(struct vm_area_struct *vma) } #ifdef CONFIG_X86_UV -#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS) - unsigned long memory_block_size_bytes(void) { if (is_uv_system()) { diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index cf9750004a0..68894fdc034 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -112,8 +112,10 @@ static void nmi_cpu_start(void *dummy) static int nmi_start(void) { get_online_cpus(); - on_each_cpu(nmi_cpu_start, NULL, 1); ctr_running = 1; + /* make ctr_running visible to the nmi handler: */ + smp_mb(); + on_each_cpu(nmi_cpu_start, NULL, 1); put_online_cpus(); return 0; } @@ -504,15 +506,18 @@ static int nmi_setup(void) nmi_enabled = 0; ctr_running = 0; - barrier(); + /* make variables visible to the nmi handler: */ + smp_mb(); err = register_die_notifier(&profile_exceptions_nb); if (err) goto fail; get_online_cpus(); register_cpu_notifier(&oprofile_cpu_nb); - on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; + /* make nmi_enabled visible to the nmi handler: */ + smp_mb(); + on_each_cpu(nmi_cpu_setup, NULL, 1); put_online_cpus(); return 0; @@ -531,7 +536,8 @@ static void nmi_shutdown(void) nmi_enabled = 0; ctr_running = 0; put_online_cpus(); - barrier(); + /* make variables visible to the nmi handler: */ + smp_mb(); unregister_die_notifier(&profile_exceptions_nb); msrs = &get_cpu_var(cpu_msrs); model->shutdown(msrs); diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index fe008309ffe..f567965c062 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -327,13 +327,12 @@ int __init pci_xen_hvm_init(void) } #ifdef CONFIG_XEN_DOM0 -static int xen_register_pirq(u32 gsi, int triggering) +static int xen_register_pirq(u32 gsi, int gsi_override, int triggering) { int rc, pirq, irq = -1; struct physdev_map_pirq map_irq; int shareable = 0; char *name; - bool gsi_override = false; if (!xen_pv_domain()) return -1; @@ -345,31 +344,12 @@ static int xen_register_pirq(u32 gsi, int triggering) shareable = 1; name = "ioapic-level"; } - pirq = xen_allocate_pirq_gsi(gsi); if (pirq < 0) goto out; - /* Before we bind the GSI to a Linux IRQ, check whether - * we need to override it with bus_irq (IRQ) value. Usually for - * IRQs below IRQ_LEGACY_IRQ this holds IRQ == GSI, as so: - * ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 low level) - * but there are oddballs where the IRQ != GSI: - * ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 20 low level) - * which ends up being: gsi_to_irq[9] == 20 - * (which is what acpi_gsi_to_irq ends up calling when starting the - * the ACPI interpreter and keels over since IRQ 9 has not been - * setup as we had setup IRQ 20 for it). - */ - if (gsi == acpi_sci_override_gsi) { - /* Check whether the GSI != IRQ */ - acpi_gsi_to_irq(gsi, &irq); - if (irq != gsi) - /* Bugger, we MUST have that IRQ. */ - gsi_override = true; - } - if (gsi_override) - irq = xen_bind_pirq_gsi_to_irq(irq, pirq, shareable, name); + if (gsi_override >= 0) + irq = xen_bind_pirq_gsi_to_irq(gsi_override, pirq, shareable, name); else irq = xen_bind_pirq_gsi_to_irq(gsi, pirq, shareable, name); if (irq < 0) @@ -392,7 +372,7 @@ out: return irq; } -static int xen_register_gsi(u32 gsi, int triggering, int polarity) +static int xen_register_gsi(u32 gsi, int gsi_override, int triggering, int polarity) { int rc, irq; struct physdev_setup_gsi setup_gsi; @@ -403,7 +383,7 @@ static int xen_register_gsi(u32 gsi, int triggering, int polarity) printk(KERN_DEBUG "xen: registering gsi %u triggering %d polarity %d\n", gsi, triggering, polarity); - irq = xen_register_pirq(gsi, triggering); + irq = xen_register_pirq(gsi, gsi_override, triggering); setup_gsi.gsi = gsi; setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ? 0 : 1); @@ -425,6 +405,8 @@ static __init void xen_setup_acpi_sci(void) int rc; int trigger, polarity; int gsi = acpi_sci_override_gsi; + int irq = -1; + int gsi_override = -1; if (!gsi) return; @@ -441,7 +423,25 @@ static __init void xen_setup_acpi_sci(void) printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d " "polarity=%d\n", gsi, trigger, polarity); - gsi = xen_register_gsi(gsi, trigger, polarity); + /* Before we bind the GSI to a Linux IRQ, check whether + * we need to override it with bus_irq (IRQ) value. Usually for + * IRQs below IRQ_LEGACY_IRQ this holds IRQ == GSI, as so: + * ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 low level) + * but there are oddballs where the IRQ != GSI: + * ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 20 low level) + * which ends up being: gsi_to_irq[9] == 20 + * (which is what acpi_gsi_to_irq ends up calling when starting the + * the ACPI interpreter and keels over since IRQ 9 has not been + * setup as we had setup IRQ 20 for it). + */ + /* Check whether the GSI != IRQ */ + if (acpi_gsi_to_irq(gsi, &irq) == 0) { + if (irq >= 0 && irq != gsi) + /* Bugger, we MUST have that IRQ. */ + gsi_override = irq; + } + + gsi = xen_register_gsi(gsi, gsi_override, trigger, polarity); printk(KERN_INFO "xen: acpi sci %d\n", gsi); return; @@ -450,7 +450,7 @@ static __init void xen_setup_acpi_sci(void) static int acpi_register_gsi_xen(struct device *dev, u32 gsi, int trigger, int polarity) { - return xen_register_gsi(gsi, trigger, polarity); + return xen_register_gsi(gsi, -1 /* no GSI override */, trigger, polarity); } static int __init pci_xen_initial_domain(void) @@ -489,7 +489,7 @@ void __init xen_setup_pirqs(void) if (acpi_get_override_irq(irq, &trigger, &polarity) == -1) continue; - xen_register_pirq(irq, + xen_register_pirq(irq, -1 /* no GSI override */, trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE); } } diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 474356b98ed..899e393d8e7 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -504,9 +504,6 @@ void __init efi_init(void) x86_platform.set_wallclock = efi_set_rtc_mmss; #endif - /* Setup for EFI runtime service */ - reboot_type = BOOT_EFI; - #if EFI_DEBUG print_efi_memmap(); #endif diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index f3799432676..ae21919f15e 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -2773,11 +2773,14 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd, smp_wmb(); cic->key = cfqd_dead_key(cfqd); + rcu_read_lock(); if (rcu_dereference(ioc->ioc_data) == cic) { + rcu_read_unlock(); spin_lock(&ioc->lock); rcu_assign_pointer(ioc->ioc_data, NULL); spin_unlock(&ioc->lock); - } + } else + rcu_read_unlock(); if (cic->cfqq[BLK_RW_ASYNC]) { cfq_exit_cfqq(cfqd, cic->cfqq[BLK_RW_ASYNC]); @@ -3084,7 +3087,8 @@ cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc, spin_lock_irqsave(&ioc->lock, flags); - BUG_ON(ioc->ioc_data == cic); + BUG_ON(rcu_dereference_check(ioc->ioc_data, + lockdep_is_held(&ioc->lock)) == cic); radix_tree_delete(&ioc->radix_root, cfqd->cic_index); hlist_del_rcu(&cic->cic_list); diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index abda3786a5d..181bc2f7bb7 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -139,13 +139,23 @@ static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data) { struct platform_device *ghes_dev; struct ghes_arr *ghes_arr = data; - int rc; + int rc, i; if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR) return 0; if (!((struct acpi_hest_generic *)hest_hdr)->enabled) return 0; + for (i = 0; i < ghes_arr->count; i++) { + struct acpi_hest_header *hdr; + ghes_dev = ghes_arr->ghes_devs[i]; + hdr = *(struct acpi_hest_header **)ghes_dev->dev.platform_data; + if (hdr->source_id == hest_hdr->source_id) { + pr_warning(FW_WARN HEST_PFX "Duplicated hardware error source ID: %d.\n", + hdr->source_id); + return -EIO; + } + } ghes_dev = platform_device_alloc("GHES", hest_hdr->source_id); if (!ghes_dev) return -ENOMEM; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 52ca9649d76..372f9b70f7f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1333,23 +1333,6 @@ int acpi_resources_are_enforced(void) EXPORT_SYMBOL(acpi_resources_are_enforced); /* - * Create and initialize a spinlock. - */ -acpi_status -acpi_os_create_lock(acpi_spinlock *out_handle) -{ - spinlock_t *lock; - - lock = ACPI_ALLOCATE(sizeof(spinlock_t)); - if (!lock) - return AE_NO_MEMORY; - spin_lock_init(lock); - *out_handle = lock; - - return AE_OK; -} - -/* * Deallocate the memory for a spinlock. */ void acpi_os_delete_lock(acpi_spinlock handle) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 9f9b2359f71..45d7c8fc73b 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -30,7 +30,6 @@ static DEFINE_MUTEX(mem_sysfs_mutex); #define MEMORY_CLASS_NAME "memory" -#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS) static int sections_per_block; diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index c126db3cb7d..e8d11b6630e 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -9,6 +9,7 @@ #include <linux/syscore_ops.h> #include <linux/mutex.h> #include <linux/module.h> +#include <linux/interrupt.h> static LIST_HEAD(syscore_ops_list); static DEFINE_MUTEX(syscore_ops_lock); @@ -48,6 +49,13 @@ int syscore_suspend(void) struct syscore_ops *ops; int ret = 0; + pr_debug("Checking wakeup interrupts\n"); + + /* Return error code if there are any wakeup interrupts pending. */ + ret = check_wakeup_irqs(); + if (ret) + return ret; + WARN_ONCE(!irqs_disabled(), "Interrupts enabled before system core suspend.\n"); diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 09ef9a878ef..cf0e63dd97d 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -79,7 +79,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev, md_io.error = 0; if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags)) - rw |= REQ_FUA; + rw |= REQ_FUA | REQ_FLUSH; rw |= REQ_SYNC; bio = bio_alloc(GFP_NOIO, 1); diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index f440a02dfdb..7b976296b56 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -112,9 +112,6 @@ struct drbd_bitmap { struct task_struct *bm_task; }; -static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, - unsigned long e, int val, const enum km_type km); - #define bm_print_lock_info(m) __bm_print_lock_info(m, __func__) static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) { @@ -994,6 +991,9 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must bio_endio(bio, -EIO); } else { submit_bio(rw, bio); + /* this should not count as user activity and cause the + * resync to throttle -- see drbd_rs_should_slow_down(). */ + atomic_add(len >> 9, &mdev->rs_sect_ev); } } @@ -1256,7 +1256,7 @@ unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_f * expected to be called for only a few bits (e - s about BITS_PER_LONG). * Must hold bitmap lock already. */ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, - unsigned long e, int val, const enum km_type km) + unsigned long e, int val) { struct drbd_bitmap *b = mdev->bitmap; unsigned long *p_addr = NULL; @@ -1274,14 +1274,14 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, unsigned int page_nr = bm_bit_to_page_idx(b, bitnr); if (page_nr != last_page_nr) { if (p_addr) - __bm_unmap(p_addr, km); + __bm_unmap(p_addr, KM_IRQ1); if (c < 0) bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); else if (c > 0) bm_set_page_need_writeout(b->bm_pages[last_page_nr]); changed_total += c; c = 0; - p_addr = __bm_map_pidx(b, page_nr, km); + p_addr = __bm_map_pidx(b, page_nr, KM_IRQ1); last_page_nr = page_nr; } if (val) @@ -1290,7 +1290,7 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, c -= (0 != __test_and_clear_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr)); } if (p_addr) - __bm_unmap(p_addr, km); + __bm_unmap(p_addr, KM_IRQ1); if (c < 0) bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); else if (c > 0) @@ -1318,7 +1318,7 @@ static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags) bm_print_lock_info(mdev); - c = __bm_change_bits_to(mdev, s, e, val, KM_IRQ1); + c = __bm_change_bits_to(mdev, s, e, val); spin_unlock_irqrestore(&b->bm_lock, flags); return c; @@ -1343,16 +1343,17 @@ static inline void bm_set_full_words_within_one_page(struct drbd_bitmap *b, { int i; int bits; - unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr], KM_USER0); + unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr], KM_IRQ1); for (i = first_word; i < last_word; i++) { bits = hweight_long(paddr[i]); paddr[i] = ~0UL; b->bm_set += BITS_PER_LONG - bits; } - kunmap_atomic(paddr, KM_USER0); + kunmap_atomic(paddr, KM_IRQ1); } -/* Same thing as drbd_bm_set_bits, but without taking the spin_lock_irqsave. +/* Same thing as drbd_bm_set_bits, + * but more efficient for a large bit range. * You must first drbd_bm_lock(). * Can be called to set the whole bitmap in one go. * Sets bits from s to e _inclusive_. */ @@ -1366,6 +1367,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi * Do not use memset, because we must account for changes, * so we need to loop over the words with hweight() anyways. */ + struct drbd_bitmap *b = mdev->bitmap; unsigned long sl = ALIGN(s,BITS_PER_LONG); unsigned long el = (e+1) & ~((unsigned long)BITS_PER_LONG-1); int first_page; @@ -1376,15 +1378,19 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi if (e - s <= 3*BITS_PER_LONG) { /* don't bother; el and sl may even be wrong. */ - __bm_change_bits_to(mdev, s, e, 1, KM_USER0); + spin_lock_irq(&b->bm_lock); + __bm_change_bits_to(mdev, s, e, 1); + spin_unlock_irq(&b->bm_lock); return; } /* difference is large enough that we can trust sl and el */ + spin_lock_irq(&b->bm_lock); + /* bits filling the current long */ if (sl) - __bm_change_bits_to(mdev, s, sl-1, 1, KM_USER0); + __bm_change_bits_to(mdev, s, sl-1, 1); first_page = sl >> (3 + PAGE_SHIFT); last_page = el >> (3 + PAGE_SHIFT); @@ -1397,8 +1403,10 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi /* first and full pages, unless first page == last page */ for (page_nr = first_page; page_nr < last_page; page_nr++) { bm_set_full_words_within_one_page(mdev->bitmap, page_nr, first_word, last_word); + spin_unlock_irq(&b->bm_lock); cond_resched(); first_word = 0; + spin_lock_irq(&b->bm_lock); } /* last page (respectively only page, for first page == last page) */ @@ -1411,7 +1419,8 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi * it would trigger an assert in __bm_change_bits_to() */ if (el <= e) - __bm_change_bits_to(mdev, el, e, 1, KM_USER0); + __bm_change_bits_to(mdev, el, e, 1); + spin_unlock_irq(&b->bm_lock); } /* returns bit state diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 25d32c5aa50..43beaca5317 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4602,6 +4602,11 @@ int drbd_asender(struct drbd_thread *thi) dev_err(DEV, "meta connection shut down by peer.\n"); goto reconnect; } else if (rv == -EAGAIN) { + /* If the data socket received something meanwhile, + * that is good enough: peer is still alive. */ + if (time_after(mdev->last_received, + jiffies - mdev->meta.socket->sk->sk_rcvtimeo)) + continue; if (ping_timeout_active) { dev_err(DEV, "PingAck did not arrive in time.\n"); goto reconnect; @@ -4637,6 +4642,7 @@ int drbd_asender(struct drbd_thread *thi) goto reconnect; } if (received == expect) { + mdev->last_received = jiffies; D_ASSERT(cmd != NULL); if (!cmd->process(mdev, h)) goto reconnect; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 4d76b06b6b2..4d3e6f6213b 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -536,12 +536,7 @@ static int w_make_resync_request(struct drbd_conf *mdev, return 1; } - /* starting with drbd 8.3.8, we can handle multi-bio EEs, - * if it should be necessary */ - max_bio_size = - mdev->agreed_pro_version < 94 ? queue_max_hw_sectors(mdev->rq_queue) << 9 : - mdev->agreed_pro_version < 95 ? DRBD_MAX_SIZE_H80_PACKET : DRBD_MAX_BIO_SIZE; - + max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9; number = drbd_rs_number_requests(mdev); if (number == 0) goto requeue; diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 999803ce10d..5da67f165af 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -90,9 +90,10 @@ #define G4x_GMCH_SIZE_MASK (0xf << 8) #define G4x_GMCH_SIZE_1M (0x1 << 8) #define G4x_GMCH_SIZE_2M (0x3 << 8) -#define G4x_GMCH_SIZE_VT_1M (0x9 << 8) -#define G4x_GMCH_SIZE_VT_1_5M (0xa << 8) -#define G4x_GMCH_SIZE_VT_2M (0xc << 8) +#define G4x_GMCH_SIZE_VT_EN (0x8 << 8) +#define G4x_GMCH_SIZE_VT_1M (G4x_GMCH_SIZE_1M | G4x_GMCH_SIZE_VT_EN) +#define G4x_GMCH_SIZE_VT_1_5M ((0x2 << 8) | G4x_GMCH_SIZE_VT_EN) +#define G4x_GMCH_SIZE_VT_2M (G4x_GMCH_SIZE_2M | G4x_GMCH_SIZE_VT_EN) #define GFX_FLSH_CNTL 0x2170 /* 915+ */ diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 4e04e127438..596d5dd32f4 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -759,7 +759,7 @@ static void __exit acpi_cpufreq_exit(void) cpufreq_unregister_driver(&acpi_cpufreq_driver); - free_percpu(acpi_perf_data); + free_acpi_perf_data(); } module_param(acpi_pstate_strict, uint, 0644); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 438e6c83117..ebb897329c1 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -264,6 +264,7 @@ static char ohci_driver_name[] = KBUILD_MODNAME; #define PCI_DEVICE_ID_AGERE_FW643 0x5901 #define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 +#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd #define QUIRK_CYCLE_TIMER 1 #define QUIRK_RESET_PACKET 2 @@ -3190,6 +3191,11 @@ static int __devinit pci_probe(struct pci_dev *dev, int i, err; size_t size; + if (dev->vendor == PCI_VENDOR_ID_PINNACLE_SYSTEMS) { + dev_err(&dev->dev, "Pinnacle MovieBoard is not yet supported\n"); + return -ENOSYS; + } + ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); if (ohci == NULL) { err = -ENOMEM; diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index bd6571e0097..644ba1255d3 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -223,7 +223,7 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) gedr = gpio_reg(&lnw->chip, base, GEDR); pending = readl(gedr); while (pending) { - gpio = __ffs(pending) - 1; + gpio = __ffs(pending); mask = BIT(gpio); pending &= ~mask; /* Clear before handling so we can't lose an edge */ diff --git a/drivers/gpio/tps65910-gpio.c b/drivers/gpio/tps65910-gpio.c index 8d1ddfdd63e..15097ca616d 100644 --- a/drivers/gpio/tps65910-gpio.c +++ b/drivers/gpio/tps65910-gpio.c @@ -81,8 +81,10 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base) switch(tps65910_chip_id(tps65910)) { case TPS65910: tps65910->gpio.ngpio = 6; + break; case TPS65911: tps65910->gpio.ngpio = 9; + break; default: return; } diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c index 309644cf4d9..2bcfb0be09f 100644 --- a/drivers/gpio/wm831x-gpio.c +++ b/drivers/gpio/wm831x-gpio.c @@ -180,6 +180,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) break; case WM831X_GPIO_PULL_UP: pull = "pullup"; + break; default: pull = "INVALID PULL"; break; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 21058e6ad2b..82db1850666 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -886,9 +886,6 @@ int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) total_objects += dev->mode_config.num_connector; total_objects += dev->mode_config.num_encoder; - if (total_objects == 0) - return -EINVAL; - group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL); if (!group->id_list) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e1787022d6c..296fbd66f0e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1943,7 +1943,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (!dev_priv->mm.gtt) { DRM_ERROR("Failed to initialize GTT\n"); ret = -ENODEV; - goto out_iomapfree; + goto out_rmmap; } agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; @@ -1987,7 +1987,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (dev_priv->wq == NULL) { DRM_ERROR("Failed to create our workqueue.\n"); ret = -ENOMEM; - goto out_iomapfree; + goto out_mtrrfree; } /* enable GEM by default */ @@ -2074,13 +2074,21 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) return 0; out_gem_unload: + if (dev_priv->mm.inactive_shrinker.shrink) + unregister_shrinker(&dev_priv->mm.inactive_shrinker); + if (dev->pdev->msi_enabled) pci_disable_msi(dev->pdev); intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->wq); -out_iomapfree: +out_mtrrfree: + if (dev_priv->mm.gtt_mtrr >= 0) { + mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base, + dev->agp->agp_info.aper_size * 1024 * 1024); + dev_priv->mm.gtt_mtrr = -1; + } io_mapping_free(dev_priv->mm.gtt_mapping); out_rmmap: pci_iounmap(dev->pdev, dev_priv->regs); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 013d304455b..eb91e2dd791 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -52,7 +52,7 @@ module_param_named(powersave, i915_powersave, int, 0600); unsigned int i915_semaphores = 0; module_param_named(semaphores, i915_semaphores, int, 0600); -unsigned int i915_enable_rc6 = 1; +unsigned int i915_enable_rc6 = 0; module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); unsigned int i915_enable_fbc = 0; @@ -577,6 +577,7 @@ int i915_reset(struct drm_device *dev, u8 flags) if (get_seconds() - dev_priv->last_gpu_reset < 5) { DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); } else switch (INTEL_INFO(dev)->gen) { + case 7: case 6: ret = gen6_do_reset(dev, flags); /* If reset with a user forcewake, try to restore */ diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 391b55f1cc7..e2aced6eec4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -50,7 +50,6 @@ 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[4]; @@ -138,8 +137,8 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp) { int max_lane_count = 4; - if (intel_dp->dpcd[0] >= 0x11) { - max_lane_count = intel_dp->dpcd[2] & 0x1f; + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) { + max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f; switch (max_lane_count) { case 1: case 2: case 4: break; @@ -153,7 +152,7 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp) static int intel_dp_max_link_bw(struct intel_dp *intel_dp) { - int max_link_bw = intel_dp->dpcd[1]; + int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE]; switch (max_link_bw) { case DP_LINK_BW_1_62: @@ -774,7 +773,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, /* * Check for DPCD version > 1.1 and enhanced framing support */ - if (intel_dp->dpcd[0] >= 0x11 && (intel_dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)) { + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 && + (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) { intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; intel_dp->DP |= DP_ENHANCED_FRAMING; } @@ -942,11 +942,44 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder) udelay(200); } +/* If the sink supports it, try to set the power state appropriately */ +static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) +{ + int ret, i; + + /* Should have a valid DPCD by this point */ + if (intel_dp->dpcd[DP_DPCD_REV] < 0x11) + return; + + if (mode != DRM_MODE_DPMS_ON) { + ret = intel_dp_aux_native_write_1(intel_dp, DP_SET_POWER, + DP_SET_POWER_D3); + if (ret != 1) + DRM_DEBUG_DRIVER("failed to write sink power state\n"); + } else { + /* + * When turning on, we need to retry for 1ms to give the sink + * time to wake up. + */ + for (i = 0; i < 3; i++) { + ret = intel_dp_aux_native_write_1(intel_dp, + DP_SET_POWER, + DP_SET_POWER_D0); + if (ret == 1) + break; + msleep(1); + } + } +} + static void intel_dp_prepare(struct drm_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = encoder->dev; + /* Wake up the sink first */ + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + if (is_edp(intel_dp)) { ironlake_edp_backlight_off(dev); ironlake_edp_panel_off(dev); @@ -990,6 +1023,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) if (mode != DRM_MODE_DPMS_ON) { if (is_edp(intel_dp)) ironlake_edp_backlight_off(dev); + intel_dp_sink_dpms(intel_dp, mode); intel_dp_link_down(intel_dp); if (is_edp(intel_dp)) ironlake_edp_panel_off(dev); @@ -998,6 +1032,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) } else { if (is_edp(intel_dp)) ironlake_edp_panel_vdd_on(intel_dp); + intel_dp_sink_dpms(intel_dp, mode); if (!(dp_reg & DP_PORT_EN)) { intel_dp_start_link_train(intel_dp); if (is_edp(intel_dp)) { @@ -1009,7 +1044,31 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) if (is_edp(intel_dp)) ironlake_edp_backlight_on(dev); } - intel_dp->dpms_mode = mode; +} + +/* + * Native read with retry for link status and receiver capability reads for + * cases where the sink may still be asleep. + */ +static bool +intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address, + uint8_t *recv, int recv_bytes) +{ + int ret, i; + + /* + * Sinks are *supposed* to come up within 1ms from an off state, + * but we're also supposed to retry 3 times per the spec. + */ + for (i = 0; i < 3; i++) { + ret = intel_dp_aux_native_read(intel_dp, address, recv, + recv_bytes); + if (ret == recv_bytes) + return true; + msleep(1); + } + + return false; } /* @@ -1019,14 +1078,10 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) static bool intel_dp_get_link_status(struct intel_dp *intel_dp) { - int ret; - - ret = intel_dp_aux_native_read(intel_dp, - DP_LANE0_1_STATUS, - intel_dp->link_status, DP_LINK_STATUS_SIZE); - if (ret != DP_LINK_STATUS_SIZE) - return false; - return true; + return intel_dp_aux_native_read_retry(intel_dp, + DP_LANE0_1_STATUS, + intel_dp->link_status, + DP_LINK_STATUS_SIZE); } static uint8_t @@ -1515,6 +1570,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { + int ret; + if (!intel_dp->base.base.crtc) return; @@ -1523,6 +1580,15 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) return; } + /* 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)) { intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); @@ -1533,6 +1599,7 @@ 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)) { @@ -1543,13 +1610,11 @@ ironlake_dp_detect(struct intel_dp *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[0] != 0) - status = connector_status_connected; - } + 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; @@ -1586,7 +1651,7 @@ g4x_dp_detect(struct intel_dp *intel_dp) if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd, sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) { - if (intel_dp->dpcd[0] != 0) + if (intel_dp->dpcd[DP_DPCD_REV] != 0) status = connector_status_connected; } @@ -1790,8 +1855,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder) { struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); - if (intel_dp->dpms_mode == DRM_MODE_DPMS_ON) - intel_dp_check_link_status(intel_dp); + intel_dp_check_link_status(intel_dp); } /* Return which DP Port should be selected for Transcoder DP control */ @@ -1859,7 +1923,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) { @@ -1954,8 +2017,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) sizeof(intel_dp->dpcd)); ironlake_edp_panel_vdd_off(intel_dp); if (ret == sizeof(intel_dp->dpcd)) { - if (intel_dp->dpcd[0] >= 0x11) - dev_priv->no_aux_handshake = intel_dp->dpcd[3] & + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) + dev_priv->no_aux_handshake = + intel_dp->dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING; } else { /* if this fails, presume the device is a ghost */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index c0e0ee63fbf..39ac2b634ae 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -165,7 +165,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n); static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring) { - return intel_wait_ring_buffer(ring, ring->space - 8); + return intel_wait_ring_buffer(ring, ring->size - 8); } int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e8a5ffb0124..15bd0477a3e 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -985,17 +985,19 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav { save->vga_control[0] = RREG32(D1VGA_CONTROL); save->vga_control[1] = RREG32(D2VGA_CONTROL); - save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL); - save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL); - save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL); - save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL); save->vga_render_control = RREG32(VGA_RENDER_CONTROL); save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET); save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { + save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL); + save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL); save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET); save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); + } + if (rdev->num_crtc >= 6) { + save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL); + save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL); save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET); save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); } @@ -1004,35 +1006,45 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav WREG32(VGA_RENDER_CONTROL, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); + } + if (rdev->num_crtc >= 6) { WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); } WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + } + if (rdev->num_crtc >= 6) { WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); } WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + } + if (rdev->num_crtc >= 6) { WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); } WREG32(D1VGA_CONTROL, 0); WREG32(D2VGA_CONTROL, 0); - WREG32(EVERGREEN_D3VGA_CONTROL, 0); - WREG32(EVERGREEN_D4VGA_CONTROL, 0); - WREG32(EVERGREEN_D5VGA_CONTROL, 0); - WREG32(EVERGREEN_D6VGA_CONTROL, 0); + if (rdev->num_crtc >= 4) { + WREG32(EVERGREEN_D3VGA_CONTROL, 0); + WREG32(EVERGREEN_D4VGA_CONTROL, 0); + } + if (rdev->num_crtc >= 6) { + WREG32(EVERGREEN_D5VGA_CONTROL, 0); + WREG32(EVERGREEN_D6VGA_CONTROL, 0); + } } void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save) @@ -1055,7 +1067,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET, (u32)rdev->mc.vram_start); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, upper_32_bits(rdev->mc.vram_start)); WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, @@ -1073,7 +1085,8 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s (u32)rdev->mc.vram_start); WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, (u32)rdev->mc.vram_start); - + } + if (rdev->num_crtc >= 6) { WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, upper_32_bits(rdev->mc.vram_start)); WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, @@ -1101,31 +1114,41 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s /* Restore video state */ WREG32(D1VGA_CONTROL, save->vga_control[0]); WREG32(D2VGA_CONTROL, save->vga_control[1]); - WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]); - WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]); - WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]); - WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]); + if (rdev->num_crtc >= 4) { + WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]); + WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]); + } + if (rdev->num_crtc >= 6) { + WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]); + WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]); + } WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); + } + if (rdev->num_crtc >= 6) { WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); } WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]); WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]); WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]); + } + if (rdev->num_crtc >= 6) { WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]); WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]); } WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + } + if (rdev->num_crtc >= 6) { WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); } @@ -1977,7 +2000,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) gb_backend_map = 0x66442200; break; case CHIP_JUNIPER: - gb_backend_map = 0x00006420; + gb_backend_map = 0x00002200; break; default: gb_backend_map = @@ -2417,18 +2440,22 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev) WREG32(GRBM_INT_CNTL, 0); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + } + if (rdev->num_crtc >= 6) { WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); } WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + } + if (rdev->num_crtc >= 6) { WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); } @@ -2547,19 +2574,25 @@ int evergreen_irq_set(struct radeon_device *rdev) WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); - if (!(rdev->flags & RADEON_IS_IGP)) { + if (rdev->num_crtc >= 4) { WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3); WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4); + } + if (rdev->num_crtc >= 6) { WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5); WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6); } WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1); WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6); + if (rdev->num_crtc >= 4) { + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4); + } + if (rdev->num_crtc >= 6) { + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6); + } WREG32(DC_HPD1_INT_CONTROL, hpd1); WREG32(DC_HPD2_INT_CONTROL, hpd2); @@ -2583,53 +2616,57 @@ static inline void evergreen_irq_ack(struct radeon_device *rdev) rdev->irq.stat_regs.evergreen.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5); rdev->irq.stat_regs.evergreen.d1grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET); rdev->irq.stat_regs.evergreen.d2grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET); - rdev->irq.stat_regs.evergreen.d3grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET); - rdev->irq.stat_regs.evergreen.d4grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET); - rdev->irq.stat_regs.evergreen.d5grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET); - rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET); + if (rdev->num_crtc >= 4) { + rdev->irq.stat_regs.evergreen.d3grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET); + rdev->irq.stat_regs.evergreen.d4grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET); + } + if (rdev->num_crtc >= 6) { + rdev->irq.stat_regs.evergreen.d5grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET); + rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET); + } if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED) WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED) WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); - if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED) - WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); - if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED) - WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); - if (rdev->irq.stat_regs.evergreen.d5grph_int & GRPH_PFLIP_INT_OCCURRED) - WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); - if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED) - WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK); if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK); - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK); if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK); - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK); - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK); - - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK); - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK); - - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK); - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK); - - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK); - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK); + if (rdev->num_crtc >= 4) { + if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK); + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK); + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK); + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK); + } + + if (rdev->num_crtc >= 6) { + if (rdev->irq.stat_regs.evergreen.d5grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK); + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK); + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK); + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK); + } if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { tmp = RREG32(DC_HPD1_INT_CONTROL); @@ -3237,6 +3274,7 @@ void evergreen_fini(struct radeon_device *rdev) r700_cp_fini(rdev); r600_irq_fini(rdev); radeon_wb_fini(rdev); + radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); evergreen_pcie_gart_fini(rdev); radeon_gem_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index 57f3bc17b87..2eb251858e7 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -252,7 +252,7 @@ draw_auto(struct radeon_device *rdev) } -/* emits 36 */ +/* emits 39 */ static void set_default_state(struct radeon_device *rdev) { @@ -531,6 +531,11 @@ set_default_state(struct radeon_device *rdev) radeon_ring_write(rdev, (SQ_DYN_GPR_CNTL_PS_FLUSH_REQ - PACKET3_SET_CONFIG_REG_START) >> 2); radeon_ring_write(rdev, 0); + /* setup LDS */ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, (SQ_LDS_RESOURCE_MGMT - PACKET3_SET_CONFIG_REG_START) >> 2); + radeon_ring_write(rdev, 0x10001000); + /* SQ config */ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 11)); radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_START) >> 2); @@ -773,7 +778,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes) /* calculate number of loops correctly */ ring_size = num_loops * dwords_per_loop; /* set default + shaders */ - ring_size += 52; /* shaders + def state */ + ring_size += 55; /* shaders + def state */ ring_size += 10; /* fence emit for VB IB */ ring_size += 5; /* done copy */ ring_size += 10; /* fence emit for done copy */ diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 1636e344982..b7b2714f0b3 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -466,7 +466,7 @@ #define IH_RB_WPTR_ADDR_LO 0x3e14 #define IH_CNTL 0x3e18 # define ENABLE_INTR (1 << 0) -# define IH_MC_SWAP(x) ((x) << 2) +# define IH_MC_SWAP(x) ((x) << 1) # define IH_MC_SWAP_NONE 0 # define IH_MC_SWAP_16BIT 1 # define IH_MC_SWAP_32BIT 2 @@ -547,7 +547,7 @@ # define LB_D5_VBLANK_INTERRUPT (1 << 3) # define DC_HPD5_INTERRUPT (1 << 17) # define DC_HPD5_RX_INTERRUPT (1 << 18) -#define DISP_INTERRUPT_STATUS_CONTINUE5 0x6050 +#define DISP_INTERRUPT_STATUS_CONTINUE5 0x6150 # define LB_D6_VLINE_INTERRUPT (1 << 2) # define LB_D6_VBLANK_INTERRUPT (1 << 3) # define DC_HPD6_INTERRUPT (1 << 17) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 16caafeadf5..559dbd41290 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1581,6 +1581,7 @@ void cayman_fini(struct radeon_device *rdev) cayman_cp_fini(rdev); r600_irq_fini(rdev); radeon_wb_fini(rdev); + radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); cayman_pcie_gart_fini(rdev); radeon_gem_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index f79d2ccb675..bc54b26cb32 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2628,6 +2628,7 @@ void r600_fini(struct radeon_device *rdev) r600_cp_fini(rdev); r600_irq_fini(rdev); radeon_wb_fini(rdev); + radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); r600_pcie_gart_fini(rdev); radeon_agp_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index f140a0d5cb5..0245ae6c204 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -536,7 +536,7 @@ #define IH_RB_WPTR_ADDR_LO 0x3e14 #define IH_CNTL 0x3e18 # define ENABLE_INTR (1 << 0) -# define IH_MC_SWAP(x) ((x) << 2) +# define IH_MC_SWAP(x) ((x) << 1) # define IH_MC_SWAP_NONE 0 # define IH_MC_SWAP_16BIT 1 # define IH_MC_SWAP_32BIT 2 diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 3fc5fa1aefd..229a20f10e2 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -331,7 +331,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev) seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1); viph_control = RREG32(RADEON_VIPH_CONTROL); - bus_cntl = RREG32(RADEON_BUS_CNTL); + bus_cntl = RREG32(RV370_BUS_CNTL); d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); @@ -350,7 +350,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev) WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); /* enable the rom */ - WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM)); /* Disable VGA mode */ WREG32(AVIVO_D1VGA_CONTROL, @@ -367,7 +367,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev) /* restore regs */ WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1); WREG32(RADEON_VIPH_CONTROL, viph_control); - WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(RV370_BUS_CNTL, bus_cntl); WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); @@ -390,7 +390,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev) seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1); viph_control = RREG32(RADEON_VIPH_CONTROL); - bus_cntl = RREG32(RADEON_BUS_CNTL); + if (rdev->flags & RADEON_IS_PCIE) + bus_cntl = RREG32(RV370_BUS_CNTL); + else + bus_cntl = RREG32(RADEON_BUS_CNTL); crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL); crtc2_gen_cntl = 0; crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); @@ -412,7 +415,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev) WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); /* enable the rom */ - WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + if (rdev->flags & RADEON_IS_PCIE) + WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM)); + else + WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); /* Turn off mem requests and CRTC for both controllers */ WREG32(RADEON_CRTC_GEN_CNTL, @@ -439,7 +445,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev) /* restore regs */ WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1); WREG32(RADEON_VIPH_CONTROL, viph_control); - WREG32(RADEON_BUS_CNTL, bus_cntl); + if (rdev->flags & RADEON_IS_PCIE) + WREG32(RV370_BUS_CNTL, bus_cntl); + else + WREG32(RADEON_BUS_CNTL, bus_cntl); WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); if (!(rdev->flags & RADEON_SINGLE_CRTC)) { WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index cbfca3a24fd..9792d4ffdc8 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -52,6 +52,12 @@ void radeon_connector_hotplug(struct drm_connector *connector) struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); + /* bail if the connector does not have hpd pin, e.g., + * VGA, TV, etc. + */ + if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) + return; + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); /* powering up/down the eDP panel generates hpd events which diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index ec93a75369e..bc44a3d35ec 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -300,6 +300,8 @@ # define RADEON_BUS_READ_BURST (1 << 30) #define RADEON_BUS_CNTL1 0x0034 # define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4) +#define RV370_BUS_CNTL 0x004c +# define RV370_BUS_BIOS_DIS_ROM (1 << 2) /* rv370/rv380, rv410, r423/r430/r480, r5xx */ #define RADEON_MSI_REARM_EN 0x0160 # define RV370_MSI_REARM_EN (1 << 0) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 6e3b11e5abb..1f5850e473c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -426,7 +426,7 @@ int rs600_gart_init(struct radeon_device *rdev) return radeon_gart_table_vram_alloc(rdev); } -int rs600_gart_enable(struct radeon_device *rdev) +static int rs600_gart_enable(struct radeon_device *rdev) { u32 tmp; int r, i; @@ -440,8 +440,8 @@ int rs600_gart_enable(struct radeon_device *rdev) return r; radeon_gart_restore(rdev); /* Enable bus master */ - tmp = RREG32(R_00004C_BUS_CNTL) & C_00004C_BUS_MASTER_DIS; - WREG32(R_00004C_BUS_CNTL, tmp); + tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS; + WREG32(RADEON_BUS_CNTL, tmp); /* FIXME: setup default page */ WREG32_MC(R_000100_MC_PT0_CNTL, (S_000100_EFFECTIVE_L2_CACHE_SIZE(6) | diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 8bb347d23ca..4de51891aa6 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1368,6 +1368,7 @@ void rv770_fini(struct radeon_device *rdev) r700_cp_fini(rdev); r600_irq_fini(rdev); radeon_wb_fini(rdev); + radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); rv770_pcie_gart_fini(rdev); rv770_vram_scratch_fini(rdev); diff --git a/drivers/hwmon/adm1275.c b/drivers/hwmon/adm1275.c index b9b7caf4a1d..8bc1bd66372 100644 --- a/drivers/hwmon/adm1275.c +++ b/drivers/hwmon/adm1275.c @@ -53,23 +53,23 @@ static int adm1275_probe(struct i2c_client *client, info->direct[PSC_VOLTAGE_IN] = true; info->direct[PSC_VOLTAGE_OUT] = true; info->direct[PSC_CURRENT_OUT] = true; - info->m[PSC_CURRENT_OUT] = 800; + info->m[PSC_CURRENT_OUT] = 807; info->b[PSC_CURRENT_OUT] = 20475; info->R[PSC_CURRENT_OUT] = -1; info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; if (config & ADM1275_VRANGE) { - info->m[PSC_VOLTAGE_IN] = 19045; + info->m[PSC_VOLTAGE_IN] = 19199; info->b[PSC_VOLTAGE_IN] = 0; info->R[PSC_VOLTAGE_IN] = -2; - info->m[PSC_VOLTAGE_OUT] = 19045; + info->m[PSC_VOLTAGE_OUT] = 19199; info->b[PSC_VOLTAGE_OUT] = 0; info->R[PSC_VOLTAGE_OUT] = -2; } else { - info->m[PSC_VOLTAGE_IN] = 6666; + info->m[PSC_VOLTAGE_IN] = 6720; info->b[PSC_VOLTAGE_IN] = 0; info->R[PSC_VOLTAGE_IN] = -1; - info->m[PSC_VOLTAGE_OUT] = 6666; + info->m[PSC_VOLTAGE_OUT] = 6720; info->b[PSC_VOLTAGE_OUT] = 0; info->R[PSC_VOLTAGE_OUT] = -1; } diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index dcb78a7a804..00e98517f94 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -674,6 +674,7 @@ static int atk_debugfs_gitm_get(void *p, u64 *val) else err = -EIO; + ACPI_FREE(ret); return err; } diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index bb6405b9200..5f524775043 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -1538,7 +1538,7 @@ static struct attribute *it87_attributes_label[] = { }; static const struct attribute_group it87_group_label = { - .attrs = it87_attributes_vid, + .attrs = it87_attributes_label, }; /* SuperIO detection - will change isa_address if a chip is found */ diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 1a6dfb6df1e..d3b464b74ce 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -98,11 +98,16 @@ struct lm95241_data { }; /* Conversions */ -static int TempFromReg(u8 val_h, u8 val_l) +static int temp_from_reg_signed(u8 val_h, u8 val_l) { - if (val_h & 0x80) - return val_h - 0x100; - return val_h * 1000 + val_l * 1000 / 256; + s16 val_hl = (val_h << 8) | val_l; + return val_hl * 1000 / 256; +} + +static int temp_from_reg_unsigned(u8 val_h, u8 val_l) +{ + u16 val_hl = (val_h << 8) | val_l; + return val_hl * 1000 / 256; } static struct lm95241_data *lm95241_update_device(struct device *dev) @@ -135,10 +140,13 @@ static ssize_t show_input(struct device *dev, struct device_attribute *attr, char *buf) { struct lm95241_data *data = lm95241_update_device(dev); + int index = to_sensor_dev_attr(attr)->index; return snprintf(buf, PAGE_SIZE - 1, "%d\n", - TempFromReg(data->temp[to_sensor_dev_attr(attr)->index], - data->temp[to_sensor_dev_attr(attr)->index + 1])); + index == 0 || (data->config & (1 << (index / 2))) ? + temp_from_reg_signed(data->temp[index], data->temp[index + 1]) : + temp_from_reg_unsigned(data->temp[index], + data->temp[index + 1])); } static ssize_t show_type(struct device *dev, struct device_attribute *attr, @@ -339,7 +347,7 @@ static int lm95241_detect(struct i2c_client *new_client, if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID) == MANUFACTURER_ID) && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID) - >= DEFAULT_REVISION)) { + == DEFAULT_REVISION)) { name = DEVNAME; } else { dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n", diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index 12a54aa2977..14335bbc9bd 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -40,6 +40,8 @@ struct max1111_data { struct spi_transfer xfer[2]; uint8_t *tx_buf; uint8_t *rx_buf; + struct mutex drvdata_lock; + /* protect msg, xfer and buffers from multiple access */ }; static int max1111_read(struct device *dev, int channel) @@ -48,6 +50,9 @@ static int max1111_read(struct device *dev, int channel) uint8_t v1, v2; int err; + /* writing to drvdata struct is not thread safe, wait on mutex */ + mutex_lock(&data->drvdata_lock); + data->tx_buf[0] = (channel << MAX1111_CTRL_SEL_SH) | MAX1111_CTRL_PD0 | MAX1111_CTRL_PD1 | MAX1111_CTRL_SGL | MAX1111_CTRL_UNI | MAX1111_CTRL_STR; @@ -55,12 +60,15 @@ static int max1111_read(struct device *dev, int channel) err = spi_sync(data->spi, &data->msg); if (err < 0) { dev_err(dev, "spi_sync failed with %d\n", err); + mutex_unlock(&data->drvdata_lock); return err; } v1 = data->rx_buf[0]; v2 = data->rx_buf[1]; + mutex_unlock(&data->drvdata_lock); + if ((v1 & 0xc0) || (v2 & 0x3f)) return -EINVAL; @@ -176,6 +184,8 @@ static int __devinit max1111_probe(struct spi_device *spi) if (err) goto err_free_data; + mutex_init(&data->drvdata_lock); + data->spi = spi; spi_set_drvdata(spi, data); @@ -213,6 +223,7 @@ static int __devexit max1111_remove(struct spi_device *spi) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group); + mutex_destroy(&data->drvdata_lock); kfree(data->rx_buf); kfree(data->tx_buf); kfree(data); diff --git a/drivers/hwmon/pmbus.c b/drivers/hwmon/pmbus.c index 931d940923a..9b1f0c37ef7 100644 --- a/drivers/hwmon/pmbus.c +++ b/drivers/hwmon/pmbus.c @@ -59,16 +59,17 @@ static void pmbus_find_sensor_groups(struct i2c_client *client, if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34)) info->func[0] |= PMBUS_HAVE_STATUS_FAN34; } - if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) { + if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) info->func[0] |= PMBUS_HAVE_TEMP; - if (pmbus_check_byte_register(client, 0, - PMBUS_STATUS_TEMPERATURE)) - info->func[0] |= PMBUS_HAVE_STATUS_TEMP; - } if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2)) info->func[0] |= PMBUS_HAVE_TEMP2; if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3)) info->func[0] |= PMBUS_HAVE_TEMP3; + if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_TEMP3) + && pmbus_check_byte_register(client, 0, + PMBUS_STATUS_TEMPERATURE)) + info->func[0] |= PMBUS_HAVE_STATUS_TEMP; /* Sensors detected on all pages */ for (page = 0; page < info->pages; page++) { diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c index 744672c1f26..8e31a8e2c74 100644 --- a/drivers/hwmon/pmbus_core.c +++ b/drivers/hwmon/pmbus_core.c @@ -362,8 +362,8 @@ static struct pmbus_data *pmbus_update_device(struct device *dev) * Convert linear sensor values to milli- or micro-units * depending on sensor type. */ -static int pmbus_reg2data_linear(struct pmbus_data *data, - struct pmbus_sensor *sensor) +static long pmbus_reg2data_linear(struct pmbus_data *data, + struct pmbus_sensor *sensor) { s16 exponent; s32 mantissa; @@ -397,15 +397,15 @@ static int pmbus_reg2data_linear(struct pmbus_data *data, else val >>= -exponent; - return (int)val; + return val; } /* * Convert direct sensor values to milli- or micro-units * depending on sensor type. */ -static int pmbus_reg2data_direct(struct pmbus_data *data, - struct pmbus_sensor *sensor) +static long pmbus_reg2data_direct(struct pmbus_data *data, + struct pmbus_sensor *sensor) { long val = (s16) sensor->data; long m, b, R; @@ -440,12 +440,12 @@ static int pmbus_reg2data_direct(struct pmbus_data *data, R++; } - return (int)((val - b) / m); + return (val - b) / m; } -static int pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) +static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) { - int val; + long val; if (data->info->direct[sensor->class]) val = pmbus_reg2data_direct(data, sensor); @@ -619,7 +619,7 @@ static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val) if (!s1 && !s2) *val = !!regval; else { - int v1, v2; + long v1, v2; struct pmbus_sensor *sensor1, *sensor2; sensor1 = &data->sensors[s1]; @@ -661,7 +661,7 @@ static ssize_t pmbus_show_sensor(struct device *dev, if (sensor->data < 0) return sensor->data; - return snprintf(buf, PAGE_SIZE, "%d\n", pmbus_reg2data(data, sensor)); + return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor)); } static ssize_t pmbus_set_sensor(struct device *dev, diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 52b545a795f..cbc98aea5b0 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -193,7 +193,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, return; } if (twi_int_status & MCOMP) { - if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + if ((read_MASTER_CTL(iface) & MEN) == 0 && + (iface->cur_mode == TWI_I2C_MODE_REPEAT || + iface->cur_mode == TWI_I2C_MODE_COMBINED)) { + iface->result = -1; + write_INT_MASK(iface, 0); + write_MASTER_CTL(iface, 0); + } else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { if (iface->readNum == 0) { /* set the read number to 1 and ask for manual * stop in block combine mode diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 6c00c107ebf..f84a63c6dd9 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -248,12 +248,12 @@ static inline int is_msgend(struct s3c24xx_i2c *i2c) return i2c->msg_ptr >= i2c->msg->len; } -/* i2s_s3c_irq_nextbyte +/* i2c_s3c_irq_nextbyte * * process an interrupt and work out what to do */ -static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) +static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) { unsigned long tmp; unsigned char byte; @@ -264,7 +264,6 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) case STATE_IDLE: dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__); goto out; - break; case STATE_STOP: dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__); @@ -444,7 +443,7 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id) /* pretty much this leaves us with the fact that we've * transmitted or received whatever byte we last sent */ - i2s_s3c_irq_nextbyte(i2c, status); + i2c_s3c_irq_nextbyte(i2c, status); out: return IRQ_HANDLED; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 4d9319665e3..fb3b4f8f815 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -40,8 +40,10 @@ #define I2C_CNFG_NEW_MASTER_FSM (1<<11) #define I2C_STATUS 0x01C #define I2C_SL_CNFG 0x020 +#define I2C_SL_CNFG_NACK (1<<1) #define I2C_SL_CNFG_NEWSL (1<<2) #define I2C_SL_ADDR1 0x02c +#define I2C_SL_ADDR2 0x030 #define I2C_TX_FIFO 0x050 #define I2C_RX_FIFO 0x054 #define I2C_PACKET_TRANSFER_STATUS 0x058 @@ -337,7 +339,11 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (!i2c_dev->is_dvc) { u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); - i2c_writel(i2c_dev, sl_cfg | I2C_SL_CNFG_NEWSL, I2C_SL_CNFG); + sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL; + i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG); + i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1); + i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2); + } val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 40b02ae96f8..6229c3e8e78 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -520,7 +520,8 @@ static void pmic8xxx_kp_close(struct input_dev *dev) */ static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev) { - const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev); + const struct pm8xxx_keypad_platform_data *pdata = + dev_get_platdata(&pdev->dev); const struct matrix_keymap_data *keymap_data; struct pmic8xxx_kp *kp; int rc; diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index 97e07e786e4..b3cfb9c71e6 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -90,7 +90,8 @@ static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev) unsigned int delay; u8 pon_cntl; struct pmic8xxx_pwrkey *pwrkey; - const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev); + const struct pm8xxx_pwrkey_platform_data *pdata = + dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "power key platform data not supplied\n"); diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index d8d3a1e910a..a2c874623e3 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -88,7 +88,7 @@ static const struct pca9532_chip_info pca9532_chip_info_tbl[] = { static struct i2c_driver pca9532_driver = { .driver = { - .name = "pca953x", + .name = "leds-pca953x", }, .probe = pca9532_probe, .remove = pca9532_remove, diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 98278041d75..5b6b451d469 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1988,6 +1988,14 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) goto err0; + + /* If we took control of the bus, we need to force + reinitialization. This is because many ts_bus_ctrl() + functions strobe the RESET pin on the demod, and if the + frontend thread already exists then the dvb_init() routine + won't get called (which is what usually does initial + register configuration). */ + fepriv->reinitialise = 1; } if ((ret = dvb_generic_open (inode, file)) < 0) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index e4c97fd6f05..52798a111e1 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -168,7 +168,7 @@ config RADIO_MAXIRADIO config RADIO_MIROPCM20 tristate "miroSOUND PCM20 radio" - depends on ISA && VIDEO_V4L2 && SND + depends on ISA && ISA_DMA_API && VIDEO_V4L2 && SND select SND_ISA select SND_MIRO ---help--- @@ -201,7 +201,7 @@ config RADIO_SF16FMI config RADIO_SF16FMR2 tristate "SF16FMR2 Radio" - depends on ISA && VIDEO_V4L2 + depends on ISA && VIDEO_V4L2 && SND ---help--- Choose Y here if you have one of these FM radio cards. diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index deca2e06ff2..c9f4a8e65dc 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -1033,7 +1033,7 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev, char ps_name[MAX_RDS_PS_NAME + 1]; len = control->size - 1; - if (len > MAX_RDS_PS_NAME) { + if (len < 0 || len > MAX_RDS_PS_NAME) { rval = -ERANGE; goto exit; } @@ -1057,7 +1057,7 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev, char radio_text[MAX_RDS_RADIO_TEXT + 1]; len = control->size - 1; - if (len > MAX_RDS_RADIO_TEXT) { + if (len < 0 || len > MAX_RDS_RADIO_TEXT) { rval = -ERANGE; goto exit; } diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 8fa539dde1b..7f7079b12f2 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -597,12 +597,17 @@ static void __devexit fintek_remove(struct pnp_dev *pdev) static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state) { struct fintek_dev *fintek = pnp_get_drvdata(pdev); + unsigned long flags; fit_dbg("%s called", __func__); + spin_lock_irqsave(&fintek->fintek_lock, flags); + /* disable all CIR interrupts */ fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); + spin_unlock_irqrestore(&fintek->fintek_lock, flags); + fintek_config_mode_enable(fintek); /* disable cir logical dev */ diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 3f3c7071626..6bc35eeb653 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -307,6 +307,14 @@ static const struct { /* 0xffdc iMON MCE VFD */ { 0x00010000ffffffeell, KEY_VOLUMEUP }, { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, + { 0x00000001ffffffeell, KEY_MUTE }, + { 0x0000000fffffffeell, KEY_MEDIA }, + { 0x00000012ffffffeell, KEY_UP }, + { 0x00000013ffffffeell, KEY_DOWN }, + { 0x00000014ffffffeell, KEY_LEFT }, + { 0x00000015ffffffeell, KEY_RIGHT }, + { 0x00000016ffffffeell, KEY_ENTER }, + { 0x00000017ffffffeell, KEY_ESC }, /* iMON Knob values */ { 0x000100ffffffffeell, KEY_VOLUMEUP }, { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, @@ -1582,16 +1590,16 @@ static void imon_incoming_packet(struct imon_context *ictx, /* Only panel type events left to process now */ spin_lock_irqsave(&ictx->kc_lock, flags); + do_gettimeofday(&t); /* KEY_MUTE repeats from knob need to be suppressed */ if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) { - do_gettimeofday(&t); msec = tv2int(&t, &prev_time); - prev_time = t; if (msec < ictx->idev->rep[REP_DELAY]) { spin_unlock_irqrestore(&ictx->kc_lock, flags); return; } } + prev_time = t; kc = ictx->kc; spin_unlock_irqrestore(&ictx->kc_lock, flags); @@ -1603,7 +1611,9 @@ static void imon_incoming_packet(struct imon_context *ictx, input_report_key(ictx->idev, kc, 0); input_sync(ictx->idev); + spin_lock_irqsave(&ictx->kc_lock, flags); ictx->last_keycode = kc; + spin_unlock_irqrestore(&ictx->kc_lock, flags); return; @@ -1740,6 +1750,8 @@ static void imon_get_ffdc_type(struct imon_context *ictx) detected_display_type = IMON_DISPLAY_TYPE_VFD; break; /* iMON VFD, MCE IR */ + case 0x46: + case 0x7e: case 0x9e: dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; @@ -1755,6 +1767,9 @@ static void imon_get_ffdc_type(struct imon_context *ictx) dev_info(ictx->dev, "Unknown 0xffdc device, " "defaulting to VFD and iMON IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; + /* We don't know which one it is, allow user to set the + * RC6 one from userspace if OTHER wasn't correct. */ + allowed_protos |= RC_TYPE_RC6; break; } diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 11c19d8d0ee..423ed45d6c5 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -114,18 +114,20 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type) s64 delta; /* ns */ DEFINE_IR_RAW_EVENT(ev); int rc = 0; + int delay; if (!dev->raw) return -EINVAL; now = ktime_get(); delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); + delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]); /* Check for a long duration since last event or if we're * being called for the first time, note that delta can't * possibly be negative. */ - if (delta > IR_MAX_DURATION || !dev->raw->last_type) + if (delta > delay || !dev->raw->last_type) type |= IR_START_EVENT; else ev.duration = delta; diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index e716b931cf7..ecd3d028076 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1347,6 +1347,7 @@ static const struct ite_dev_params ite_dev_descs[] = { { /* 0: ITE8704 */ .model = "ITE8704 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, + .io_rsrc_no = 0, .hw_tx_capable = true, .sample_period = (u32) (1000000000ULL / 115200), .tx_carrier_freq = 38000, @@ -1371,6 +1372,7 @@ static const struct ite_dev_params ite_dev_descs[] = { { /* 1: ITE8713 */ .model = "ITE8713 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, + .io_rsrc_no = 0, .hw_tx_capable = true, .sample_period = (u32) (1000000000ULL / 115200), .tx_carrier_freq = 38000, @@ -1395,6 +1397,7 @@ static const struct ite_dev_params ite_dev_descs[] = { { /* 2: ITE8708 */ .model = "ITE8708 CIR transceiver", .io_region_size = IT8708_IOREG_LENGTH, + .io_rsrc_no = 0, .hw_tx_capable = true, .sample_period = (u32) (1000000000ULL / 115200), .tx_carrier_freq = 38000, @@ -1420,6 +1423,7 @@ static const struct ite_dev_params ite_dev_descs[] = { { /* 3: ITE8709 */ .model = "ITE8709 CIR transceiver", .io_region_size = IT8709_IOREG_LENGTH, + .io_rsrc_no = 2, .hw_tx_capable = true, .sample_period = (u32) (1000000000ULL / 115200), .tx_carrier_freq = 38000, @@ -1461,6 +1465,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id struct rc_dev *rdev = NULL; int ret = -ENOMEM; int model_no; + int io_rsrc_no; ite_dbg("%s called", __func__); @@ -1490,10 +1495,11 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* get the description for the device */ dev_desc = &ite_dev_descs[model_no]; + io_rsrc_no = dev_desc->io_rsrc_no; /* validate pnp resources */ - if (!pnp_port_valid(pdev, 0) || - pnp_port_len(pdev, 0) != dev_desc->io_region_size) { + if (!pnp_port_valid(pdev, io_rsrc_no) || + pnp_port_len(pdev, io_rsrc_no) != dev_desc->io_region_size) { dev_err(&pdev->dev, "IR PNP Port not valid!\n"); goto failure; } @@ -1504,7 +1510,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id } /* store resource values */ - itdev->cir_addr = pnp_port_start(pdev, 0); + itdev->cir_addr = pnp_port_start(pdev, io_rsrc_no); itdev->cir_irq = pnp_irq(pdev, 0); /* initialize spinlocks */ diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h index 16a19f5fd71..aa899a0b975 100644 --- a/drivers/media/rc/ite-cir.h +++ b/drivers/media/rc/ite-cir.h @@ -57,6 +57,9 @@ struct ite_dev_params { /* size of the I/O region */ int io_region_size; + /* IR pnp I/O resource number */ + int io_rsrc_no; + /* true if the hardware supports transmission */ bool hw_tx_capable; diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index bb10ffe086b..8d558ae6345 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -15,43 +15,39 @@ /* Pinnacle PCTV HD 800i mini remote */ static struct rc_map_table pinnacle_pctv_hd[] = { - - { 0x0f, KEY_1 }, - { 0x15, KEY_2 }, - { 0x10, KEY_3 }, - { 0x18, KEY_4 }, - { 0x1b, KEY_5 }, - { 0x1e, KEY_6 }, - { 0x11, KEY_7 }, - { 0x21, KEY_8 }, - { 0x12, KEY_9 }, - { 0x27, KEY_0 }, - - { 0x24, KEY_ZOOM }, - { 0x2a, KEY_SUBTITLE }, - - { 0x00, KEY_MUTE }, - { 0x01, KEY_ENTER }, /* Pinnacle Logo */ - { 0x39, KEY_POWER }, - - { 0x03, KEY_VOLUMEUP }, - { 0x09, KEY_VOLUMEDOWN }, - { 0x06, KEY_CHANNELUP }, - { 0x0c, KEY_CHANNELDOWN }, - - { 0x2d, KEY_REWIND }, - { 0x30, KEY_PLAYPAUSE }, - { 0x33, KEY_FASTFORWARD }, - { 0x3c, KEY_STOP }, - { 0x36, KEY_RECORD }, - { 0x3f, KEY_EPG }, /* Labeled "?" */ + /* Key codes for the tiny Pinnacle remote*/ + { 0x0700, KEY_MUTE }, + { 0x0701, KEY_MENU }, /* Pinnacle logo */ + { 0x0739, KEY_POWER }, + { 0x0703, KEY_VOLUMEUP }, + { 0x0709, KEY_VOLUMEDOWN }, + { 0x0706, KEY_CHANNELUP }, + { 0x070c, KEY_CHANNELDOWN }, + { 0x070f, KEY_1 }, + { 0x0715, KEY_2 }, + { 0x0710, KEY_3 }, + { 0x0718, KEY_4 }, + { 0x071b, KEY_5 }, + { 0x071e, KEY_6 }, + { 0x0711, KEY_7 }, + { 0x0721, KEY_8 }, + { 0x0712, KEY_9 }, + { 0x0727, KEY_0 }, + { 0x0724, KEY_ZOOM }, /* 'Square' key */ + { 0x072a, KEY_SUBTITLE }, /* 'T' key */ + { 0x072d, KEY_REWIND }, + { 0x0730, KEY_PLAYPAUSE }, + { 0x0733, KEY_FASTFORWARD }, + { 0x0736, KEY_RECORD }, + { 0x073c, KEY_STOP }, + { 0x073f, KEY_HELP }, /* '?' key */ }; static struct rc_map_list pinnacle_pctv_hd_map = { .map = { .scan = pinnacle_pctv_hd, .size = ARRAY_SIZE(pinnacle_pctv_hd), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .rc_type = RC_TYPE_RC5, .name = RC_MAP_PINNACLE_PCTV_HD, } }; diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index fd237ab120b..27997a9ceb0 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -55,6 +55,8 @@ struct irctl { struct lirc_buffer *buf; unsigned int chunk_size; + struct cdev *cdev; + struct task_struct *task; long jiffies_to_wait; }; @@ -62,7 +64,6 @@ struct irctl { static DEFINE_MUTEX(lirc_dev_lock); static struct irctl *irctls[MAX_IRCTL_DEVICES]; -static struct cdev cdevs[MAX_IRCTL_DEVICES]; /* Only used for sysfs but defined to void otherwise */ static struct class *lirc_class; @@ -167,9 +168,13 @@ static struct file_operations lirc_dev_fops = { static int lirc_cdev_add(struct irctl *ir) { - int retval; + int retval = -ENOMEM; struct lirc_driver *d = &ir->d; - struct cdev *cdev = &cdevs[d->minor]; + struct cdev *cdev; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + goto err_out; if (d->fops) { cdev_init(cdev, d->fops); @@ -180,12 +185,20 @@ static int lirc_cdev_add(struct irctl *ir) } retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); if (retval) - return retval; + goto err_out; retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); - if (retval) + if (retval) { kobject_put(&cdev->kobj); + goto err_out; + } + + ir->cdev = cdev; + + return 0; +err_out: + kfree(cdev); return retval; } @@ -214,7 +227,7 @@ int lirc_register_driver(struct lirc_driver *d) if (MAX_IRCTL_DEVICES <= d->minor) { dev_err(d->dev, "lirc_dev: lirc_register_driver: " "\"minor\" must be between 0 and %d (%d)!\n", - MAX_IRCTL_DEVICES-1, d->minor); + MAX_IRCTL_DEVICES - 1, d->minor); err = -EBADRQC; goto out; } @@ -369,7 +382,7 @@ int lirc_unregister_driver(int minor) if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between " - "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1); + "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES - 1); return -EBADRQC; } @@ -380,7 +393,7 @@ int lirc_unregister_driver(int minor) return -ENOENT; } - cdev = &cdevs[minor]; + cdev = ir->cdev; mutex_lock(&lirc_dev_lock); @@ -410,6 +423,7 @@ int lirc_unregister_driver(int minor) } else { lirc_irctl_cleanup(ir); cdev_del(cdev); + kfree(cdev); kfree(ir); irctls[minor] = NULL; } @@ -453,7 +467,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) goto error; } - cdev = &cdevs[iminor(inode)]; + cdev = ir->cdev; if (try_module_get(cdev->owner)) { ir->open++; retval = ir->d.set_use_inc(ir->d.data); @@ -484,13 +498,15 @@ EXPORT_SYMBOL(lirc_dev_fop_open); int lirc_dev_fop_close(struct inode *inode, struct file *file) { struct irctl *ir = irctls[iminor(inode)]; - struct cdev *cdev = &cdevs[iminor(inode)]; + struct cdev *cdev; if (!ir) { printk(KERN_ERR "%s: called with invalid irctl\n", __func__); return -EINVAL; } + cdev = ir->cdev; + dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); WARN_ON(mutex_lock_killable(&lirc_dev_lock)); @@ -503,6 +519,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) lirc_irctl_cleanup(ir); cdev_del(cdev); irctls[ir->d.minor] = NULL; + kfree(cdev); kfree(ir); } diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index ad927fcaa02..ec972dc2579 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -108,6 +108,12 @@ static int debug = 1; static int debug; #endif +#define mce_dbg(dev, fmt, ...) \ + do { \ + if (debug) \ + dev_info(dev, fmt, ## __VA_ARGS__); \ + } while (0) + /* general constants */ #define SEND_FLAG_IN_PROGRESS 1 #define SEND_FLAG_COMPLETE 2 @@ -246,6 +252,9 @@ static struct usb_device_id mceusb_dev_table[] = { .driver_info = MCE_GEN2_TX_INV }, /* SMK eHome Infrared Transceiver */ { USB_DEVICE(VENDOR_SMK, 0x0338) }, + /* SMK/I-O Data GV-MC7/RCKIT Receiver */ + { USB_DEVICE(VENDOR_SMK, 0x0353), + .driver_info = MCE_GEN2_NO_TX }, /* Tatung eHome Infrared Transceiver */ { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, /* Shuttle eHome Infrared Transceiver */ @@ -549,9 +558,10 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, inout, data1); break; case MCE_CMD_S_TIMEOUT: - /* value is in units of 50us, so x*50/100 or x/2 ms */ + /* value is in units of 50us, so x*50/1000 ms */ dev_info(dev, "%s receive timeout of %d ms\n", - inout, ((data1 << 8) | data2) / 2); + inout, + ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000); break; case MCE_CMD_G_TIMEOUT: dev_info(dev, "Get receive timeout\n"); @@ -606,12 +616,15 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs) if (ir) { len = urb->actual_length; - dev_dbg(ir->dev, "callback called (status=%d len=%d)\n", + mce_dbg(ir->dev, "callback called (status=%d len=%d)\n", urb->status, len); mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true); } + /* the transfer buffer and urb were allocated in mce_request_packet */ + kfree(urb->transfer_buffer); + usb_free_urb(urb); } /* request incoming or send outgoing usb packet - used to initialize remote */ @@ -655,17 +668,17 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, return; } - dev_dbg(dev, "receive request called (size=%#x)\n", size); + mce_dbg(dev, "receive request called (size=%#x)\n", size); async_urb->transfer_buffer_length = size; async_urb->dev = ir->usbdev; res = usb_submit_urb(async_urb, GFP_ATOMIC); if (res) { - dev_dbg(dev, "receive request FAILED! (res=%d)\n", res); + mce_dbg(dev, "receive request FAILED! (res=%d)\n", res); return; } - dev_dbg(dev, "receive request complete (res=%d)\n", res); + mce_dbg(dev, "receive request complete (res=%d)\n", res); } static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) @@ -673,9 +686,9 @@ static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) mce_request_packet(ir, data, size, MCEUSB_TX); } -static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) +static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size) { - mce_request_packet(ir, data, size, MCEUSB_RX); + mce_request_packet(ir, NULL, size, MCEUSB_RX); } /* Send data out the IR blaster port(s) */ @@ -794,7 +807,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) ir->carrier = carrier; cmdbuf[2] = MCE_CMD_SIG_END; cmdbuf[3] = MCE_IRDATA_TRAILER; - dev_dbg(ir->dev, "%s: disabling carrier " + mce_dbg(ir->dev, "%s: disabling carrier " "modulation\n", __func__); mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); return carrier; @@ -806,7 +819,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) ir->carrier = carrier; cmdbuf[2] = prescaler; cmdbuf[3] = divisor; - dev_dbg(ir->dev, "%s: requesting %u HZ " + mce_dbg(ir->dev, "%s: requesting %u HZ " "carrier\n", __func__, carrier); /* Transmit new carrier to mce device */ @@ -835,7 +848,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) switch (ir->buf_in[index]) { /* 2-byte return value commands */ case MCE_CMD_S_TIMEOUT: - ir->rc->timeout = US_TO_NS((hi << 8 | lo) / 2); + ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT); break; /* 1-byte return value commands */ @@ -879,7 +892,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) * US_TO_NS(MCE_TIME_UNIT); - dev_dbg(ir->dev, "Storing %s with duration %d\n", + mce_dbg(ir->dev, "Storing %s with duration %d\n", rawir.pulse ? "pulse" : "space", rawir.duration); @@ -911,7 +924,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) if (ir->parser_state != CMD_HEADER && !ir->rem) ir->parser_state = CMD_HEADER; } - dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n"); + mce_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n"); ir_raw_event_handle(ir->rc); } @@ -933,7 +946,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { ir->send_flags = SEND_FLAG_COMPLETE; - dev_dbg(ir->dev, "setup answer received %d bytes\n", + mce_dbg(ir->dev, "setup answer received %d bytes\n", buf_len); } @@ -951,7 +964,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) case -EPIPE: default: - dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status); + mce_dbg(ir->dev, "Error: urb status = %d\n", urb->status); break; } @@ -961,7 +974,6 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) static void mceusb_gen1_init(struct mceusb_dev *ir) { int ret; - int maxp = ir->len_in; struct device *dev = ir->dev; char *data; @@ -978,8 +990,8 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, data, USB_CTRL_MSG_SZ, HZ * 3); - dev_dbg(dev, "%s - ret = %d\n", __func__, ret); - dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", + mce_dbg(dev, "%s - ret = %d\n", __func__, ret); + mce_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", __func__, data[0], data[1]); /* set feature: bit rate 38400 bps */ @@ -987,71 +999,56 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, 0xc04e, 0x0000, NULL, 0, HZ * 3); - dev_dbg(dev, "%s - ret = %d\n", __func__, ret); + mce_dbg(dev, "%s - ret = %d\n", __func__, ret); /* bRequest 4: set char length to 8 bits */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), 4, USB_TYPE_VENDOR, 0x0808, 0x0000, NULL, 0, HZ * 3); - dev_dbg(dev, "%s - retB = %d\n", __func__, ret); + mce_dbg(dev, "%s - retB = %d\n", __func__, ret); /* bRequest 2: set handshaking to use DTR/DSR */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), 2, USB_TYPE_VENDOR, 0x0000, 0x0100, NULL, 0, HZ * 3); - dev_dbg(dev, "%s - retC = %d\n", __func__, ret); + mce_dbg(dev, "%s - retC = %d\n", __func__, ret); /* device reset */ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); - mce_sync_in(ir, NULL, maxp); /* get hw/sw revision? */ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); - mce_sync_in(ir, NULL, maxp); kfree(data); }; static void mceusb_gen2_init(struct mceusb_dev *ir) { - int maxp = ir->len_in; - /* device reset */ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); - mce_sync_in(ir, NULL, maxp); /* get hw/sw revision? */ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); - mce_sync_in(ir, NULL, maxp); /* unknown what the next two actually return... */ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); - mce_sync_in(ir, NULL, maxp); mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); - mce_sync_in(ir, NULL, maxp); } static void mceusb_get_parameters(struct mceusb_dev *ir) { - int maxp = ir->len_in; - /* get the carrier and frequency */ mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); - mce_sync_in(ir, NULL, maxp); - if (!ir->flags.no_tx) { + if (!ir->flags.no_tx) /* get the transmitter bitmask */ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); - mce_sync_in(ir, NULL, maxp); - } /* get receiver timeout value */ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); - mce_sync_in(ir, NULL, maxp); /* get receiver sensor setting */ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); - mce_sync_in(ir, NULL, maxp); } static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) @@ -1082,7 +1079,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->priv = ir; rc->driver_type = RC_DRIVER_IR_RAW; rc->allowed_protos = RC_TYPE_ALL; - rc->timeout = US_TO_NS(1000); + rc->timeout = MS_TO_NS(100); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; rc->s_tx_carrier = mceusb_set_tx_carrier; @@ -1122,7 +1119,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, bool tx_mask_normal; int ir_intfnum; - dev_dbg(&intf->dev, "%s called\n", __func__); + mce_dbg(&intf->dev, "%s called\n", __func__); idesc = intf->cur_altsetting; @@ -1150,7 +1147,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ep_in = ep; ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; ep_in->bInterval = 1; - dev_dbg(&intf->dev, "acceptable inbound endpoint " + mce_dbg(&intf->dev, "acceptable inbound endpoint " "found\n"); } @@ -1165,12 +1162,12 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ep_out = ep; ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; ep_out->bInterval = 1; - dev_dbg(&intf->dev, "acceptable outbound endpoint " + mce_dbg(&intf->dev, "acceptable outbound endpoint " "found\n"); } } if (ep_in == NULL) { - dev_dbg(&intf->dev, "inbound and/or endpoint not found\n"); + mce_dbg(&intf->dev, "inbound and/or endpoint not found\n"); return -ENODEV; } @@ -1215,16 +1212,16 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, if (!ir->rc) goto rc_dev_fail; - /* flush buffers on the device */ - mce_sync_in(ir, NULL, maxp); - mce_sync_in(ir, NULL, maxp); - /* wire up inbound data handler */ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + /* flush buffers on the device */ + mce_dbg(&intf->dev, "Flushing receive buffers\n"); + mce_flush_rx_buffer(ir, maxp); + /* initialize device */ if (ir->flags.microsoft_gen1) mceusb_gen1_init(ir); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index bf3060ea610..ce595f9ab4c 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -991,7 +991,6 @@ static int nvt_open(struct rc_dev *dev) unsigned long flags; spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->in_use = true; nvt_enable_cir(nvt); spin_unlock_irqrestore(&nvt->nvt_lock, flags); @@ -1004,7 +1003,6 @@ static void nvt_close(struct rc_dev *dev) unsigned long flags; spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->in_use = false; nvt_disable_cir(nvt); spin_unlock_irqrestore(&nvt->nvt_lock, flags); } @@ -1112,7 +1110,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) rdev->dev.parent = &pdev->dev; rdev->driver_name = NVT_DRIVER_NAME; rdev->map_name = RC_MAP_RC6_MCE; - rdev->timeout = US_TO_NS(1000); + rdev->timeout = MS_TO_NS(100); /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */ rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD); #if 0 diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index 379795d61ea..1241fc89a36 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -70,7 +70,6 @@ struct nvt_dev { struct ir_raw_event rawir; spinlock_t nvt_lock; - bool in_use; /* for rx */ u8 buf[RX_BUF_LEN]; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f57cd5677ac..3186ac7c2c1 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -522,18 +522,20 @@ EXPORT_SYMBOL_GPL(rc_g_keycode_from_table); /** * ir_do_keyup() - internal function to signal the release of a keypress * @dev: the struct rc_dev descriptor of the device + * @sync: whether or not to call input_sync * * This function is used internally to release a keypress, it must be * called with keylock held. */ -static void ir_do_keyup(struct rc_dev *dev) +static void ir_do_keyup(struct rc_dev *dev, bool sync) { if (!dev->keypressed) return; IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); input_report_key(dev->input_dev, dev->last_keycode, 0); - input_sync(dev->input_dev); + if (sync) + input_sync(dev->input_dev); dev->keypressed = false; } @@ -549,7 +551,7 @@ void rc_keyup(struct rc_dev *dev) unsigned long flags; spin_lock_irqsave(&dev->keylock, flags); - ir_do_keyup(dev); + ir_do_keyup(dev, true); spin_unlock_irqrestore(&dev->keylock, flags); } EXPORT_SYMBOL_GPL(rc_keyup); @@ -578,7 +580,7 @@ static void ir_timer_keyup(unsigned long cookie) */ spin_lock_irqsave(&dev->keylock, flags); if (time_is_before_eq_jiffies(dev->keyup_jiffies)) - ir_do_keyup(dev); + ir_do_keyup(dev, true); spin_unlock_irqrestore(&dev->keylock, flags); } @@ -597,6 +599,7 @@ void rc_repeat(struct rc_dev *dev) spin_lock_irqsave(&dev->keylock, flags); input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); + input_sync(dev->input_dev); if (!dev->keypressed) goto out; @@ -622,29 +625,28 @@ EXPORT_SYMBOL_GPL(rc_repeat); static void ir_do_keydown(struct rc_dev *dev, int scancode, u32 keycode, u8 toggle) { - input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); - - /* Repeat event? */ - if (dev->keypressed && - dev->last_scancode == scancode && - dev->last_toggle == toggle) - return; + bool new_event = !dev->keypressed || + dev->last_scancode != scancode || + dev->last_toggle != toggle; - /* Release old keypress */ - ir_do_keyup(dev); + if (new_event && dev->keypressed) + ir_do_keyup(dev, false); - dev->last_scancode = scancode; - dev->last_toggle = toggle; - dev->last_keycode = keycode; + input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); - if (keycode == KEY_RESERVED) - return; + if (new_event && keycode != KEY_RESERVED) { + /* Register a keypress */ + dev->keypressed = true; + dev->last_scancode = scancode; + dev->last_toggle = toggle; + dev->last_keycode = keycode; + + IR_dprintk(1, "%s: key down event, " + "key 0x%04x, scancode 0x%04x\n", + dev->input_name, keycode, scancode); + input_report_key(dev->input_dev, keycode, 1); + } - /* Register a keypress */ - dev->keypressed = true; - IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n", - dev->input_name, keycode, scancode); - input_report_key(dev->input_dev, dev->last_keycode, 1); input_sync(dev->input_dev); } diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index a97cf2750bd..834a48394bc 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3474,7 +3474,7 @@ static int radio_s_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - bttv_call_all(btv, tuner, g_tuner, t); + bttv_call_all(btv, tuner, s_tuner, t); return 0; } diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 1933d4d11bf..e80134f52ef 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -695,14 +695,10 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) cx18_call_all(cx, tuner, g_tuner, vt); - if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + if (vt->type == V4L2_TUNER_RADIO) strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_RADIO; - } else { + else strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_ANALOG_TV; - } - return 0; } diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 64d9b2136ff..419777a832e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -2060,12 +2060,8 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, goto fail_irq; } - if (!pci_enable_msi(pci_dev)) - err = request_irq(pci_dev->irq, cx23885_irq, - IRQF_DISABLED, dev->name, dev); - else - err = request_irq(pci_dev->irq, cx23885_irq, - IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + err = request_irq(pci_dev->irq, cx23885_irq, + IRQF_SHARED | IRQF_DISABLED, dev->name, dev); if (err < 0) { printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, pci_dev->irq); @@ -2114,7 +2110,6 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev) /* unregister stuff */ free_irq(pci_dev->irq, dev); - pci_disable_msi(pci_dev); cx23885_dev_unregister(dev); v4l2_device_unregister(v4l2_dev); diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index f9e347dae73..120c7d8e089 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1184,14 +1184,10 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) ivtv_call_all(itv, tuner, g_tuner, vt); - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + if (vt->type == V4L2_TUNER_RADIO) strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_RADIO; - } else { + else strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_ANALOG_TV; - } - return 0; } diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h index 10b55c85448..89d09a8914f 100644 --- a/drivers/media/video/m5mols/m5mols.h +++ b/drivers/media/video/m5mols/m5mols.h @@ -2,10 +2,10 @@ * Header for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -106,23 +106,23 @@ struct m5mols_capture { * The each value according to each scenemode is recommended in the documents. */ struct m5mols_scenemode { - u32 metering; - u32 ev_bias; - u32 wb_mode; - u32 wb_preset; - u32 chroma_en; - u32 chroma_lvl; - u32 edge_en; - u32 edge_lvl; - u32 af_range; - u32 fd_mode; - u32 mcc; - u32 light; - u32 flash; - u32 tone; - u32 iso; - u32 capt_mode; - u32 wdr; + u8 metering; + u8 ev_bias; + u8 wb_mode; + u8 wb_preset; + u8 chroma_en; + u8 chroma_lvl; + u8 edge_en; + u8 edge_lvl; + u8 af_range; + u8 fd_mode; + u8 mcc; + u8 light; + u8 flash; + u8 tone; + u8 iso; + u8 capt_mode; + u8 wdr; }; /** @@ -154,7 +154,6 @@ struct m5mols_version { u8 str[VERSION_STRING_SIZE]; u8 af; }; -#define VERSION_SIZE sizeof(struct m5mols_version) /** * struct m5mols_info - M-5MOLS driver data structure @@ -216,9 +215,9 @@ struct m5mols_info { bool lock_ae; bool lock_awb; u8 resolution; - u32 interrupt; - u32 mode; - u32 mode_save; + u8 interrupt; + u8 mode; + u8 mode_save; int (*set_power)(struct device *dev, int on); }; @@ -256,9 +255,11 @@ struct m5mols_info { * +-------+---+----------+-----+------+------+------+------+ * - d[0..3]: according to size1 */ -int m5mols_read(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); +int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val); +int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val); +int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); -int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value); +int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value); /* * Mode operation of the M-5MOLS @@ -280,12 +281,12 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value); * The available executing order between each modes are as follows: * PARAMETER <---> MONITOR <---> CAPTURE */ -int m5mols_mode(struct m5mols_info *info, u32 mode); +int m5mols_mode(struct m5mols_info *info, u8 mode); -int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg); +int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); int m5mols_sync_controls(struct m5mols_info *info); int m5mols_start_capture(struct m5mols_info *info); -int m5mols_do_scenemode(struct m5mols_info *info, u32 mode); +int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); int m5mols_lock_3a(struct m5mols_info *info, bool lock); int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c index d71a3903b60..d9471928369 100644 --- a/drivers/media/video/m5mols/m5mols_capture.c +++ b/drivers/media/video/m5mols/m5mols_capture.c @@ -2,10 +2,10 @@ * The Capture code for Fujitsu M-5MOLS ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,9 +58,9 @@ static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num, { u32 num, den; - int ret = m5mols_read(sd, addr_num, &num); + int ret = m5mols_read_u32(sd, addr_num, &num); if (!ret) - ret = m5mols_read(sd, addr_den, &den); + ret = m5mols_read_u32(sd, addr_den, &den); if (ret) return ret; *val = den == 0 ? 0 : num / den; @@ -99,20 +99,20 @@ static int m5mols_capture_info(struct m5mols_info *info) if (ret) return ret; - ret = m5mols_read(sd, EXIF_INFO_ISO, (u32 *)&exif->iso_speed); + ret = m5mols_read_u16(sd, EXIF_INFO_ISO, &exif->iso_speed); if (!ret) - ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash); + ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash); if (!ret) - ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr); + ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr); if (!ret) - ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval); + ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval); if (ret) return ret; if (!ret) - ret = m5mols_read(sd, CAPC_IMAGE_SIZE, &info->cap.main); + ret = m5mols_read_u32(sd, CAPC_IMAGE_SIZE, &info->cap.main); if (!ret) - ret = m5mols_read(sd, CAPC_THUMB_SIZE, &info->cap.thumb); + ret = m5mols_read_u32(sd, CAPC_THUMB_SIZE, &info->cap.thumb); if (!ret) info->cap.total = info->cap.main + info->cap.thumb; @@ -122,7 +122,7 @@ static int m5mols_capture_info(struct m5mols_info *info) int m5mols_start_capture(struct m5mols_info *info) { struct v4l2_subdev *sd = &info->sd; - u32 resolution = info->resolution; + u8 resolution = info->resolution; int timeout; int ret; diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c index 817c16fec36..d135d20d09c 100644 --- a/drivers/media/video/m5mols/m5mols_controls.c +++ b/drivers/media/video/m5mols/m5mols_controls.c @@ -2,10 +2,10 @@ * Controls for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -130,7 +130,7 @@ static struct m5mols_scenemode m5mols_default_scenemode[] = { * * WARNING: The execution order is important. Do not change the order. */ -int m5mols_do_scenemode(struct m5mols_info *info, u32 mode) +int m5mols_do_scenemode(struct m5mols_info *info, u8 mode) { struct v4l2_subdev *sd = &info->sd; struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode]; diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index 76eac26e84a..43c68f51c5c 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c @@ -2,10 +2,10 @@ * Driver for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -133,13 +133,13 @@ static u32 m5mols_swap_byte(u8 *data, u8 length) /** * m5mols_read - I2C read function * @reg: combination of size, category and command for the I2C packet + * @size: desired size of I2C packet * @val: read value */ -int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) +static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) { struct i2c_client *client = v4l2_get_subdevdata(sd); u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; - u8 size = I2C_SIZE(reg); u8 category = I2C_CATEGORY(reg); u8 cmd = I2C_COMMAND(reg); struct i2c_msg msg[2]; @@ -149,11 +149,6 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) if (!client->adapter) return -ENODEV; - if (size != 1 && size != 2 && size != 4) { - v4l2_err(sd, "Wrong data size\n"); - return -EINVAL; - } - msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = 5; @@ -184,6 +179,52 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) return 0; } +int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val) +{ + u32 val_32; + int ret; + + if (I2C_SIZE(reg) != 1) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); + if (ret) + return ret; + + *val = (u8)val_32; + return ret; +} + +int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val) +{ + u32 val_32; + int ret; + + if (I2C_SIZE(reg) != 2) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); + if (ret) + return ret; + + *val = (u16)val_32; + return ret; +} + +int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val) +{ + if (I2C_SIZE(reg) != 4) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + return m5mols_read(sd, I2C_SIZE(reg), reg, val); +} + /** * m5mols_write - I2C command write function * @reg: combination of size, category and command for the I2C packet @@ -231,13 +272,14 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) return 0; } -int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask) +int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask) { - u32 busy, i; + u8 busy; + int i; int ret; for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { - ret = m5mols_read(sd, I2C_REG(category, cmd, 1), &busy); + ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy); if (ret < 0) return ret; if ((busy & mask) == mask) @@ -252,14 +294,14 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask) * Before writing desired interrupt value the INT_FACTOR register should * be read to clear pending interrupts. */ -int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg) +int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) { struct m5mols_info *info = to_m5mols(sd); - u32 mask = is_available_af(info) ? REG_INT_AF : 0; - u32 dummy; + u8 mask = is_available_af(info) ? REG_INT_AF : 0; + u8 dummy; int ret; - ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy); + ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy); if (!ret) ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); return ret; @@ -271,7 +313,7 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg) * It always accompanies a little delay changing the M-5MOLS mode, so it is * needed checking current busy status to guarantee right mode. */ -static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode) +static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) { int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); @@ -286,16 +328,16 @@ static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode) * can be guaranteed only when the sensor is operating in mode which which * a command belongs to. */ -int m5mols_mode(struct m5mols_info *info, u32 mode) +int m5mols_mode(struct m5mols_info *info, u8 mode) { struct v4l2_subdev *sd = &info->sd; int ret = -EINVAL; - u32 reg; + u8 reg; if (mode < REG_PARAMETER && mode > REG_CAPTURE) return ret; - ret = m5mols_read(sd, SYSTEM_SYSMODE, ®); + ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); if ((!ret && reg == mode) || ret) return ret; @@ -344,41 +386,37 @@ int m5mols_mode(struct m5mols_info *info, u32 mode) static int m5mols_get_version(struct v4l2_subdev *sd) { struct m5mols_info *info = to_m5mols(sd); - union { - struct m5mols_version ver; - u8 bytes[VERSION_SIZE]; - } version; - u32 *value; - u8 cmd = CAT0_VER_CUSTOMER; + struct m5mols_version *ver = &info->ver; + u8 *str = ver->str; + int i; int ret; - do { - value = (u32 *)&version.bytes[cmd]; - ret = m5mols_read(sd, SYSTEM_CMD(cmd), value); - if (ret) - return ret; - } while (cmd++ != CAT0_VER_AWB); + ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer); + if (!ret) + ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb); + if (!ret) + ret = m5mols_read_u8(sd, AF_VERSION, &ver->af); + if (ret) + return ret; - do { - value = (u32 *)&version.bytes[cmd]; - ret = m5mols_read(sd, SYSTEM_VER_STRING, value); + for (i = 0; i < VERSION_STRING_SIZE; i++) { + ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]); if (ret) return ret; - if (cmd >= VERSION_SIZE - 1) - return -EINVAL; - } while (version.bytes[cmd++]); - - value = (u32 *)&version.bytes[cmd]; - ret = m5mols_read(sd, AF_VERSION, value); - if (ret) - return ret; + } - /* store version information swapped for being readable */ - info->ver = version.ver; - info->ver.fw = be16_to_cpu(info->ver.fw); - info->ver.hw = be16_to_cpu(info->ver.hw); - info->ver.param = be16_to_cpu(info->ver.param); - info->ver.awb = be16_to_cpu(info->ver.awb); + ver->fw = be16_to_cpu(ver->fw); + ver->hw = be16_to_cpu(ver->hw); + ver->param = be16_to_cpu(ver->param); + ver->awb = be16_to_cpu(ver->awb); v4l2_info(sd, "Manufacturer\t[%s]\n", is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? @@ -722,7 +760,7 @@ static int m5mols_init_controls(struct m5mols_info *info) int ret; /* Determine value's range & step of controls for various FW version */ - ret = m5mols_read(sd, AE_MAX_GAIN_MON, (u32 *)&max_exposure); + ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure); if (!ret) step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; if (ret) @@ -842,18 +880,18 @@ static void m5mols_irq_work(struct work_struct *work) struct m5mols_info *info = container_of(work, struct m5mols_info, work_irq); struct v4l2_subdev *sd = &info->sd; - u32 reg; + u8 reg; int ret; if (!is_powered(info) || - m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt)) + m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt)) return; switch (info->interrupt & REG_INT_MASK) { case REG_INT_AF: if (!is_available_af(info)) break; - ret = m5mols_read(sd, AF_STATUS, ®); + ret = m5mols_read_u8(sd, AF_STATUS, ®); v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", reg == REG_AF_FAIL ? "Failed" : reg == REG_AF_SUCCESS ? "Success" : diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h index b83e36fc6ac..c755bd6edfe 100644 --- a/drivers/media/video/m5mols/m5mols_reg.h +++ b/drivers/media/video/m5mols/m5mols_reg.h @@ -2,10 +2,10 @@ * Register map for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,13 +56,24 @@ * more specific contents, see definition if file m5mols.h. */ #define CAT0_VER_CUSTOMER 0x00 /* customer version */ -#define CAT0_VER_AWB 0x09 /* Auto WB version */ +#define CAT0_VER_PROJECT 0x01 /* project version */ +#define CAT0_VER_FIRMWARE 0x02 /* Firmware version */ +#define CAT0_VER_HARDWARE 0x04 /* Hardware version */ +#define CAT0_VER_PARAMETER 0x06 /* Parameter version */ +#define CAT0_VER_AWB 0x08 /* Auto WB version */ #define CAT0_VER_STRING 0x0a /* string including M-5MOLS */ #define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ #define CAT0_STATUS 0x0c /* SYSTEM mode status register */ #define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ #define CAT0_INT_ENABLE 0x11 /* interrupt enable register */ +#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, CAT0_VER_CUSTOMER, 1) +#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, CAT0_VER_PROJECT, 1) +#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, CAT0_VER_FIRMWARE, 2) +#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, CAT0_VER_HARDWARE, 2) +#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, CAT0_VER_PARAMETER, 2) +#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, CAT0_VER_AWB, 2) + #define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1) #define REG_SYSINIT 0x00 /* SYSTEM mode */ #define REG_PARAMETER 0x01 /* PARAMETER mode */ @@ -382,8 +393,8 @@ #define REG_CAP_START_MAIN 0x01 #define REG_CAP_START_THUMB 0x03 -#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 1) -#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 1) +#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 4) +#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4) /* * Category F - Flash diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index de5d481b032..c43c81f5f97 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -480,12 +480,14 @@ static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - if (state->radio) + if (vt->type != V4L2_TUNER_ANALOG_TV) return 0; - if (state->opmode == OPMODE_AUTOSELECT) - msp_detect_stereo(client); - vt->audmode = state->audmode; - vt->rxsubchans = state->rxsubchans; + if (!state->radio) { + if (state->opmode == OPMODE_AUTOSELECT) + msp_detect_stereo(client); + vt->rxsubchans = state->rxsubchans; + } + vt->audmode = state->audmode; vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; return 0; diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index bc0c23a1009..63f8a0cc33d 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -444,12 +444,9 @@ static int mx1_camera_add_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx1_camera_dev *pcdev = ici->priv; - int ret; - if (pcdev->icd) { - ret = -EBUSY; - goto ebusy; - } + if (pcdev->icd) + return -EBUSY; dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n", icd->devnum); @@ -458,8 +455,7 @@ static int mx1_camera_add_device(struct soc_camera_device *icd) pcdev->icd = icd; -ebusy: - return ret; + return 0; } static void mx1_camera_remove_device(struct soc_camera_device *icd) diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 4ada9be1d43..4d07c584440 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -982,6 +982,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, startindex = (vout->vid == OMAP_VIDEO1) ? video1_numbuffers : video2_numbuffers; + /* Check the size of the buffer */ + if (*size > vout->buffer_size) { + v4l2_err(&vout->vid_dev->v4l2_dev, + "buffer allocation mismatch [%u] [%u]\n", + *size, vout->buffer_size); + return -ENOMEM; + } + for (i = startindex; i < *count; i++) { vout->buffer_size = *size; @@ -1228,6 +1236,14 @@ static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma) (vma->vm_pgoff << PAGE_SHIFT)); return -EINVAL; } + /* Check the size of the buffer */ + if (size > vout->buffer_size) { + v4l2_err(&vout->vid_dev->v4l2_dev, + "insufficient memory [%lu] [%u]\n", + size, vout->buffer_size); + return -ENOMEM; + } + q->bufs[i]->baddr = vma->vm_start; vma->vm_flags |= VM_RESERVED; @@ -2391,7 +2407,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) /* Register the Video device with V4L2 */ vfd = vout->vfd; - if (video_register_device(vfd, VFL_TYPE_GRABBER, k + 1) < 0) { + if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) { dev_err(&pdev->dev, ": Could not register " "Video for Linux device\n"); vfd->minor = -1; diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c index 2aa6a76c5e5..8ae74817a11 100644 --- a/drivers/media/video/omap/omap_voutlib.c +++ b/drivers/media/video/omap/omap_voutlib.c @@ -193,7 +193,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, return -EINVAL; if (cpu_is_omap24xx()) { - if (crop->height != win->w.height) { + if (try_crop.height != win->w.height) { /* If we're resizing vertically, we can't support a * crop width wider than 768 pixels. */ @@ -202,7 +202,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, } } /* vertical resizing */ - vresize = (1024 * crop->height) / win->w.height; + vresize = (1024 * try_crop.height) / win->w.height; if (cpu_is_omap24xx() && (vresize > 2048)) vresize = 2048; else if (cpu_is_omap34xx() && (vresize > 4096)) @@ -221,7 +221,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, try_crop.height = 2; } /* horizontal resizing */ - hresize = (1024 * crop->width) / win->w.width; + hresize = (1024 * try_crop.width) / win->w.width; if (cpu_is_omap24xx() && (hresize > 2048)) hresize = 2048; else if (cpu_is_omap34xx() && (hresize > 4096)) diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index c9fd04ee70a..94b6ed89e19 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -1748,7 +1748,7 @@ static int isp_register_entities(struct isp_device *isp) goto done; /* Register external entities */ - for (subdevs = pdata->subdevs; subdevs->subdevs; ++subdevs) { + for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) { struct v4l2_subdev *sensor; struct media_entity *input; unsigned int flags; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 9d0dd08f57f..e98d3821279 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -3046,6 +3046,8 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw) if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) { struct v4l2_tuner vt; memset(&vt, 0, sizeof(vt)); + vt.type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; vt.audmode = hdw->audiomode_val; v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt); } @@ -5171,6 +5173,8 @@ void pvr2_hdw_status_poll(struct pvr2_hdw *hdw) { struct v4l2_tuner *vtp = &hdw->tuner_signal_info; memset(vtp, 0, sizeof(*vtp)); + vtp->type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; hdw->tuner_signal_stale = 0; /* Note: There apparently is no replacement for VIDIOC_CROPCAP using v4l2-subdev - therefore we can't support that AT ALL right diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 1593f8deb81..760b4de13ad 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -1414,7 +1414,7 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) { ARG_DEF(struct pwc_probe, probe) - strcpy(ARGR(probe).name, pdev->vdev->name); + strcpy(ARGR(probe).name, pdev->vdev.name); ARGR(probe).type = pdev->type; ARG_OUT(probe) break; diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 356cd42b593..b0bde5a87c8 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -40,7 +40,7 @@ Oh yes, convention: to disctinguish between all the various pointers to device-structures, I use these names for the pointer variables: udev: struct usb_device * - vdev: struct video_device * + vdev: struct video_device (member of pwc_dev) pdev: struct pwc_devive * */ @@ -152,6 +152,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); static unsigned int pwc_video_poll(struct file *file, poll_table *wait); static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); +static void pwc_video_release(struct video_device *vfd); static const struct v4l2_file_operations pwc_fops = { .owner = THIS_MODULE, @@ -164,42 +165,12 @@ static const struct v4l2_file_operations pwc_fops = { }; static struct video_device pwc_template = { .name = "Philips Webcam", /* Filled in later */ - .release = video_device_release, + .release = pwc_video_release, .fops = &pwc_fops, + .ioctl_ops = &pwc_ioctl_ops, }; /***************************************************************************/ - -/* Okay, this is some magic that I worked out and the reasoning behind it... - - The biggest problem with any USB device is of course: "what to do - when the user unplugs the device while it is in use by an application?" - We have several options: - 1) Curse them with the 7 plagues when they do (requires divine intervention) - 2) Tell them not to (won't work: they'll do it anyway) - 3) Oops the kernel (this will have a negative effect on a user's uptime) - 4) Do something sensible. - - Of course, we go for option 4. - - It happens that this device will be linked to two times, once from - usb_device and once from the video_device in their respective 'private' - pointers. This is done when the device is probed() and all initialization - succeeded. The pwc_device struct links back to both structures. - - When a device is unplugged while in use it will be removed from the - list of known USB devices; I also de-register it as a V4L device, but - unfortunately I can't free the memory since the struct is still in use - by the file descriptor. This free-ing is then deferend until the first - opportunity. Crude, but it works. - - A small 'advantage' is that if a user unplugs the cam and plugs it back - in, it should get assigned the same video device minor, but unfortunately - it's non-trivial to re-link the cam back to the video device... (that - would surely be magic! :)) -*/ - -/***************************************************************************/ /* Private functions */ /* Here we want the physical address of the memory. @@ -1016,16 +987,15 @@ static ssize_t show_snapshot_button_status(struct device *class_dev, static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, NULL); -static int pwc_create_sysfs_files(struct video_device *vdev) +static int pwc_create_sysfs_files(struct pwc_device *pdev) { - struct pwc_device *pdev = video_get_drvdata(vdev); int rc; - rc = device_create_file(&vdev->dev, &dev_attr_button); + rc = device_create_file(&pdev->vdev.dev, &dev_attr_button); if (rc) goto err; if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt); + rc = device_create_file(&pdev->vdev.dev, &dev_attr_pan_tilt); if (rc) goto err_button; } @@ -1033,19 +1003,17 @@ static int pwc_create_sysfs_files(struct video_device *vdev) return 0; err_button: - device_remove_file(&vdev->dev, &dev_attr_button); + device_remove_file(&pdev->vdev.dev, &dev_attr_button); err: PWC_ERROR("Could not create sysfs files.\n"); return rc; } -static void pwc_remove_sysfs_files(struct video_device *vdev) +static void pwc_remove_sysfs_files(struct pwc_device *pdev) { - struct pwc_device *pdev = video_get_drvdata(vdev); - if (pdev->features & FEATURE_MOTOR_PANTILT) - device_remove_file(&vdev->dev, &dev_attr_pan_tilt); - device_remove_file(&vdev->dev, &dev_attr_button); + device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt); + device_remove_file(&pdev->vdev.dev, &dev_attr_button); } #ifdef CONFIG_USB_PWC_DEBUG @@ -1106,7 +1074,7 @@ static int pwc_video_open(struct file *file) if (ret >= 0) { PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n", - pdev->vdev->name, + pdev->vdev.name, pwc_sensor_type_to_string(i), i); } } @@ -1180,16 +1148,15 @@ static int pwc_video_open(struct file *file) return 0; } - -static void pwc_cleanup(struct pwc_device *pdev) +static void pwc_video_release(struct video_device *vfd) { - pwc_remove_sysfs_files(pdev->vdev); - video_unregister_device(pdev->vdev); + struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev); + int hint; -#ifdef CONFIG_USB_PWC_INPUT_EVDEV - if (pdev->button_dev) - input_unregister_device(pdev->button_dev); -#endif + /* search device_hint[] table if we occupy a slot, by any chance */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) + if (device_hint[hint].pdev == pdev) + device_hint[hint].pdev = NULL; kfree(pdev); } @@ -1199,7 +1166,7 @@ static int pwc_video_close(struct file *file) { struct video_device *vdev = file->private_data; struct pwc_device *pdev; - int i, hint; + int i; PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); @@ -1234,12 +1201,6 @@ static int pwc_video_close(struct file *file) } pdev->vopen--; PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen); - } else { - pwc_cleanup(pdev); - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; } return 0; @@ -1715,19 +1676,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id init_waitqueue_head(&pdev->frameq); pdev->vcompression = pwc_preferred_compression; - /* Allocate video_device structure */ - pdev->vdev = video_device_alloc(); - if (!pdev->vdev) { - PWC_ERROR("Err, cannot allocate video_device struture. Failing probe."); - rc = -ENOMEM; - goto err_free_mem; - } - memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); - pdev->vdev->parent = &intf->dev; - pdev->vdev->lock = &pdev->modlock; - pdev->vdev->ioctl_ops = &pwc_ioctl_ops; - strcpy(pdev->vdev->name, name); - video_set_drvdata(pdev->vdev, pdev); + /* Init video_device structure */ + memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template)); + pdev->vdev.parent = &intf->dev; + pdev->vdev.lock = &pdev->modlock; + strcpy(pdev->vdev.name, name); + video_set_drvdata(&pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); @@ -1746,8 +1700,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id } } - pdev->vdev->release = video_device_release; - /* occupy slot */ if (hint < MAX_DEV_HINTS) device_hint[hint].pdev = pdev; @@ -1759,16 +1711,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); - rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); + rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); if (rc < 0) { PWC_ERROR("Failed to register as video device (%d).\n", rc); - goto err_video_release; + goto err_free_mem; } - rc = pwc_create_sysfs_files(pdev->vdev); + rc = pwc_create_sysfs_files(pdev); if (rc) goto err_video_unreg; - PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev)); + PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev)); #ifdef CONFIG_USB_PWC_INPUT_EVDEV /* register webcam snapshot button input device */ @@ -1776,7 +1728,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (!pdev->button_dev) { PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); rc = -ENOMEM; - pwc_remove_sysfs_files(pdev->vdev); + pwc_remove_sysfs_files(pdev); goto err_video_unreg; } @@ -1794,7 +1746,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (rc) { input_free_device(pdev->button_dev); pdev->button_dev = NULL; - pwc_remove_sysfs_files(pdev->vdev); + pwc_remove_sysfs_files(pdev); goto err_video_unreg; } #endif @@ -1804,10 +1756,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id err_video_unreg: if (hint < MAX_DEV_HINTS) device_hint[hint].pdev = NULL; - video_unregister_device(pdev->vdev); - pdev->vdev = NULL; /* So we don't try to release it below */ -err_video_release: - video_device_release(pdev->vdev); + video_unregister_device(&pdev->vdev); err_free_mem: kfree(pdev); return rc; @@ -1816,10 +1765,8 @@ err_free_mem: /* The user yanked out the cable... */ static void usb_pwc_disconnect(struct usb_interface *intf) { - struct pwc_device *pdev; - int hint; + struct pwc_device *pdev = usb_get_intfdata(intf); - pdev = usb_get_intfdata (intf); mutex_lock(&pdev->modlock); usb_set_intfdata (intf, NULL); if (pdev == NULL) { @@ -1836,30 +1783,25 @@ static void usb_pwc_disconnect(struct usb_interface *intf) } /* We got unplugged; this is signalled by an EPIPE error code */ - if (pdev->vopen) { - PWC_INFO("Disconnected while webcam is in use!\n"); - pdev->error_status = EPIPE; - } + pdev->error_status = EPIPE; + pdev->unplugged = 1; /* Alert waiting processes */ wake_up_interruptible(&pdev->frameq); - /* Wait until device is closed */ - if (pdev->vopen) { - pdev->unplugged = 1; - pwc_iso_stop(pdev); - } else { - /* Device is closed, so we can safely unregister it */ - PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); -disconnect_out: - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; - } + /* No need to keep the urbs around after disconnection */ + pwc_isoc_cleanup(pdev); +disconnect_out: mutex_unlock(&pdev->modlock); - pwc_cleanup(pdev); + + pwc_remove_sysfs_files(pdev); + video_unregister_device(&pdev->vdev); + +#ifdef CONFIG_USB_PWC_INPUT_EVDEV + if (pdev->button_dev) + input_unregister_device(pdev->button_dev); +#endif } diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index e947766337d..083f8b15df7 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -162,9 +162,9 @@ struct pwc_imgbuf struct pwc_device { - struct video_device *vdev; + struct video_device vdev; - /* Pointer to our usb_device */ + /* Pointer to our usb_device, may be NULL after unplug */ struct usb_device *udev; int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index d142b40ea64..81b4a826ee5 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -1,7 +1,7 @@ /* - * Samsung S5P SoC series camera interface (camera capture) driver + * Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver * - * Copyright (c) 2010 Samsung Electronics Co., Ltd + * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com> * * This program is free software; you can redistribute it and/or modify @@ -262,12 +262,7 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) { if (!fr || plane >= fr->fmt->memplanes) return 0; - - dbg("%s: w: %d. h: %d. depth[%d]: %d", - __func__, fr->width, fr->height, plane, fr->fmt->depth[plane]); - return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; - } static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, @@ -283,24 +278,14 @@ static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, *num_planes = fmt->memplanes; - dbg("%s, buffer count=%d, plane count=%d", - __func__, *num_buffers, *num_planes); - for (i = 0; i < fmt->memplanes; i++) { sizes[i] = get_plane_size(&ctx->d_frame, i); - dbg("plane: %u, plane_size: %lu", i, sizes[i]); allocators[i] = ctx->fimc_dev->alloc_ctx; } return 0; } -static int buffer_init(struct vb2_buffer *vb) -{ - /* TODO: */ - return 0; -} - static int buffer_prepare(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; @@ -380,7 +365,6 @@ static struct vb2_ops fimc_capture_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .buf_init = buffer_init, .wait_prepare = fimc_unlock, .wait_finish = fimc_lock, .start_streaming = start_streaming, @@ -903,6 +887,7 @@ err_vd_reg: err_v4l2_reg: v4l2_device_unregister(v4l2_dev); err_info: + kfree(ctx); dev_err(&fimc->pdev->dev, "failed to install\n"); return ret; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index dc91a8511af..bdf19ada917 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -1,9 +1,8 @@ /* - * S5P camera interface (video postprocessor) driver + * Samsung S5P/EXYNOS4 SoC series camera interface (video postprocessor) driver * - * Copyright (c) 2010 Samsung Electronics Co., Ltd - * - * Sylwester Nawrocki, <s.nawrocki@samsung.com> + * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published @@ -42,7 +41,6 @@ static struct fimc_fmt fimc_formats[] = { .color = S5P_FIMC_RGB565, .memplanes = 1, .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE, .flags = FMT_FLAGS_M2M, }, { .name = "BGR666", @@ -232,11 +230,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) return 0; } } - *shift = 0, *ratio = 1; - - dbg("s: %d, t: %d, shift: %d, ratio: %d", - src, tar, *shift, *ratio); return 0; } @@ -268,10 +262,8 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) err("invalid source size: %d x %d", sx, sy); return -EINVAL; } - sc->real_width = sx; sc->real_height = sy; - dbg("sx= %d, sy= %d, tx= %d, ty= %d", sx, sy, tx, ty); ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor); if (ret) @@ -711,22 +703,18 @@ static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, f = ctx_get_frame(ctx, vq->type); if (IS_ERR(f)) return PTR_ERR(f); - /* * Return number of non-contigous planes (plane buffers) * depending on the configured color format. */ - if (f->fmt) - *num_planes = f->fmt->memplanes; + if (!f->fmt) + return -EINVAL; + *num_planes = f->fmt->memplanes; for (i = 0; i < f->fmt->memplanes; i++) { - sizes[i] = (f->width * f->height * f->fmt->depth[i]) >> 3; + sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8; allocators[i] = ctx->fimc_dev->alloc_ctx; } - - if (*num_buffers == 0) - *num_buffers = 1; - return 0; } @@ -852,7 +840,7 @@ struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask) for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { fmt = &fimc_formats[i]; - if (fmt->fourcc == f->fmt.pix.pixelformat && + if (fmt->fourcc == f->fmt.pix_mp.pixelformat && (fmt->flags & mask)) break; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 3beb1e5320c..1f70772daaf 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -1,7 +1,5 @@ /* - * Copyright (c) 2010 Samsung Electronics - * - * Sylwester Nawrocki, <s.nawrocki@samsung.com> + * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd. * * 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 @@ -135,9 +133,10 @@ enum fimc_color_fmt { * @name: format description * @fourcc: the fourcc code for this format, 0 if not applicable * @color: the corresponding fimc_color_fmt - * @depth: per plane driver's private 'number of bits per pixel' * @memplanes: number of physically non-contiguous data planes * @colplanes: number of physically contiguous data planes + * @depth: per plane driver's private 'number of bits per pixel' + * @flags: flags indicating which operation mode format applies to */ struct fimc_fmt { enum v4l2_mbus_pixelcode mbus_code; @@ -171,7 +170,7 @@ struct fimc_dma_offset { }; /** - * struct fimc_effect - the configuration data for the "Arbitrary" image effect + * struct fimc_effect - color effect information * @type: effect type * @pat_cb: cr value when type is "arbitrary" * @pat_cr: cr value when type is "arbitrary" @@ -184,7 +183,6 @@ struct fimc_effect { /** * struct fimc_scaler - the configuration data for FIMC inetrnal scaler - * * @scaleup_h: flag indicating scaling up horizontally * @scaleup_v: flag indicating scaling up vertically * @copy_mode: flag indicating transparent DMA transfer (no scaling @@ -220,7 +218,6 @@ struct fimc_scaler { /** * struct fimc_addr - the FIMC physical address set for DMA - * * @y: luminance plane physical address * @cb: Cb plane physical address * @cr: Cr plane physical address @@ -234,6 +231,7 @@ struct fimc_addr { /** * struct fimc_vid_buffer - the driver's video buffer * @vb: v4l videobuf buffer + * @list: linked list structure for buffer queue * @paddr: precalculated physical address set * @index: buffer index for the output DMA engine */ @@ -254,11 +252,10 @@ struct fimc_vid_buffer { * @offs_v: image vertical pixel offset * @width: image pixel width * @height: image pixel weight - * @paddr: image frame buffer physical addresses - * @buf_cnt: number of buffers depending on a color format * @payload: image size in bytes (w x h x bpp) - * @color: color format + * @paddr: image frame buffer physical addresses * @dma_offset: DMA offset in bytes + * @fmt: fimc color format pointer */ struct fimc_frame { u32 f_width; @@ -390,21 +387,22 @@ struct fimc_ctx; /** * struct fimc_dev - abstraction for FIMC entity - * * @slock: the spinlock protecting this data structure * @lock: the mutex protecting this data structure * @pdev: pointer to the FIMC platform device * @pdata: pointer to the device platform data + * @variant: the IP variant information * @id: FIMC device index (0..FIMC_MAX_DEVS) * @num_clocks: the number of clocks managed by this device instance - * @clock[]: the clocks required for FIMC operation + * @clock: clocks required for FIMC operation * @regs: the mapped hardware registers * @regs_res: the resource claimed for IO registers - * @irq: interrupt number of the FIMC subdevice - * @irq_queue: + * @irq: FIMC interrupt number + * @irq_queue: interrupt handler waitqueue * @m2m: memory-to-memory V4L2 device information * @vid_cap: camera capture device information * @state: flags used to synchronize m2m and capture mode operation + * @alloc_ctx: videobuf2 memory allocator context */ struct fimc_dev { spinlock_t slock; @@ -427,8 +425,7 @@ struct fimc_dev { /** * fimc_ctx - the device context data - * - * @lock: mutex protecting this data structure + * @slock: spinlock protecting this data structure * @s_frame: source frame properties * @d_frame: destination frame properties * @out_order_1p: output 1-plane YCBCR order diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index ff6c0e97563..d4ee24bf692 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -963,7 +963,7 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev) * to work with other protocols. */ if (!ir->active) { - timeout = jiffies + jiffies_to_msecs(15); + timeout = jiffies + msecs_to_jiffies(15); mod_timer(&ir->timer, timeout); ir->active = true; } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9363ed91a4c..a03945ab9f0 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -714,29 +714,34 @@ static int tuner_remove(struct i2c_client *client) * returns 0. * This function is needed for boards that have a separate tuner for * radio (like devices with tea5767). + * NOTE: mt20xx uses V4L2_TUNER_DIGITAL_TV and calls set_tv_freq to + * select a TV frequency. So, t_mode = T_ANALOG_TV could actually + * be used to represent a Digital TV too. */ static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode) { - if ((1 << mode & t->mode_mask) == 0) + int t_mode; + if (mode == V4L2_TUNER_RADIO) + t_mode = T_RADIO; + else + t_mode = T_ANALOG_TV; + + if ((t_mode & t->mode_mask) == 0) return -EINVAL; return 0; } /** - * set_mode_freq - Switch tuner to other mode. - * @client: struct i2c_client pointer + * set_mode - Switch tuner to other mode. * @t: a pointer to the module's internal struct_tuner * @mode: enum v4l2_type (radio or TV) - * @freq: frequency to set (0 means to use the previous one) * * If tuner doesn't support the needed mode (radio or TV), prints a * debug message and returns -EINVAL, changing its state to standby. - * Otherwise, changes the state and sets frequency to the last value, if - * the tuner can sleep or if it supports both Radio and TV. + * Otherwise, changes the mode and returns 0. */ -static int set_mode_freq(struct i2c_client *client, struct tuner *t, - enum v4l2_tuner_type mode, unsigned int freq) +static int set_mode(struct tuner *t, enum v4l2_tuner_type mode) { struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; @@ -752,17 +757,27 @@ static int set_mode_freq(struct i2c_client *client, struct tuner *t, t->mode = mode; tuner_dbg("Changing to mode %d\n", mode); } + return 0; +} + +/** + * set_freq - Set the tuner to the desired frequency. + * @t: a pointer to the module's internal struct_tuner + * @freq: frequency to set (0 means to use the current frequency) + */ +static void set_freq(struct tuner *t, unsigned int freq) +{ + struct i2c_client *client = v4l2_get_subdevdata(&t->sd); + if (t->mode == V4L2_TUNER_RADIO) { - if (freq) - t->radio_freq = freq; - set_radio_freq(client, t->radio_freq); + if (!freq) + freq = t->radio_freq; + set_radio_freq(client, freq); } else { - if (freq) - t->tv_freq = freq; - set_tv_freq(client, t->tv_freq); + if (!freq) + freq = t->tv_freq; + set_tv_freq(client, freq); } - - return 0; } /* @@ -817,7 +832,8 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) /** * tuner_fixup_std - force a given video standard variant * - * @t: tuner internal struct + * @t: tuner internal struct + * @std: TV standard * * A few devices or drivers have problem to detect some standard variations. * On other operational systems, the drivers generally have a per-country @@ -827,57 +843,39 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) * to distinguish all video standard variations, a modprobe parameter can * be used to force a video standard match. */ -static int tuner_fixup_std(struct tuner *t) +static v4l2_std_id tuner_fixup_std(struct tuner *t, v4l2_std_id std) { - if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { + if (pal[0] != '-' && (std & V4L2_STD_PAL) == V4L2_STD_PAL) { switch (pal[0]) { case '6': - tuner_dbg("insmod fixup: PAL => PAL-60\n"); - t->std = V4L2_STD_PAL_60; - break; + return V4L2_STD_PAL_60; case 'b': case 'B': case 'g': case 'G': - tuner_dbg("insmod fixup: PAL => PAL-BG\n"); - t->std = V4L2_STD_PAL_BG; - break; + return V4L2_STD_PAL_BG; case 'i': case 'I': - tuner_dbg("insmod fixup: PAL => PAL-I\n"); - t->std = V4L2_STD_PAL_I; - break; + return V4L2_STD_PAL_I; case 'd': case 'D': case 'k': case 'K': - tuner_dbg("insmod fixup: PAL => PAL-DK\n"); - t->std = V4L2_STD_PAL_DK; - break; + return V4L2_STD_PAL_DK; case 'M': case 'm': - tuner_dbg("insmod fixup: PAL => PAL-M\n"); - t->std = V4L2_STD_PAL_M; - break; + return V4L2_STD_PAL_M; case 'N': case 'n': - if (pal[1] == 'c' || pal[1] == 'C') { - tuner_dbg("insmod fixup: PAL => PAL-Nc\n"); - t->std = V4L2_STD_PAL_Nc; - } else { - tuner_dbg("insmod fixup: PAL => PAL-N\n"); - t->std = V4L2_STD_PAL_N; - } - break; - case '-': - /* default parameter, do nothing */ - break; + if (pal[1] == 'c' || pal[1] == 'C') + return V4L2_STD_PAL_Nc; + return V4L2_STD_PAL_N; default: tuner_warn("pal= argument not recognised\n"); break; } } - if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { + if (secam[0] != '-' && (std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { switch (secam[0]) { case 'b': case 'B': @@ -885,63 +883,42 @@ static int tuner_fixup_std(struct tuner *t) case 'G': case 'h': case 'H': - tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n"); - t->std = V4L2_STD_SECAM_B | - V4L2_STD_SECAM_G | - V4L2_STD_SECAM_H; - break; + return V4L2_STD_SECAM_B | + V4L2_STD_SECAM_G | + V4L2_STD_SECAM_H; case 'd': case 'D': case 'k': case 'K': - tuner_dbg("insmod fixup: SECAM => SECAM-DK\n"); - t->std = V4L2_STD_SECAM_DK; - break; + return V4L2_STD_SECAM_DK; case 'l': case 'L': - if ((secam[1] == 'C') || (secam[1] == 'c')) { - tuner_dbg("insmod fixup: SECAM => SECAM-L'\n"); - t->std = V4L2_STD_SECAM_LC; - } else { - tuner_dbg("insmod fixup: SECAM => SECAM-L\n"); - t->std = V4L2_STD_SECAM_L; - } - break; - case '-': - /* default parameter, do nothing */ - break; + if ((secam[1] == 'C') || (secam[1] == 'c')) + return V4L2_STD_SECAM_LC; + return V4L2_STD_SECAM_L; default: tuner_warn("secam= argument not recognised\n"); break; } } - if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) { + if (ntsc[0] != '-' && (std & V4L2_STD_NTSC) == V4L2_STD_NTSC) { switch (ntsc[0]) { case 'm': case 'M': - tuner_dbg("insmod fixup: NTSC => NTSC-M\n"); - t->std = V4L2_STD_NTSC_M; - break; + return V4L2_STD_NTSC_M; case 'j': case 'J': - tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n"); - t->std = V4L2_STD_NTSC_M_JP; - break; + return V4L2_STD_NTSC_M_JP; case 'k': case 'K': - tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n"); - t->std = V4L2_STD_NTSC_M_KR; - break; - case '-': - /* default parameter, do nothing */ - break; + return V4L2_STD_NTSC_M_KR; default: tuner_info("ntsc= argument not recognised\n"); break; } } - return 0; + return std; } /* @@ -1016,7 +993,7 @@ static void tuner_status(struct dvb_frontend *fe) case V4L2_TUNER_RADIO: p = "radio"; break; - case V4L2_TUNER_DIGITAL_TV: + case V4L2_TUNER_DIGITAL_TV: /* Used by mt20xx */ p = "digital TV"; break; case V4L2_TUNER_ANALOG_TV: @@ -1058,10 +1035,9 @@ static void tuner_status(struct dvb_frontend *fe) static int tuner_s_radio(struct v4l2_subdev *sd) { struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - if (set_mode_freq(client, t, V4L2_TUNER_RADIO, 0) == -EINVAL) - return 0; + if (set_mode(t, V4L2_TUNER_RADIO) == 0) + set_freq(t, 0); return 0; } @@ -1072,16 +1048,20 @@ static int tuner_s_radio(struct v4l2_subdev *sd) /** * tuner_s_power - controls the power state of the tuner * @sd: pointer to struct v4l2_subdev - * @on: a zero value puts the tuner to sleep + * @on: a zero value puts the tuner to sleep, non-zero wakes it up */ static int tuner_s_power(struct v4l2_subdev *sd, int on) { struct tuner *t = to_tuner(sd); struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - /* FIXME: Why this function don't wake the tuner if on != 0 ? */ - if (on) + if (on) { + if (t->standby && set_mode(t, t->mode) == 0) { + tuner_dbg("Waking up tuner\n"); + set_freq(t, 0); + } return 0; + } tuner_dbg("Putting tuner to sleep\n"); t->standby = true; @@ -1093,28 +1073,36 @@ static int tuner_s_power(struct v4l2_subdev *sd, int on) static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - if (set_mode_freq(client, t, V4L2_TUNER_ANALOG_TV, 0) == -EINVAL) + if (set_mode(t, V4L2_TUNER_ANALOG_TV)) return 0; - t->std = std; - tuner_fixup_std(t); - + t->std = tuner_fixup_std(t, std); + if (t->std != std) + tuner_dbg("Fixup standard %llx to %llx\n", std, t->std); + set_freq(t, 0); return 0; } static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) { struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (set_mode_freq(client, t, f->type, f->frequency) == -EINVAL) - return 0; + if (set_mode(t, f->type) == 0) + set_freq(t, f->frequency); return 0; } +/** + * tuner_g_frequency - Get the tuned frequency for the tuner + * @sd: pointer to struct v4l2_subdev + * @f: pointer to struct v4l2_frequency + * + * At return, the structure f will be filled with tuner frequency + * if the tuner matches the f->type. + * Note: f->type should be initialized before calling it. + * This is done by either video_ioctl2 or by the bridge driver. + */ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) { struct tuner *t = to_tuner(sd); @@ -1122,8 +1110,7 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) if (check_mode(t, f->type) == -EINVAL) return 0; - f->type = t->mode; - if (fe_tuner_ops->get_frequency && !t->standby) { + if (f->type == t->mode && fe_tuner_ops->get_frequency && !t->standby) { u32 abs_freq; fe_tuner_ops->get_frequency(&t->fe, &abs_freq); @@ -1131,12 +1118,22 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) DIV_ROUND_CLOSEST(abs_freq * 2, 125) : DIV_ROUND_CLOSEST(abs_freq, 62500); } else { - f->frequency = (V4L2_TUNER_RADIO == t->mode) ? + f->frequency = (V4L2_TUNER_RADIO == f->type) ? t->radio_freq : t->tv_freq; } return 0; } +/** + * tuner_g_tuner - Fill in tuner information + * @sd: pointer to struct v4l2_subdev + * @vt: pointer to struct v4l2_tuner + * + * At return, the structure vt will be filled with tuner information + * if the tuner matches vt->type. + * Note: vt->type should be initialized before calling it. + * This is done by either video_ioctl2 or by the bridge driver. + */ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) { struct tuner *t = to_tuner(sd); @@ -1145,48 +1142,57 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) if (check_mode(t, vt->type) == -EINVAL) return 0; - vt->type = t->mode; - if (analog_ops->get_afc) + if (vt->type == t->mode && analog_ops->get_afc) vt->afc = analog_ops->get_afc(&t->fe); - if (t->mode == V4L2_TUNER_ANALOG_TV) - vt->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { + vt->capability |= V4L2_TUNER_CAP_NORM; vt->rangelow = tv_range[0] * 16; vt->rangehigh = tv_range[1] * 16; return 0; } /* radio mode */ - vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - if (fe_tuner_ops->get_status) { - u32 tuner_status; - - fe_tuner_ops->get_status(&t->fe, &tuner_status); - vt->rxsubchans = - (tuner_status & TUNER_STATUS_STEREO) ? - V4L2_TUNER_SUB_STEREO : - V4L2_TUNER_SUB_MONO; + if (vt->type == t->mode) { + vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + vt->rxsubchans = + (tuner_status & TUNER_STATUS_STEREO) ? + V4L2_TUNER_SUB_STEREO : + V4L2_TUNER_SUB_MONO; + } + if (analog_ops->has_signal) + vt->signal = analog_ops->has_signal(&t->fe); + vt->audmode = t->audmode; } - if (analog_ops->has_signal) - vt->signal = analog_ops->has_signal(&t->fe); vt->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - vt->audmode = t->audmode; vt->rangelow = radio_range[0] * 16000; vt->rangehigh = radio_range[1] * 16000; return 0; } +/** + * tuner_s_tuner - Set the tuner's audio mode + * @sd: pointer to struct v4l2_subdev + * @vt: pointer to struct v4l2_tuner + * + * Sets the audio mode if the tuner matches vt->type. + * Note: vt->type should be initialized before calling it. + * This is done by either video_ioctl2 or by the bridge driver. + */ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) { struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - if (set_mode_freq(client, t, vt->type, 0) == -EINVAL) + if (set_mode(t, vt->type)) return 0; if (t->mode == V4L2_TUNER_RADIO) t->audmode = vt->audmode; + set_freq(t, 0); return 0; } @@ -1221,7 +1227,8 @@ static int tuner_resume(struct i2c_client *c) tuner_dbg("resume\n"); if (!t->standby) - set_mode_freq(c, t, t->type, 0); + if (set_mode(t, t->mode) == 0) + set_freq(t, 0); return 0; } diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c index c3ab0c813be..48fea373c25 100644 --- a/drivers/media/video/uvc/uvc_entity.c +++ b/drivers/media/video/uvc/uvc_entity.c @@ -27,14 +27,20 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, struct uvc_entity *entity) { const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; - struct uvc_entity *remote; + struct media_entity *sink; unsigned int i; - u8 remote_pad; - int ret = 0; + int ret; + + sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) + ? (entity->vdev ? &entity->vdev->entity : NULL) + : &entity->subdev.entity; + if (sink == NULL) + return 0; for (i = 0; i < entity->num_pads; ++i) { struct media_entity *source; - struct media_entity *sink; + struct uvc_entity *remote; + u8 remote_pad; if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK)) continue; @@ -43,10 +49,11 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, if (remote == NULL) return -EINVAL; - source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING) - ? &remote->vdev->entity : &remote->subdev.entity; - sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) - ? &entity->vdev->entity : &entity->subdev.entity; + source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING) + ? (remote->vdev ? &remote->vdev->entity : NULL) + : &remote->subdev.entity; + if (source == NULL) + continue; remote_pad = remote->num_pads - 1; ret = media_entity_create_link(source, remote_pad, @@ -55,11 +62,10 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, return ret; } - if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) - ret = v4l2_device_register_subdev(&chain->dev->vdev, - &entity->subdev); + if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) + return 0; - return ret; + return v4l2_device_register_subdev(&chain->dev->vdev, &entity->subdev); } static struct v4l2_subdev_ops uvc_subdev_ops = { @@ -84,9 +90,11 @@ static int uvc_mc_init_entity(struct uvc_entity *entity) ret = media_entity_init(&entity->subdev.entity, entity->num_pads, entity->pads, 0); - } else + } else if (entity->vdev != NULL) { ret = media_entity_init(&entity->vdev->entity, entity->num_pads, entity->pads, 0); + } else + ret = 0; return ret; } diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 109a06384a8..f90ce9fce53 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -104,6 +104,8 @@ static int __uvc_free_buffers(struct uvc_video_queue *queue) } if (queue->count) { + uvc_queue_cancel(queue, 0); + INIT_LIST_HEAD(&queue->mainqueue); vfree(queue->mem); queue->count = 0; } diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index fc766b9f24c..49994793cc7 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -1255,8 +1255,10 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) /* Commit the streaming parameters. */ ret = uvc_commit_video(stream, &stream->ctrl); - if (ret < 0) + if (ret < 0) { + uvc_queue_enable(&stream->queue, 0); return ret; + } return uvc_init_video(stream, GFP_KERNEL); } diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 19d5ae29378..06f14008b34 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -167,6 +167,12 @@ static void v4l2_device_release(struct device *cd) mutex_unlock(&videodev_lock); +#if defined(CONFIG_MEDIA_CONTROLLER) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) + media_device_unregister_entity(&vdev->entity); +#endif + /* Release video_device and perform other cleanups as needed. */ vdev->release(vdev); @@ -389,9 +395,6 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) static int v4l2_open(struct inode *inode, struct file *filp) { struct video_device *vdev; -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity *entity = NULL; -#endif int ret = 0; /* Check if the video device is available */ @@ -405,17 +408,6 @@ static int v4l2_open(struct inode *inode, struct file *filp) /* and increase the device refcount */ video_get(vdev); mutex_unlock(&videodev_lock); -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) { - entity = media_entity_get(&vdev->entity); - if (!entity) { - ret = -EBUSY; - video_put(vdev); - return ret; - } - } -#endif if (vdev->fops->open) { if (vdev->lock && mutex_lock_interruptible(vdev->lock)) { ret = -ERESTARTSYS; @@ -431,14 +423,8 @@ static int v4l2_open(struct inode *inode, struct file *filp) err: /* decrease the refcount in case of an error */ - if (ret) { -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) - media_entity_put(entity); -#endif + if (ret) video_put(vdev); - } return ret; } @@ -455,11 +441,6 @@ static int v4l2_release(struct inode *inode, struct file *filp) if (vdev->lock) mutex_unlock(vdev->lock); } -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) - media_entity_put(&vdev->entity); -#endif /* decrease the refcount unconditionally since the release() return value is ignored. */ video_put(vdev); @@ -754,12 +735,6 @@ void video_unregister_device(struct video_device *vdev) if (!vdev || !video_is_registered(vdev)) return; -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) - media_device_unregister_entity(&vdev->entity); -#endif - mutex_lock(&videodev_lock); /* This must be in a critical section to prevent a race with v4l2_open. * Once this bit has been cleared video_get may never be called again. diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 506edcc2dde..69e8c6ffcc4 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -1822,6 +1822,8 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_g_tuner) break; + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; ret = ops->vidioc_g_tuner(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " @@ -1840,6 +1842,8 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_tuner) break; + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; dbgarg(cmd, "index=%d, name=%s, type=%d, " "capability=0x%x, rangelow=%d, " "rangehigh=%d, signal=%d, afc=%d, " @@ -1858,6 +1862,8 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_g_frequency) break; + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; ret = ops->vidioc_g_frequency(file, fh, p); if (!ret) dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", @@ -1940,13 +1946,19 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_S_HW_FREQ_SEEK: { struct v4l2_hw_freq_seek *p = arg; + enum v4l2_tuner_type type; if (!ops->vidioc_s_hw_freq_seek) break; + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; dbgarg(cmd, - "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", - p->tuner, p->type, p->seek_upward, p->wrap_around); - ret = ops->vidioc_s_hw_freq_seek(file, fh, p); + "tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u\n", + p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing); + if (p->type != type) + ret = -EINVAL; + else + ret = ops->vidioc_s_hw_freq_seek(file, fh, p); break; } case VIDIOC_ENUM_FRAMESIZES: diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 6ba1461d51e..3015e600094 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -492,13 +492,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -EINVAL; } - /* - * If the same number of buffers and memory access method is requested - * then return immediately. - */ - if (q->memory == req->memory && req->count == q->num_buffers) - return 0; - if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) { /* * We already have buffers allocated, so first check if they @@ -539,9 +532,9 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) /* Finally, allocate buffers and video memory */ ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes, plane_sizes); - if (ret < 0) { - dprintk(1, "Memory allocation failed with error: %d\n", ret); - return ret; + if (ret == 0) { + dprintk(1, "Memory allocation failed\n"); + return -ENOMEM; } /* @@ -1196,6 +1189,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * has not already dequeued before initiating cancel. */ INIT_LIST_HEAD(&q->done_list); + atomic_set(&q->queued_count, 0); wake_up_all(&q->done_wq); /* diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c index b2d9485aac7..10a20d9509d 100644 --- a/drivers/media/video/videobuf2-dma-sg.c +++ b/drivers/media/video/videobuf2-dma-sg.c @@ -62,7 +62,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) goto fail_pages_array_alloc; for (i = 0; i < buf->sg_desc.num_pages; ++i) { - buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); + buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN); if (NULL == buf->pages[i]) goto fail_pages_alloc; sg_set_page(&buf->sg_desc.sglist[i], diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0f09c057e79..6ca938a6bf9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -728,6 +728,9 @@ config MFD_TPS65910 if you say yes here you get support for the TPS65910 series of Power Management chips. +config TPS65911_COMPARATOR + tristate + endif # MFD_SUPPORT menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index efe3cc33ed9..d7d47d2a4c7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -94,3 +94,4 @@ obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o +obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index c27fd1fc3b8..c71ae09430c 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -619,6 +619,7 @@ static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk) /* MFD cells (SPI, PWM, LED, DS1WM, MMC) */ static struct ds1wm_driver_data ds1wm_pdata = { .active_high = 1, + .reset_recover_delay = 1, }; static struct resource ds1wm_resources[] = { diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 2808bd125d1..04c7093d649 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -99,6 +99,7 @@ static int ds1wm_disable(struct platform_device *pdev) static struct ds1wm_driver_data ds1wm_pdata = { .active_high = 0, + .reset_recover_delay = 1, }; static struct resource ds1wm_resources[] __initdata = { diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 855219526cc..1717144fe7f 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -26,7 +26,6 @@ #include <linux/spinlock.h> #include <linux/gpio.h> #include <plat/usb.h> -#include <linux/pm_runtime.h> #define USBHS_DRIVER_NAME "usbhs-omap" #define OMAP_EHCI_DEVICE "ehci-omap" @@ -147,6 +146,9 @@ struct usbhs_hcd_omap { + struct clk *usbhost_ick; + struct clk *usbhost_hs_fck; + struct clk *usbhost_fs_fck; struct clk *xclk60mhsp1_ck; struct clk *xclk60mhsp2_ck; struct clk *utmi_p1_fck; @@ -156,6 +158,8 @@ struct usbhs_hcd_omap { struct clk *usbhost_p2_fck; struct clk *usbtll_p2_fck; struct clk *init_60m_fclk; + struct clk *usbtll_fck; + struct clk *usbtll_ick; void __iomem *uhh_base; void __iomem *tll_base; @@ -349,13 +353,46 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) omap->platdata.ehci_data = pdata->ehci_data; omap->platdata.ohci_data = pdata->ohci_data; - pm_runtime_enable(&pdev->dev); + omap->usbhost_ick = clk_get(dev, "usbhost_ick"); + if (IS_ERR(omap->usbhost_ick)) { + ret = PTR_ERR(omap->usbhost_ick); + dev_err(dev, "usbhost_ick failed error:%d\n", ret); + goto err_end; + } + + omap->usbhost_hs_fck = clk_get(dev, "hs_fck"); + if (IS_ERR(omap->usbhost_hs_fck)) { + ret = PTR_ERR(omap->usbhost_hs_fck); + dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret); + goto err_usbhost_ick; + } + + omap->usbhost_fs_fck = clk_get(dev, "fs_fck"); + if (IS_ERR(omap->usbhost_fs_fck)) { + ret = PTR_ERR(omap->usbhost_fs_fck); + dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret); + goto err_usbhost_hs_fck; + } + + omap->usbtll_fck = clk_get(dev, "usbtll_fck"); + if (IS_ERR(omap->usbtll_fck)) { + ret = PTR_ERR(omap->usbtll_fck); + dev_err(dev, "usbtll_fck failed error:%d\n", ret); + goto err_usbhost_fs_fck; + } + + omap->usbtll_ick = clk_get(dev, "usbtll_ick"); + if (IS_ERR(omap->usbtll_ick)) { + ret = PTR_ERR(omap->usbtll_ick); + dev_err(dev, "usbtll_ick failed error:%d\n", ret); + goto err_usbtll_fck; + } omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); if (IS_ERR(omap->utmi_p1_fck)) { ret = PTR_ERR(omap->utmi_p1_fck); dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); - goto err_end; + goto err_usbtll_ick; } omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); @@ -485,8 +522,22 @@ err_xclk60mhsp1_ck: err_utmi_p1_fck: clk_put(omap->utmi_p1_fck); +err_usbtll_ick: + clk_put(omap->usbtll_ick); + +err_usbtll_fck: + clk_put(omap->usbtll_fck); + +err_usbhost_fs_fck: + clk_put(omap->usbhost_fs_fck); + +err_usbhost_hs_fck: + clk_put(omap->usbhost_hs_fck); + +err_usbhost_ick: + clk_put(omap->usbhost_ick); + err_end: - pm_runtime_disable(&pdev->dev); kfree(omap); end_probe: @@ -520,7 +571,11 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev) clk_put(omap->utmi_p2_fck); clk_put(omap->xclk60mhsp1_ck); clk_put(omap->utmi_p1_fck); - pm_runtime_disable(&pdev->dev); + clk_put(omap->usbtll_ick); + clk_put(omap->usbtll_fck); + clk_put(omap->usbhost_fs_fck); + clk_put(omap->usbhost_hs_fck); + clk_put(omap->usbhost_ick); kfree(omap); return 0; @@ -640,6 +695,7 @@ static int usbhs_enable(struct device *dev) struct usbhs_omap_platform_data *pdata = &omap->platdata; unsigned long flags = 0; int ret = 0; + unsigned long timeout; unsigned reg; dev_dbg(dev, "starting TI HSUSB Controller\n"); @@ -652,7 +708,11 @@ static int usbhs_enable(struct device *dev) if (omap->count > 0) goto end_count; - pm_runtime_get_sync(dev); + clk_enable(omap->usbhost_ick); + clk_enable(omap->usbhost_hs_fck); + clk_enable(omap->usbhost_fs_fck); + clk_enable(omap->usbtll_fck); + clk_enable(omap->usbtll_ick); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { @@ -676,6 +736,50 @@ static int usbhs_enable(struct device *dev) omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); + /* perform TLL soft reset, and wait until reset is complete */ + usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, + OMAP_USBTLL_SYSCONFIG_SOFTRESET); + + /* Wait for TLL reset to complete */ + timeout = jiffies + msecs_to_jiffies(1000); + while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) + & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { + cpu_relax(); + + if (time_after(jiffies, timeout)) { + dev_dbg(dev, "operation timed out\n"); + ret = -EINVAL; + goto err_tll; + } + } + + dev_dbg(dev, "TLL RESET DONE\n"); + + /* (1<<3) = no idle mode only for initial debugging */ + usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, + OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | + OMAP_USBTLL_SYSCONFIG_SIDLEMODE | + OMAP_USBTLL_SYSCONFIG_AUTOIDLE); + + /* Put UHH in NoIdle/NoStandby mode */ + reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG); + if (is_omap_usbhs_rev1(omap)) { + reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP + | OMAP_UHH_SYSCONFIG_SIDLEMODE + | OMAP_UHH_SYSCONFIG_CACTIVITY + | OMAP_UHH_SYSCONFIG_MIDLEMODE); + reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; + + + } else if (is_omap_usbhs_rev2(omap)) { + reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; + reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; + reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; + reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; + } + + usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); + reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN @@ -815,8 +919,6 @@ end_count: return 0; err_tll: - pm_runtime_put_sync(dev); - spin_unlock_irqrestore(&omap->lock, flags); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_free(pdata->ehci_data->reset_gpio_port[0]); @@ -824,6 +926,13 @@ err_tll: if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_free(pdata->ehci_data->reset_gpio_port[1]); } + + clk_disable(omap->usbtll_ick); + clk_disable(omap->usbtll_fck); + clk_disable(omap->usbhost_fs_fck); + clk_disable(omap->usbhost_hs_fck); + clk_disable(omap->usbhost_ick); + spin_unlock_irqrestore(&omap->lock, flags); return ret; } @@ -896,7 +1005,11 @@ static void usbhs_disable(struct device *dev) clk_disable(omap->utmi_p1_fck); } - pm_runtime_put_sync(dev); + clk_disable(omap->usbtll_ick); + clk_disable(omap->usbtll_fck); + clk_disable(omap->usbhost_fs_fck); + clk_disable(omap->usbhost_hs_fck); + clk_disable(omap->usbhost_ick); /* The gpio_free migh sleep; so unlock the spinlock */ spin_unlock_irqrestore(&omap->lock, flags); diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c index 3d2dc56a3d4..283ac675975 100644 --- a/drivers/mfd/tps65911-comparator.c +++ b/drivers/mfd/tps65911-comparator.c @@ -125,7 +125,7 @@ static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL); static __devinit int tps65911_comparator_probe(struct platform_device *pdev) { struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); - struct tps65910_platform_data *pdata = dev_get_platdata(tps65910->dev); + struct tps65910_board *pdata = dev_get_platdata(tps65910->dev); int ret; ret = comp_threshold_set(tps65910, COMP1, pdata->vmbch_threshold); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 2a7e43bc796..aa7d1d79b8c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -247,12 +247,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) return 0; /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ + card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { - int ext_csd_struct = ext_csd[EXT_CSD_STRUCTURE]; - if (ext_csd_struct > 2) { + if (card->ext_csd.raw_ext_csd_structure > 2) { printk(KERN_ERR "%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), - ext_csd_struct); + card->ext_csd.raw_ext_csd_structure); err = -EINVAL; goto out; } @@ -266,6 +266,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) goto out; } + card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0]; + card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1]; + card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2]; + card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3]; if (card->ext_csd.rev >= 2) { card->ext_csd.sectors = ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | @@ -277,7 +281,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) mmc_card_set_blockaddr(card); } - + card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: @@ -307,6 +311,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_hostname(card->host)); } + card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; + card->ext_csd.raw_erase_timeout_mult = + ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; + card->ext_csd.raw_hc_erase_grp_size = + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; @@ -334,6 +343,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; } + card->ext_csd.raw_hc_erase_gap_size = + ext_csd[EXT_CSD_PARTITION_ATTRIBUTE]; + card->ext_csd.raw_sec_trim_mult = + ext_csd[EXT_CSD_SEC_TRIM_MULT]; + card->ext_csd.raw_sec_erase_mult = + ext_csd[EXT_CSD_SEC_ERASE_MULT]; + card->ext_csd.raw_sec_feature_support = + ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; + card->ext_csd.raw_trim_mult = + ext_csd[EXT_CSD_TRIM_MULT]; if (card->ext_csd.rev >= 4) { /* * Enhanced area feature support -- check whether the eMMC @@ -341,7 +360,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) * area offset and size to user by adding sysfs interface. */ if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && - (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { + (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { u8 hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; u8 hc_wp_grp_sz = @@ -401,17 +420,17 @@ static inline void mmc_free_ext_csd(u8 *ext_csd) } -static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd, - unsigned bus_width) +static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) { u8 *bw_ext_csd; int err; + if (bus_width == MMC_BUS_WIDTH_1) + return 0; + err = mmc_get_ext_csd(card, &bw_ext_csd); - if (err) - return err; - if ((ext_csd == NULL || bw_ext_csd == NULL)) { + if (err || bw_ext_csd == NULL) { if (bus_width != MMC_BUS_WIDTH_1) err = -EINVAL; goto out; @@ -421,35 +440,40 @@ static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd, goto out; /* only compare read only fields */ - err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] == + err = (!(card->ext_csd.raw_partition_support == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && - (ext_csd[EXT_CSD_ERASED_MEM_CONT] == + (card->ext_csd.raw_erased_mem_count == bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && - (ext_csd[EXT_CSD_REV] == + (card->ext_csd.rev == bw_ext_csd[EXT_CSD_REV]) && - (ext_csd[EXT_CSD_STRUCTURE] == + (card->ext_csd.raw_ext_csd_structure == bw_ext_csd[EXT_CSD_STRUCTURE]) && - (ext_csd[EXT_CSD_CARD_TYPE] == + (card->ext_csd.raw_card_type == bw_ext_csd[EXT_CSD_CARD_TYPE]) && - (ext_csd[EXT_CSD_S_A_TIMEOUT] == + (card->ext_csd.raw_s_a_timeout == bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) && - (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == + (card->ext_csd.raw_hc_erase_gap_size == bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) && - (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == + (card->ext_csd.raw_erase_timeout_mult == bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) && - (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == + (card->ext_csd.raw_hc_erase_grp_size == bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && - (ext_csd[EXT_CSD_SEC_TRIM_MULT] == + (card->ext_csd.raw_sec_trim_mult == bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) && - (ext_csd[EXT_CSD_SEC_ERASE_MULT] == + (card->ext_csd.raw_sec_erase_mult == bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) && - (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == + (card->ext_csd.raw_sec_feature_support == bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) && - (ext_csd[EXT_CSD_TRIM_MULT] == + (card->ext_csd.raw_trim_mult == bw_ext_csd[EXT_CSD_TRIM_MULT]) && - memcmp(&ext_csd[EXT_CSD_SEC_CNT], - &bw_ext_csd[EXT_CSD_SEC_CNT], - 4) != 0); + (card->ext_csd.raw_sectors[0] == + bw_ext_csd[EXT_CSD_SEC_CNT + 0]) && + (card->ext_csd.raw_sectors[1] == + bw_ext_csd[EXT_CSD_SEC_CNT + 1]) && + (card->ext_csd.raw_sectors[2] == + bw_ext_csd[EXT_CSD_SEC_CNT + 2]) && + (card->ext_csd.raw_sectors[3] == + bw_ext_csd[EXT_CSD_SEC_CNT + 3])); if (err) err = -EINVAL; @@ -770,7 +794,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) err = mmc_compare_ext_csds(card, - ext_csd, bus_width); else err = mmc_bus_test(card, bus_width); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 7721de942c6..50f4f77ed20 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -582,6 +582,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, data->error = -EILSEQ; } else if (status & MCI_DATATIMEOUT) { data->error = -ETIMEDOUT; + } else if (status & MCI_STARTBITERR) { + data->error = -ECOMM; } else if (status & MCI_TXUNDERRUN) { data->error = -EIO; } else if (status & MCI_RXOVERRUN) { @@ -1061,7 +1063,15 @@ static int __devinit mmci_probe(struct amba_device *dev, } mmc->ops = &mmci_ops; - mmc->f_min = (host->mclk + 511) / 512; + /* + * The ARM and ST versions of the block have slightly different + * clock divider equations which means that the minimum divider + * differs too. + */ + if (variant->st_clkdiv) + mmc->f_min = DIV_ROUND_UP(host->mclk, 257); + else + mmc->f_min = DIV_ROUND_UP(host->mclk, 512); /* * If the platform data supplies a maximum operating * frequency, this takes precedence. Else, we fall back diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index bb32e21c09d..2164e8c6476 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -86,6 +86,7 @@ #define MCI_CMDRESPEND (1 << 6) #define MCI_CMDSENT (1 << 7) #define MCI_DATAEND (1 << 8) +#define MCI_STARTBITERR (1 << 9) #define MCI_DATABLOCKEND (1 << 10) #define MCI_CMDACTIVE (1 << 11) #define MCI_TXACTIVE (1 << 12) @@ -112,6 +113,7 @@ #define MCI_CMDRESPENDCLR (1 << 6) #define MCI_CMDSENTCLR (1 << 7) #define MCI_DATAENDCLR (1 << 8) +#define MCI_STARTBITERRCLR (1 << 9) #define MCI_DATABLOCKENDCLR (1 << 10) /* Extended status bits for the ST Micro variants */ #define MCI_ST_SDIOITC (1 << 22) @@ -127,6 +129,7 @@ #define MCI_CMDRESPENDMASK (1 << 6) #define MCI_CMDSENTMASK (1 << 7) #define MCI_DATAENDMASK (1 << 8) +#define MCI_STARTBITERRMASK (1 << 9) #define MCI_DATABLOCKENDMASK (1 << 10) #define MCI_CMDACTIVEMASK (1 << 11) #define MCI_TXACTIVEMASK (1 << 12) @@ -150,7 +153,7 @@ #define MCI_IRQENABLE \ (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ - MCI_CMDRESPENDMASK|MCI_CMDSENTMASK) + MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_STARTBITERRMASK) /* These interrupts are directed to IRQ1 when two IRQ lines are available */ #define MCI_IRQ1MASK \ diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 98517a37347..e3bad8247fd 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -992,6 +992,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, * features */ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA; + dev->vlan_features = dev->features; dev->irq = pdev->irq; diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c index 7d25a97d33f..44e219c910d 100644 --- a/drivers/net/bna/bnad.c +++ b/drivers/net/bna/bnad.c @@ -1111,7 +1111,7 @@ bnad_mbox_irq_alloc(struct bnad *bnad, struct bna_intr_info *intr_info) { int err = 0; - unsigned long flags; + unsigned long irq_flags = 0, flags; u32 irq; irq_handler_t irq_handler; @@ -1125,18 +1125,17 @@ bnad_mbox_irq_alloc(struct bnad *bnad, if (bnad->cfg_flags & BNAD_CF_MSIX) { irq_handler = (irq_handler_t)bnad_msix_mbox_handler; irq = bnad->msix_table[bnad->msix_num - 1].vector; - flags = 0; intr_info->intr_type = BNA_INTR_T_MSIX; intr_info->idl[0].vector = bnad->msix_num - 1; } else { irq_handler = (irq_handler_t)bnad_isr; irq = bnad->pcidev->irq; - flags = IRQF_SHARED; + irq_flags = IRQF_SHARED; intr_info->intr_type = BNA_INTR_T_INTX; /* intr_info->idl.vector = 0 ? */ } spin_unlock_irqrestore(&bnad->bna_lock, flags); - + flags = irq_flags; sprintf(bnad->mbox_irq_name, "%s", BNAD_NAME); /* diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index eafe44a528a..63c22b0bb5a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1428,9 +1428,9 @@ out: return features; } -#define BOND_VLAN_FEATURES (NETIF_F_ALL_TX_OFFLOADS | \ - NETIF_F_SOFT_FEATURES | \ - NETIF_F_LRO) +#define BOND_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \ + NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ + NETIF_F_HIGHDMA | NETIF_F_LRO) static void bond_compute_features(struct bonding *bond) { diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 2dfcc804784..dfa55f94ba7 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2289,6 +2289,23 @@ static int gfar_set_mac_address(struct net_device *dev) return 0; } +/* Check if rx parser should be activated */ +void gfar_check_rx_parser_mode(struct gfar_private *priv) +{ + struct gfar __iomem *regs; + u32 tempval; + + regs = priv->gfargrp[0].regs; + + tempval = gfar_read(®s->rctrl); + /* If parse is no longer required, then disable parser */ + if (tempval & RCTRL_REQ_PARSER) + tempval |= RCTRL_PRSDEP_INIT; + else + tempval &= ~RCTRL_PRSDEP_INIT; + gfar_write(®s->rctrl, tempval); +} + /* Enables and disables VLAN insertion/extraction */ static void gfar_vlan_rx_register(struct net_device *dev, @@ -2325,12 +2342,9 @@ static void gfar_vlan_rx_register(struct net_device *dev, /* Disable VLAN tag extraction */ tempval = gfar_read(®s->rctrl); tempval &= ~RCTRL_VLEX; - /* If parse is no longer required, then disable parser */ - if (tempval & RCTRL_REQ_PARSER) - tempval |= RCTRL_PRSDEP_INIT; - else - tempval &= ~RCTRL_PRSDEP_INIT; gfar_write(®s->rctrl, tempval); + + gfar_check_rx_parser_mode(priv); } gfar_change_mtu(dev, dev->mtu); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index ba36dc7a343..440e69d8bef 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -274,7 +274,7 @@ extern const char gfar_driver_version[]; #define RCTRL_PROM 0x00000008 #define RCTRL_EMEN 0x00000002 #define RCTRL_REQ_PARSER (RCTRL_VLEX | RCTRL_IPCSEN | \ - RCTRL_TUCSEN) + RCTRL_TUCSEN | RCTRL_FILREN) #define RCTRL_CHECKSUMMING (RCTRL_IPCSEN | RCTRL_TUCSEN | \ RCTRL_PRSDEP_INIT) #define RCTRL_EXTHASH (RCTRL_GHTX) @@ -1156,6 +1156,7 @@ extern void gfar_configure_coalescing(struct gfar_private *priv, unsigned long tx_mask, unsigned long rx_mask); void gfar_init_sysfs(struct net_device *dev); int gfar_set_features(struct net_device *dev, u32 features); +extern void gfar_check_rx_parser_mode(struct gfar_private *priv); extern const struct ethtool_ops gfar_ethtool_ops; diff --git a/drivers/net/greth.c b/drivers/net/greth.c index f181304a7ab..672f096fe09 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -1015,11 +1015,10 @@ static int greth_set_mac_add(struct net_device *dev, void *p) return -EINVAL; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + GRETH_REGSAVE(regs->esa_msb, dev->dev_addr[0] << 8 | dev->dev_addr[1]); + GRETH_REGSAVE(regs->esa_lsb, dev->dev_addr[2] << 24 | dev->dev_addr[3] << 16 | + dev->dev_addr[4] << 8 | dev->dev_addr[5]); - GRETH_REGSAVE(regs->esa_msb, addr->sa_data[0] << 8 | addr->sa_data[1]); - GRETH_REGSAVE(regs->esa_lsb, - addr->sa_data[2] << 24 | addr-> - sa_data[3] << 16 | addr->sa_data[4] << 8 | addr->sa_data[5]); return 0; } diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 3e5d0b6b651..0d283781bc5 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -692,10 +692,10 @@ static void sixpack_close(struct tty_struct *tty) { struct sixpack *sp; - write_lock(&disc_data_lock); + write_lock_bh(&disc_data_lock); sp = tty->disc_data; tty->disc_data = NULL; - write_unlock(&disc_data_lock); + write_unlock_bh(&disc_data_lock); if (!sp) return; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 4c628393c8b..bc02968cee1 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -813,10 +813,10 @@ static void mkiss_close(struct tty_struct *tty) { struct mkiss *ax; - write_lock(&disc_data_lock); + write_lock_bh(&disc_data_lock); ax = tty->disc_data; tty->disc_data = NULL; - write_unlock(&disc_data_lock); + write_unlock_bh(&disc_data_lock); if (!ax) return; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index b78be088c4a..60f46bc2bf6 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -140,7 +140,7 @@ MODULE_LICENSE("GPL"); module_param(mtu, int, 0); module_param(debug, int, 0); module_param(rx_copybreak, int, 0); -module_param(dspcfg_workaround, int, 1); +module_param(dspcfg_workaround, int, 0); module_param_array(options, int, NULL, 0); module_param_array(full_duplex, int, NULL, 0); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); @@ -2028,8 +2028,8 @@ static void drain_rx(struct net_device *dev) np->rx_ring[i].cmd_status = 0; np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (np->rx_skbuff[i]) { - pci_unmap_single(np->pci_dev, - np->rx_dma[i], buflen, + pci_unmap_single(np->pci_dev, np->rx_dma[i], + buflen + NATSEMI_PADDING, PCI_DMA_FROMDEVICE); dev_kfree_skb(np->rx_skbuff[i]); } @@ -2360,7 +2360,8 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) PCI_DMA_FROMDEVICE); } else { pci_unmap_single(np->pci_dev, np->rx_dma[entry], - buflen, PCI_DMA_FROMDEVICE); + buflen + NATSEMI_PADDING, + PCI_DMA_FROMDEVICE); skb_put(skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; } diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 718879b35b7..bc9a4bb3198 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -348,8 +348,9 @@ static int pppoe_device_event(struct notifier_block *this, /* Only look at sockets that are using this specific device. */ switch (event) { + case NETDEV_CHANGEADDR: case NETDEV_CHANGEMTU: - /* A change in mtu is a bad thing, requiring + /* A change in mtu or address is a bad thing, requiring * LCP re-negotiation. */ diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index d32850715f5..ca306fd5f58 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -16,7 +16,7 @@ */ #define DRV_NAME "qlge" #define DRV_STRING "QLogic 10 Gigabit PCI-E Ethernet Driver " -#define DRV_VERSION "v1.00.00.27.00.00-01" +#define DRV_VERSION "v1.00.00.29.00.00-01" #define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */ @@ -1996,6 +1996,7 @@ enum { QL_LB_LINK_UP = 10, QL_FRC_COREDUMP = 11, QL_EEH_FATAL = 12, + QL_ASIC_RECOVERY = 14, /* We are in ascic recovery. */ }; /* link_status bit definitions */ diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 930ae45457b..6b4ff970972 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2152,6 +2152,10 @@ void ql_queue_asic_error(struct ql_adapter *qdev) * thread */ clear_bit(QL_ADAPTER_UP, &qdev->flags); + /* Set asic recovery bit to indicate reset process that we are + * in fatal error recovery process rather than normal close + */ + set_bit(QL_ASIC_RECOVERY, &qdev->flags); queue_delayed_work(qdev->workqueue, &qdev->asic_reset_work, 0); } @@ -2166,23 +2170,20 @@ static void ql_process_chip_ae_intr(struct ql_adapter *qdev, return; case CAM_LOOKUP_ERR_EVENT: - netif_err(qdev, link, qdev->ndev, - "Multiple CAM hits lookup occurred.\n"); - netif_err(qdev, drv, qdev->ndev, - "This event shouldn't occur.\n"); + netdev_err(qdev->ndev, "Multiple CAM hits lookup occurred.\n"); + netdev_err(qdev->ndev, "This event shouldn't occur.\n"); ql_queue_asic_error(qdev); return; case SOFT_ECC_ERROR_EVENT: - netif_err(qdev, rx_err, qdev->ndev, - "Soft ECC error detected.\n"); + netdev_err(qdev->ndev, "Soft ECC error detected.\n"); ql_queue_asic_error(qdev); break; case PCI_ERR_ANON_BUF_RD: - netif_err(qdev, rx_err, qdev->ndev, - "PCI error occurred when reading anonymous buffers from rx_ring %d.\n", - ib_ae_rsp->q_id); + netdev_err(qdev->ndev, "PCI error occurred when reading " + "anonymous buffers from rx_ring %d.\n", + ib_ae_rsp->q_id); ql_queue_asic_error(qdev); break; @@ -2437,11 +2438,10 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) */ if (var & STS_FE) { ql_queue_asic_error(qdev); - netif_err(qdev, intr, qdev->ndev, - "Got fatal error, STS = %x.\n", var); + netdev_err(qdev->ndev, "Got fatal error, STS = %x.\n", var); var = ql_read32(qdev, ERR_STS); - netif_err(qdev, intr, qdev->ndev, - "Resetting chip. Error Status Register = 0x%x\n", var); + netdev_err(qdev->ndev, "Resetting chip. " + "Error Status Register = 0x%x\n", var); return IRQ_HANDLED; } @@ -3818,11 +3818,17 @@ static int ql_adapter_reset(struct ql_adapter *qdev) end_jiffies = jiffies + max((unsigned long)1, usecs_to_jiffies(30)); - /* Stop management traffic. */ - ql_mb_set_mgmnt_traffic_ctl(qdev, MB_SET_MPI_TFK_STOP); + /* Check if bit is set then skip the mailbox command and + * clear the bit, else we are in normal reset process. + */ + if (!test_bit(QL_ASIC_RECOVERY, &qdev->flags)) { + /* Stop management traffic. */ + ql_mb_set_mgmnt_traffic_ctl(qdev, MB_SET_MPI_TFK_STOP); - /* Wait for the NIC and MGMNT FIFOs to empty. */ - ql_wait_fifo_empty(qdev); + /* Wait for the NIC and MGMNT FIFOs to empty. */ + ql_wait_fifo_empty(qdev); + } else + clear_bit(QL_ASIC_RECOVERY, &qdev->flags); ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR); diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 200a363c3bf..0ffec460844 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -677,9 +677,11 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id) if (status & RX_FIFO_FULL) dev->stats.rx_fifo_errors++; - /* Mask off RX interrupt */ - misr &= ~RX_INTS; - napi_schedule(&lp->napi); + if (likely(napi_schedule_prep(&lp->napi))) { + /* Mask off RX interrupt */ + misr &= ~RX_INTS; + __napi_schedule(&lp->napi); + } } /* TX interrupt request */ diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 8a72a979ee7..1f3f7b4dd63 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -140,6 +140,8 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = { .tpauser = 1, .hw_swap = 1, .no_ade = 1, + .rpadir = 1, + .rpadir_value = 2 << 16, }; #define SH_GIGA_ETH_BASE 0xfee00000 @@ -1184,8 +1186,8 @@ static void sh_eth_adjust_link(struct net_device *ndev) mdp->cd->set_rate(ndev); } if (mdp->link == PHY_DOWN) { - sh_eth_write(ndev, (sh_eth_read(ndev, ECMR) & ~ECMR_TXF) - | ECMR_DM, ECMR); + sh_eth_write(ndev, + (sh_eth_read(ndev, ECMR) & ~ECMR_TXF), ECMR); new_state = 1; mdp->link = phydev->link; } diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 8ec1a9a0bb9..2f110fb30da 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -182,11 +182,11 @@ static int sl_alloc_bufs(struct slip *sl, int mtu) #ifdef SL_INCLUDE_CSLIP cbuff = xchg(&sl->cbuff, cbuff); slcomp = xchg(&sl->slcomp, slcomp); +#endif #ifdef CONFIG_SLIP_MODE_SLIP6 sl->xdata = 0; sl->xbits = 0; #endif -#endif spin_unlock_bh(&sl->lock); err = 0; diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 46851273196..9a21ca3873f 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -879,7 +879,6 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) txptr = db->tx_remove_ptr; while(db->tx_packet_cnt) { tdes0 = le32_to_cpu(txptr->tdes0); - pr_debug("tdes0=%x\n", tdes0); if (tdes0 & 0x80000000) break; @@ -889,7 +888,6 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) /* Transmit statistic counter */ if ( tdes0 != 0x7fffffff ) { - pr_debug("tdes0=%x\n", tdes0); dev->stats.collisions += (tdes0 >> 3) & 0xf; dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; if (tdes0 & TDES0_ERR_MASK) { @@ -986,7 +984,6 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) /* error summary bit check */ if (rdes0 & 0x8000) { /* This is a error packet */ - pr_debug("rdes0: %x\n", rdes0); dev->stats.rx_errors++; if (rdes0 & 1) dev->stats.rx_fifo_errors++; @@ -1638,7 +1635,6 @@ static u8 dmfe_sense_speed(struct dmfe_board_info * db) else /* DM9102/DM9102A */ phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000; - pr_debug("Phy_mode %x\n", phy_mode); switch (phy_mode) { case 0x1000: db->op_mode = DMFE_10MHF; break; case 0x2000: db->op_mode = DMFE_10MFD; break; diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 387ca43f26f..304fe78ff60 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2421,10 +2421,8 @@ static void hso_free_net_device(struct hso_device *hso_dev) remove_net_device(hso_net->parent); - if (hso_net->net) { + if (hso_net->net) unregister_netdev(hso_net->net); - free_netdev(hso_net->net); - } /* start freeing */ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { @@ -2436,6 +2434,9 @@ static void hso_free_net_device(struct hso_device *hso_dev) kfree(hso_net->mux_bulk_tx_buf); hso_net->mux_bulk_tx_buf = NULL; + if (hso_net->net) + free_netdev(hso_net->net); + kfree(hso_dev); } diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index fa6e2ac7475..67402350d0d 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -575,7 +575,7 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx, struct vmxnet3_cmd_ring *ring = &rq->rx_ring[ring_idx]; u32 val; - while (num_allocated < num_to_alloc) { + while (num_allocated <= num_to_alloc) { struct vmxnet3_rx_buf_info *rbi; union Vmxnet3_GenericDesc *gd; @@ -621,9 +621,15 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx, BUG_ON(rbi->dma_addr == 0); gd->rxd.addr = cpu_to_le64(rbi->dma_addr); - gd->dword[2] = cpu_to_le32((ring->gen << VMXNET3_RXD_GEN_SHIFT) + gd->dword[2] = cpu_to_le32((!ring->gen << VMXNET3_RXD_GEN_SHIFT) | val | rbi->len); + /* Fill the last buffer but dont mark it ready, or else the + * device will think that the queue is full */ + if (num_allocated == num_to_alloc) + break; + + gd->dword[2] |= cpu_to_le32(ring->gen << VMXNET3_RXD_GEN_SHIFT); num_allocated++; vmxnet3_cmd_ring_adv_next2fill(ring); } @@ -1140,6 +1146,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, VMXNET3_REG_RXPROD, VMXNET3_REG_RXPROD2 }; u32 num_rxd = 0; + bool skip_page_frags = false; struct Vmxnet3_RxCompDesc *rcd; struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx; #ifdef __BIG_ENDIAN_BITFIELD @@ -1150,11 +1157,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, &rxComp); while (rcd->gen == rq->comp_ring.gen) { struct vmxnet3_rx_buf_info *rbi; - struct sk_buff *skb; + struct sk_buff *skb, *new_skb = NULL; + struct page *new_page = NULL; int num_to_alloc; struct Vmxnet3_RxDesc *rxd; u32 idx, ring_idx; - + struct vmxnet3_cmd_ring *ring = NULL; if (num_rxd >= quota) { /* we may stop even before we see the EOP desc of * the current pkt @@ -1165,6 +1173,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2); idx = rcd->rxdIdx; ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1; + ring = rq->rx_ring + ring_idx; vmxnet3_getRxDesc(rxd, &rq->rx_ring[ring_idx].base[idx].rxd, &rxCmdDesc); rbi = rq->buf_info[ring_idx] + idx; @@ -1193,37 +1202,80 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, goto rcd_done; } + skip_page_frags = false; ctx->skb = rbi->skb; - rbi->skb = NULL; + new_skb = dev_alloc_skb(rbi->len + NET_IP_ALIGN); + if (new_skb == NULL) { + /* Skb allocation failed, do not handover this + * skb to stack. Reuse it. Drop the existing pkt + */ + rq->stats.rx_buf_alloc_failure++; + ctx->skb = NULL; + rq->stats.drop_total++; + skip_page_frags = true; + goto rcd_done; + } pci_unmap_single(adapter->pdev, rbi->dma_addr, rbi->len, PCI_DMA_FROMDEVICE); skb_put(ctx->skb, rcd->len); + + /* Immediate refill */ + new_skb->dev = adapter->netdev; + skb_reserve(new_skb, NET_IP_ALIGN); + rbi->skb = new_skb; + rbi->dma_addr = pci_map_single(adapter->pdev, + rbi->skb->data, rbi->len, + PCI_DMA_FROMDEVICE); + rxd->addr = cpu_to_le64(rbi->dma_addr); + rxd->len = rbi->len; + } else { - BUG_ON(ctx->skb == NULL); + BUG_ON(ctx->skb == NULL && !skip_page_frags); + /* non SOP buffer must be type 1 in most cases */ - if (rbi->buf_type == VMXNET3_RX_BUF_PAGE) { - BUG_ON(rxd->btype != VMXNET3_RXD_BTYPE_BODY); + BUG_ON(rbi->buf_type != VMXNET3_RX_BUF_PAGE); + BUG_ON(rxd->btype != VMXNET3_RXD_BTYPE_BODY); - if (rcd->len) { - pci_unmap_page(adapter->pdev, - rbi->dma_addr, rbi->len, - PCI_DMA_FROMDEVICE); + /* If an sop buffer was dropped, skip all + * following non-sop fragments. They will be reused. + */ + if (skip_page_frags) + goto rcd_done; - vmxnet3_append_frag(ctx->skb, rcd, rbi); - rbi->page = NULL; - } - } else { - /* - * The only time a non-SOP buffer is type 0 is - * when it's EOP and error flag is raised, which - * has already been handled. + new_page = alloc_page(GFP_ATOMIC); + if (unlikely(new_page == NULL)) { + /* Replacement page frag could not be allocated. + * Reuse this page. Drop the pkt and free the + * skb which contained this page as a frag. Skip + * processing all the following non-sop frags. */ - BUG_ON(true); + rq->stats.rx_buf_alloc_failure++; + dev_kfree_skb(ctx->skb); + ctx->skb = NULL; + skip_page_frags = true; + goto rcd_done; + } + + if (rcd->len) { + pci_unmap_page(adapter->pdev, + rbi->dma_addr, rbi->len, + PCI_DMA_FROMDEVICE); + + vmxnet3_append_frag(ctx->skb, rcd, rbi); } + + /* Immediate refill */ + rbi->page = new_page; + rbi->dma_addr = pci_map_page(adapter->pdev, rbi->page, + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + rxd->addr = cpu_to_le64(rbi->dma_addr); + rxd->len = rbi->len; } + skb = ctx->skb; if (rcd->eop) { skb->len += skb->data_len; @@ -1244,26 +1296,27 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, } rcd_done: - /* device may skip some rx descs */ - rq->rx_ring[ring_idx].next2comp = idx; - VMXNET3_INC_RING_IDX_ONLY(rq->rx_ring[ring_idx].next2comp, - rq->rx_ring[ring_idx].size); - - /* refill rx buffers frequently to avoid starving the h/w */ - num_to_alloc = vmxnet3_cmd_ring_desc_avail(rq->rx_ring + - ring_idx); - if (unlikely(num_to_alloc > VMXNET3_RX_ALLOC_THRESHOLD(rq, - ring_idx, adapter))) { - vmxnet3_rq_alloc_rx_buf(rq, ring_idx, num_to_alloc, - adapter); - - /* if needed, update the register */ - if (unlikely(rq->shared->updateRxProd)) { - VMXNET3_WRITE_BAR0_REG(adapter, - rxprod_reg[ring_idx] + rq->qid * 8, - rq->rx_ring[ring_idx].next2fill); - rq->uncommitted[ring_idx] = 0; - } + /* device may have skipped some rx descs */ + ring->next2comp = idx; + num_to_alloc = vmxnet3_cmd_ring_desc_avail(ring); + ring = rq->rx_ring + ring_idx; + while (num_to_alloc) { + vmxnet3_getRxDesc(rxd, &ring->base[ring->next2fill].rxd, + &rxCmdDesc); + BUG_ON(!rxd->addr); + + /* Recv desc is ready to be used by the device */ + rxd->gen = ring->gen; + vmxnet3_cmd_ring_adv_next2fill(ring); + num_to_alloc--; + } + + /* if needed, update the register */ + if (unlikely(rq->shared->updateRxProd)) { + VMXNET3_WRITE_BAR0_REG(adapter, + rxprod_reg[ring_idx] + rq->qid * 8, + ring->next2fill); + rq->uncommitted[ring_idx] = 0; } vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring); @@ -2894,6 +2947,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, else #endif num_rx_queues = 1; + num_rx_queues = rounddown_pow_of_two(num_rx_queues); if (enable_mq) num_tx_queues = min(VMXNET3_DEVICE_MAX_TX_QUEUES, @@ -2901,6 +2955,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, else num_tx_queues = 1; + num_tx_queues = rounddown_pow_of_two(num_tx_queues); netdev = alloc_etherdev_mq(sizeof(struct vmxnet3_adapter), max(num_tx_queues, num_rx_queues)); printk(KERN_INFO "# of Tx queues : %d, # of Rx queues : %d\n", @@ -3085,6 +3140,7 @@ vmxnet3_remove_device(struct pci_dev *pdev) else #endif num_rx_queues = 1; + num_rx_queues = rounddown_pow_of_two(num_rx_queues); cancel_work_sync(&adapter->work); diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index f50d36fdf40..e08d75e3f17 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -55,6 +55,7 @@ #include <linux/if_vlan.h> #include <linux/if_arp.h> #include <linux/inetdevice.h> +#include <linux/log2.h> #include "vmxnet3_defs.h" @@ -68,10 +69,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.1.9.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.1.18.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01010900 +#define VMXNET3_DRIVER_VERSION_NUM 0x01011200 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 62172d58572..f82383b3ed3 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -107,10 +107,13 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, case AR5K_PKT_TYPE_BEACON: case AR5K_PKT_TYPE_PROBE_RESP: frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; + break; case AR5K_PKT_TYPE_PIFS: frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; + break; default: frame_type = type; + break; } tx_ctl->tx_control_0 |= diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 1fef84f87c7..392771f9375 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -691,14 +691,12 @@ ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) if (!chinfo[pier].pd_curves) continue; - for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { + for (pdg = 0; pdg < AR5K_EEPROM_N_PD_CURVES; pdg++) { struct ath5k_pdgain_info *pd = &chinfo[pier].pd_curves[pdg]; - if (pd != NULL) { - kfree(pd->pd_step); - kfree(pd->pd_pwr); - } + kfree(pd->pd_step); + kfree(pd->pd_pwr); } kfree(chinfo[pier].pd_curves); diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 296c316a834..f2c0c236392 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -297,7 +297,9 @@ ath5k_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM_SLEEP static int ath5k_pci_suspend(struct device *dev) { - struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; ath5k_led_off(sc); return 0; @@ -306,7 +308,8 @@ static int ath5k_pci_suspend(struct device *dev) static int ath5k_pci_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct ath5k_softc *sc = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; /* * Suspend/Resume resets the PCI configuration space, so we have to diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c index 929c68cdf8a..a073cdce1f1 100644 --- a/drivers/net/wireless/ath/ath5k/sysfs.c +++ b/drivers/net/wireless/ath/ath5k/sysfs.c @@ -10,7 +10,8 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - struct ath5k_softc *sc = dev_get_drvdata(dev); \ + struct ieee80211_hw *hw = dev_get_drvdata(dev); \ + struct ath5k_softc *sc = hw->priv; \ return snprintf(buf, PAGE_SIZE, "%d\n", get); \ } \ \ @@ -18,7 +19,8 @@ static ssize_t ath5k_attr_store_##name(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct ath5k_softc *sc = dev_get_drvdata(dev); \ + struct ieee80211_hw *hw = dev_get_drvdata(dev); \ + struct ath5k_softc *sc = hw->priv; \ int val; \ \ val = (int)simple_strtoul(buf, NULL, 10); \ @@ -33,7 +35,8 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - struct ath5k_softc *sc = dev_get_drvdata(dev); \ + struct ieee80211_hw *hw = dev_get_drvdata(dev); \ + struct ath5k_softc *sc = hw->priv; \ return snprintf(buf, PAGE_SIZE, "%d\n", get); \ } \ static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index b8cbfc70721..3bad0b2cf9a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -278,6 +278,12 @@ static int ath_pci_suspend(struct device *device) ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); + /* The device has to be moved to FULLSLEEP forcibly. + * Otherwise the chip never moved to full sleep, + * when no interface is up. + */ + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3779b8977d4..33443bcaa8d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -671,7 +671,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, * TODO - this could be improved to be dependent on the rate. * The hardware can keep up at lower rates, but not higher rates */ - if (fi->keyix != ATH9K_TXKEYIX_INVALID) + if ((fi->keyix != ATH9K_TXKEYIX_INVALID) && + !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) ndelim += ATH_AGGR_ENCRYPTDELIM; /* diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 2fb53d06751..333b69ef2ae 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -112,6 +112,8 @@ static struct usb_device_id carl9170_usb_ids[] = { { USB_DEVICE(0x04bb, 0x093f) }, /* NEC WL300NU-G */ { USB_DEVICE(0x0409, 0x0249) }, + /* NEC WL300NU-AG */ + { USB_DEVICE(0x0409, 0x02b4) }, /* AVM FRITZ!WLAN USB Stick N */ { USB_DEVICE(0x057c, 0x8401) }, /* AVM FRITZ!WLAN USB Stick N 2.4 */ diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 61d4a11f566..2a88e73bb39 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -36,6 +36,7 @@ #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> +#include <linux/stringify.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -55,10 +56,10 @@ #define IWL100_UCODE_API_MIN 5 #define IWL1000_FW_PRE "iwlwifi-1000-" -#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" +#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode" #define IWL100_FW_PRE "iwlwifi-100-" -#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" +#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode" /* diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 2282279cffc..3df76f53a41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -36,6 +36,7 @@ #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> +#include <linux/stringify.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -58,13 +59,13 @@ #define IWL105_UCODE_API_MIN 5 #define IWL2030_FW_PRE "iwlwifi-2030-" -#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" +#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode" #define IWL2000_FW_PRE "iwlwifi-2000-" -#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" +#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode" #define IWL105_FW_PRE "iwlwifi-105-" -#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE #api ".ucode" +#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode" static void iwl2000_set_ct_threshold(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index f99f9c19335..e816c27db79 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -37,6 +37,7 @@ #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> +#include <linux/stringify.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -57,10 +58,10 @@ #define IWL5150_UCODE_API_MIN 1 #define IWL5000_FW_PRE "iwlwifi-5000-" -#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" +#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode" #define IWL5150_FW_PRE "iwlwifi-5150-" -#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" +#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode" /* NIC configuration for 5000 series */ static void iwl5000_nic_config(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index fbe565c816e..5b150bc70b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -36,6 +36,7 @@ #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> +#include <linux/stringify.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -58,16 +59,16 @@ #define IWL6000G2_UCODE_API_MIN 4 #define IWL6000_FW_PRE "iwlwifi-6000-" -#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" +#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode" #define IWL6050_FW_PRE "iwlwifi-6050-" -#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" +#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode" #define IWL6005_FW_PRE "iwlwifi-6000g2a-" -#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" +#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode" #define IWL6030_FW_PRE "iwlwifi-6000g2b-" -#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" +#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode" static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 213c80c6a66..45cc51c9c93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1763,6 +1763,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_context *tmp; + enum nl80211_iftype newviftype = newtype; u32 interface_modes; int err; @@ -1818,7 +1819,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* success */ iwl_teardown_interface(priv, vif, true); - vif->type = newtype; + vif->type = newviftype; vif->p2p = newp2p; err = iwl_setup_interface(priv, ctx); WARN_ON(err); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 686e176b5eb..137dba95b1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -126,7 +126,7 @@ static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) } static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta, - struct iwl_tfd *tfd) + struct iwl_tfd *tfd, int dma_dir) { struct pci_dev *dev = priv->pci_dev; int i; @@ -151,7 +151,7 @@ static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta, /* Unmap chunks, if any. */ for (i = 1; i < num_tbs; i++) pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i), - iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE); + iwl_tfd_tb_get_len(tfd, i), dma_dir); } /** @@ -167,7 +167,8 @@ void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) struct iwl_tfd *tfd_tmp = txq->tfds; int index = txq->q.read_ptr; - iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index]); + iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index], + PCI_DMA_TODEVICE); /* free SKB */ if (txq->txb) { @@ -310,9 +311,7 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv) i = get_cmd_index(q, q->read_ptr); if (txq->meta[i].flags & CMD_MAPPED) { - pci_unmap_single(priv->pci_dev, - dma_unmap_addr(&txq->meta[i], mapping), - dma_unmap_len(&txq->meta[i], len), + iwlagn_unmap_tfd(priv, &txq->meta[i], &txq->tfds[i], PCI_DMA_BIDIRECTIONAL); txq->meta[i].flags = 0; } @@ -535,12 +534,7 @@ out_free_arrays: void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, int slots_num, u32 txq_id) { - int actual_slots = slots_num; - - if (txq_id == priv->cmd_queue) - actual_slots++; - - memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots); + memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * slots_num); txq->need_update = 0; @@ -700,10 +694,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) continue; phys_addr = pci_map_single(priv->pci_dev, (void *)cmd->data[i], - cmd->len[i], PCI_DMA_TODEVICE); + cmd->len[i], PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(priv->pci_dev, phys_addr)) { iwlagn_unmap_tfd(priv, out_meta, - &txq->tfds[q->write_ptr]); + &txq->tfds[q->write_ptr], + PCI_DMA_BIDIRECTIONAL); idx = -ENOMEM; goto out; } @@ -807,7 +802,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; - iwlagn_unmap_tfd(priv, meta, &txq->tfds[index]); + iwlagn_unmap_tfd(priv, meta, &txq->tfds[index], PCI_DMA_BIDIRECTIONAL); /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 092e342c19d..942f7a3969a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -298,6 +298,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ + {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ {RTL_USB_DEVICE(0x0Df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/ /* HP - Lite-On ,8188CUS Slim Combo */ diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2c5b9b99127..692671b1166 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3483,6 +3483,8 @@ static int __init pci_setup(char *str) pci_no_msi(); } else if (!strcmp(str, "noaer")) { pci_no_aer(); + } else if (!strncmp(str, "realloc", 7)) { + pci_realloc(); } else if (!strcmp(str, "nodomains")) { pci_no_domains(); } else if (!strncmp(str, "cbiosize=", 9)) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 731e20265ac..3a39bf1f1e2 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -146,6 +146,8 @@ static inline void pci_no_msi(void) { } static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } #endif +extern void pci_realloc(void); + static inline int pci_no_d1d2(struct pci_dev *dev) { unsigned int parent_dstates = 0; diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 1e9e5a5b8c8..9995842e45b 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -47,6 +47,13 @@ struct resource_list_x { (head)->next = NULL; \ } while (0) +int pci_realloc_enable = 0; +#define pci_realloc_enabled() pci_realloc_enable +void pci_realloc(void) +{ + pci_realloc_enable = 1; +} + /** * add_to_list() - add a new resource tracker to the list * @head: Head of the list @@ -1025,6 +1032,7 @@ static int __init pci_get_max_depth(void) return depth; } + /* * first try will not touch pci bridge res * second and later try will clear small leaf bridge res @@ -1068,6 +1076,13 @@ again: /* any device complain? */ if (!head.next) goto enable_and_dump; + + /* don't realloc if asked to do so */ + if (!pci_realloc_enabled()) { + free_list(resource_list_x, &head); + goto enable_and_dump; + } + failed_type = 0; for (list = head.next; list;) { failed_type |= list->flags; diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c index 712baab3c83..e956f659089 100644 --- a/drivers/pcmcia/pxa2xx_vpac270.c +++ b/drivers/pcmcia/pxa2xx_vpac270.c @@ -76,10 +76,10 @@ static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { if (skt->nr == 0) - gpio_request_array(vpac270_pcmcia_gpios, + gpio_free_array(vpac270_pcmcia_gpios, ARRAY_SIZE(vpac270_pcmcia_gpios)); else - gpio_request_array(vpac270_cf_gpios, + gpio_free_array(vpac270_cf_gpios, ARRAY_SIZE(vpac270_cf_gpios)); } diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 005417bd429..e1c4938b301 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1156,9 +1156,9 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device) struct wmid3_gds_input_param params = { .function_num = 0x1, .hotkey_number = 0x01, - .devices = ACER_WMID3_GDS_WIRELESS & - ACER_WMID3_GDS_THREEG & - ACER_WMID3_GDS_WIMAX & + .devices = ACER_WMID3_GDS_WIRELESS | + ACER_WMID3_GDS_THREEG | + ACER_WMID3_GDS_WIMAX | ACER_WMID3_GDS_BLUETOOTH, }; struct acpi_buffer input = { @@ -1445,6 +1445,8 @@ static void acer_wmi_notify(u32 value, void *context) union acpi_object *obj; struct event_return_value return_value; acpi_status status; + u16 device_state; + const struct key_entry *key; status = wmi_get_event_data(value, &response); if (status != AE_OK) { @@ -1472,23 +1474,32 @@ static void acer_wmi_notify(u32 value, void *context) switch (return_value.function) { case WMID_HOTKEY_EVENT: - if (return_value.device_state) { - u16 device_state = return_value.device_state; - pr_debug("device state: 0x%x\n", device_state); - if (has_cap(ACER_CAP_WIRELESS)) - rfkill_set_sw_state(wireless_rfkill, - !(device_state & ACER_WMID3_GDS_WIRELESS)); - if (has_cap(ACER_CAP_BLUETOOTH)) - rfkill_set_sw_state(bluetooth_rfkill, - !(device_state & ACER_WMID3_GDS_BLUETOOTH)); - if (has_cap(ACER_CAP_THREEG)) - rfkill_set_sw_state(threeg_rfkill, - !(device_state & ACER_WMID3_GDS_THREEG)); - } - if (!sparse_keymap_report_event(acer_wmi_input_dev, - return_value.key_num, 1, true)) + device_state = return_value.device_state; + pr_debug("device state: 0x%x\n", device_state); + + key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev, + return_value.key_num); + if (!key) { pr_warn("Unknown key number - 0x%x\n", return_value.key_num); + } else { + switch (key->keycode) { + case KEY_WLAN: + case KEY_BLUETOOTH: + if (has_cap(ACER_CAP_WIRELESS)) + rfkill_set_sw_state(wireless_rfkill, + !(device_state & ACER_WMID3_GDS_WIRELESS)); + if (has_cap(ACER_CAP_THREEG)) + rfkill_set_sw_state(threeg_rfkill, + !(device_state & ACER_WMID3_GDS_THREEG)); + if (has_cap(ACER_CAP_BLUETOOTH)) + rfkill_set_sw_state(bluetooth_rfkill, + !(device_state & ACER_WMID3_GDS_BLUETOOTH)); + break; + } + sparse_keymap_report_entry(acer_wmi_input_dev, key, + 1, true); + } break; default: pr_warn("Unknown function number - %d - %d\n", diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 00460cb9587..3c7857c71a2 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1025,6 +1025,7 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus) return power; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = max; bd = backlight_device_register(asus->driver->name, &asus->platform_device->dev, asus, diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 3f204fde1b0..8877b836d27 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -1030,8 +1030,10 @@ static int __devinit compal_probe(struct platform_device *pdev) initialize_fan_control_data(data); err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group); - if (err) + if (err) { + kfree(data); return err; + } data->hwmon_dev = hwmon_device_register(&pdev->dev); if (IS_ERR(data->hwmon_dev)) { diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index d3841de6a8c..e39ab1d3ed8 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -292,12 +292,9 @@ static int dell_rfkill_set(void *data, bool blocked) dell_send_request(buffer, 17, 11); /* If the hardware switch controls this radio, and the hardware - switch is disabled, don't allow changing the software state. - If the hardware switch is reported as not supported, always - fire the SMI to toggle the killswitch. */ + switch is disabled, don't allow changing the software state */ if ((hwswitch_state & BIT(hwswitch_bit)) && - !(buffer->output[1] & BIT(16)) && - (buffer->output[1] & BIT(0))) { + !(buffer->output[1] & BIT(16))) { ret = -EINVAL; goto out; } @@ -403,23 +400,6 @@ static const struct file_operations dell_debugfs_fops = { static void dell_update_rfkill(struct work_struct *ignored) { - int status; - - get_buffer(); - dell_send_request(buffer, 17, 11); - status = buffer->output[1]; - release_buffer(); - - /* if hardware rfkill is not supported, set it explicitly */ - if (!(status & BIT(0))) { - if (wifi_rfkill) - dell_rfkill_set((void *)1, !((status & BIT(17)) >> 17)); - if (bluetooth_rfkill) - dell_rfkill_set((void *)2, !((status & BIT(18)) >> 18)); - if (wwan_rfkill) - dell_rfkill_set((void *)3, !((status & BIT(19)) >> 19)); - } - if (wifi_rfkill) dell_rfkill_query(wifi_rfkill, (void *)1); if (bluetooth_rfkill) @@ -560,11 +540,11 @@ static int dell_get_intensity(struct backlight_device *bd) else dell_send_request(buffer, 0, 1); + ret = buffer->output[1]; + out: release_buffer(); - if (ret) - return ret; - return buffer->output[1]; + return ret; } static const struct backlight_ops dell_ops = { diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index f94017bcdd6..e2faa3cbb79 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -207,6 +207,7 @@ static int hp_wmi_perform_query(int query, int write, void *buffer, }; struct acpi_buffer input = { sizeof(struct bios_args), &args }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + u32 rc; if (WARN_ON(insize > sizeof(args.data))) return -EINVAL; @@ -224,13 +225,13 @@ static int hp_wmi_perform_query(int query, int write, void *buffer, } bios_return = (struct bios_return *)obj->buffer.pointer; + rc = bios_return->return_code; - if (bios_return->return_code) { - if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE) - pr_warn("query 0x%x returned error 0x%x\n", - query, bios_return->return_code); + if (rc) { + if (rc != HPWMI_RET_UNKNOWN_CMDTYPE) + pr_warn("query 0x%x returned error 0x%x\n", query, rc); kfree(obj); - return bios_return->return_code; + return rc; } if (!outsize) { diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c index e936364a609..7f88c7923fc 100644 --- a/drivers/platform/x86/intel_oaktrail.c +++ b/drivers/platform/x86/intel_oaktrail.c @@ -250,6 +250,7 @@ static int oaktrail_backlight_init(void) struct backlight_properties props; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = OT_EC_BL_BRIGHTNESS_MAX; bd = backlight_device_register(DRIVER_NAME, &oaktrail_device->dev, NULL, diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 77f6e707a2a..26c5b117df2 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -184,6 +184,10 @@ enum tpacpi_hkey_event_t { /* Misc bay events */ TP_HKEY_EV_OPTDRV_EJ = 0x3006, /* opt. drive tray ejected */ + TP_HKEY_EV_HOTPLUG_DOCK = 0x4010, /* docked into hotplug dock + or port replicator */ + TP_HKEY_EV_HOTPLUG_UNDOCK = 0x4011, /* undocked from hotplug + dock or port replicator */ /* User-interface events */ TP_HKEY_EV_LID_CLOSE = 0x5001, /* laptop lid closed */ @@ -194,6 +198,10 @@ enum tpacpi_hkey_event_t { TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */ TP_HKEY_EV_BRGHT_CHANGED = 0x5010, /* backlight control event */ + /* Key-related user-interface events */ + TP_HKEY_EV_KEY_NUMLOCK = 0x6000, /* NumLock key pressed */ + TP_HKEY_EV_KEY_FN = 0x6005, /* Fn key pressed? E420 */ + /* Thermal events */ TP_HKEY_EV_ALARM_BAT_HOT = 0x6011, /* battery too hot */ TP_HKEY_EV_ALARM_BAT_XHOT = 0x6012, /* battery critically hot */ @@ -201,6 +209,10 @@ enum tpacpi_hkey_event_t { TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */ TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* thermal table changed */ + TP_HKEY_EV_UNK_6040 = 0x6040, /* Related to AC change? + some sort of APM hint, + W520 */ + /* Misc */ TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ }; @@ -3513,6 +3525,34 @@ static bool hotkey_notify_wakeup(const u32 hkey, return true; } +static bool hotkey_notify_dockevent(const u32 hkey, + bool *send_acpi_ev, + bool *ignore_acpi_ev) +{ + /* 0x4000-0x4FFF: dock-related events */ + *send_acpi_ev = true; + *ignore_acpi_ev = false; + + switch (hkey) { + case TP_HKEY_EV_UNDOCK_ACK: + /* ACPI undock operation completed after wakeup */ + hotkey_autosleep_ack = 1; + pr_info("undocked\n"); + hotkey_wakeup_hotunplug_complete_notify_change(); + return true; + + case TP_HKEY_EV_HOTPLUG_DOCK: /* docked to port replicator */ + pr_info("docked into hotplug port replicator\n"); + return true; + case TP_HKEY_EV_HOTPLUG_UNDOCK: /* undocked from port replicator */ + pr_info("undocked from hotplug port replicator\n"); + return true; + + default: + return false; + } +} + static bool hotkey_notify_usrevent(const u32 hkey, bool *send_acpi_ev, bool *ignore_acpi_ev) @@ -3547,13 +3587,13 @@ static bool hotkey_notify_usrevent(const u32 hkey, static void thermal_dump_all_sensors(void); -static bool hotkey_notify_thermal(const u32 hkey, +static bool hotkey_notify_6xxx(const u32 hkey, bool *send_acpi_ev, bool *ignore_acpi_ev) { bool known = true; - /* 0x6000-0x6FFF: thermal alarms */ + /* 0x6000-0x6FFF: thermal alarms/notices and keyboard events */ *send_acpi_ev = true; *ignore_acpi_ev = false; @@ -3582,8 +3622,17 @@ static bool hotkey_notify_thermal(const u32 hkey, "a sensor reports something is extremely hot!\n"); /* recommended action: immediate sleep/hibernate */ break; + + case TP_HKEY_EV_KEY_NUMLOCK: + case TP_HKEY_EV_KEY_FN: + /* key press events, we just ignore them as long as the EC + * is still reporting them in the normal keyboard stream */ + *send_acpi_ev = false; + *ignore_acpi_ev = true; + return true; + default: - pr_alert("THERMAL ALERT: unknown thermal alarm received\n"); + pr_warn("unknown possible thermal alarm or keyboard event received\n"); known = false; } @@ -3652,15 +3701,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) } break; case 4: - /* 0x4000-0x4FFF: dock-related wakeups */ - if (hkey == TP_HKEY_EV_UNDOCK_ACK) { - hotkey_autosleep_ack = 1; - pr_info("undocked\n"); - hotkey_wakeup_hotunplug_complete_notify_change(); - known_ev = true; - } else { - known_ev = false; - } + /* 0x4000-0x4FFF: dock-related events */ + known_ev = hotkey_notify_dockevent(hkey, &send_acpi_ev, + &ignore_acpi_ev); break; case 5: /* 0x5000-0x5FFF: human interface helpers */ @@ -3668,8 +3711,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) &ignore_acpi_ev); break; case 6: - /* 0x6000-0x6FFF: thermal alarms */ - known_ev = hotkey_notify_thermal(hkey, &send_acpi_ev, + /* 0x6000-0x6FFF: thermal alarms/notices and + * keyboard events */ + known_ev = hotkey_notify_6xxx(hkey, &send_acpi_ev, &ignore_acpi_ev); break; case 7: diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index e5f7b8fe51f..2bb8f451cc0 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -266,7 +266,7 @@ static struct regulator_ops db8500_regulator_switch_ops = { * Regulator information */ static struct db8500_regulator_info - db8500_regulator_info[DB8500_NUM_REGULATORS] = { +db8500_regulator_info[DB8500_NUM_REGULATORS] = { [DB8500_REGULATOR_VAPE] = { .desc = { .name = "db8500-vape", @@ -492,11 +492,9 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev) info->desc.name, err); /* if failing, unregister all earlier regulators */ - i--; - while (i >= 0) { + while (--i >= 0) { info = &db8500_regulator_info[i]; regulator_unregister(info->rdev); - i--; } return err; } @@ -536,13 +534,7 @@ static struct platform_driver db8500_regulator_driver = { static int __init db8500_regulator_init(void) { - int ret; - - ret = platform_driver_register(&db8500_regulator_driver); - if (ret < 0) - return -ENODEV; - - return 0; + return platform_driver_register(&db8500_regulator_driver); } static void __exit db8500_regulator_exit(void) diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index daff7fd0e95..486ed8141fc 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -139,7 +139,7 @@ static int max8952_set_voltage(struct regulator_dev *rdev, s8 vid = -1, i; if (!gpio_is_valid(max8952->pdata->gpio_vid0) || - !gpio_is_valid(max8952->pdata->gpio_vid0)) { + !gpio_is_valid(max8952->pdata->gpio_vid1)) { /* DVS not supported */ return -EPERM; } diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 10d5a1d9768..ad6628ca94f 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -39,25 +39,28 @@ struct max8997_data { struct regulator_dev **rdev; int ramp_delay; /* in mV/us */ + bool buck1_gpiodvs; + bool buck2_gpiodvs; + bool buck5_gpiodvs; u8 buck1_vol[8]; u8 buck2_vol[8]; u8 buck5_vol[8]; + int buck125_gpios[3]; int buck125_gpioindex; + bool ignore_gpiodvs_side_effect; u8 saved_states[MAX8997_REG_MAX]; }; static inline void max8997_set_gpio(struct max8997_data *max8997) { - struct max8997_platform_data *pdata = - dev_get_platdata(max8997->iodev->dev); int set3 = (max8997->buck125_gpioindex) & 0x1; int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1; int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1; - gpio_set_value(pdata->buck125_gpios[0], set1); - gpio_set_value(pdata->buck125_gpios[1], set2); - gpio_set_value(pdata->buck125_gpios[2], set3); + gpio_set_value(max8997->buck125_gpios[0], set1); + gpio_set_value(max8997->buck125_gpios[1], set2); + gpio_set_value(max8997->buck125_gpios[2], set3); } struct voltage_map_desc { @@ -380,8 +383,6 @@ static int max8997_get_voltage_register(struct regulator_dev *rdev, static int max8997_get_voltage(struct regulator_dev *rdev) { struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct max8997_platform_data *pdata = - dev_get_platdata(max8997->iodev->dev); struct i2c_client *i2c = max8997->iodev->i2c; int reg, shift, mask, ret; int rid = max8997_get_rid(rdev); @@ -391,9 +392,9 @@ static int max8997_get_voltage(struct regulator_dev *rdev) if (ret) return ret; - if ((rid == MAX8997_BUCK1 && pdata->buck1_gpiodvs) || - (rid == MAX8997_BUCK2 && pdata->buck2_gpiodvs) || - (rid == MAX8997_BUCK5 && pdata->buck5_gpiodvs)) + if ((rid == MAX8997_BUCK1 && max8997->buck1_gpiodvs) || + (rid == MAX8997_BUCK2 && max8997->buck2_gpiodvs) || + (rid == MAX8997_BUCK5 && max8997->buck5_gpiodvs)) reg += max8997->buck125_gpioindex; ret = max8997_read_reg(i2c, reg, &val); @@ -543,7 +544,8 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, rid == MAX8997_BUCK4 || rid == MAX8997_BUCK5) { /* If the voltage is increasing */ if (org < i) - udelay(desc->step * (i - org) / max8997->ramp_delay); + udelay(DIV_ROUND_UP(desc->step * (i - org), + max8997->ramp_delay)); } return ret; @@ -561,8 +563,6 @@ static int max8997_assess_side_effect(struct regulator_dev *rdev, u8 new_val, int *best) { struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct max8997_platform_data *pdata = - dev_get_platdata(max8997->iodev->dev); int rid = max8997_get_rid(rdev); u8 *buckx_val[3]; bool buckx_gpiodvs[3]; @@ -589,9 +589,9 @@ static int max8997_assess_side_effect(struct regulator_dev *rdev, buckx_val[0] = max8997->buck1_vol; buckx_val[1] = max8997->buck2_vol; buckx_val[2] = max8997->buck5_vol; - buckx_gpiodvs[0] = pdata->buck1_gpiodvs; - buckx_gpiodvs[1] = pdata->buck2_gpiodvs; - buckx_gpiodvs[2] = pdata->buck5_gpiodvs; + buckx_gpiodvs[0] = max8997->buck1_gpiodvs; + buckx_gpiodvs[1] = max8997->buck2_gpiodvs; + buckx_gpiodvs[2] = max8997->buck5_gpiodvs; for (i = 0; i < 8; i++) { int others; @@ -640,8 +640,6 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { struct max8997_data *max8997 = rdev_get_drvdata(rdev); - struct max8997_platform_data *pdata = - dev_get_platdata(max8997->iodev->dev); int rid = max8997_get_rid(rdev); const struct voltage_map_desc *desc; int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; @@ -653,15 +651,15 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, switch (rid) { case MAX8997_BUCK1: - if (pdata->buck1_gpiodvs) + if (max8997->buck1_gpiodvs) gpio_dvs_mode = true; break; case MAX8997_BUCK2: - if (pdata->buck2_gpiodvs) + if (max8997->buck2_gpiodvs) gpio_dvs_mode = true; break; case MAX8997_BUCK5: - if (pdata->buck5_gpiodvs) + if (max8997->buck5_gpiodvs) gpio_dvs_mode = true; break; } @@ -695,7 +693,7 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, new_idx = tmp_idx; new_val = tmp_val; - if (pdata->ignore_gpiodvs_side_effect == false) + if (max8997->ignore_gpiodvs_side_effect == false) return -EINVAL; dev_warn(&rdev->dev, "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:" @@ -993,6 +991,11 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) i2c = max8997->iodev->i2c; max8997->buck125_gpioindex = pdata->buck125_default_idx; + max8997->buck1_gpiodvs = pdata->buck1_gpiodvs; + max8997->buck2_gpiodvs = pdata->buck2_gpiodvs; + max8997->buck5_gpiodvs = pdata->buck5_gpiodvs; + memcpy(max8997->buck125_gpios, pdata->buck125_gpios, sizeof(int) * 3); + max8997->ignore_gpiodvs_side_effect = pdata->ignore_gpiodvs_side_effect; for (i = 0; i < 8; i++) { max8997->buck1_vol[i] = ret = @@ -1124,6 +1127,10 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) 0x3f); } + /* Misc Settings */ + max8997->ramp_delay = 10; /* set 10mV/us, which is the default */ + max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9); + for (i = 0; i < pdata->num_regulators; i++) { const struct voltage_map_desc *desc; int id = pdata->regulators[i].id; @@ -1148,10 +1155,6 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) } } - /* Misc Settings */ - max8997->ramp_delay = 10; /* set 10mV/us, which is the default */ - max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9); - return 0; err: for (i = 0; i < max8997->num_regulators; i++) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 795828b90f4..8945e201e42 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -116,9 +116,7 @@ (((i)->fifo_lvl_mask + 1))) \ ? 1 : 0) -#define S3C64XX_SPI_ST_TX_DONE(v, i) ((((v) >> (i)->rx_lvl_offset) & \ - (((i)->fifo_lvl_mask + 1) << 1)) \ - ? 1 : 0) +#define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & (1 << (i)->tx_st_done)) ? 1 : 0) #define TX_FIFO_LVL(v, i) (((v) >> 6) & (i)->fifo_lvl_mask) #define RX_FIFO_LVL(v, i) (((v) >> (i)->rx_lvl_offset) & (i)->fifo_lvl_mask) diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 2a20dabec76..d6620ad309c 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -516,8 +516,17 @@ static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) { + ssb_pcicore_fix_sprom_core_index(pc); + /* Disable PCI interrupts. */ ssb_write32(pc->dev, SSB_INTVEC, 0); + + /* Additional PCIe always once-executed workarounds */ + if (pc->dev->id.coreid == SSB_DEV_PCIE) { + ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + /* TODO: Clock Request Update */ + } } void ssb_pcicore_init(struct ssb_pcicore *pc) @@ -529,8 +538,6 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) if (!ssb_device_is_enabled(dev)) ssb_device_enable(dev, 0); - ssb_pcicore_fix_sprom_core_index(pc); - #ifdef CONFIG_SSB_PCICORE_HOSTMODE pc->hostmode = pcicore_is_in_hostmode(pc); if (pc->hostmode) @@ -538,13 +545,6 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ if (!pc->hostmode) ssb_pcicore_init_clientmode(pc); - - /* Additional PCIe always once-executed workarounds */ - if (dev->id.coreid == SSB_DEV_PCIE) { - ssb_pcicore_serdes_workaround(pc); - /* TODO: ASPM */ - /* TODO: Clock Request Update */ - } } static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c index 4039eda2a15..4a9e563f40f 100644 --- a/drivers/staging/lirc/lirc_imon.c +++ b/drivers/staging/lirc/lirc_imon.c @@ -672,8 +672,6 @@ static void imon_incoming_packet(struct imon_context *context, static void usb_rx_callback(struct urb *urb) { struct imon_context *context; - unsigned char *buf; - int len; int intfnum = 0; if (!urb) @@ -683,9 +681,6 @@ static void usb_rx_callback(struct urb *urb) if (!context) return; - buf = urb->transfer_buffer; - len = urb->actual_length; - switch (urb->status) { case -ENOENT: /* usbcore unlink successful! */ return; @@ -728,7 +723,6 @@ static int imon_probe(struct usb_interface *interface, int ir_ep_found = 0; int alloc_status = 0; int vfd_proto_6p = 0; - int code_length; struct imon_context *context = NULL; int i; u16 vendor, product; @@ -749,8 +743,6 @@ static int imon_probe(struct usb_interface *interface, else context->display = 1; - code_length = BUF_CHUNK_SIZE * 8; - usbdev = usb_get_dev(interface_to_usbdev(interface)); iface_desc = interface->cur_altsetting; num_endpts = iface_desc->desc.bNumEndpoints; @@ -856,7 +848,7 @@ static int imon_probe(struct usb_interface *interface, strcpy(driver->name, MOD_NAME); driver->minor = -1; - driver->code_length = sizeof(int) * 8; + driver->code_length = BUF_CHUNK_SIZE * 8; driver->sample_rate = 0; driver->features = LIRC_CAN_REC_MODE2; driver->data = context; diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c index 4a3cca03224..805df913bb6 100644 --- a/drivers/staging/lirc/lirc_serial.c +++ b/drivers/staging/lirc/lirc_serial.c @@ -838,7 +838,23 @@ static int hardware_init_port(void) static int init_port(void) { - int i, nlow, nhigh; + int i, nlow, nhigh, result; + + result = request_irq(irq, irq_handler, + IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0), + LIRC_DRIVER_NAME, (void *)&hardware); + + switch (result) { + case -EBUSY: + printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); + return -EBUSY; + case -EINVAL: + printk(KERN_ERR LIRC_DRIVER_NAME + ": Bad irq number or handler\n"); + return -EINVAL; + default: + break; + }; /* Reserve io region. */ /* @@ -893,34 +909,17 @@ static int init_port(void) printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " "%s receiver\n", sense ? "low" : "high"); + dprintk("Interrupt %d, port %04x obtained\n", irq, io); return 0; } static int set_use_inc(void *data) { - int result; unsigned long flags; /* initialize timestamp */ do_gettimeofday(&lasttv); - result = request_irq(irq, irq_handler, - IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0), - LIRC_DRIVER_NAME, (void *)&hardware); - - switch (result) { - case -EBUSY: - printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); - return -EBUSY; - case -EINVAL: - printk(KERN_ERR LIRC_DRIVER_NAME - ": Bad irq number or handler\n"); - return -EINVAL; - default: - dprintk("Interrupt %d, port %04x obtained\n", irq, io); - break; - } - spin_lock_irqsave(&hardware[type].lock, flags); /* Set DLAB 0. */ @@ -945,10 +944,6 @@ static void set_use_dec(void *data) soutp(UART_IER, sinp(UART_IER) & (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); spin_unlock_irqrestore(&hardware[type].lock, flags); - - free_irq(irq, (void *)&hardware); - - dprintk("freed IRQ %d\n", irq); } static ssize_t lirc_write(struct file *file, const char *buf, @@ -1256,6 +1251,9 @@ exit_serial_exit: static void __exit lirc_serial_exit_module(void) { lirc_serial_exit(); + + free_irq(irq, (void *)&hardware); + if (iommap != 0) release_mem_region(iommap, 8 << ioshift); else diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c index a7b46f24f24..0d3864594b1 100644 --- a/drivers/staging/lirc/lirc_sir.c +++ b/drivers/staging/lirc/lirc_sir.c @@ -739,23 +739,16 @@ static void send_space(unsigned long len) static void send_pulse(unsigned long len) { long bytes_out = len / TIME_CONST; - long time_left; - time_left = (long)len - (long)bytes_out * (long)TIME_CONST; - if (bytes_out == 0) { + if (bytes_out == 0) bytes_out++; - time_left = 0; - } + while (bytes_out--) { outb(PULSE, io + UART_TX); /* FIXME treba seriozne cakanie z char/serial.c */ while (!(inb(io + UART_LSR) & UART_LSR_THRE)) ; } -#if 0 - if (time_left > 0) - safe_udelay(time_left); -#endif } #endif diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index dd6a57c3c3a..4e051f6b52d 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -475,14 +475,14 @@ static int lirc_thread(void *arg) dprintk("poll thread started\n"); while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + /* if device not opened, we can sleep half a second */ if (atomic_read(&ir->open_count) == 0) { schedule_timeout(HZ/2); continue; } - set_current_state(TASK_INTERRUPTIBLE); - /* * This is ~113*2 + 24 + jitter (2*repeat gap + code length). * We use this interval as the chip resets every time you poll diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 64c7ab4702d..0b5ec234c78 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1147,6 +1147,14 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) * any drivers bound to them (a key side effect) */ if (dev->actconfig) { + /* + * FIXME: In order to avoid self-deadlock involving the + * bandwidth_mutex, we have to mark all the interfaces + * before unregistering any of them. + */ + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) + dev->actconfig->interface[i]->unregistering = 1; + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *interface; @@ -1156,7 +1164,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) continue; dev_dbg(&dev->dev, "unregistering interface %s\n", dev_name(&interface->dev)); - interface->unregistering = 1; remove_intf_ep_devs(interface); device_del(&interface->dev); } @@ -1286,6 +1293,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) interface); return -EINVAL; } + if (iface->unregistering) + return -ENODEV; alt = usb_altnum_to_altsetting(iface, alternate); if (!alt) { diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 2cd9a60c7f3..4e483316808 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -46,7 +46,6 @@ #include <asm/system.h> #include <asm/unaligned.h> #include <asm/dma.h> -#include <asm/cacheflush.h> #include "fsl_usb2_udc.h" @@ -118,6 +117,17 @@ static void (*_fsl_writel)(u32 v, unsigned __iomem *p); #define fsl_readl(p) (*_fsl_readl)((p)) #define fsl_writel(v, p) (*_fsl_writel)((v), (p)) +static inline void fsl_set_accessors(struct fsl_usb2_platform_data *pdata) +{ + if (pdata->big_endian_mmio) { + _fsl_readl = _fsl_readl_be; + _fsl_writel = _fsl_writel_be; + } else { + _fsl_readl = _fsl_readl_le; + _fsl_writel = _fsl_writel_le; + } +} + static inline u32 cpu_to_hc32(const u32 x) { return udc_controller->pdata->big_endian_desc @@ -132,6 +142,8 @@ static inline u32 hc32_to_cpu(const u32 x) : le32_to_cpu((__force __le32)x); } #else /* !CONFIG_PPC32 */ +static inline void fsl_set_accessors(struct fsl_usb2_platform_data *pdata) {} + #define fsl_readl(addr) readl(addr) #define fsl_writel(val32, addr) writel(val32, addr) #define cpu_to_hc32(x) cpu_to_le32(x) @@ -1277,6 +1289,11 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction) req->req.complete = NULL; req->dtd_count = 0; + req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, + req->req.buf, req->req.length, + ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + if (fsl_req_to_dtd(req) == 0) fsl_queue_td(ep, req); else @@ -1348,9 +1365,6 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, /* Fill in the reqest structure */ *((u16 *) req->req.buf) = cpu_to_le16(tmp); - /* flush cache for the req buffer */ - flush_dcache_range((u32)req->req.buf, (u32)req->req.buf + 8); - req->ep = ep; req->req.length = 2; req->req.status = -EINPROGRESS; @@ -1358,6 +1372,11 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, req->req.complete = NULL; req->dtd_count = 0; + req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, + req->req.buf, req->req.length, + ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + /* prime the data phase */ if ((fsl_req_to_dtd(req) == 0)) fsl_queue_td(ep, req); @@ -2354,7 +2373,6 @@ static int __init struct_udc_setup(struct fsl_udc *udc, struct fsl_req, req); /* allocate a small amount of memory to get valid address */ udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); - udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf); udc->resume_state = USB_STATE_NOTATTACHED; udc->usb_state = USB_STATE_POWERED; @@ -2470,13 +2488,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) } /* Set accessors only after pdata->init() ! */ - if (pdata->big_endian_mmio) { - _fsl_readl = _fsl_readl_be; - _fsl_writel = _fsl_writel_be; - } else { - _fsl_readl = _fsl_readl_le; - _fsl_writel = _fsl_writel_le; - } + fsl_set_accessors(pdata); #ifndef CONFIG_ARCH_MXC if (pdata->have_sysif_regs) diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index ad57593d224..a0c8965c1a7 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -109,6 +109,7 @@ struct ds1wm_data { /* byte to write that makes all intr disabled, */ /* considering active_state (IAS) (optimization) */ u8 int_en_reg_none; + unsigned int reset_recover_delay; /* see ds1wm.h */ }; static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg, @@ -187,6 +188,9 @@ static int ds1wm_reset(struct ds1wm_data *ds1wm_data) return 1; } + if (ds1wm_data->reset_recover_delay) + msleep(ds1wm_data->reset_recover_delay); + return 0; } @@ -490,6 +494,7 @@ static int ds1wm_probe(struct platform_device *pdev) } ds1wm_data->irq = res->start; ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0); + ds1wm_data->reset_recover_delay = plat->reset_recover_delay; if (res->flags & IORESOURCE_IRQ_HIGHEDGE) irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9536d386bb3..21d816e9dfa 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -599,8 +599,7 @@ config IT87_WDT config HP_WATCHDOG tristate "HP ProLiant iLO2+ Hardware Watchdog Timer" - depends on X86 - default m + depends on X86 && PCI help A software monitoring watchdog and NMI sourcing driver. This driver will detect lockups and provide a stack trace. This is a driver that diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 63039ed9576..2bc5dc644b4 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1864,6 +1864,7 @@ cleanup: kfree(psinfo); kfree(notes); kfree(fpu); + kfree(shdr4extnum); #ifdef ELF_CORE_COPY_XFPREGS kfree(xfpu); #endif diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f30ac05dbda..3b859a3e6a0 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1335,6 +1335,11 @@ struct btrfs_ioctl_defrag_range_args { */ #define BTRFS_STRING_ITEM_KEY 253 +/* + * Flags for mount options. + * + * Note: don't forget to add new options to btrfs_show_options() + */ #define BTRFS_MOUNT_NODATASUM (1 << 0) #define BTRFS_MOUNT_NODATACOW (1 << 1) #define BTRFS_MOUNT_NOBARRIER (1 << 2) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d340f63d8f0..3601f0aebdd 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2678,12 +2678,14 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, int ret; /* - * If root is tree root, it means this inode is used to - * store free space information. And these inodes are updated - * when committing the transaction, so they needn't delaye to - * be updated, or deadlock will occured. + * If the inode is a free space inode, we can deadlock during commit + * if we put it into the delayed code. + * + * The data relocation inode should also be directly updated + * without delay */ - if (!is_free_space_inode(root, inode)) { + if (!is_free_space_inode(root, inode) + && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) { ret = btrfs_delayed_update_inode(trans, root, inode); if (!ret) btrfs_set_inode_last_trans(trans, inode); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 0bb4ebbb71b..15634d4648d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -723,6 +723,12 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) seq_puts(seq, ",clear_cache"); if (btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED)) seq_puts(seq, ",user_subvol_rm_allowed"); + if (btrfs_test_opt(root, ENOSPC_DEBUG)) + seq_puts(seq, ",enospc_debug"); + if (btrfs_test_opt(root, AUTO_DEFRAG)) + seq_puts(seq, ",autodefrag"); + if (btrfs_test_opt(root, INODE_MAP_CACHE)) + seq_puts(seq, ",inode_cache"); return 0; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1efa56e18f9..19450bc5363 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2098,7 +2098,8 @@ int btrfs_balance(struct btrfs_root *dev_root) chunk_root->root_key.objectid, found_key.objectid, found_key.offset); - BUG_ON(ret && ret != -ENOSPC); + if (ret && ret != -ENOSPC) + goto error; key.offset = found_key.offset - 1; } ret = 0; diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 9542f07d0b9..4698a5c553d 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -290,7 +290,6 @@ static int striped_read(struct inode *inode, struct ceph_inode_info *ci = ceph_inode(inode); u64 pos, this_len; int io_align, page_align; - int page_off = off & ~PAGE_CACHE_MASK; /* first byte's offset in page */ int left, pages_left; int read; struct page **page_pos; @@ -326,12 +325,11 @@ more: ret, hit_stripe ? " HITSTRIPE" : "", was_short ? " SHORT" : ""); if (ret > 0) { - int didpages = - ((pos & ~PAGE_CACHE_MASK) + ret) >> PAGE_CACHE_SHIFT; + int didpages = (page_align + ret) >> PAGE_CACHE_SHIFT; if (read < pos - off) { dout(" zero gap %llu to %llu\n", off + read, pos); - ceph_zero_page_vector_range(page_off + read, + ceph_zero_page_vector_range(page_align + read, pos - off - read, pages); } pos += ret; @@ -356,7 +354,7 @@ more: left = inode->i_size - pos; dout("zero tail %d\n", left); - ceph_zero_page_vector_range(page_off + read, left, + ceph_zero_page_vector_range(page_align + read, left, pages); read += left; } @@ -478,9 +476,6 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, else pos = *offset; - io_align = pos & ~PAGE_MASK; - buf_align = (unsigned long)data & ~PAGE_MASK; - ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left); if (ret < 0) return ret; @@ -504,6 +499,8 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, * boundary. this isn't atomic, unfortunately. :( */ more: + io_align = pos & ~PAGE_MASK; + buf_align = (unsigned long)data & ~PAGE_MASK; len = left; if (file->f_flags & O_DIRECT) { /* write from beginning of first page, regardless of @@ -593,6 +590,7 @@ out: pos += len; written += len; left -= len; + data += written; if (left) goto more; diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 79743d146be..0c1d9175652 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1438,12 +1438,15 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base, struct dentry *temp; char *path; int len, pos; + unsigned seq; if (dentry == NULL) return ERR_PTR(-EINVAL); retry: len = 0; + seq = read_seqbegin(&rename_lock); + rcu_read_lock(); for (temp = dentry; !IS_ROOT(temp);) { struct inode *inode = temp->d_inode; if (inode && ceph_snap(inode) == CEPH_SNAPDIR) @@ -1455,10 +1458,12 @@ retry: len += 1 + temp->d_name.len; temp = temp->d_parent; if (temp == NULL) { + rcu_read_unlock(); pr_err("build_path corrupt dentry %p\n", dentry); return ERR_PTR(-EINVAL); } } + rcu_read_unlock(); if (len) len--; /* no leading '/' */ @@ -1467,9 +1472,12 @@ retry: return ERR_PTR(-ENOMEM); pos = len; path[pos] = 0; /* trailing null */ + rcu_read_lock(); for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) { - struct inode *inode = temp->d_inode; + struct inode *inode; + spin_lock(&temp->d_lock); + inode = temp->d_inode; if (inode && ceph_snap(inode) == CEPH_SNAPDIR) { dout("build_path path+%d: %p SNAPDIR\n", pos, temp); @@ -1478,21 +1486,26 @@ retry: break; } else { pos -= temp->d_name.len; - if (pos < 0) + if (pos < 0) { + spin_unlock(&temp->d_lock); break; + } strncpy(path + pos, temp->d_name.name, temp->d_name.len); } + spin_unlock(&temp->d_lock); if (pos) path[--pos] = '/'; temp = temp->d_parent; if (temp == NULL) { + rcu_read_unlock(); pr_err("build_path corrupt dentry\n"); kfree(path); return ERR_PTR(-EINVAL); } } - if (pos != 0) { + rcu_read_unlock(); + if (pos != 0 || read_seqretry(&rename_lock, seq)) { pr_err("build_path did not end path lookup where " "expected, namelen is %d, pos is %d\n", len, pos); /* presumably this is only possible if racing with a diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 35f9154615f..bc4b12ca537 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -35,6 +35,7 @@ #include <linux/delay.h> #include <linux/kthread.h> #include <linux/freezer.h> +#include <linux/namei.h> #include <net/ipv6.h> #include "cifsfs.h" #include "cifspdu.h" @@ -542,14 +543,12 @@ static const struct super_operations cifs_super_ops = { static struct dentry * cifs_get_root(struct smb_vol *vol, struct super_block *sb) { - int xid, rc; - struct inode *inode; - struct qstr name; - struct dentry *dparent = NULL, *dchild = NULL, *alias; + struct dentry *dentry; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - unsigned int i, full_len, len; - char *full_path = NULL, *pstart; + char *full_path = NULL; + char *s, *p; char sep; + int xid; full_path = cifs_build_path_to_root(vol, cifs_sb, cifs_sb_master_tcon(cifs_sb)); @@ -560,73 +559,32 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) xid = GetXid(); sep = CIFS_DIR_SEP(cifs_sb); - dparent = dget(sb->s_root); - full_len = strlen(full_path); - full_path[full_len] = sep; - pstart = full_path + 1; - - for (i = 1, len = 0; i <= full_len; i++) { - if (full_path[i] != sep || !len) { - len++; - continue; - } - - full_path[i] = 0; - cFYI(1, "get dentry for %s", pstart); - - name.name = pstart; - name.len = len; - name.hash = full_name_hash(pstart, len); - dchild = d_lookup(dparent, &name); - if (dchild == NULL) { - cFYI(1, "not exists"); - dchild = d_alloc(dparent, &name); - if (dchild == NULL) { - dput(dparent); - dparent = ERR_PTR(-ENOMEM); - goto out; - } - } - - cFYI(1, "get inode"); - if (dchild->d_inode == NULL) { - cFYI(1, "not exists"); - inode = NULL; - if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) - rc = cifs_get_inode_info_unix(&inode, full_path, - sb, xid); - else - rc = cifs_get_inode_info(&inode, full_path, - NULL, sb, xid, NULL); - if (rc) { - dput(dchild); - dput(dparent); - dparent = ERR_PTR(rc); - goto out; - } - alias = d_materialise_unique(dchild, inode); - if (alias != NULL) { - dput(dchild); - if (IS_ERR(alias)) { - dput(dparent); - dparent = ERR_PTR(-EINVAL); /* XXX */ - goto out; - } - dchild = alias; - } - } - cFYI(1, "parent %p, child %p", dparent, dchild); - - dput(dparent); - dparent = dchild; - len = 0; - pstart = full_path + i + 1; - full_path[i] = sep; - } -out: + dentry = dget(sb->s_root); + p = s = full_path; + + do { + struct inode *dir = dentry->d_inode; + struct dentry *child; + + /* skip separators */ + while (*s == sep) + s++; + if (!*s) + break; + p = s++; + /* next separator */ + while (*s && *s != sep) + s++; + + mutex_lock(&dir->i_mutex); + child = lookup_one_len(p, dentry, s - p); + mutex_unlock(&dir->i_mutex); + dput(dentry); + dentry = child; + } while (!IS_ERR(dentry)); _FreeXid(xid); kfree(full_path); - return dparent; + return dentry; } static int cifs_set_super(struct super_block *sb, void *data) @@ -649,9 +607,9 @@ cifs_do_mount(struct file_system_type *fs_type, cFYI(1, "Devname: %s flags: %d ", dev_name, flags); - rc = cifs_setup_volume_info(&volume_info, (char *)data, dev_name); - if (rc) - return ERR_PTR(rc); + volume_info = cifs_get_volume_info((char *)data, dev_name); + if (IS_ERR(volume_info)) + return ERR_CAST(volume_info); cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); if (cifs_sb == NULL) { @@ -713,7 +671,7 @@ cifs_do_mount(struct file_system_type *fs_type, out_super: deactivate_locked_super(sb); out: - cifs_cleanup_volume_info(&volume_info); + cifs_cleanup_volume_info(volume_info); return root; out_mountdata: diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 0900e1658c9..036ca83e5f4 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -129,5 +129,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern const struct export_operations cifs_export_ops; #endif /* CIFS_NFSD_EXPORT */ -#define CIFS_VERSION "1.73" +#define CIFS_VERSION "1.74" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 257f312ede4..8df28e925e5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -154,9 +154,9 @@ extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, struct cifs_sb_info *cifs_sb); extern int cifs_match_super(struct super_block *, void *); -extern void cifs_cleanup_volume_info(struct smb_vol **pvolume_info); -extern int cifs_setup_volume_info(struct smb_vol **pvolume_info, - char *mount_data, const char *devname); +extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info); +extern struct smb_vol *cifs_get_volume_info(char *mount_data, + const char *devname); extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); extern void cifs_umount(struct cifs_sb_info *); extern void cifs_dfs_release_automount_timer(void); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c8cb83ef6f6..ccc1afa0bf3 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -65,6 +65,8 @@ static int ip_connect(struct TCP_Server_Info *server); static int generic_ip_connect(struct TCP_Server_Info *server); static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); static void cifs_prune_tlinks(struct work_struct *work); +static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, + const char *devname); /* * cifs tcp session reconnection @@ -2240,8 +2242,8 @@ cifs_match_super(struct super_block *sb, void *data) rc = compare_mount_options(sb, mnt_data); out: - cifs_put_tlink(tlink); spin_unlock(&cifs_tcp_ses_lock); + cifs_put_tlink(tlink); return rc; } @@ -2830,15 +2832,9 @@ is_path_accessible(int xid, struct cifs_tcon *tcon, return rc; } -void -cifs_cleanup_volume_info(struct smb_vol **pvolume_info) +static void +cleanup_volume_info_contents(struct smb_vol *volume_info) { - struct smb_vol *volume_info; - - if (!pvolume_info || !*pvolume_info) - return; - - volume_info = *pvolume_info; kfree(volume_info->username); kzfree(volume_info->password); kfree(volume_info->UNC); @@ -2846,28 +2842,44 @@ cifs_cleanup_volume_info(struct smb_vol **pvolume_info) kfree(volume_info->domainname); kfree(volume_info->iocharset); kfree(volume_info->prepath); +} + +void +cifs_cleanup_volume_info(struct smb_vol *volume_info) +{ + if (!volume_info) + return; + cleanup_volume_info_contents(volume_info); kfree(volume_info); - *pvolume_info = NULL; - return; } + #ifdef CONFIG_CIFS_DFS_UPCALL /* build_path_to_root returns full path to root when * we do not have an exiting connection (tcon) */ static char * -build_unc_path_to_root(const struct smb_vol *volume_info, +build_unc_path_to_root(const struct smb_vol *vol, const struct cifs_sb_info *cifs_sb) { - char *full_path; + char *full_path, *pos; + unsigned int pplen = vol->prepath ? strlen(vol->prepath) : 0; + unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); - int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1); - full_path = kmalloc(unc_len + 1, GFP_KERNEL); + full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL); if (full_path == NULL) return ERR_PTR(-ENOMEM); - strncpy(full_path, volume_info->UNC, unc_len); - full_path[unc_len] = 0; /* add trailing null */ + strncpy(full_path, vol->UNC, unc_len); + pos = full_path + unc_len; + + if (pplen) { + strncpy(pos, vol->prepath, pplen); + pos += pplen; + } + + *pos = '\0'; /* add trailing null */ convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb)); + cFYI(1, "%s: full_path=%s", __func__, full_path); return full_path; } @@ -2910,15 +2922,18 @@ expand_dfs_referral(int xid, struct cifs_ses *pSesInfo, &fake_devname); free_dfs_info_array(referrals, num_referrals); - kfree(fake_devname); - - if (cifs_sb->mountdata != NULL) - kfree(cifs_sb->mountdata); if (IS_ERR(mdata)) { rc = PTR_ERR(mdata); mdata = NULL; + } else { + cleanup_volume_info_contents(volume_info); + memset(volume_info, '\0', sizeof(*volume_info)); + rc = cifs_setup_volume_info(volume_info, mdata, + fake_devname); } + kfree(fake_devname); + kfree(cifs_sb->mountdata); cifs_sb->mountdata = mdata; } kfree(full_path); @@ -2926,33 +2941,20 @@ expand_dfs_referral(int xid, struct cifs_ses *pSesInfo, } #endif -int cifs_setup_volume_info(struct smb_vol **pvolume_info, char *mount_data, - const char *devname) +static int +cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, + const char *devname) { - struct smb_vol *volume_info; int rc = 0; - *pvolume_info = NULL; - - volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL); - if (!volume_info) { - rc = -ENOMEM; - goto out; - } - - if (cifs_parse_mount_options(mount_data, devname, - volume_info)) { - rc = -EINVAL; - goto out; - } + if (cifs_parse_mount_options(mount_data, devname, volume_info)) + return -EINVAL; if (volume_info->nullauth) { cFYI(1, "null user"); volume_info->username = kzalloc(1, GFP_KERNEL); - if (volume_info->username == NULL) { - rc = -ENOMEM; - goto out; - } + if (volume_info->username == NULL) + return -ENOMEM; } else if (volume_info->username) { /* BB fixme parse for domain name here */ cFYI(1, "Username: %s", volume_info->username); @@ -2960,8 +2962,7 @@ int cifs_setup_volume_info(struct smb_vol **pvolume_info, char *mount_data, cifserror("No username specified"); /* In userspace mount helper we can get user name from alternate locations such as env variables and files on disk */ - rc = -EINVAL; - goto out; + return -EINVAL; } /* this is needed for ASCII cp to Unicode converts */ @@ -2973,18 +2974,32 @@ int cifs_setup_volume_info(struct smb_vol **pvolume_info, char *mount_data, if (volume_info->local_nls == NULL) { cERROR(1, "CIFS mount error: iocharset %s not found", volume_info->iocharset); - rc = -ELIBACC; - goto out; + return -ELIBACC; } } - *pvolume_info = volume_info; - return rc; -out: - cifs_cleanup_volume_info(&volume_info); return rc; } +struct smb_vol * +cifs_get_volume_info(char *mount_data, const char *devname) +{ + int rc; + struct smb_vol *volume_info; + + volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL); + if (!volume_info) + return ERR_PTR(-ENOMEM); + + rc = cifs_setup_volume_info(volume_info, mount_data, devname); + if (rc) { + cifs_cleanup_volume_info(volume_info); + volume_info = ERR_PTR(rc); + } + + return volume_info; +} + int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) { @@ -2997,6 +3012,7 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) struct tcon_link *tlink; #ifdef CONFIG_CIFS_DFS_UPCALL int referral_walks_count = 0; +#endif rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY); if (rc) @@ -3004,6 +3020,7 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; +#ifdef CONFIG_CIFS_DFS_UPCALL try_mount_again: /* cleanup activities if we're chasing a referral */ if (referral_walks_count) { @@ -3012,7 +3029,6 @@ try_mount_again: else if (pSesInfo) cifs_put_smb_ses(pSesInfo); - cifs_cleanup_volume_info(&volume_info); FreeXid(xid); } #endif @@ -3469,7 +3485,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) goto out; } - snprintf(username, MAX_USERNAME_SIZE, "krb50x%x", fsuid); + snprintf(username, sizeof(username), "krb50x%x", fsuid); vol_info->username = username; vol_info->local_nls = cifs_sb->local_nls; vol_info->linux_uid = fsuid; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 81914df47ef..fa8c21d913b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -55,6 +55,7 @@ build_path_from_dentry(struct dentry *direntry) char dirsep; struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); + unsigned seq; if (direntry == NULL) return NULL; /* not much we can do if dentry is freed and @@ -68,22 +69,29 @@ build_path_from_dentry(struct dentry *direntry) dfsplen = 0; cifs_bp_rename_retry: namelen = dfsplen; + seq = read_seqbegin(&rename_lock); + rcu_read_lock(); for (temp = direntry; !IS_ROOT(temp);) { namelen += (1 + temp->d_name.len); temp = temp->d_parent; if (temp == NULL) { cERROR(1, "corrupt dentry"); + rcu_read_unlock(); return NULL; } } + rcu_read_unlock(); full_path = kmalloc(namelen+1, GFP_KERNEL); if (full_path == NULL) return full_path; full_path[namelen] = 0; /* trailing null */ + rcu_read_lock(); for (temp = direntry; !IS_ROOT(temp);) { + spin_lock(&temp->d_lock); namelen -= 1 + temp->d_name.len; if (namelen < 0) { + spin_unlock(&temp->d_lock); break; } else { full_path[namelen] = dirsep; @@ -91,14 +99,17 @@ cifs_bp_rename_retry: temp->d_name.len); cFYI(0, "name: %s", full_path + namelen); } + spin_unlock(&temp->d_lock); temp = temp->d_parent; if (temp == NULL) { cERROR(1, "corrupt dentry"); + rcu_read_unlock(); kfree(full_path); return NULL; } } - if (namelen != dfsplen) { + rcu_read_unlock(); + if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) { cERROR(1, "did not end path lookup where expected namelen is %d", namelen); /* presumably this is only possible if racing with a rename diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index 816696621ec..42e5363b410 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -92,6 +92,7 @@ static void cifs_fscache_disable_inode_cookie(struct inode *inode) if (cifsi->fscache) { cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache); + fscache_uncache_all_inode_pages(cifsi->fscache, inode); fscache_relinquish_cookie(cifsi->fscache, 1); cifsi->fscache = NULL; } diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 3892ab817a3..d3e619692ee 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -428,8 +428,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { flags |= NTLMSSP_NEGOTIATE_SIGN; if (!ses->server->session_estab) - flags |= NTLMSSP_NEGOTIATE_KEY_XCH | - NTLMSSP_NEGOTIATE_EXTENDED_SEC; + flags |= NTLMSSP_NEGOTIATE_KEY_XCH; } sec_blob->NegotiateFlags = cpu_to_le32(flags); @@ -465,10 +464,11 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; if (ses->server->sec_mode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { flags |= NTLMSSP_NEGOTIATE_SIGN; - if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) - flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + if (!ses->server->session_estab) + flags |= NTLMSSP_NEGOTIATE_KEY_XCH; + } tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); sec_blob->NegotiateFlags = cpu_to_le32(flags); diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index e141939080f..739fb59bcdc 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -37,7 +37,7 @@ static DEFINE_MUTEX(read_mutex); /* These macros may change in future, to provide better st_ino semantics. */ #define OFFSET(x) ((x)->i_ino) -static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset) +static unsigned long cramino(const struct cramfs_inode *cino, unsigned int offset) { if (!cino->offset) return offset + 1; @@ -61,7 +61,7 @@ static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset) } static struct inode *get_cramfs_inode(struct super_block *sb, - struct cramfs_inode *cramfs_inode, unsigned int offset) + const struct cramfs_inode *cramfs_inode, unsigned int offset) { struct inode *inode; static struct timespec zerotime; @@ -317,7 +317,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) /* Set it all up.. */ sb->s_op = &cramfs_ops; root = get_cramfs_inode(sb, &super.root, 0); - if (!root) + if (IS_ERR(root)) goto out; sb->s_root = d_alloc_root(root); if (!sb->s_root) { @@ -423,6 +423,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir) static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { unsigned int offset = 0; + struct inode *inode = NULL; int sorted; mutex_lock(&read_mutex); @@ -449,8 +450,8 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s for (;;) { if (!namelen) { - mutex_unlock(&read_mutex); - return ERR_PTR(-EIO); + inode = ERR_PTR(-EIO); + goto out; } if (name[namelen-1]) break; @@ -462,17 +463,18 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s if (retval > 0) continue; if (!retval) { - struct cramfs_inode entry = *de; - mutex_unlock(&read_mutex); - d_add(dentry, get_cramfs_inode(dir->i_sb, &entry, dir_off)); - return NULL; + inode = get_cramfs_inode(dir->i_sb, de, dir_off); + break; } /* else (retval < 0) */ if (sorted) break; } +out: mutex_unlock(&read_mutex); - d_add(dentry, NULL); + if (IS_ERR(inode)) + return ERR_CAST(inode); + d_add(dentry, inode); return NULL; } diff --git a/fs/dcache.c b/fs/dcache.c index 37f72ee5bf7..6e4ea6d8777 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2213,14 +2213,15 @@ static void dentry_unlock_parents_for_move(struct dentry *dentry, * The hash value has to match the hash queue that the dentry is on.. */ /* - * d_move - move a dentry + * __d_move - move a dentry * @dentry: entry to move * @target: new dentry * * Update the dcache to reflect the move of a file name. Negative - * dcache entries should not be moved in this way. + * dcache entries should not be moved in this way. Caller hold + * rename_lock. */ -void d_move(struct dentry * dentry, struct dentry * target) +static void __d_move(struct dentry * dentry, struct dentry * target) { if (!dentry->d_inode) printk(KERN_WARNING "VFS: moving negative dcache entry\n"); @@ -2228,8 +2229,6 @@ void d_move(struct dentry * dentry, struct dentry * target) BUG_ON(d_ancestor(dentry, target)); BUG_ON(d_ancestor(target, dentry)); - write_seqlock(&rename_lock); - dentry_lock_for_move(dentry, target); write_seqcount_begin(&dentry->d_seq); @@ -2275,6 +2274,20 @@ void d_move(struct dentry * dentry, struct dentry * target) spin_unlock(&target->d_lock); fsnotify_d_move(dentry); spin_unlock(&dentry->d_lock); +} + +/* + * d_move - move a dentry + * @dentry: entry to move + * @target: new dentry + * + * Update the dcache to reflect the move of a file name. Negative + * dcache entries should not be moved in this way. + */ +void d_move(struct dentry *dentry, struct dentry *target) +{ + write_seqlock(&rename_lock); + __d_move(dentry, target); write_sequnlock(&rename_lock); } EXPORT_SYMBOL(d_move); @@ -2302,7 +2315,7 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) * This helper attempts to cope with remotely renamed directories * * It assumes that the caller is already holding - * dentry->d_parent->d_inode->i_mutex and the inode->i_lock + * dentry->d_parent->d_inode->i_mutex, inode->i_lock and rename_lock * * Note: If ever the locking in lock_rename() changes, then please * remember to update this too... @@ -2317,11 +2330,6 @@ static struct dentry *__d_unalias(struct inode *inode, if (alias->d_parent == dentry->d_parent) goto out_unalias; - /* Check for loops */ - ret = ERR_PTR(-ELOOP); - if (d_ancestor(alias, dentry)) - goto out_err; - /* See lock_rename() */ ret = ERR_PTR(-EBUSY); if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex)) @@ -2331,7 +2339,7 @@ static struct dentry *__d_unalias(struct inode *inode, goto out_err; m2 = &alias->d_parent->d_inode->i_mutex; out_unalias: - d_move(alias, dentry); + __d_move(alias, dentry); ret = alias; out_err: spin_unlock(&inode->i_lock); @@ -2416,15 +2424,24 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) alias = __d_find_alias(inode, 0); if (alias) { actual = alias; - /* Is this an anonymous mountpoint that we could splice - * into our tree? */ - if (IS_ROOT(alias)) { + write_seqlock(&rename_lock); + + if (d_ancestor(alias, dentry)) { + /* Check for loops */ + actual = ERR_PTR(-ELOOP); + } else if (IS_ROOT(alias)) { + /* Is this an anonymous mountpoint that we + * could splice into our tree? */ __d_materialise_dentry(dentry, alias); + write_sequnlock(&rename_lock); __d_drop(alias); goto found; + } else { + /* Nope, but we must(!) avoid directory + * aliasing */ + actual = __d_unalias(inode, dentry, alias); } - /* Nope, but we must(!) avoid directory aliasing */ - actual = __d_unalias(inode, dentry, alias); + write_sequnlock(&rename_lock); if (IS_ERR(actual)) dput(alias); goto out_nolock; diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 06065bd37fc..c57beddcc21 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -913,7 +913,7 @@ struct dentry *exofs_get_parent(struct dentry *child) unsigned long ino = exofs_parent_ino(child); if (!ino) - return NULL; + return ERR_PTR(-ESTALE); return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino)); } diff --git a/fs/fscache/page.c b/fs/fscache/page.c index a2a5d19ece6..2f343b4d7a7 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -954,3 +954,47 @@ void fscache_mark_pages_cached(struct fscache_retrieval *op, pagevec_reinit(pagevec); } EXPORT_SYMBOL(fscache_mark_pages_cached); + +/* + * Uncache all the pages in an inode that are marked PG_fscache, assuming them + * to be associated with the given cookie. + */ +void __fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, + struct inode *inode) +{ + struct address_space *mapping = inode->i_mapping; + struct pagevec pvec; + pgoff_t next; + int i; + + _enter("%p,%p", cookie, inode); + + if (!mapping || mapping->nrpages == 0) { + _leave(" [no pages]"); + return; + } + + pagevec_init(&pvec, 0); + next = 0; + while (next <= (loff_t)-1 && + pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE) + ) { + for (i = 0; i < pagevec_count(&pvec); i++) { + struct page *page = pvec.pages[i]; + pgoff_t page_index = page->index; + + ASSERTCMP(page_index, >=, next); + next = page_index + 1; + + if (PageFsCache(page)) { + __fscache_wait_on_page_write(cookie, page); + __fscache_uncache_page(cookie, page); + } + } + pagevec_release(&pvec); + cond_resched(); + } + + _leave(""); +} +EXPORT_SYMBOL(__fscache_uncache_all_inode_pages); diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 802ac5eeba2..f9fbbe96c22 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -1069,6 +1069,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) return 0; gfs2_log_lock(sdp); + spin_lock(&sdp->sd_ail_lock); head = bh = page_buffers(page); do { if (atomic_read(&bh->b_count)) @@ -1080,6 +1081,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) goto not_possible; bh = bh->b_this_page; } while(bh != head); + spin_unlock(&sdp->sd_ail_lock); gfs2_log_unlock(sdp); head = bh = page_buffers(page); @@ -1112,6 +1114,7 @@ not_possible: /* Should never happen */ WARN_ON(buffer_dirty(bh)); WARN_ON(buffer_pinned(bh)); cannot_release: + spin_unlock(&sdp->sd_ail_lock); gfs2_log_unlock(sdp); return 0; } diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 8ef70f46473..2cca29316bd 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -47,10 +47,10 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl) bd_ail_gl_list); bh = bd->bd_bh; gfs2_remove_from_ail(bd); - spin_unlock(&sdp->sd_ail_lock); - bd->bd_bh = NULL; bh->b_private = NULL; + spin_unlock(&sdp->sd_ail_lock); + bd->bd_blkno = bh->b_blocknr; gfs2_log_lock(sdp); gfs2_assert_withdraw(sdp, !buffer_busy(bh)); @@ -221,8 +221,10 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) } } - if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) + if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) { + gfs2_log_flush(gl->gl_sbd, NULL); gl->gl_sbd->sd_rindex_uptodate = 0; + } if (ip && S_ISREG(ip->i_inode.i_mode)) truncate_inode_pages(ip->i_inode.i_mapping, 0); } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 0a064e91ac7..81206e70cbf 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -17,6 +17,7 @@ #include <linux/buffer_head.h> #include <linux/rcupdate.h> #include <linux/rculist_bl.h> +#include <linux/completion.h> #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 @@ -546,6 +547,7 @@ struct gfs2_sbd { struct gfs2_glock *sd_trans_gl; wait_queue_head_t sd_glock_wait; atomic_t sd_glock_disposal; + struct completion sd_locking_init; /* Inode Stuff */ diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 903115f2bb3..85c62923ee2 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -903,6 +903,7 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp) if (gfs2_ail1_empty(sdp)) break; } + gfs2_log_flush(sdp, NULL); } static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 8ac9ae189b5..2a77071fb7b 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -72,6 +72,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) init_waitqueue_head(&sdp->sd_glock_wait); atomic_set(&sdp->sd_glock_disposal, 0); + init_completion(&sdp->sd_locking_init); spin_lock_init(&sdp->sd_statfs_spin); spin_lock_init(&sdp->sd_rindex_spin); @@ -1017,11 +1018,13 @@ hostdata_error: fsname++; if (lm->lm_mount == NULL) { fs_info(sdp, "Now mounting FS...\n"); + complete(&sdp->sd_locking_init); return 0; } ret = lm->lm_mount(sdp, fsname); if (ret == 0) fs_info(sdp, "Joined cluster. Now mounting FS...\n"); + complete(&sdp->sd_locking_init); return ret; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index ed540e7018b..fb0edf73548 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -757,13 +757,17 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) struct timespec atime; struct gfs2_dinode *di; int ret = -EAGAIN; + int unlock_required = 0; /* Skip timestamp update, if this is from a memalloc */ if (current->flags & PF_MEMALLOC) goto do_flush; - ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); - if (ret) - goto do_flush; + if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { + ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + if (ret) + goto do_flush; + unlock_required = 1; + } ret = gfs2_trans_begin(sdp, RES_DINODE, 0); if (ret) goto do_unlock; @@ -780,7 +784,8 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) } gfs2_trans_end(sdp); do_unlock: - gfs2_glock_dq_uninit(&gh); + if (unlock_required) + gfs2_glock_dq_uninit(&gh); do_flush: if (wbc->sync_mode == WB_SYNC_ALL) gfs2_log_flush(GFS2_SB(inode), ip->i_gl); @@ -1427,7 +1432,20 @@ out: return error; } -/* +/** + * gfs2_evict_inode - Remove an inode from cache + * @inode: The inode to evict + * + * There are three cases to consider: + * 1. i_nlink == 0, we are final opener (and must deallocate) + * 2. i_nlink == 0, we are not the final opener (and cannot deallocate) + * 3. i_nlink > 0 + * + * If the fs is read only, then we have to treat all cases as per #3 + * since we are unable to do any deallocation. The inode will be + * deallocated by the next read/write node to attempt an allocation + * in the same resource group + * * We have to (at the moment) hold the inodes main lock to cover * the gap between unlocking the shared lock on the iopen lock and * taking the exclusive lock. I'd rather do a shared -> exclusive @@ -1470,6 +1488,8 @@ static void gfs2_evict_inode(struct inode *inode) if (error) goto out_truncate; + /* Case 1 starts here */ + if (S_ISDIR(inode->i_mode) && (ip->i_diskflags & GFS2_DIF_EXHASH)) { error = gfs2_dir_exhash_dealloc(ip); @@ -1493,13 +1513,16 @@ static void gfs2_evict_inode(struct inode *inode) goto out_unlock; out_truncate: + /* Case 2 starts here */ error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); if (error) goto out_unlock; - gfs2_final_release_pages(ip); + /* Needs to be done before glock release & also in a transaction */ + truncate_inode_pages(&inode->i_data, 0); gfs2_trans_end(sdp); out_unlock: + /* Error path for case 1 */ if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) gfs2_glock_dq(&ip->i_iopen_gh); gfs2_holder_uninit(&ip->i_iopen_gh); @@ -1507,6 +1530,7 @@ out_unlock: if (error && error != GLR_TRYFAILED && error != -EROFS) fs_warn(sdp, "gfs2_evict_inode: %d\n", error); out: + /* Case 3 starts here */ truncate_inode_pages(&inode->i_data, 0); end_writeback(inode); diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index e20eab37bc8..443cabcfcd2 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -338,6 +338,9 @@ static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len) rv = sscanf(buf, "%u", &first); if (rv != 1 || first > 1) return -EINVAL; + rv = wait_for_completion_killable(&sdp->sd_locking_init); + if (rv) + return rv; spin_lock(&sdp->sd_jindex_spin); rv = -EBUSY; if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0) @@ -414,7 +417,9 @@ static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len) rv = sscanf(buf, "%d", &jid); if (rv != 1) return -EINVAL; - + rv = wait_for_completion_killable(&sdp->sd_locking_init); + if (rv) + return rv; spin_lock(&sdp->sd_jindex_spin); rv = -EINVAL; if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index b49b55584c8..84a47b709f5 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -500,7 +500,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) out_put_hidden_dir: iput(sbi->hidden_dir); out_put_root: - iput(sbi->alloc_file); + iput(root); out_put_alloc_file: iput(sbi->alloc_file); out_close_cat_tree: diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index 3031d81f5f0..4ac88ff79aa 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c @@ -36,6 +36,7 @@ int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, { DECLARE_COMPLETION_ONSTACK(wait); struct bio *bio; + int ret = 0; bio = bio_alloc(GFP_NOIO, 1); bio->bi_sector = sector; @@ -54,8 +55,10 @@ int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, wait_for_completion(&wait); if (!bio_flagged(bio, BIO_UPTODATE)) - return -EIO; - return 0; + ret = -EIO; + + bio_put(bio); + return ret; } static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index 87ed48e0343..85c098a499f 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -139,7 +139,8 @@ static int file_removed(struct dentry *dentry, const char *file) static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, struct nameidata *nd) { - struct dentry *proc_dentry, *new, *parent; + struct dentry *proc_dentry, *parent; + struct qstr *name = &dentry->d_name; struct inode *inode; int err, deleted; @@ -149,23 +150,9 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, else if (deleted) return ERR_PTR(-ENOENT); - err = -ENOMEM; parent = HPPFS_I(ino)->proc_dentry; mutex_lock(&parent->d_inode->i_mutex); - proc_dentry = d_lookup(parent, &dentry->d_name); - if (proc_dentry == NULL) { - proc_dentry = d_alloc(parent, &dentry->d_name); - if (proc_dentry == NULL) { - mutex_unlock(&parent->d_inode->i_mutex); - goto out; - } - new = (*parent->d_inode->i_op->lookup)(parent->d_inode, - proc_dentry, NULL); - if (new) { - dput(proc_dentry); - proc_dentry = new; - } - } + proc_dentry = lookup_one_len(name->name, parent, name->len); mutex_unlock(&parent->d_inode->i_mutex); if (IS_ERR(proc_dentry)) @@ -174,13 +161,11 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, err = -ENOMEM; inode = get_inode(ino->i_sb, proc_dentry); if (!inode) - goto out_dput; + goto out; d_add(dentry, inode); return NULL; - out_dput: - dput(proc_dentry); out: return ERR_PTR(err); } @@ -690,8 +675,10 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) struct inode *proc_ino = dentry->d_inode; struct inode *inode = new_inode(sb); - if (!inode) + if (!inode) { + dput(dentry); return ERR_PTR(-ENOMEM); + } if (S_ISDIR(dentry->d_inode->i_mode)) { inode->i_op = &hppfs_dir_iops; @@ -704,7 +691,7 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) inode->i_fop = &hppfs_file_fops; } - HPPFS_I(inode)->proc_dentry = dget(dentry); + HPPFS_I(inode)->proc_dentry = dentry; inode->i_uid = proc_ino->i_uid; inode->i_gid = proc_ino->i_gid; @@ -737,7 +724,7 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent) sb->s_fs_info = proc_mnt; err = -ENOMEM; - root_inode = get_inode(sb, proc_mnt->mnt_sb->s_root); + root_inode = get_inode(sb, dget(proc_mnt->mnt_sb->s_root)); if (!root_inode) goto out_mntput; diff --git a/fs/libfs.c b/fs/libfs.c index c88eab55aec..275ca4749a2 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -822,7 +822,7 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf, goto out; attr->set_buf[size] = '\0'; - val = simple_strtol(attr->set_buf, NULL, 0); + val = simple_strtoll(attr->set_buf, NULL, 0); ret = attr->set(attr->data, val); if (ret == 0) ret = len; /* on success, claim we got the whole input */ diff --git a/fs/locks.c b/fs/locks.c index 0a4f50dfadf..b286539d547 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -160,10 +160,28 @@ EXPORT_SYMBOL_GPL(unlock_flocks); static struct kmem_cache *filelock_cache __read_mostly; +static void locks_init_lock_always(struct file_lock *fl) +{ + fl->fl_next = NULL; + fl->fl_fasync = NULL; + fl->fl_owner = NULL; + fl->fl_pid = 0; + fl->fl_nspid = NULL; + fl->fl_file = NULL; + fl->fl_flags = 0; + fl->fl_type = 0; + fl->fl_start = fl->fl_end = 0; +} + /* Allocate an empty lock structure. */ struct file_lock *locks_alloc_lock(void) { - return kmem_cache_alloc(filelock_cache, GFP_KERNEL); + struct file_lock *fl = kmem_cache_alloc(filelock_cache, GFP_KERNEL); + + if (fl) + locks_init_lock_always(fl); + + return fl; } EXPORT_SYMBOL_GPL(locks_alloc_lock); @@ -200,17 +218,9 @@ void locks_init_lock(struct file_lock *fl) INIT_LIST_HEAD(&fl->fl_link); INIT_LIST_HEAD(&fl->fl_block); init_waitqueue_head(&fl->fl_wait); - fl->fl_next = NULL; - fl->fl_fasync = NULL; - fl->fl_owner = NULL; - fl->fl_pid = 0; - fl->fl_nspid = NULL; - fl->fl_file = NULL; - fl->fl_flags = 0; - fl->fl_type = 0; - fl->fl_start = fl->fl_end = 0; fl->fl_ops = NULL; fl->fl_lmops = NULL; + locks_init_lock_always(fl); } EXPORT_SYMBOL(locks_init_lock); diff --git a/fs/namei.c b/fs/namei.c index 0223c41fb11..14ab8d3f2f0 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -433,6 +433,8 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry) goto err_parent; BUG_ON(nd->inode != parent->d_inode); } else { + if (dentry->d_parent != parent) + goto err_parent; spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); if (!__d_rcu_to_refcount(dentry, nd->seq)) goto err_child; @@ -940,7 +942,6 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, * Don't forget we might have a non-mountpoint managed dentry * that wants to block transit. */ - *inode = path->dentry->d_inode; if (unlikely(managed_dentry_might_block(path->dentry))) return false; @@ -953,6 +954,12 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, path->mnt = mounted; path->dentry = mounted->mnt_root; nd->seq = read_seqcount_begin(&path->dentry->d_seq); + /* + * Update the inode too. We don't need to re-check the + * dentry sequence number here after this d_inode read, + * because a mount-point is always pinned. + */ + *inode = path->dentry->d_inode; } return true; } diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index ce153a6b3ae..419119c371b 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c @@ -259,12 +259,10 @@ static void nfs_fscache_disable_inode_cookie(struct inode *inode) dfprintk(FSCACHE, "NFS: nfsi 0x%p turning cache off\n", NFS_I(inode)); - /* Need to invalidate any mapped pages that were read in before - * turning off the cache. + /* Need to uncache any pages attached to this inode that + * fscache knows about before turning off the cache. */ - if (inode->i_mapping && inode->i_mapping->nrpages) - invalidate_inode_pages2(inode->i_mapping); - + fscache_uncache_all_inode_pages(NFS_I(inode)->fscache, inode); nfs_fscache_zap_inode_cookie(inode); } } diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 0bafcc91c27..f9d03abcd04 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -398,7 +398,6 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) * this offset and save the original offset. */ data->args.offset = filelayout_get_dserver_offset(lseg, offset); - data->mds_offset = offset; /* Perform an asynchronous write */ status = nfs_initiate_write(data, ds->ds_clp->cl_rpcclient, diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 6870bc61cee..e6e8f3b9a1d 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -91,7 +91,7 @@ static int nfs4_stat_to_errno(int); #define encode_getfh_maxsz (op_encode_hdr_maxsz) #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ ((3+NFS4_FHSIZE) >> 2)) -#define nfs4_fattr_bitmap_maxsz 3 +#define nfs4_fattr_bitmap_maxsz 4 #define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e268e3b2349..72716805968 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -864,6 +864,8 @@ static int nfs_write_rpcsetup(struct nfs_page *req, data->args.fh = NFS_FH(inode); data->args.offset = req_offset(req) + offset; + /* pnfs_set_layoutcommit needs this */ + data->mds_offset = data->args.offset; data->args.pgbase = req->wb_pgbase + offset; data->args.pages = data->pagevec; data->args.count = count; diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 29309e25417..b57aab9a118 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -56,16 +56,12 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru lock_ufs(dir->i_sb); ino = ufs_inode_by_name(dir, &dentry->d_name); - if (ino) { + if (ino) inode = ufs_iget(dir->i_sb, ino); - if (IS_ERR(inode)) { - unlock_ufs(dir->i_sb); - return ERR_CAST(inode); - } - } unlock_ufs(dir->i_sb); - d_add(dentry, inode); - return NULL; + if (IS_ERR(inode)) + return ERR_CAST(inode); + return d_splice_alias(inode, dentry); } /* diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 09983a3344a..b1e88d56069 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -681,15 +681,15 @@ xfs_inode_item_unlock( * where the cluster buffer may be unpinned before the inode is inserted into * the AIL during transaction committed processing. If the buffer is unpinned * before the inode item has been committed and inserted, then it is possible - * for the buffer to be written and IO completions before the inode is inserted + * for the buffer to be written and IO completes before the inode is inserted * into the AIL. In that case, we'd be inserting a clean, stale inode into the * AIL which will never get removed. It will, however, get reclaimed which * triggers an assert in xfs_inode_free() complaining about freein an inode * still in the AIL. * - * To avoid this, return a lower LSN than the one passed in so that the - * transaction committed code will not move the inode forward in the AIL but - * will still unpin it properly. + * To avoid this, just unpin the inode directly and return a LSN of -1 so the + * transaction committed code knows that it does not need to do any further + * processing on the item. */ STATIC xfs_lsn_t xfs_inode_item_committed( @@ -699,8 +699,10 @@ xfs_inode_item_committed( struct xfs_inode_log_item *iip = INODE_ITEM(lip); struct xfs_inode *ip = iip->ili_inode; - if (xfs_iflags_test(ip, XFS_ISTALE)) - return lsn - 1; + if (xfs_iflags_test(ip, XFS_ISTALE)) { + xfs_inode_item_unpin(lip, 0); + return -1; + } return lsn; } diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 7c7bc2b786b..c83f63b33aa 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -1361,7 +1361,7 @@ xfs_trans_item_committed( lip->li_flags |= XFS_LI_ABORTED; item_lsn = IOP_COMMITTED(lip, commit_lsn); - /* If the committed routine returns -1, item has been freed. */ + /* item_lsn of -1 means the item needs no further processing */ if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) return; @@ -1474,7 +1474,7 @@ xfs_trans_committed_bulk( lip->li_flags |= XFS_LI_ABORTED; item_lsn = IOP_COMMITTED(lip, commit_lsn); - /* item_lsn of -1 means the item was freed */ + /* item_lsn of -1 means the item needs no further processing */ if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) continue; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 3a10ef5914e..6cd5b6403a7 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -210,7 +210,7 @@ struct acpi_device_power_state { struct acpi_device_power { int state; /* Current state */ struct acpi_device_power_flags flags; - struct acpi_device_power_state states[4]; /* Power states (D0-D3) */ + struct acpi_device_power_state states[ACPI_D_STATE_COUNT]; /* Power states (D0-D3Cold) */ }; /* Performance Management */ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index a756bc8d866..4543b6f7586 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -98,8 +98,11 @@ acpi_os_table_override(struct acpi_table_header *existing_table, /* * Spinlock primitives */ + +#ifndef acpi_os_create_lock acpi_status acpi_os_create_lock(acpi_spinlock *out_handle); +#endif void acpi_os_delete_lock(acpi_spinlock handle); diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 5d2a5e9544d..2ce1be9f629 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -159,6 +159,24 @@ static inline void *acpi_os_acquire_object(acpi_cache_t * cache) } while (0) #endif +/* + * When lockdep is enabled, the spin_lock_init() macro stringifies it's + * argument and uses that as a name for the lock in debugging. + * By executing spin_lock_init() in a macro the key changes from "lock" for + * all locks to the name of the argument of acpi_os_create_lock(), which + * prevents lockdep from reporting false positives for ACPICA locks. + */ +#define acpi_os_create_lock(__handle) \ +({ \ + spinlock_t *lock = ACPI_ALLOCATE(sizeof(*lock)); \ + \ + if (lock) { \ + *(__handle) = lock; \ + spin_lock_init(*(__handle)); \ + } \ + lock ? AE_OK : AE_NO_MEMORY; \ +}) + #endif /* __KERNEL__ */ #endif /* __ACLINUX_H__ */ diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index e08f344c6cf..3d53efd25ab 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -182,6 +182,7 @@ {0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6759, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x675F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6761, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6762, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ @@ -192,6 +193,7 @@ {0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6888, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h index 246f576c981..447c3675238 100644 --- a/include/linux/drbd_limits.h +++ b/include/linux/drbd_limits.h @@ -117,10 +117,10 @@ /* drbdsetup XY resize -d Z * you are free to reduce the device size to nothing, if you want to. * the upper limit with 64bit kernel, enough ram and flexible meta data - * is 16 TB, currently. */ + * is 1 PiB, currently. */ /* DRBD_MAX_SECTORS */ #define DRBD_DISK_SIZE_SECT_MIN 0 -#define DRBD_DISK_SIZE_SECT_MAX (16 * (2LLU << 30)) +#define DRBD_DISK_SIZE_SECT_MAX (1 * (2LLU << 40)) #define DRBD_DISK_SIZE_SECT_DEF 0 /* = disabled = no user size... */ #define DRBD_ON_IO_ERROR_DEF EP_PASS_ON diff --git a/include/linux/fscache.h b/include/linux/fscache.h index 7c4d72f5581..9ec20dec335 100644 --- a/include/linux/fscache.h +++ b/include/linux/fscache.h @@ -204,6 +204,8 @@ extern bool __fscache_check_page_write(struct fscache_cookie *, struct page *); extern void __fscache_wait_on_page_write(struct fscache_cookie *, struct page *); extern bool __fscache_maybe_release_page(struct fscache_cookie *, struct page *, gfp_t); +extern void __fscache_uncache_all_inode_pages(struct fscache_cookie *, + struct inode *); /** * fscache_register_netfs - Register a filesystem as desiring caching services @@ -643,4 +645,23 @@ bool fscache_maybe_release_page(struct fscache_cookie *cookie, return false; } +/** + * fscache_uncache_all_inode_pages - Uncache all an inode's pages + * @cookie: The cookie representing the inode's cache object. + * @inode: The inode to uncache pages from. + * + * Uncache all the pages in an inode that are marked PG_fscache, assuming them + * to be associated with the given cookie. + * + * This function may sleep. It will wait for pages that are being written out + * and will wait whilst the PG_fscache mark is removed by the cache. + */ +static inline +void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, + struct inode *inode) +{ + if (fscache_cookie_valid(cookie)) + __fscache_uncache_all_inode_pages(cookie, inode); +} + #endif /* _LINUX_FSCACHE_H */ diff --git a/include/linux/irq.h b/include/linux/irq.h index 8b453844663..baa397eb9c3 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -676,7 +676,8 @@ void irq_gc_mask_disable_reg(struct irq_data *d); void irq_gc_mask_set_bit(struct irq_data *d); void irq_gc_mask_clr_bit(struct irq_data *d); void irq_gc_unmask_enable_reg(struct irq_data *d); -void irq_gc_ack(struct irq_data *d); +void irq_gc_ack_set_bit(struct irq_data *d); +void irq_gc_ack_clr_bit(struct irq_data *d); void irq_gc_mask_disable_reg_and_ack(struct irq_data *d); void irq_gc_eoi(struct irq_data *d); int irq_gc_set_wake(struct irq_data *d, unsigned int on); diff --git a/include/linux/memory.h b/include/linux/memory.h index e1e3b2b84f8..935699b30b7 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -20,6 +20,8 @@ #include <linux/compiler.h> #include <linux/mutex.h> +#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS) + struct memory_block { unsigned long start_section_nr; unsigned long end_section_nr; diff --git a/include/linux/mfd/ds1wm.h b/include/linux/mfd/ds1wm.h index be469a357cb..38a372a0e28 100644 --- a/include/linux/mfd/ds1wm.h +++ b/include/linux/mfd/ds1wm.h @@ -3,4 +3,11 @@ struct ds1wm_driver_data { int active_high; int clock_rate; + /* in milliseconds, the amount of time to */ + /* sleep following a reset pulse. Zero */ + /* should work if your bus devices recover*/ + /* time respects the 1-wire spec since the*/ + /* ds1wm implements the precise timings of*/ + /* a reset pulse/presence detect sequence.*/ + unsigned int reset_recover_delay; }; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index c6927a4d157..6ad43554ac0 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -64,6 +64,19 @@ struct mmc_ext_csd { unsigned long long enhanced_area_offset; /* Units: Byte */ unsigned int enhanced_area_size; /* Units: KB */ unsigned int boot_size; /* in bytes */ + u8 raw_partition_support; /* 160 */ + u8 raw_erased_mem_count; /* 181 */ + u8 raw_ext_csd_structure; /* 194 */ + u8 raw_card_type; /* 196 */ + u8 raw_s_a_timeout; /* 217 */ + u8 raw_hc_erase_gap_size; /* 221 */ + u8 raw_erase_timeout_mult; /* 223 */ + u8 raw_hc_erase_grp_size; /* 224 */ + u8 raw_sec_trim_mult; /* 229 */ + u8 raw_sec_erase_mult; /* 230 */ + u8 raw_sec_feature_support;/* 231 */ + u8 raw_trim_mult; /* 232 */ + u8 raw_sectors[4]; /* 212 - 4 bytes */ }; struct sd_scr { diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 54b8b4d7b68..9e19477991a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1097,12 +1097,6 @@ struct net_device { #define NETIF_F_ALL_FCOE (NETIF_F_FCOE_CRC | NETIF_F_FCOE_MTU | \ NETIF_F_FSO) -#define NETIF_F_ALL_TX_OFFLOADS (NETIF_F_ALL_CSUM | NETIF_F_SG | \ - NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ - NETIF_F_HIGHDMA | \ - NETIF_F_SCTP_CSUM | \ - NETIF_F_ALL_FCOE) - /* * If one device supports one of these features, then enable them * for all in netdev_increment_features. diff --git a/include/linux/sched.h b/include/linux/sched.h index a837b20ba19..14a6c7b545d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -808,7 +808,7 @@ enum cpu_idle_type { * when BITS_PER_LONG <= 32 are pretty high and the returns do not justify the * increased costs. */ -#if BITS_PER_LONG > 32 +#if 0 /* BITS_PER_LONG > 32 -- currently broken: it increases power usage under light load */ # define SCHED_LOAD_RESOLUTION 10 # define scale_load(w) ((w) << SCHED_LOAD_RESOLUTION) # define scale_load_down(w) ((w) >> SCHED_LOAD_RESOLUTION) @@ -844,6 +844,7 @@ enum cpu_idle_type { #define SD_SERIALIZE 0x0400 /* Only a single load balancing instance */ #define SD_ASYM_PACKING 0x0800 /* Place busy groups earlier in the domain */ #define SD_PREFER_SIBLING 0x1000 /* Prefer to place tasks in a sibling domain */ +#define SD_OVERLAP 0x2000 /* sched_domains of this level overlap */ enum powersavings_balance_level { POWERSAVINGS_BALANCE_NONE = 0, /* No power saving load balance */ @@ -893,16 +894,21 @@ static inline int sd_power_saving_flags(void) return 0; } -struct sched_group { - struct sched_group *next; /* Must be a circular list */ +struct sched_group_power { atomic_t ref; - /* * CPU power of this group, SCHED_LOAD_SCALE being max power for a * single CPU. */ - unsigned int cpu_power, cpu_power_orig; + unsigned int power, power_orig; +}; + +struct sched_group { + struct sched_group *next; /* Must be a circular list */ + atomic_t ref; + unsigned int group_weight; + struct sched_group_power *sgp; /* * The CPUs this group covers. @@ -1254,6 +1260,9 @@ struct task_struct { #ifdef CONFIG_PREEMPT_RCU int rcu_read_lock_nesting; char rcu_read_unlock_special; +#if defined(CONFIG_RCU_BOOST) && defined(CONFIG_TREE_PREEMPT_RCU) + int rcu_boosted; +#endif /* #if defined(CONFIG_RCU_BOOST) && defined(CONFIG_TREE_PREEMPT_RCU) */ struct list_head rcu_node_entry; #endif /* #ifdef CONFIG_PREEMPT_RCU */ #ifdef CONFIG_TREE_PREEMPT_RCU diff --git a/include/linux/sdla.h b/include/linux/sdla.h index 564acd3a71c..9995c7fc3f6 100644 --- a/include/linux/sdla.h +++ b/include/linux/sdla.h @@ -112,11 +112,7 @@ struct sdla_dlci_conf { short Tb_max; }; -#ifndef __KERNEL__ - -void sdla(void *cfg_info, char *dev, struct frad_conf *conf, int quiet); - -#else +#ifdef __KERNEL__ /* important Z80 window addresses */ #define SDLA_CONTROL_WND 0xE000 diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h index 630e702c951..168dd0b1bae 100644 --- a/include/media/lirc_dev.h +++ b/include/media/lirc_dev.h @@ -9,7 +9,7 @@ #ifndef _LINUX_LIRC_DEV_H #define _LINUX_LIRC_DEV_H -#define MAX_IRCTL_DEVICES 4 +#define MAX_IRCTL_DEVICES 8 #define BUFLEN 16 #define mod(n, div) ((n) % (div)) diff --git a/include/media/m5mols.h b/include/media/m5mols.h index 2d7e7ca2313..aac2c0e06d5 100644 --- a/include/media/m5mols.h +++ b/include/media/m5mols.h @@ -2,10 +2,10 @@ * Driver header for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 1562c4ff3a6..2884e3e69cb 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -173,16 +173,20 @@ struct v4l2_subdev_core_ops { struct v4l2_event_subscription *sub); }; -/* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio. +/* s_radio: v4l device was opened in radio mode. - s_radio: v4l device was opened in Radio mode, to be replaced by s_mode. + g_frequency: freq->type must be filled in. Normally done by video_ioctl2 + or the bridge driver. + + g_tuner: + s_tuner: vt->type must be filled in. Normally done by video_ioctl2 or the + bridge driver. s_type_addr: sets tuner type and its I2C addr. s_config: sets tda9887 specific stuff, like port1, port2 and qss */ struct v4l2_subdev_tuner_ops { - int (*s_mode)(struct v4l2_subdev *sd, enum v4l2_tuner_type); int (*s_radio)(struct v4l2_subdev *sd); int (*s_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0589f554788..396e8fc8910 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2688,7 +2688,7 @@ void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, * @dev: network device * @addr: The source MAC address of the frame * @key_type: The key type that the received frame used - * @key_id: Key identifier (0..3) + * @key_id: Key identifier (0..3). Can be -1 if missing. * @tsc: The TSC value of the frame that generated the MIC failure (6 octets) * @gfp: allocation flags * diff --git a/include/net/dst.h b/include/net/dst.h index 7d15d238b6e..e12ddfb9eb1 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -77,6 +77,7 @@ struct dst_entry { #define DST_NOPOLICY 0x0004 #define DST_NOHASH 0x0008 #define DST_NOCACHE 0x0010 +#define DST_NOCOUNT 0x0020 union { struct dst_entry *next; struct rtable __rcu *rt_next; diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index dd6847e5d6e..6506458ccd3 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -63,6 +63,7 @@ typedef enum { SCTP_CMD_ECN_ECNE, /* Do delayed ECNE processing. */ SCTP_CMD_ECN_CWR, /* Do delayed CWR processing. */ SCTP_CMD_TIMER_START, /* Start a timer. */ + SCTP_CMD_TIMER_START_ONCE, /* Start a timer once */ SCTP_CMD_TIMER_RESTART, /* Restart a timer. */ SCTP_CMD_TIMER_STOP, /* Stop a timer. */ SCTP_CMD_INIT_CHOOSE_TRANSPORT, /* Choose transport for an INIT. */ diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 99b027b2adc..ca4693b4e09 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -80,7 +80,7 @@ static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb) void sctp_ulpevent_free(struct sctp_ulpevent *); int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); -void sctp_queue_purge_ulpevents(struct sk_buff_head *list); +unsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list); struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( const struct sctp_association *asoc, diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 31a9db71190..3a2cab407b9 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -101,10 +101,10 @@ void irq_gc_unmask_enable_reg(struct irq_data *d) } /** - * irq_gc_ack - Ack pending interrupt + * irq_gc_ack_set_bit - Ack pending interrupt via setting bit * @d: irq_data */ -void irq_gc_ack(struct irq_data *d) +void irq_gc_ack_set_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); u32 mask = 1 << (d->irq - gc->irq_base); @@ -115,6 +115,20 @@ void irq_gc_ack(struct irq_data *d) } /** + * irq_gc_ack_clr_bit - Ack pending interrupt via clearing bit + * @d: irq_data + */ +void irq_gc_ack_clr_bit(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = ~(1 << (d->irq - gc->irq_base)); + + irq_gc_lock(gc); + irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); + irq_gc_unlock(gc); +} + +/** * irq_gc_mask_disable_reg_and_ack- Mask and ack pending interrupt * @d: irq_data */ diff --git a/kernel/jump_label.c b/kernel/jump_label.c index fa27e750dbc..a8ce45097f3 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -375,15 +375,19 @@ int jump_label_text_reserved(void *start, void *end) static void jump_label_update(struct jump_label_key *key, int enable) { - struct jump_entry *entry = key->entries; - - /* if there are no users, entry can be NULL */ - if (entry) - __jump_label_update(key, entry, __stop___jump_table, enable); + struct jump_entry *entry = key->entries, *stop = __stop___jump_table; #ifdef CONFIG_MODULES + struct module *mod = __module_address((jump_label_t)key); + __jump_label_mod_update(key, enable); + + if (mod) + stop = mod->jump_entries + mod->num_jump_entries; #endif + /* if there are no users, entry can be NULL */ + if (entry) + __jump_label_update(key, entry, stop, enable); } #endif diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index ace55889f70..06efa54f93d 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1211,7 +1211,11 @@ static void free_unnecessary_pages(void) to_free_highmem = alloc_highmem - save; } else { to_free_highmem = 0; - to_free_normal -= save - alloc_highmem; + save -= alloc_highmem; + if (to_free_normal > save) + to_free_normal -= save; + else + to_free_normal = 0; } memory_bm_position_reset(©_bm); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 7e59ffb3d0b..ba06207b1dd 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -84,9 +84,32 @@ DEFINE_PER_CPU(struct rcu_data, rcu_bh_data); static struct rcu_state *rcu_state; +/* + * The rcu_scheduler_active variable transitions from zero to one just + * before the first task is spawned. So when this variable is zero, RCU + * can assume that there is but one task, allowing RCU to (for example) + * optimized synchronize_sched() to a simple barrier(). When this variable + * is one, RCU must actually do all the hard work required to detect real + * grace periods. This variable is also used to suppress boot-time false + * positives from lockdep-RCU error checking. + */ int rcu_scheduler_active __read_mostly; EXPORT_SYMBOL_GPL(rcu_scheduler_active); +/* + * The rcu_scheduler_fully_active variable transitions from zero to one + * during the early_initcall() processing, which is after the scheduler + * is capable of creating new tasks. So RCU processing (for example, + * creating tasks for RCU priority boosting) must be delayed until after + * rcu_scheduler_fully_active transitions from zero to one. We also + * currently delay invocation of any RCU callbacks until after this point. + * + * It might later prove better for people registering RCU callbacks during + * early boot to take responsibility for these callbacks, but one step at + * a time. + */ +static int rcu_scheduler_fully_active __read_mostly; + #ifdef CONFIG_RCU_BOOST /* @@ -98,7 +121,6 @@ DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status); DEFINE_PER_CPU(int, rcu_cpu_kthread_cpu); DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops); DEFINE_PER_CPU(char, rcu_cpu_has_work); -static char rcu_kthreads_spawnable; #endif /* #ifdef CONFIG_RCU_BOOST */ @@ -1467,6 +1489,8 @@ static void rcu_process_callbacks(struct softirq_action *unused) */ static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) { + if (unlikely(!ACCESS_ONCE(rcu_scheduler_fully_active))) + return; if (likely(!rsp->boost)) { rcu_do_batch(rsp, rdp); return; diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 14dc7dd0090..8aafbb80b8b 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -68,6 +68,7 @@ struct rcu_state rcu_preempt_state = RCU_STATE_INITIALIZER(rcu_preempt_state); DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data); static struct rcu_state *rcu_state = &rcu_preempt_state; +static void rcu_read_unlock_special(struct task_struct *t); static int rcu_preempted_readers_exp(struct rcu_node *rnp); /* @@ -147,7 +148,7 @@ static void rcu_preempt_note_context_switch(int cpu) struct rcu_data *rdp; struct rcu_node *rnp; - if (t->rcu_read_lock_nesting && + if (t->rcu_read_lock_nesting > 0 && (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) { /* Possibly blocking in an RCU read-side critical section. */ @@ -190,6 +191,14 @@ static void rcu_preempt_note_context_switch(int cpu) rnp->gp_tasks = &t->rcu_node_entry; } raw_spin_unlock_irqrestore(&rnp->lock, flags); + } else if (t->rcu_read_lock_nesting < 0 && + t->rcu_read_unlock_special) { + + /* + * Complete exit from RCU read-side critical section on + * behalf of preempted instance of __rcu_read_unlock(). + */ + rcu_read_unlock_special(t); } /* @@ -284,7 +293,7 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t, * notify RCU core processing or task having blocked during the RCU * read-side critical section. */ -static void rcu_read_unlock_special(struct task_struct *t) +static noinline void rcu_read_unlock_special(struct task_struct *t) { int empty; int empty_exp; @@ -309,7 +318,7 @@ static void rcu_read_unlock_special(struct task_struct *t) } /* Hardware IRQ handlers cannot block. */ - if (in_irq()) { + if (in_irq() || in_serving_softirq()) { local_irq_restore(flags); return; } @@ -342,6 +351,11 @@ static void rcu_read_unlock_special(struct task_struct *t) #ifdef CONFIG_RCU_BOOST if (&t->rcu_node_entry == rnp->boost_tasks) rnp->boost_tasks = np; + /* Snapshot and clear ->rcu_boosted with rcu_node lock held. */ + if (t->rcu_boosted) { + special |= RCU_READ_UNLOCK_BOOSTED; + t->rcu_boosted = 0; + } #endif /* #ifdef CONFIG_RCU_BOOST */ t->rcu_blocked_node = NULL; @@ -358,7 +372,6 @@ static void rcu_read_unlock_special(struct task_struct *t) #ifdef CONFIG_RCU_BOOST /* Unboost if we were boosted. */ if (special & RCU_READ_UNLOCK_BOOSTED) { - t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BOOSTED; rt_mutex_unlock(t->rcu_boost_mutex); t->rcu_boost_mutex = NULL; } @@ -387,13 +400,22 @@ void __rcu_read_unlock(void) struct task_struct *t = current; barrier(); /* needed if we ever invoke rcu_read_unlock in rcutree.c */ - --t->rcu_read_lock_nesting; - barrier(); /* decrement before load of ->rcu_read_unlock_special */ - if (t->rcu_read_lock_nesting == 0 && - unlikely(ACCESS_ONCE(t->rcu_read_unlock_special))) - rcu_read_unlock_special(t); + if (t->rcu_read_lock_nesting != 1) + --t->rcu_read_lock_nesting; + else { + t->rcu_read_lock_nesting = INT_MIN; + barrier(); /* assign before ->rcu_read_unlock_special load */ + if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special))) + rcu_read_unlock_special(t); + barrier(); /* ->rcu_read_unlock_special load before assign */ + t->rcu_read_lock_nesting = 0; + } #ifdef CONFIG_PROVE_LOCKING - WARN_ON_ONCE(ACCESS_ONCE(t->rcu_read_lock_nesting) < 0); + { + int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting); + + WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2); + } #endif /* #ifdef CONFIG_PROVE_LOCKING */ } EXPORT_SYMBOL_GPL(__rcu_read_unlock); @@ -589,7 +611,8 @@ static void rcu_preempt_check_callbacks(int cpu) rcu_preempt_qs(cpu); return; } - if (per_cpu(rcu_preempt_data, cpu).qs_pending) + if (t->rcu_read_lock_nesting > 0 && + per_cpu(rcu_preempt_data, cpu).qs_pending) t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS; } @@ -695,9 +718,12 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp) raw_spin_lock_irqsave(&rnp->lock, flags); for (;;) { - if (!sync_rcu_preempt_exp_done(rnp)) + if (!sync_rcu_preempt_exp_done(rnp)) { + raw_spin_unlock_irqrestore(&rnp->lock, flags); break; + } if (rnp->parent == NULL) { + raw_spin_unlock_irqrestore(&rnp->lock, flags); wake_up(&sync_rcu_preempt_exp_wq); break; } @@ -707,7 +733,6 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp) raw_spin_lock(&rnp->lock); /* irqs already disabled */ rnp->expmask &= ~mask; } - raw_spin_unlock_irqrestore(&rnp->lock, flags); } /* @@ -1174,7 +1199,7 @@ static int rcu_boost(struct rcu_node *rnp) t = container_of(tb, struct task_struct, rcu_node_entry); rt_mutex_init_proxy_locked(&mtx, t); t->rcu_boost_mutex = &mtx; - t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BOOSTED; + t->rcu_boosted = 1; raw_spin_unlock_irqrestore(&rnp->lock, flags); rt_mutex_lock(&mtx); /* Side effect: boosts task t's priority. */ rt_mutex_unlock(&mtx); /* Keep lockdep happy. */ @@ -1532,7 +1557,7 @@ static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu) struct sched_param sp; struct task_struct *t; - if (!rcu_kthreads_spawnable || + if (!rcu_scheduler_fully_active || per_cpu(rcu_cpu_kthread_task, cpu) != NULL) return 0; t = kthread_create(rcu_cpu_kthread, (void *)(long)cpu, "rcuc%d", cpu); @@ -1639,7 +1664,7 @@ static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp, struct sched_param sp; struct task_struct *t; - if (!rcu_kthreads_spawnable || + if (!rcu_scheduler_fully_active || rnp->qsmaskinit == 0) return 0; if (rnp->node_kthread_task == NULL) { @@ -1665,7 +1690,7 @@ static int __init rcu_spawn_kthreads(void) int cpu; struct rcu_node *rnp; - rcu_kthreads_spawnable = 1; + rcu_scheduler_fully_active = 1; for_each_possible_cpu(cpu) { per_cpu(rcu_cpu_has_work, cpu) = 0; if (cpu_online(cpu)) @@ -1687,7 +1712,7 @@ static void __cpuinit rcu_prepare_kthreads(int cpu) struct rcu_node *rnp = rdp->mynode; /* Fire up the incoming CPU's kthread and leaf rcu_node kthread. */ - if (rcu_kthreads_spawnable) { + if (rcu_scheduler_fully_active) { (void)rcu_spawn_one_cpu_kthread(cpu); if (rnp->node_kthread_task == NULL) (void)rcu_spawn_one_node_kthread(rcu_state, rnp); @@ -1726,6 +1751,13 @@ static void rcu_cpu_kthread_setrt(int cpu, int to_rt) { } +static int __init rcu_scheduler_really_started(void) +{ + rcu_scheduler_fully_active = 1; + return 0; +} +early_initcall(rcu_scheduler_really_started); + static void __cpuinit rcu_prepare_kthreads(int cpu) { } diff --git a/kernel/resource.c b/kernel/resource.c index 798e2fae2a0..3ff40178dce 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -38,6 +38,14 @@ struct resource iomem_resource = { }; EXPORT_SYMBOL(iomem_resource); +/* constraints to be met while allocating resources */ +struct resource_constraint { + resource_size_t min, max, align; + resource_size_t (*alignf)(void *, const struct resource *, + resource_size_t, resource_size_t); + void *alignf_data; +}; + static DEFINE_RWLOCK(resource_lock); static void *r_next(struct seq_file *m, void *v, loff_t *pos) @@ -384,16 +392,13 @@ static bool resource_contains(struct resource *res1, struct resource *res2) } /* - * Find empty slot in the resource tree given range and alignment. + * Find empty slot in the resource tree with the given range and + * alignment constraints */ -static int find_resource(struct resource *root, struct resource *new, - resource_size_t size, resource_size_t min, - resource_size_t max, resource_size_t align, - resource_size_t (*alignf)(void *, - const struct resource *, - resource_size_t, - resource_size_t), - void *alignf_data) +static int __find_resource(struct resource *root, struct resource *old, + struct resource *new, + resource_size_t size, + struct resource_constraint *constraint) { struct resource *this = root->child; struct resource tmp = *new, avail, alloc; @@ -404,25 +409,26 @@ static int find_resource(struct resource *root, struct resource *new, * Skip past an allocated resource that starts at 0, since the assignment * of this->start - 1 to tmp->end below would cause an underflow. */ - if (this && this->start == 0) { - tmp.start = this->end + 1; + if (this && this->start == root->start) { + tmp.start = (this == old) ? old->start : this->end + 1; this = this->sibling; } for(;;) { if (this) - tmp.end = this->start - 1; + tmp.end = (this == old) ? this->end : this->start - 1; else tmp.end = root->end; - resource_clip(&tmp, min, max); + resource_clip(&tmp, constraint->min, constraint->max); arch_remove_reservations(&tmp); /* Check for overflow after ALIGN() */ avail = *new; - avail.start = ALIGN(tmp.start, align); + avail.start = ALIGN(tmp.start, constraint->align); avail.end = tmp.end; if (avail.start >= tmp.start) { - alloc.start = alignf(alignf_data, &avail, size, align); + alloc.start = constraint->alignf(constraint->alignf_data, &avail, + size, constraint->align); alloc.end = alloc.start + size - 1; if (resource_contains(&avail, &alloc)) { new->start = alloc.start; @@ -432,14 +438,75 @@ static int find_resource(struct resource *root, struct resource *new, } if (!this) break; - tmp.start = this->end + 1; + if (this != old) + tmp.start = this->end + 1; this = this->sibling; } return -EBUSY; } +/* + * Find empty slot in the resource tree given range and alignment. + */ +static int find_resource(struct resource *root, struct resource *new, + resource_size_t size, + struct resource_constraint *constraint) +{ + return __find_resource(root, NULL, new, size, constraint); +} + /** - * allocate_resource - allocate empty slot in the resource tree given range & alignment + * reallocate_resource - allocate a slot in the resource tree given range & alignment. + * The resource will be relocated if the new size cannot be reallocated in the + * current location. + * + * @root: root resource descriptor + * @old: resource descriptor desired by caller + * @newsize: new size of the resource descriptor + * @constraint: the size and alignment constraints to be met. + */ +int reallocate_resource(struct resource *root, struct resource *old, + resource_size_t newsize, + struct resource_constraint *constraint) +{ + int err=0; + struct resource new = *old; + struct resource *conflict; + + write_lock(&resource_lock); + + if ((err = __find_resource(root, old, &new, newsize, constraint))) + goto out; + + if (resource_contains(&new, old)) { + old->start = new.start; + old->end = new.end; + goto out; + } + + if (old->child) { + err = -EBUSY; + goto out; + } + + if (resource_contains(old, &new)) { + old->start = new.start; + old->end = new.end; + } else { + __release_resource(old); + *old = new; + conflict = __request_resource(root, old); + BUG_ON(conflict); + } +out: + write_unlock(&resource_lock); + return err; +} + + +/** + * allocate_resource - allocate empty slot in the resource tree given range & alignment. + * The resource will be reallocated with a new size if it was already allocated * @root: root resource descriptor * @new: resource descriptor desired by caller * @size: requested resource region size @@ -459,12 +526,25 @@ int allocate_resource(struct resource *root, struct resource *new, void *alignf_data) { int err; + struct resource_constraint constraint; if (!alignf) alignf = simple_align_resource; + constraint.min = min; + constraint.max = max; + constraint.align = align; + constraint.alignf = alignf; + constraint.alignf_data = alignf_data; + + if ( new->parent ) { + /* resource is already allocated, try reallocating with + the new constraints */ + return reallocate_resource(root, new, size, &constraint); + } + write_lock(&resource_lock); - err = find_resource(root, new, size, min, max, align, alignf, alignf_data); + err = find_resource(root, new, size, &constraint); if (err >= 0 && __request_resource(root, new)) err = -EBUSY; write_unlock(&resource_lock); diff --git a/kernel/sched.c b/kernel/sched.c index 3f2e502d609..fde6ff90352 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -292,8 +292,8 @@ static DEFINE_SPINLOCK(task_group_lock); * (The default weight is 1024 - so there's no practical * limitation from this.) */ -#define MIN_SHARES 2 -#define MAX_SHARES (1UL << (18 + SCHED_LOAD_RESOLUTION)) +#define MIN_SHARES (1UL << 1) +#define MAX_SHARES (1UL << 18) static int root_task_group_load = ROOT_TASK_GROUP_LOAD; #endif @@ -2544,13 +2544,9 @@ static int ttwu_remote(struct task_struct *p, int wake_flags) } #ifdef CONFIG_SMP -static void sched_ttwu_pending(void) +static void sched_ttwu_do_pending(struct task_struct *list) { struct rq *rq = this_rq(); - struct task_struct *list = xchg(&rq->wake_list, NULL); - - if (!list) - return; raw_spin_lock(&rq->lock); @@ -2563,9 +2559,45 @@ static void sched_ttwu_pending(void) raw_spin_unlock(&rq->lock); } +#ifdef CONFIG_HOTPLUG_CPU + +static void sched_ttwu_pending(void) +{ + struct rq *rq = this_rq(); + struct task_struct *list = xchg(&rq->wake_list, NULL); + + if (!list) + return; + + sched_ttwu_do_pending(list); +} + +#endif /* CONFIG_HOTPLUG_CPU */ + void scheduler_ipi(void) { - sched_ttwu_pending(); + struct rq *rq = this_rq(); + struct task_struct *list = xchg(&rq->wake_list, NULL); + + if (!list) + return; + + /* + * Not all reschedule IPI handlers call irq_enter/irq_exit, since + * traditionally all their work was done from the interrupt return + * path. Now that we actually do some work, we need to make sure + * we do call them. + * + * Some archs already do call them, luckily irq_enter/exit nest + * properly. + * + * Arguably we should visit all archs and update all handlers, + * however a fair share of IPIs are still resched only so this would + * somewhat pessimize the simple resched case. + */ + irq_enter(); + sched_ttwu_do_pending(list); + irq_exit(); } static void ttwu_queue_remote(struct task_struct *p, int cpu) @@ -6557,7 +6589,7 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, break; } - if (!group->cpu_power) { + if (!group->sgp->power) { printk(KERN_CONT "\n"); printk(KERN_ERR "ERROR: domain->cpu_power not " "set\n"); @@ -6581,9 +6613,9 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, cpulist_scnprintf(str, sizeof(str), sched_group_cpus(group)); printk(KERN_CONT " %s", str); - if (group->cpu_power != SCHED_POWER_SCALE) { + if (group->sgp->power != SCHED_POWER_SCALE) { printk(KERN_CONT " (cpu_power = %d)", - group->cpu_power); + group->sgp->power); } group = group->next; @@ -6774,11 +6806,39 @@ static struct root_domain *alloc_rootdomain(void) return rd; } +static void free_sched_groups(struct sched_group *sg, int free_sgp) +{ + struct sched_group *tmp, *first; + + if (!sg) + return; + + first = sg; + do { + tmp = sg->next; + + if (free_sgp && atomic_dec_and_test(&sg->sgp->ref)) + kfree(sg->sgp); + + kfree(sg); + sg = tmp; + } while (sg != first); +} + static void free_sched_domain(struct rcu_head *rcu) { struct sched_domain *sd = container_of(rcu, struct sched_domain, rcu); - if (atomic_dec_and_test(&sd->groups->ref)) + + /* + * If its an overlapping domain it has private groups, iterate and + * nuke them all. + */ + if (sd->flags & SD_OVERLAP) { + free_sched_groups(sd->groups, 1); + } else if (atomic_dec_and_test(&sd->groups->ref)) { + kfree(sd->groups->sgp); kfree(sd->groups); + } kfree(sd); } @@ -6945,6 +7005,7 @@ int sched_smt_power_savings = 0, sched_mc_power_savings = 0; struct sd_data { struct sched_domain **__percpu sd; struct sched_group **__percpu sg; + struct sched_group_power **__percpu sgp; }; struct s_data { @@ -6964,15 +7025,73 @@ struct sched_domain_topology_level; typedef struct sched_domain *(*sched_domain_init_f)(struct sched_domain_topology_level *tl, int cpu); typedef const struct cpumask *(*sched_domain_mask_f)(int cpu); +#define SDTL_OVERLAP 0x01 + struct sched_domain_topology_level { sched_domain_init_f init; sched_domain_mask_f mask; + int flags; struct sd_data data; }; -/* - * Assumes the sched_domain tree is fully constructed - */ +static int +build_overlap_sched_groups(struct sched_domain *sd, int cpu) +{ + struct sched_group *first = NULL, *last = NULL, *groups = NULL, *sg; + const struct cpumask *span = sched_domain_span(sd); + struct cpumask *covered = sched_domains_tmpmask; + struct sd_data *sdd = sd->private; + struct sched_domain *child; + int i; + + cpumask_clear(covered); + + for_each_cpu(i, span) { + struct cpumask *sg_span; + + if (cpumask_test_cpu(i, covered)) + continue; + + sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), + GFP_KERNEL, cpu_to_node(i)); + + if (!sg) + goto fail; + + sg_span = sched_group_cpus(sg); + + child = *per_cpu_ptr(sdd->sd, i); + if (child->child) { + child = child->child; + cpumask_copy(sg_span, sched_domain_span(child)); + } else + cpumask_set_cpu(i, sg_span); + + cpumask_or(covered, covered, sg_span); + + sg->sgp = *per_cpu_ptr(sdd->sgp, cpumask_first(sg_span)); + atomic_inc(&sg->sgp->ref); + + if (cpumask_test_cpu(cpu, sg_span)) + groups = sg; + + if (!first) + first = sg; + if (last) + last->next = sg; + last = sg; + last->next = first; + } + sd->groups = groups; + + return 0; + +fail: + free_sched_groups(first, 0); + + return -ENOMEM; +} + static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg) { struct sched_domain *sd = *per_cpu_ptr(sdd->sd, cpu); @@ -6981,24 +7100,24 @@ static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg) if (child) cpu = cpumask_first(sched_domain_span(child)); - if (sg) + if (sg) { *sg = *per_cpu_ptr(sdd->sg, cpu); + (*sg)->sgp = *per_cpu_ptr(sdd->sgp, cpu); + atomic_set(&(*sg)->sgp->ref, 1); /* for claim_allocations */ + } return cpu; } /* - * build_sched_groups takes the cpumask we wish to span, and a pointer - * to a function which identifies what group(along with sched group) a CPU - * belongs to. The return value of group_fn must be a >= 0 and < nr_cpu_ids - * (due to the fact that we keep track of groups covered with a struct cpumask). - * * build_sched_groups will build a circular linked list of the groups * covered by the given span, and will set each group's ->cpumask correctly, * and ->cpu_power to 0. + * + * Assumes the sched_domain tree is fully constructed */ -static void -build_sched_groups(struct sched_domain *sd) +static int +build_sched_groups(struct sched_domain *sd, int cpu) { struct sched_group *first = NULL, *last = NULL; struct sd_data *sdd = sd->private; @@ -7006,6 +7125,12 @@ build_sched_groups(struct sched_domain *sd) struct cpumask *covered; int i; + get_group(cpu, sdd, &sd->groups); + atomic_inc(&sd->groups->ref); + + if (cpu != cpumask_first(sched_domain_span(sd))) + return 0; + lockdep_assert_held(&sched_domains_mutex); covered = sched_domains_tmpmask; @@ -7020,7 +7145,7 @@ build_sched_groups(struct sched_domain *sd) continue; cpumask_clear(sched_group_cpus(sg)); - sg->cpu_power = 0; + sg->sgp->power = 0; for_each_cpu(j, span) { if (get_group(j, sdd, NULL) != group) @@ -7037,6 +7162,8 @@ build_sched_groups(struct sched_domain *sd) last = sg; } last->next = first; + + return 0; } /* @@ -7051,12 +7178,17 @@ build_sched_groups(struct sched_domain *sd) */ static void init_sched_groups_power(int cpu, struct sched_domain *sd) { - WARN_ON(!sd || !sd->groups); + struct sched_group *sg = sd->groups; - if (cpu != group_first_cpu(sd->groups)) - return; + WARN_ON(!sd || !sg); + + do { + sg->group_weight = cpumask_weight(sched_group_cpus(sg)); + sg = sg->next; + } while (sg != sd->groups); - sd->groups->group_weight = cpumask_weight(sched_group_cpus(sd->groups)); + if (cpu != group_first_cpu(sg)) + return; update_group_power(sd, cpu); } @@ -7177,15 +7309,15 @@ static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, static void claim_allocations(int cpu, struct sched_domain *sd) { struct sd_data *sdd = sd->private; - struct sched_group *sg = sd->groups; WARN_ON_ONCE(*per_cpu_ptr(sdd->sd, cpu) != sd); *per_cpu_ptr(sdd->sd, cpu) = NULL; - if (cpu == cpumask_first(sched_group_cpus(sg))) { - WARN_ON_ONCE(*per_cpu_ptr(sdd->sg, cpu) != sg); + if (atomic_read(&(*per_cpu_ptr(sdd->sg, cpu))->ref)) *per_cpu_ptr(sdd->sg, cpu) = NULL; - } + + if (atomic_read(&(*per_cpu_ptr(sdd->sgp, cpu))->ref)) + *per_cpu_ptr(sdd->sgp, cpu) = NULL; } #ifdef CONFIG_SCHED_SMT @@ -7210,7 +7342,7 @@ static struct sched_domain_topology_level default_topology[] = { #endif { sd_init_CPU, cpu_cpu_mask, }, #ifdef CONFIG_NUMA - { sd_init_NODE, cpu_node_mask, }, + { sd_init_NODE, cpu_node_mask, SDTL_OVERLAP, }, { sd_init_ALLNODES, cpu_allnodes_mask, }, #endif { NULL, }, @@ -7234,9 +7366,14 @@ static int __sdt_alloc(const struct cpumask *cpu_map) if (!sdd->sg) return -ENOMEM; + sdd->sgp = alloc_percpu(struct sched_group_power *); + if (!sdd->sgp) + return -ENOMEM; + for_each_cpu(j, cpu_map) { struct sched_domain *sd; struct sched_group *sg; + struct sched_group_power *sgp; sd = kzalloc_node(sizeof(struct sched_domain) + cpumask_size(), GFP_KERNEL, cpu_to_node(j)); @@ -7251,6 +7388,13 @@ static int __sdt_alloc(const struct cpumask *cpu_map) return -ENOMEM; *per_cpu_ptr(sdd->sg, j) = sg; + + sgp = kzalloc_node(sizeof(struct sched_group_power), + GFP_KERNEL, cpu_to_node(j)); + if (!sgp) + return -ENOMEM; + + *per_cpu_ptr(sdd->sgp, j) = sgp; } } @@ -7266,11 +7410,15 @@ static void __sdt_free(const struct cpumask *cpu_map) struct sd_data *sdd = &tl->data; for_each_cpu(j, cpu_map) { - kfree(*per_cpu_ptr(sdd->sd, j)); + struct sched_domain *sd = *per_cpu_ptr(sdd->sd, j); + if (sd && (sd->flags & SD_OVERLAP)) + free_sched_groups(sd->groups, 0); kfree(*per_cpu_ptr(sdd->sg, j)); + kfree(*per_cpu_ptr(sdd->sgp, j)); } free_percpu(sdd->sd); free_percpu(sdd->sg); + free_percpu(sdd->sgp); } } @@ -7316,8 +7464,13 @@ static int build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_topology_level *tl; sd = NULL; - for (tl = sched_domain_topology; tl->init; tl++) + for (tl = sched_domain_topology; tl->init; tl++) { sd = build_sched_domain(tl, &d, cpu_map, attr, sd, i); + if (tl->flags & SDTL_OVERLAP || sched_feat(FORCE_SD_OVERLAP)) + sd->flags |= SD_OVERLAP; + if (cpumask_equal(cpu_map, sched_domain_span(sd))) + break; + } while (sd->child) sd = sd->child; @@ -7329,13 +7482,13 @@ static int build_sched_domains(const struct cpumask *cpu_map, for_each_cpu(i, cpu_map) { for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) { sd->span_weight = cpumask_weight(sched_domain_span(sd)); - get_group(i, sd->private, &sd->groups); - atomic_inc(&sd->groups->ref); - - if (i != cpumask_first(sched_domain_span(sd))) - continue; - - build_sched_groups(sd); + if (sd->flags & SD_OVERLAP) { + if (build_overlap_sched_groups(sd, i)) + goto error; + } else { + if (build_sched_groups(sd, i)) + goto error; + } } } @@ -7757,6 +7910,9 @@ static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq) #endif #endif cfs_rq->min_vruntime = (u64)(-(1LL << 20)); +#ifndef CONFIG_64BIT + cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime; +#endif } static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq) @@ -8450,10 +8606,7 @@ int sched_group_set_shares(struct task_group *tg, unsigned long shares) if (!tg->se[0]) return -EINVAL; - if (shares < MIN_SHARES) - shares = MIN_SHARES; - else if (shares > MAX_SHARES) - shares = MAX_SHARES; + shares = clamp(shares, scale_load(MIN_SHARES), scale_load(MAX_SHARES)); mutex_lock(&shares_mutex); if (tg->shares == shares) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 433491c2dc8..c768588e180 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1585,7 +1585,7 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, } /* Adjust by relative CPU power of the group */ - avg_load = (avg_load * SCHED_POWER_SCALE) / group->cpu_power; + avg_load = (avg_load * SCHED_POWER_SCALE) / group->sgp->power; if (local_group) { this_load = avg_load; @@ -2631,7 +2631,7 @@ static void update_cpu_power(struct sched_domain *sd, int cpu) power >>= SCHED_POWER_SHIFT; } - sdg->cpu_power_orig = power; + sdg->sgp->power_orig = power; if (sched_feat(ARCH_POWER)) power *= arch_scale_freq_power(sd, cpu); @@ -2647,7 +2647,7 @@ static void update_cpu_power(struct sched_domain *sd, int cpu) power = 1; cpu_rq(cpu)->cpu_power = power; - sdg->cpu_power = power; + sdg->sgp->power = power; } static void update_group_power(struct sched_domain *sd, int cpu) @@ -2665,11 +2665,11 @@ static void update_group_power(struct sched_domain *sd, int cpu) group = child->groups; do { - power += group->cpu_power; + power += group->sgp->power; group = group->next; } while (group != child->groups); - sdg->cpu_power = power; + sdg->sgp->power = power; } /* @@ -2691,7 +2691,7 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group) /* * If ~90% of the cpu_power is still there, we're good. */ - if (group->cpu_power * 32 > group->cpu_power_orig * 29) + if (group->sgp->power * 32 > group->sgp->power_orig * 29) return 1; return 0; @@ -2771,7 +2771,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, } /* Adjust by relative CPU power of the group */ - sgs->avg_load = (sgs->group_load*SCHED_POWER_SCALE) / group->cpu_power; + sgs->avg_load = (sgs->group_load*SCHED_POWER_SCALE) / group->sgp->power; /* * Consider the group unbalanced when the imbalance is larger @@ -2788,7 +2788,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, if ((max_cpu_load - min_cpu_load) >= avg_load_per_task && max_nr_running > 1) sgs->group_imb = 1; - sgs->group_capacity = DIV_ROUND_CLOSEST(group->cpu_power, + sgs->group_capacity = DIV_ROUND_CLOSEST(group->sgp->power, SCHED_POWER_SCALE); if (!sgs->group_capacity) sgs->group_capacity = fix_small_capacity(sd, group); @@ -2877,7 +2877,7 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, return; sds->total_load += sgs.group_load; - sds->total_pwr += sg->cpu_power; + sds->total_pwr += sg->sgp->power; /* * In case the child domain prefers tasks go to siblings @@ -2962,7 +2962,7 @@ static int check_asym_packing(struct sched_domain *sd, if (this_cpu > busiest_cpu) return 0; - *imbalance = DIV_ROUND_CLOSEST(sds->max_load * sds->busiest->cpu_power, + *imbalance = DIV_ROUND_CLOSEST(sds->max_load * sds->busiest->sgp->power, SCHED_POWER_SCALE); return 1; } @@ -2993,7 +2993,7 @@ static inline void fix_small_imbalance(struct sd_lb_stats *sds, scaled_busy_load_per_task = sds->busiest_load_per_task * SCHED_POWER_SCALE; - scaled_busy_load_per_task /= sds->busiest->cpu_power; + scaled_busy_load_per_task /= sds->busiest->sgp->power; if (sds->max_load - sds->this_load + scaled_busy_load_per_task >= (scaled_busy_load_per_task * imbn)) { @@ -3007,28 +3007,28 @@ static inline void fix_small_imbalance(struct sd_lb_stats *sds, * moving them. */ - pwr_now += sds->busiest->cpu_power * + pwr_now += sds->busiest->sgp->power * min(sds->busiest_load_per_task, sds->max_load); - pwr_now += sds->this->cpu_power * + pwr_now += sds->this->sgp->power * min(sds->this_load_per_task, sds->this_load); pwr_now /= SCHED_POWER_SCALE; /* Amount of load we'd subtract */ tmp = (sds->busiest_load_per_task * SCHED_POWER_SCALE) / - sds->busiest->cpu_power; + sds->busiest->sgp->power; if (sds->max_load > tmp) - pwr_move += sds->busiest->cpu_power * + pwr_move += sds->busiest->sgp->power * min(sds->busiest_load_per_task, sds->max_load - tmp); /* Amount of load we'd add */ - if (sds->max_load * sds->busiest->cpu_power < + if (sds->max_load * sds->busiest->sgp->power < sds->busiest_load_per_task * SCHED_POWER_SCALE) - tmp = (sds->max_load * sds->busiest->cpu_power) / - sds->this->cpu_power; + tmp = (sds->max_load * sds->busiest->sgp->power) / + sds->this->sgp->power; else tmp = (sds->busiest_load_per_task * SCHED_POWER_SCALE) / - sds->this->cpu_power; - pwr_move += sds->this->cpu_power * + sds->this->sgp->power; + pwr_move += sds->this->sgp->power * min(sds->this_load_per_task, sds->this_load + tmp); pwr_move /= SCHED_POWER_SCALE; @@ -3074,7 +3074,7 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu, load_above_capacity *= (SCHED_LOAD_SCALE * SCHED_POWER_SCALE); - load_above_capacity /= sds->busiest->cpu_power; + load_above_capacity /= sds->busiest->sgp->power; } /* @@ -3090,8 +3090,8 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu, max_pull = min(sds->max_load - sds->avg_load, load_above_capacity); /* How much load to actually move to equalise the imbalance */ - *imbalance = min(max_pull * sds->busiest->cpu_power, - (sds->avg_load - sds->this_load) * sds->this->cpu_power) + *imbalance = min(max_pull * sds->busiest->sgp->power, + (sds->avg_load - sds->this_load) * sds->this->sgp->power) / SCHED_POWER_SCALE; /* diff --git a/kernel/sched_features.h b/kernel/sched_features.h index be40f7371ee..1e7066d76c2 100644 --- a/kernel/sched_features.h +++ b/kernel/sched_features.h @@ -70,3 +70,5 @@ SCHED_FEAT(NONIRQ_POWER, 1) * using the scheduler IPI. Reduces rq->lock contention/bounces. */ SCHED_FEAT(TTWU_QUEUE, 1) + +SCHED_FEAT(FORCE_SD_OVERLAP, 0) diff --git a/kernel/signal.c b/kernel/signal.c index ff767860332..415d85d6f6c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1178,18 +1178,25 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, { struct sighand_struct *sighand; - rcu_read_lock(); for (;;) { + local_irq_save(*flags); + rcu_read_lock(); sighand = rcu_dereference(tsk->sighand); - if (unlikely(sighand == NULL)) + if (unlikely(sighand == NULL)) { + rcu_read_unlock(); + local_irq_restore(*flags); break; + } - spin_lock_irqsave(&sighand->siglock, *flags); - if (likely(sighand == tsk->sighand)) + spin_lock(&sighand->siglock); + if (likely(sighand == tsk->sighand)) { + rcu_read_unlock(); break; - spin_unlock_irqrestore(&sighand->siglock, *flags); + } + spin_unlock(&sighand->siglock); + rcu_read_unlock(); + local_irq_restore(*flags); } - rcu_read_unlock(); return sighand; } diff --git a/kernel/softirq.c b/kernel/softirq.c index 40cf63ddd4b..fca82c32042 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -315,16 +315,24 @@ static inline void invoke_softirq(void) { if (!force_irqthreads) __do_softirq(); - else + else { + __local_bh_disable((unsigned long)__builtin_return_address(0), + SOFTIRQ_OFFSET); wakeup_softirqd(); + __local_bh_enable(SOFTIRQ_OFFSET); + } } #else static inline void invoke_softirq(void) { if (!force_irqthreads) do_softirq(); - else + else { + __local_bh_disable((unsigned long)__builtin_return_address(0), + SOFTIRQ_OFFSET); wakeup_softirqd(); + __local_bh_enable(SOFTIRQ_OFFSET); + } } #endif diff --git a/lib/debugobjects.c b/lib/debugobjects.c index 9d86e45086f..a78b7c6e042 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c @@ -198,7 +198,7 @@ static void free_object(struct debug_obj *obj) * initialized: */ if (obj_pool_free > ODEBUG_POOL_SIZE && obj_cache) - sched = !work_pending(&debug_obj_work); + sched = keventd_up() && !work_pending(&debug_obj_work); hlist_add_head(&obj->node, &obj_pool); obj_pool_free++; obj_pool_used--; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index ddffc74cdeb..e013b8e57d2 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -108,10 +108,12 @@ enum mem_cgroup_events_index { enum mem_cgroup_events_target { MEM_CGROUP_TARGET_THRESH, MEM_CGROUP_TARGET_SOFTLIMIT, + MEM_CGROUP_TARGET_NUMAINFO, MEM_CGROUP_NTARGETS, }; #define THRESHOLDS_EVENTS_TARGET (128) #define SOFTLIMIT_EVENTS_TARGET (1024) +#define NUMAINFO_EVENTS_TARGET (1024) struct mem_cgroup_stat_cpu { long count[MEM_CGROUP_STAT_NSTATS]; @@ -237,7 +239,8 @@ struct mem_cgroup { int last_scanned_node; #if MAX_NUMNODES > 1 nodemask_t scan_nodes; - unsigned long next_scan_node_update; + atomic_t numainfo_events; + atomic_t numainfo_updating; #endif /* * Should the accounting and control be hierarchical, per subtree? @@ -577,15 +580,6 @@ static long mem_cgroup_read_stat(struct mem_cgroup *mem, return val; } -static long mem_cgroup_local_usage(struct mem_cgroup *mem) -{ - long ret; - - ret = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_RSS); - ret += mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_CACHE); - return ret; -} - static void mem_cgroup_swap_statistics(struct mem_cgroup *mem, bool charge) { @@ -689,6 +683,9 @@ static void __mem_cgroup_target_update(struct mem_cgroup *mem, int target) case MEM_CGROUP_TARGET_SOFTLIMIT: next = val + SOFTLIMIT_EVENTS_TARGET; break; + case MEM_CGROUP_TARGET_NUMAINFO: + next = val + NUMAINFO_EVENTS_TARGET; + break; default: return; } @@ -707,11 +704,19 @@ static void memcg_check_events(struct mem_cgroup *mem, struct page *page) mem_cgroup_threshold(mem); __mem_cgroup_target_update(mem, MEM_CGROUP_TARGET_THRESH); if (unlikely(__memcg_event_check(mem, - MEM_CGROUP_TARGET_SOFTLIMIT))){ + MEM_CGROUP_TARGET_SOFTLIMIT))) { mem_cgroup_update_tree(mem, page); __mem_cgroup_target_update(mem, - MEM_CGROUP_TARGET_SOFTLIMIT); + MEM_CGROUP_TARGET_SOFTLIMIT); + } +#if MAX_NUMNODES > 1 + if (unlikely(__memcg_event_check(mem, + MEM_CGROUP_TARGET_NUMAINFO))) { + atomic_inc(&mem->numainfo_events); + __mem_cgroup_target_update(mem, + MEM_CGROUP_TARGET_NUMAINFO); } +#endif } } @@ -1129,7 +1134,6 @@ unsigned long mem_cgroup_zone_nr_lru_pages(struct mem_cgroup *memcg, return MEM_CGROUP_ZSTAT(mz, lru); } -#ifdef CONFIG_NUMA static unsigned long mem_cgroup_node_nr_file_lru_pages(struct mem_cgroup *memcg, int nid) { @@ -1141,6 +1145,17 @@ static unsigned long mem_cgroup_node_nr_file_lru_pages(struct mem_cgroup *memcg, return ret; } +static unsigned long mem_cgroup_node_nr_anon_lru_pages(struct mem_cgroup *memcg, + int nid) +{ + unsigned long ret; + + ret = mem_cgroup_get_zonestat_node(memcg, nid, LRU_INACTIVE_ANON) + + mem_cgroup_get_zonestat_node(memcg, nid, LRU_ACTIVE_ANON); + return ret; +} + +#if MAX_NUMNODES > 1 static unsigned long mem_cgroup_nr_file_lru_pages(struct mem_cgroup *memcg) { u64 total = 0; @@ -1152,17 +1167,6 @@ static unsigned long mem_cgroup_nr_file_lru_pages(struct mem_cgroup *memcg) return total; } -static unsigned long mem_cgroup_node_nr_anon_lru_pages(struct mem_cgroup *memcg, - int nid) -{ - unsigned long ret; - - ret = mem_cgroup_get_zonestat_node(memcg, nid, LRU_INACTIVE_ANON) + - mem_cgroup_get_zonestat_node(memcg, nid, LRU_ACTIVE_ANON); - - return ret; -} - static unsigned long mem_cgroup_nr_anon_lru_pages(struct mem_cgroup *memcg) { u64 total = 0; @@ -1559,6 +1563,28 @@ mem_cgroup_select_victim(struct mem_cgroup *root_mem) return ret; } +/** + * test_mem_cgroup_node_reclaimable + * @mem: the target memcg + * @nid: the node ID to be checked. + * @noswap : specify true here if the user wants flle only information. + * + * This function returns whether the specified memcg contains any + * reclaimable pages on a node. Returns true if there are any reclaimable + * pages in the node. + */ +static bool test_mem_cgroup_node_reclaimable(struct mem_cgroup *mem, + int nid, bool noswap) +{ + if (mem_cgroup_node_nr_file_lru_pages(mem, nid)) + return true; + if (noswap || !total_swap_pages) + return false; + if (mem_cgroup_node_nr_anon_lru_pages(mem, nid)) + return true; + return false; + +} #if MAX_NUMNODES > 1 /* @@ -1570,26 +1596,26 @@ mem_cgroup_select_victim(struct mem_cgroup *root_mem) static void mem_cgroup_may_update_nodemask(struct mem_cgroup *mem) { int nid; - - if (time_after(mem->next_scan_node_update, jiffies)) + /* + * numainfo_events > 0 means there was at least NUMAINFO_EVENTS_TARGET + * pagein/pageout changes since the last update. + */ + if (!atomic_read(&mem->numainfo_events)) + return; + if (atomic_inc_return(&mem->numainfo_updating) > 1) return; - mem->next_scan_node_update = jiffies + 10*HZ; /* make a nodemask where this memcg uses memory from */ mem->scan_nodes = node_states[N_HIGH_MEMORY]; for_each_node_mask(nid, node_states[N_HIGH_MEMORY]) { - if (mem_cgroup_get_zonestat_node(mem, nid, LRU_INACTIVE_FILE) || - mem_cgroup_get_zonestat_node(mem, nid, LRU_ACTIVE_FILE)) - continue; - - if (total_swap_pages && - (mem_cgroup_get_zonestat_node(mem, nid, LRU_INACTIVE_ANON) || - mem_cgroup_get_zonestat_node(mem, nid, LRU_ACTIVE_ANON))) - continue; - node_clear(nid, mem->scan_nodes); + if (!test_mem_cgroup_node_reclaimable(mem, nid, false)) + node_clear(nid, mem->scan_nodes); } + + atomic_set(&mem->numainfo_events, 0); + atomic_set(&mem->numainfo_updating, 0); } /* @@ -1627,11 +1653,51 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *mem) return node; } +/* + * Check all nodes whether it contains reclaimable pages or not. + * For quick scan, we make use of scan_nodes. This will allow us to skip + * unused nodes. But scan_nodes is lazily updated and may not cotain + * enough new information. We need to do double check. + */ +bool mem_cgroup_reclaimable(struct mem_cgroup *mem, bool noswap) +{ + int nid; + + /* + * quick check...making use of scan_node. + * We can skip unused nodes. + */ + if (!nodes_empty(mem->scan_nodes)) { + for (nid = first_node(mem->scan_nodes); + nid < MAX_NUMNODES; + nid = next_node(nid, mem->scan_nodes)) { + + if (test_mem_cgroup_node_reclaimable(mem, nid, noswap)) + return true; + } + } + /* + * Check rest of nodes. + */ + for_each_node_state(nid, N_HIGH_MEMORY) { + if (node_isset(nid, mem->scan_nodes)) + continue; + if (test_mem_cgroup_node_reclaimable(mem, nid, noswap)) + return true; + } + return false; +} + #else int mem_cgroup_select_victim_node(struct mem_cgroup *mem) { return 0; } + +bool mem_cgroup_reclaimable(struct mem_cgroup *mem, bool noswap) +{ + return test_mem_cgroup_node_reclaimable(mem, 0, noswap); +} #endif /* @@ -1702,7 +1768,7 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem, } } } - if (!mem_cgroup_local_usage(victim)) { + if (!mem_cgroup_reclaimable(victim, noswap)) { /* this cgroup's local usage == 0 */ css_put(&victim->css); continue; diff --git a/mm/memory.c b/mm/memory.c index 40b7531ee8b..9b8a01d941c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -305,6 +305,7 @@ int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) if (batch->nr == batch->max) { if (!tlb_next_batch(tlb)) return 0; + batch = tlb->active; } VM_BUG_ON(batch->nr > batch->max); diff --git a/mm/nommu.c b/mm/nommu.c index 1fd0c51b10a..9edc897a397 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1813,10 +1813,13 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address, return NULL; } -int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, - unsigned long to, unsigned long size, pgprot_t prot) +int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, + unsigned long pfn, unsigned long size, pgprot_t prot) { - vma->vm_start = vma->vm_pgoff << PAGE_SHIFT; + if (addr != (pfn << PAGE_SHIFT)) + return -EINVAL; + + vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; return 0; } EXPORT_SYMBOL(remap_pfn_range); diff --git a/mm/vmscan.c b/mm/vmscan.c index 4f49535d4cd..d036e59d302 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2310,7 +2310,8 @@ static bool pgdat_balanced(pg_data_t *pgdat, unsigned long balanced_pages, for (i = 0; i <= classzone_idx; i++) present_pages += pgdat->node_zones[i].present_pages; - return balanced_pages > (present_pages >> 2); + /* A special case here: if zone has no page, we think it's balanced */ + return balanced_pages >= (present_pages >> 2); } /* is kswapd sleeping prematurely? */ @@ -2326,7 +2327,7 @@ static bool sleeping_prematurely(pg_data_t *pgdat, int order, long remaining, return true; /* Check the watermark levels */ - for (i = 0; i < pgdat->nr_zones; i++) { + for (i = 0; i <= classzone_idx; i++) { struct zone *zone = pgdat->node_zones + i; if (!populated_zone(zone)) @@ -2344,7 +2345,7 @@ static bool sleeping_prematurely(pg_data_t *pgdat, int order, long remaining, } if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone), - classzone_idx, 0)) + i, 0)) all_zones_ok = false; else balanced += zone->present_pages; @@ -2451,7 +2452,6 @@ loop_again: if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone), 0, 0)) { end_zone = i; - *classzone_idx = i; break; } } @@ -2510,18 +2510,18 @@ loop_again: KSWAPD_ZONE_BALANCE_GAP_RATIO); if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone) + balance_gap, - end_zone, 0)) + end_zone, 0)) { shrink_zone(priority, zone, &sc); - reclaim_state->reclaimed_slab = 0; - nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages); - sc.nr_reclaimed += reclaim_state->reclaimed_slab; - total_scanned += sc.nr_scanned; - if (zone->all_unreclaimable) - continue; - if (nr_slab == 0 && - !zone_reclaimable(zone)) - zone->all_unreclaimable = 1; + reclaim_state->reclaimed_slab = 0; + nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages); + sc.nr_reclaimed += reclaim_state->reclaimed_slab; + total_scanned += sc.nr_scanned; + + if (nr_slab == 0 && !zone_reclaimable(zone)) + zone->all_unreclaimable = 1; + } + /* * If we've done a decent amount of scanning and * the reclaim ratio is low, start doing writepage @@ -2531,6 +2531,12 @@ loop_again: total_scanned > sc.nr_reclaimed + sc.nr_reclaimed / 2) sc.may_writepage = 1; + if (zone->all_unreclaimable) { + if (end_zone && end_zone == i) + end_zone--; + continue; + } + if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone), end_zone, 0)) { all_zones_ok = 0; @@ -2709,8 +2715,8 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order, int classzone_idx) */ static int kswapd(void *p) { - unsigned long order; - int classzone_idx; + unsigned long order, new_order; + int classzone_idx, new_classzone_idx; pg_data_t *pgdat = (pg_data_t*)p; struct task_struct *tsk = current; @@ -2740,17 +2746,23 @@ static int kswapd(void *p) tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; set_freezable(); - order = 0; - classzone_idx = MAX_NR_ZONES - 1; + order = new_order = 0; + classzone_idx = new_classzone_idx = pgdat->nr_zones - 1; for ( ; ; ) { - unsigned long new_order; - int new_classzone_idx; int ret; - new_order = pgdat->kswapd_max_order; - new_classzone_idx = pgdat->classzone_idx; - pgdat->kswapd_max_order = 0; - pgdat->classzone_idx = MAX_NR_ZONES - 1; + /* + * If the last balance_pgdat was unsuccessful it's unlikely a + * new request of a similar or harder type will succeed soon + * so consider going to sleep on the basis we reclaimed at + */ + if (classzone_idx >= new_classzone_idx && order == new_order) { + new_order = pgdat->kswapd_max_order; + new_classzone_idx = pgdat->classzone_idx; + pgdat->kswapd_max_order = 0; + pgdat->classzone_idx = pgdat->nr_zones - 1; + } + if (order < new_order || classzone_idx > new_classzone_idx) { /* * Don't sleep if someone wants a larger 'order' @@ -2763,7 +2775,7 @@ static int kswapd(void *p) order = pgdat->kswapd_max_order; classzone_idx = pgdat->classzone_idx; pgdat->kswapd_max_order = 0; - pgdat->classzone_idx = MAX_NR_ZONES - 1; + pgdat->classzone_idx = pgdat->nr_zones - 1; } ret = try_to_freeze(); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 7ea5cf9ea08..6e82148edfc 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -528,7 +528,11 @@ static int vlan_dev_init(struct net_device *dev) (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); - dev->hw_features = NETIF_F_ALL_TX_OFFLOADS; + dev->hw_features = NETIF_F_ALL_CSUM | NETIF_F_SG | + NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | + NETIF_F_HIGHDMA | NETIF_F_SCTP_CSUM | + NETIF_F_ALL_FCOE; + dev->features |= real_dev->vlan_features | NETIF_F_LLTX; dev->gso_max_size = real_dev->gso_max_size; @@ -586,9 +590,14 @@ static void vlan_dev_uninit(struct net_device *dev) static u32 vlan_dev_fix_features(struct net_device *dev, u32 features) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; + u32 old_features = features; features &= real_dev->features; features &= real_dev->vlan_features; + + if (old_features & NETIF_F_SOFT_FEATURES) + features |= old_features & NETIF_F_SOFT_FEATURES; + if (dev_ethtool_get_rx_csum(real_dev)) features |= NETIF_F_RXCSUM; features |= NETIF_F_LLTX; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index d3a05b9ade7..bcd158f40bb 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -393,6 +393,9 @@ int hci_conn_del(struct hci_conn *conn) hci_dev_put(hdev); + if (conn->handle == 0) + kfree(conn); + return 0; } diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index c405a954a60..43b4c2deb7c 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -464,7 +464,8 @@ static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } static void hidp_set_timer(struct hidp_session *session) @@ -535,7 +536,8 @@ static void hidp_process_hid_control(struct hidp_session *session, skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(current); } } @@ -706,9 +708,8 @@ static int hidp_session(void *arg) add_wait_queue(sk_sleep(intr_sk), &intr_wait); session->waiting_for_startup = 0; wake_up_interruptible(&session->startup_queue); - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - + set_current_state(TASK_INTERRUPTIBLE); + while (!atomic_read(&session->terminate)) { if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) break; @@ -726,6 +727,7 @@ static int hidp_session(void *arg) hidp_process_transmit(session); schedule(); + set_current_state(TASK_INTERRUPTIBLE); } set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(intr_sk), &intr_wait); @@ -1060,7 +1062,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, err_add_device: hid_destroy_device(session->hid); session->hid = NULL; - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); unlink: hidp_del_timer(session); @@ -1111,7 +1114,8 @@ int hidp_del_connection(struct hidp_conndel_req *req) skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } } else err = -ENOENT; diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 19e95004b28..af1bcc823f2 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -142,6 +142,7 @@ struct hidp_session { uint ctrl_mtu; uint intr_mtu; + atomic_t terminate; struct task_struct *task; unsigned char keys[8]; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 56fdd9162da..7705e26e699 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -620,7 +620,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); - parent->sk_data_ready(parent, 0); + if (parent) + parent->sk_data_ready(parent, 0); } else { sk->sk_state = BT_CONFIG; @@ -2323,7 +2324,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk = chan->sk; - if (sk->sk_state != BT_CONFIG) { + if (sk->sk_state != BT_CONFIG && sk->sk_state != BT_CONNECT2) { struct l2cap_cmd_rej rej; rej.reason = cpu_to_le16(0x0002); @@ -2334,7 +2335,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Reject if config buffer is too small. */ len = cmd_len - sizeof(*req); - if (chan->conf_len + len > sizeof(chan->conf_req)) { + if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_REJECT, flags), rsp); @@ -4009,7 +4010,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) struct sock *parent = bt_sk(sk)->parent; res = L2CAP_CR_PEND; stat = L2CAP_CS_AUTHOR_PEND; - parent->sk_data_ready(parent, 0); + if (parent) + parent->sk_data_ready(parent, 0); } else { sk->sk_state = BT_CONFIG; res = L2CAP_CR_SUCCESS; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index c188c803c09..32b8f9f7f79 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -49,7 +49,9 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) skb_pull(skb, ETH_HLEN); rcu_read_lock(); - if (is_multicast_ether_addr(dest)) { + if (is_broadcast_ether_addr(dest)) + br_flood_deliver(br, skb); + else if (is_multicast_ether_addr(dest)) { if (unlikely(netpoll_tx_running(dev))) { br_flood_deliver(br, skb); goto out; diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index f3ac1e858ee..f06ee39c73f 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -60,7 +60,7 @@ int br_handle_frame_finish(struct sk_buff *skb) br = p->br; br_fdb_update(br, p, eth_hdr(skb)->h_source); - if (is_multicast_ether_addr(dest) && + if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) && br_multicast_rcv(br, p, skb)) goto drop; @@ -77,7 +77,9 @@ int br_handle_frame_finish(struct sk_buff *skb) dst = NULL; - if (is_multicast_ether_addr(dest)) { + if (is_broadcast_ether_addr(dest)) + skb2 = skb; + else if (is_multicast_ether_addr(dest)) { mdst = br_mdb_get(br, skb); if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) { if ((mdst && mdst->mglist) || diff --git a/net/ceph/ceph_fs.c b/net/ceph/ceph_fs.c index a3a3a31d3c3..41466ccb972 100644 --- a/net/ceph/ceph_fs.c +++ b/net/ceph/ceph_fs.c @@ -36,16 +36,19 @@ int ceph_flags_to_mode(int flags) if ((flags & O_DIRECTORY) == O_DIRECTORY) return CEPH_FILE_MODE_PIN; #endif - if ((flags & O_APPEND) == O_APPEND) - flags |= O_WRONLY; - if ((flags & O_ACCMODE) == O_RDWR) - mode = CEPH_FILE_MODE_RDWR; - else if ((flags & O_ACCMODE) == O_WRONLY) + switch (flags & O_ACCMODE) { + case O_WRONLY: mode = CEPH_FILE_MODE_WR; - else + break; + case O_RDONLY: mode = CEPH_FILE_MODE_RD; - + break; + case O_RDWR: + case O_ACCMODE: /* this is what the VFS does */ + mode = CEPH_FILE_MODE_RDWR; + break; + } #ifdef O_LAZY if (flags & O_LAZY) mode |= CEPH_FILE_MODE_LAZY; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 9cb627a4073..7330c2757c0 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -477,8 +477,9 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, calc_layout(osdc, vino, layout, off, plen, req, ops); req->r_file_layout = *layout; /* keep a copy */ - /* in case it differs from natural alignment that calc_layout - filled in for us */ + /* in case it differs from natural (file) alignment that + calc_layout filled in for us */ + req->r_num_pages = calc_pages_for(page_align, *plen); req->r_page_alignment = page_align; ceph_osdc_build_request(req, off, plen, ops, @@ -2027,8 +2028,9 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, int want = calc_pages_for(req->r_page_alignment, data_len); if (unlikely(req->r_num_pages < want)) { - pr_warning("tid %lld reply %d > expected %d pages\n", - tid, want, m->nr_pages); + pr_warning("tid %lld reply has %d bytes %d pages, we" + " had only %d pages ready\n", tid, data_len, + want, req->r_num_pages); *skip = 1; ceph_msg_put(m); m = NULL; diff --git a/net/core/dst.c b/net/core/dst.c index 9ccca038444..6135f367169 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -190,7 +190,8 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, dst->lastuse = jiffies; dst->flags = flags; dst->next = NULL; - dst_entries_add(ops, 1); + if (!(flags & DST_NOCOUNT)) + dst_entries_add(ops, 1); return dst; } EXPORT_SYMBOL(dst_alloc); @@ -243,7 +244,8 @@ again: neigh_release(neigh); } - dst_entries_add(dst->ops, -1); + if (!(dst->flags & DST_NOCOUNT)) + dst_entries_add(dst->ops, -1); if (dst->ops->destroy) dst->ops->destroy(dst); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index eae1f676f87..ef1528af7ab 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -465,8 +465,10 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_len < sizeof(struct sockaddr_in)) goto out; - if (addr->sin_family != AF_INET) + if (addr->sin_family != AF_INET) { + err = -EAFNOSUPPORT; goto out; + } chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 4a7e16b5d3f..84f26e8e6c6 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -828,7 +828,7 @@ static int __ip_append_data(struct sock *sk, cork->length += length; if (((length > mtu) || (skb && skb_is_gso(skb))) && (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO)) { + (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len) { err = ip_ufo_append_data(sk, queue, getfrag, from, length, hh_len, fragheaderlen, transhdrlen, mtu, flags); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 054a59d21eb..46febcacb72 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3220,7 +3220,7 @@ __setup("thash_entries=", set_thash_entries); void __init tcp_init(void) { struct sk_buff *skb = NULL; - unsigned long nr_pages, limit; + unsigned long limit; int i, max_share, cnt; unsigned long jiffy = jiffies; @@ -3277,13 +3277,7 @@ void __init tcp_init(void) sysctl_tcp_max_orphans = cnt / 2; sysctl_max_syn_backlog = max(128, cnt / 256); - /* Set the pressure threshold to be a fraction of global memory that - * is up to 1/2 at 256 MB, decreasing toward zero with the amount of - * memory, with a floor of 128 pages. - */ - nr_pages = totalram_pages - totalhigh_pages; - limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); - limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); + limit = nr_free_buffer_pages() / 8; limit = max(limit, 128UL); sysctl_tcp_mem[0] = limit / 4 * 3; sysctl_tcp_mem[1] = limit; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 48cd88e6255..198f75b7bdd 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2209,16 +2209,10 @@ void __init udp_table_init(struct udp_table *table, const char *name) void __init udp_init(void) { - unsigned long nr_pages, limit; + unsigned long limit; udp_table_init(&udp_table, "UDP"); - /* Set the pressure threshold up by the same strategy of TCP. It is a - * fraction of global memory that is up to 1/2 at 256 MB, decreasing - * toward zero with the amount of memory, with a floor of 128 pages. - */ - nr_pages = totalram_pages - totalhigh_pages; - limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); - limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); + limit = nr_free_buffer_pages() / 8; limit = max(limit, 128UL); sysctl_udp_mem[0] = limit / 4 * 3; sysctl_udp_mem[1] = limit; diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 2d51840e53a..327a617d594 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -32,7 +32,12 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb) dst = skb_dst(skb); mtu = dst_mtu(dst); if (skb->len > mtu) { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); + if (skb->sk) + ip_local_error(skb->sk, EMSGSIZE, ip_hdr(skb)->daddr, + inet_sk(skb->sk)->inet_dport, mtu); + else + icmp_send(skb, ICMP_DEST_UNREACH, + ICMP_FRAG_NEEDED, htonl(mtu)); ret = -EMSGSIZE; } out: diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index d450a2f9fc0..3b5669a2582 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -274,7 +274,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) return -EINVAL; if (addr->sin6_family != AF_INET6) - return -EINVAL; + return -EAFNOSUPPORT; addr_type = ipv6_addr_type(&addr->sin6_addr); if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index de2b1decd78..0ef1f086feb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -228,9 +228,10 @@ static struct rt6_info ip6_blk_hole_entry_template = { /* allocate dst with ip6_dst_ops */ static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops, - struct net_device *dev) + struct net_device *dev, + int flags) { - struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, 0); + struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, flags); memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry)); @@ -1042,7 +1043,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, if (unlikely(idev == NULL)) return NULL; - rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev); + rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0); if (unlikely(rt == NULL)) { in6_dev_put(idev); goto out; @@ -1062,14 +1063,6 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); rt->dst.output = ip6_output; -#if 0 /* there's no chance to use these for ndisc */ - rt->dst.flags = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST - ? DST_HOST - : 0; - ipv6_addr_copy(&rt->rt6i_dst.addr, addr); - rt->rt6i_dst.plen = 128; -#endif - spin_lock_bh(&icmp6_dst_lock); rt->dst.next = icmp6_dst_gc_list; icmp6_dst_gc_list = &rt->dst; @@ -1214,7 +1207,7 @@ int ip6_route_add(struct fib6_config *cfg) goto out; } - rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL); + rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL, DST_NOCOUNT); if (rt == NULL) { err = -ENOMEM; @@ -1244,7 +1237,7 @@ int ip6_route_add(struct fib6_config *cfg) ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); rt->rt6i_dst.plen = cfg->fc_dst_len; if (rt->rt6i_dst.plen == 128) - rt->dst.flags = DST_HOST; + rt->dst.flags |= DST_HOST; #ifdef CONFIG_IPV6_SUBTREES ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); @@ -1734,7 +1727,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) { struct net *net = dev_net(ort->rt6i_dev); struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, - ort->dst.dev); + ort->dst.dev, 0); if (rt) { rt->dst.input = ort->dst.input; @@ -2013,7 +2006,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, { struct net *net = dev_net(idev->dev); struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, - net->loopback_dev); + net->loopback_dev, 0); struct neighbour *neigh; if (rt == NULL) { @@ -2025,7 +2018,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, in6_dev_hold(idev); - rt->dst.flags = DST_HOST; + rt->dst.flags |= DST_HOST; rt->dst.input = ip6_input; rt->dst.output = ip6_output; rt->rt6i_idev = idev; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 58ffa7d069c..669d2e32efb 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -877,7 +877,8 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, for (i = 0; i < IEEE80211_NUM_BANDS; i++) { local->sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len, + local->scan_ies_len + + req->ie_len, GFP_KERNEL); if (!local->sched_scan_ies.ie[i]) { ret = -ENOMEM; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 9dc3b5f26e8..8f6a302d2ac 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -86,6 +86,11 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + int queue = rx->queue; + + /* otherwise, TKIP is vulnerable to TID 0 vs. non-QoS replays */ + if (rx->queue == NUM_RX_DATA_QUEUES - 1) + queue = 0; /* * it makes no sense to check for MIC errors on anything other @@ -148,13 +153,19 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) update_iv: /* update IV in key information to be able to detect replays */ - rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; - rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; + rx->key->u.tkip.rx[queue].iv32 = rx->tkip_iv32; + rx->key->u.tkip.rx[queue].iv16 = rx->tkip_iv16; return RX_CONTINUE; mic_fail: - mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, + /* + * In some cases the key can be unset - e.g. a multicast packet, in + * a driver that supports HW encryption. Send up the key idx only if + * the key is set. + */ + mac80211_ev_michael_mic_failure(rx->sdata, + rx->key ? rx->key->conf.keyidx : -1, (void *) skb->data, NULL, GFP_ATOMIC); return RX_DROP_UNUSABLE; } @@ -235,6 +246,11 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + int queue = rx->queue; + + /* otherwise, TKIP is vulnerable to TID 0 vs. non-QoS replays */ + if (rx->queue == NUM_RX_DATA_QUEUES - 1) + queue = 0; hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -255,7 +271,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, key, skb->data + hdrlen, skb->len - hdrlen, rx->sta->sta.addr, - hdr->addr1, hwaccel, rx->queue, + hdr->addr1, hwaccel, queue, &rx->tkip_iv32, &rx->tkip_iv16); if (res != TKIP_DECRYPT_OK) diff --git a/net/sctp/output.c b/net/sctp/output.c index b4f3cf06d8d..08b3cead650 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -500,23 +500,20 @@ int sctp_packet_transmit(struct sctp_packet *packet) * Note: Adler-32 is no longer applicable, as has been replaced * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>. */ - if (!sctp_checksum_disable && - !(dst->dev->features & (NETIF_F_NO_CSUM | NETIF_F_SCTP_CSUM))) { - __u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); + if (!sctp_checksum_disable) { + if (!(dst->dev->features & NETIF_F_SCTP_CSUM)) { + __u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); - /* 3) Put the resultant value into the checksum field in the - * common header, and leave the rest of the bits unchanged. - */ - sh->checksum = sctp_end_cksum(crc32); - } else { - if (dst->dev->features & NETIF_F_SCTP_CSUM) { + /* 3) Put the resultant value into the checksum field in the + * common header, and leave the rest of the bits unchanged. + */ + sh->checksum = sctp_end_cksum(crc32); + } else { /* no need to seed pseudo checksum for SCTP */ nskb->ip_summed = CHECKSUM_PARTIAL; nskb->csum_start = (skb_transport_header(nskb) - nskb->head); nskb->csum_offset = offsetof(struct sctphdr, checksum); - } else { - nskb->ip_summed = CHECKSUM_UNNECESSARY; } } diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 1c88c8911dc..d03682109b7 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -1582,6 +1582,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, #endif /* SCTP_DEBUG */ if (transport) { if (bytes_acked) { + struct sctp_association *asoc = transport->asoc; + /* We may have counted DATA that was migrated * to this transport due to DEL-IP operation. * Subtract those bytes, since the were never @@ -1600,6 +1602,17 @@ static void sctp_check_transmitted(struct sctp_outq *q, transport->error_count = 0; transport->asoc->overall_error_count = 0; + /* + * While in SHUTDOWN PENDING, we may have started + * the T5 shutdown guard timer after reaching the + * retransmission limit. Stop that timer as soon + * as the receiver acknowledged any data. + */ + if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING && + del_timer(&asoc->timers + [SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD])) + sctp_association_put(asoc); + /* Mark the destination transport address as * active if it is not so marked. */ @@ -1629,10 +1642,15 @@ static void sctp_check_transmitted(struct sctp_outq *q, * A sender is doing zero window probing when the * receiver's advertised window is zero, and there is * only one data chunk in flight to the receiver. + * + * Allow the association to timeout while in SHUTDOWN + * PENDING or SHUTDOWN RECEIVED in case the receiver + * stays in zero window mode forever. */ if (!q->asoc->peer.rwnd && !list_empty(&tlist) && - (sack_ctsn+2 == q->asoc->next_tsn)) { + (sack_ctsn+2 == q->asoc->next_tsn) && + q->asoc->state < SCTP_STATE_SHUTDOWN_PENDING) { SCTP_DEBUG_PRINTK("%s: SACK received for zero " "window probe: %u\n", __func__, sack_ctsn); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 67380a29e2e..207175b2f40 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1058,7 +1058,6 @@ SCTP_STATIC __init int sctp_init(void) int status = -EINVAL; unsigned long goal; unsigned long limit; - unsigned long nr_pages; int max_share; int order; @@ -1148,15 +1147,7 @@ SCTP_STATIC __init int sctp_init(void) /* Initialize handle used for association ids. */ idr_init(&sctp_assocs_id); - /* Set the pressure threshold to be a fraction of global memory that - * is up to 1/2 at 256 MB, decreasing toward zero with the amount of - * memory, with a floor of 128 pages. - * Note this initializes the data in sctpv6_prot too - * Unabashedly stolen from tcp_init - */ - nr_pages = totalram_pages - totalhigh_pages; - limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); - limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); + limit = nr_free_buffer_pages() / 8; limit = max(limit, 128UL); sysctl_sctp_mem[0] = limit / 4 * 3; sysctl_sctp_mem[1] = limit; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 534c2e5feb0..6e0f88295aa 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -670,10 +670,19 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the * HEARTBEAT should clear the error counter of the destination * transport address to which the HEARTBEAT was sent. - * The association's overall error count is also cleared. */ t->error_count = 0; - t->asoc->overall_error_count = 0; + + /* + * Although RFC4960 specifies that the overall error count must + * be cleared when a HEARTBEAT ACK is received, we make an + * exception while in SHUTDOWN PENDING. If the peer keeps its + * window shut forever, we may never be able to transmit our + * outstanding data and rely on the retransmission limit be reached + * to shutdown the association. + */ + if (t->asoc->state != SCTP_STATE_SHUTDOWN_PENDING) + t->asoc->overall_error_count = 0; /* Clear the hb_sent flag to signal that we had a good * acknowledgement. @@ -1437,6 +1446,13 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, sctp_cmd_setup_t2(commands, asoc, cmd->obj.ptr); break; + case SCTP_CMD_TIMER_START_ONCE: + timer = &asoc->timers[cmd->obj.to]; + + if (timer_pending(timer)) + break; + /* fall through */ + case SCTP_CMD_TIMER_START: timer = &asoc->timers[cmd->obj.to]; timeout = asoc->timeouts[cmd->obj.to]; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a297283154d..246117142b5 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5154,7 +5154,7 @@ sctp_disposition_t sctp_sf_do_9_2_start_shutdown( * The sender of the SHUTDOWN MAY also start an overall guard timer * 'T5-shutdown-guard' to bound the overall time for shutdown sequence. */ - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); if (asoc->autoclose) @@ -5299,14 +5299,28 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep, SCTP_INC_STATS(SCTP_MIB_T3_RTX_EXPIREDS); if (asoc->overall_error_count >= asoc->max_retrans) { - sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, - SCTP_ERROR(ETIMEDOUT)); - /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, - SCTP_PERR(SCTP_ERROR_NO_ERROR)); - SCTP_INC_STATS(SCTP_MIB_ABORTEDS); - SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); - return SCTP_DISPOSITION_DELETE_TCB; + if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) { + /* + * We are here likely because the receiver had its rwnd + * closed for a while and we have not been able to + * transmit the locally queued data within the maximum + * retransmission attempts limit. Start the T5 + * shutdown guard timer to give the receiver one last + * chance and some additional time to recover before + * aborting. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START_ONCE, + SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); + } else { + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); + /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + SCTP_PERR(SCTP_ERROR_NO_ERROR)); + SCTP_INC_STATS(SCTP_MIB_ABORTEDS); + SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); + return SCTP_DISPOSITION_DELETE_TCB; + } } /* E1) For the destination address for which the timer diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 0338dc6fdc9..7c211a7f90f 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -827,7 +827,7 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ /* SCTP_STATE_ESTABLISHED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ + TYPE_SCTP_FUNC(sctp_sf_t5_timer_expire), \ /* SCTP_STATE_SHUTDOWN_SENT */ \ TYPE_SCTP_FUNC(sctp_sf_t5_timer_expire), \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6766913a53e..d3ccf7973c5 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1384,6 +1384,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) struct sctp_endpoint *ep; struct sctp_association *asoc; struct list_head *pos, *temp; + unsigned int data_was_unread; SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); @@ -1393,6 +1394,10 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) ep = sctp_sk(sk)->ep; + /* Clean up any skbs sitting on the receive queue. */ + data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue); + data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); + /* Walk all associations on an endpoint. */ list_for_each_safe(pos, temp, &ep->asocs) { asoc = list_entry(pos, struct sctp_association, asocs); @@ -1410,7 +1415,9 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) } } - if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { + if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) || + !skb_queue_empty(&asoc->ulpq.reasm) || + (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { struct sctp_chunk *chunk; chunk = sctp_make_abort_user(asoc, NULL, 0); @@ -1420,10 +1427,6 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) sctp_primitive_SHUTDOWN(asoc, NULL); } - /* Clean up any skbs sitting on the receive queue. */ - sctp_queue_purge_ulpevents(&sk->sk_receive_queue); - sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); - /* On a TCP-style socket, block for at most linger_time if set. */ if (sctp_style(sk, TCP) && timeout) sctp_wait_for_close(sk, timeout); @@ -2073,10 +2076,33 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk, static int sctp_setsockopt_events(struct sock *sk, char __user *optval, unsigned int optlen) { + struct sctp_association *asoc; + struct sctp_ulpevent *event; + if (optlen > sizeof(struct sctp_event_subscribe)) return -EINVAL; if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) return -EFAULT; + + /* + * At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, + * if there is no data to be sent or retransmit, the stack will + * immediately send up this notification. + */ + if (sctp_ulpevent_type_enabled(SCTP_SENDER_DRY_EVENT, + &sctp_sk(sk)->subscribe)) { + asoc = sctp_id2assoc(sk, 0); + + if (asoc && sctp_outq_is_empty(&asoc->outqueue)) { + event = sctp_ulpevent_make_sender_dry_event(asoc, + GFP_ATOMIC); + if (!event) + return -ENOMEM; + + sctp_ulpq_tail_event(&asoc->ulpq, event); + } + } + return 0; } diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index e70e5fc8789..8a84017834c 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -1081,9 +1081,19 @@ void sctp_ulpevent_free(struct sctp_ulpevent *event) } /* Purge the skb lists holding ulpevents. */ -void sctp_queue_purge_ulpevents(struct sk_buff_head *list) +unsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list) { struct sk_buff *skb; - while ((skb = skb_dequeue(list)) != NULL) - sctp_ulpevent_free(sctp_skb2event(skb)); + unsigned int data_unread = 0; + + while ((skb = skb_dequeue(list)) != NULL) { + struct sctp_ulpevent *event = sctp_skb2event(skb); + + if (!sctp_ulpevent_is_notification(event)) + data_unread += skb->len; + + sctp_ulpevent_free(event); + } + + return data_unread; } diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 9a80a922c52..e45d2fbbe5a 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -597,7 +597,7 @@ void rpcb_getport_async(struct rpc_task *task) u32 bind_version; struct rpc_xprt *xprt; struct rpc_clnt *rpcb_clnt; - static struct rpcbind_args *map; + struct rpcbind_args *map; struct rpc_task *child; struct sockaddr_storage addr; struct sockaddr *sap = (struct sockaddr *)&addr; diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index a27406b1654..4814e246a87 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -616,30 +616,25 @@ static void __rpc_execute(struct rpc_task *task) BUG_ON(RPC_IS_QUEUED(task)); for (;;) { + void (*do_action)(struct rpc_task *); /* - * Execute any pending callback. + * Execute any pending callback first. */ - if (task->tk_callback) { - void (*save_callback)(struct rpc_task *); - - /* - * We set tk_callback to NULL before calling it, - * in case it sets the tk_callback field itself: - */ - save_callback = task->tk_callback; - task->tk_callback = NULL; - save_callback(task); - } else { + do_action = task->tk_callback; + task->tk_callback = NULL; + if (do_action == NULL) { /* * Perform the next FSM step. - * tk_action may be NULL when the task has been killed - * by someone else. + * tk_action may be NULL if the task has been killed. + * In particular, note that rpc_killall_tasks may + * do this at any time, so beware when dereferencing. */ - if (task->tk_action == NULL) + do_action = task->tk_action; + if (do_action == NULL) break; - task->tk_action(task); } + do_action(task); /* * Lockless check for whether task is sleeping or not. diff --git a/net/wireless/core.c b/net/wireless/core.c index c22ef3492ee..880dbe2e6f9 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -366,6 +366,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); + mutex_init(&rdev->sched_scan_mtx); INIT_LIST_HEAD(&rdev->netdev_list); spin_lock_init(&rdev->bss_lock); INIT_LIST_HEAD(&rdev->bss_list); @@ -701,6 +702,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) rfkill_destroy(rdev->rfkill); mutex_destroy(&rdev->mtx); mutex_destroy(&rdev->devlist_mtx); + mutex_destroy(&rdev->sched_scan_mtx); list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) cfg80211_put_bss(&scan->pub); cfg80211_rdev_free_wowlan(rdev); @@ -737,12 +739,16 @@ static void wdev_cleanup_work(struct work_struct *work) ___cfg80211_scan_done(rdev, true); } + cfg80211_unlock_rdev(rdev); + + mutex_lock(&rdev->sched_scan_mtx); + if (WARN_ON(rdev->sched_scan_req && rdev->sched_scan_req->dev == wdev->netdev)) { __cfg80211_stop_sched_scan(rdev, false); } - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); mutex_lock(&rdev->devlist_mtx); rdev->opencount--; @@ -830,9 +836,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); __cfg80211_stop_sched_scan(rdev, false); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); wdev_lock(wdev); #ifdef CONFIG_CFG80211_WEXT diff --git a/net/wireless/core.h b/net/wireless/core.h index 3dce1f167eb..a570ff9214e 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -65,6 +65,8 @@ struct cfg80211_registered_device { struct work_struct scan_done_wk; struct work_struct sched_scan_results_wk; + struct mutex sched_scan_mtx; + #ifdef CONFIG_NL80211_TESTMODE struct genl_info *testmode_info; #endif diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 98fa8eb6cc4..cea338150d0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3461,9 +3461,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; - if (rdev->sched_scan_req) - return -EINPROGRESS; - if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) return -EINVAL; @@ -3502,12 +3499,21 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (ie_len > wiphy->max_scan_ie_len) return -EINVAL; + mutex_lock(&rdev->sched_scan_mtx); + + if (rdev->sched_scan_req) { + err = -EINPROGRESS; + goto out; + } + request = kzalloc(sizeof(*request) + sizeof(*request->ssids) * n_ssids + sizeof(*request->channels) * n_channels + ie_len, GFP_KERNEL); - if (!request) - return -ENOMEM; + if (!request) { + err = -ENOMEM; + goto out; + } if (n_ssids) request->ssids = (void *)&request->channels[n_channels]; @@ -3605,6 +3611,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, out_free: kfree(request); out: + mutex_unlock(&rdev->sched_scan_mtx); return err; } @@ -3612,12 +3619,17 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || !rdev->ops->sched_scan_stop) return -EOPNOTSUPP; - return __cfg80211_stop_sched_scan(rdev, false); + mutex_lock(&rdev->sched_scan_mtx); + err = __cfg80211_stop_sched_scan(rdev, false); + mutex_unlock(&rdev->sched_scan_mtx); + + return err; } static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, @@ -6463,7 +6475,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); + if (key_id != -1) + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); if (tsc) NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 7a6c67667d7..ae0c2256ba3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -100,14 +100,14 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) rdev = container_of(wk, struct cfg80211_registered_device, sched_scan_results_wk); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); /* we don't have sched_scan_req anymore if the scan is stopping */ if (rdev->sched_scan_req) nl80211_send_sched_scan_results(rdev, rdev->sched_scan_req->dev); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); } void cfg80211_sched_scan_results(struct wiphy *wiphy) @@ -123,9 +123,9 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); __cfg80211_stop_sched_scan(rdev, true); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); } EXPORT_SYMBOL(cfg80211_sched_scan_stopped); @@ -135,7 +135,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, int err; struct net_device *dev; - ASSERT_RDEV_LOCK(rdev); + lockdep_assert_held(&rdev->sched_scan_mtx); if (!rdev->sched_scan_req) return 0; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 9bec2e8a838..5ce74a38552 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -50,7 +50,7 @@ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); static void xfrm_init_pmtu(struct dst_entry *dst); static int stale_bundle(struct dst_entry *dst); -static int xfrm_bundle_ok(struct xfrm_dst *xdst, int family); +static int xfrm_bundle_ok(struct xfrm_dst *xdst); static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, @@ -2241,7 +2241,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) static int stale_bundle(struct dst_entry *dst) { - return !xfrm_bundle_ok((struct xfrm_dst *)dst, AF_UNSPEC); + return !xfrm_bundle_ok((struct xfrm_dst *)dst); } void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) @@ -2313,7 +2313,7 @@ static void xfrm_init_pmtu(struct dst_entry *dst) * still valid. */ -static int xfrm_bundle_ok(struct xfrm_dst *first, int family) +static int xfrm_bundle_ok(struct xfrm_dst *first) { struct dst_entry *dst = &first->u.dst; struct xfrm_dst *last; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index d70f85eb786..9414b9c5b1e 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1345,6 +1345,8 @@ out: xfrm_state_check_expire(x1); err = 0; + x->km.state = XFRM_STATE_DEAD; + __xfrm_state_put(x); } spin_unlock_bh(&x1->lock); diff --git a/scripts/depmod.sh b/scripts/depmod.sh index 3b029cba2ba..a2723568594 100755 --- a/scripts/depmod.sh +++ b/scripts/depmod.sh @@ -21,13 +21,15 @@ fi # older versions of depmod require the version string to start with three # numbers, so we cheat with a symlink here depmod_hack_needed=true -mkdir -p .tmp_depmod/lib/modules/$KERNELRELEASE -if "$DEPMOD" -b .tmp_depmod $KERNELRELEASE 2>/dev/null; then - if test -e .tmp_depmod/lib/modules/$KERNELRELEASE/modules.dep -o \ - -e .tmp_depmod/lib/modules/$KERNELRELEASE/modules.dep.bin; then +tmp_dir=$(mktemp -d ${TMPDIR:-/tmp}/depmod.XXXXXX) +mkdir -p "$tmp_dir/lib/modules/$KERNELRELEASE" +if "$DEPMOD" -b "$tmp_dir" $KERNELRELEASE 2>/dev/null; then + if test -e "$tmp_dir/lib/modules/$KERNELRELEASE/modules.dep" -o \ + -e "$tmp_dir/lib/modules/$KERNELRELEASE/modules.dep.bin"; then depmod_hack_needed=false fi fi +rm -rf "$tmp_dir" if $depmod_hack_needed; then symlink="$INSTALL_MOD_PATH/lib/modules/99.98.$KERNELRELEASE" ln -s "$KERNELRELEASE" "$symlink" diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d21191dcfe8..b48fb43b544 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2715,17 +2715,30 @@ typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, - getput_call_t func) + getput_call_t func, bool check_adc_switch) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - int err; + int i, err = 0; mutex_lock(&codec->control_mutex); - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); + if (check_adc_switch && spec->dual_adc_switch) { + for (i = 0; i < spec->num_adc_nids; i++) { + kcontrol->private_value = + HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], + 3, 0, HDA_INPUT); + err = func(kcontrol, ucontrol); + if (err < 0) + goto error; + } + } else { + i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + kcontrol->private_value = + HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], + 3, 0, HDA_INPUT); + err = func(kcontrol, ucontrol); + } + error: mutex_unlock(&codec->control_mutex); return err; } @@ -2734,14 +2747,14 @@ static int alc_cap_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_get); + snd_hda_mixer_amp_volume_get, false); } static int alc_cap_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_put); + snd_hda_mixer_amp_volume_put, true); } /* capture mixer elements */ @@ -2751,14 +2764,14 @@ static int alc_cap_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_get); + snd_hda_mixer_amp_switch_get, false); } static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_put); + snd_hda_mixer_amp_switch_put, true); } #define _DEFINE_CAPMIX(num) \ diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index b5101efd1c8..f1fd95bb641 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -138,11 +138,20 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) pr_debug("%s enter\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { diff = sport_curr_offset_tx(sport); - frames = bytes_to_frames(substream->runtime, diff); } else { diff = sport_curr_offset_rx(sport); - frames = bytes_to_frames(substream->runtime, diff); } + + /* + * TX at least can report one frame beyond the end of the + * buffer if we hit the wraparound case - clamp to within the + * buffer as the ALSA APIs require. + */ + if (diff == snd_pcm_lib_buffer_bytes(substream)) + diff = 0; + + frames = bytes_to_frames(substream->runtime, diff); + return frames; } diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 4be0570e3f1..65f46047b1c 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -357,7 +357,7 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) default: return -EINVAL; } - snd_soc_update_bits(codec, PW_MGMT2, MS, data); + snd_soc_update_bits(codec, PW_MGMT2, MS | MCKO | PMPLL, data); snd_soc_update_bits(codec, MD_CTL1, BCKO_MASK, bcko); /* format type */ diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index e2a7608d394..7859bdcc93d 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -161,10 +161,18 @@ static int aic26_hw_params(struct snd_pcm_substream *substream, dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL; } - /* Configure PLL */ + /** + * Configure PLL + * fsref = (mclk * PLLM) / 2048 + * where PLLM = J.DDDD (DDDD register ranges from 0 to 9999, decimal) + */ pval = 1; - jval = (fsref == 44100) ? 7 : 8; - dval = (fsref == 44100) ? 5264 : 1920; + /* compute J portion of multiplier */ + jval = fsref / (aic26->mclk / 2048); + /* compute fractional DDDD component of multiplier */ + dval = fsref - (jval * (aic26->mclk / 2048)); + dval = (10000 * dval) / (aic26->mclk / 2048); + dev_dbg(&aic26->spi->dev, "Setting PLLM to %d.%04d\n", jval, dval); qval = 0; reg = 0x8000 | qval << 11 | pval << 8 | jval << 2; aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg); diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index c3d96fc8c26..789453d44ec 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1114,12 +1114,19 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power) /* Sync reg_cache with the hardware */ codec->cache_only = 0; - for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) + for (i = AIC3X_SAMPLE_RATE_SEL_REG; i < ARRAY_SIZE(aic3x_reg); i++) snd_soc_write(codec, i, cache[i]); if (aic3x->model == AIC3X_MODEL_3007) aic3x_init_3007(codec); codec->cache_sync = 0; } else { + /* + * Do soft reset to this codec instance in order to clear + * possible VDD leakage currents in case the supply regulators + * remain on + */ + snd_soc_write(codec, AIC3X_RESET, SOFT_RESET); + codec->cache_sync = 1; aic3x->power = 0; /* HW writes are needless when bias is off */ codec->cache_only = 1; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 2dc964b55e4..76b4361e9b8 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -175,6 +175,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls = SOC_DAPM_ENUM("Input Select", wm8731_insel_enum); static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("ACTIVE",WM8731_ACTIVE, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0), SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, &wm8731_output_mixer_controls[0], @@ -204,6 +205,8 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source, static const struct snd_soc_dapm_route wm8731_intercon[] = { {"DAC", NULL, "OSC", wm8731_check_osc}, {"ADC", NULL, "OSC", wm8731_check_osc}, + {"DAC", NULL, "ACTIVE"}, + {"ADC", NULL, "ACTIVE"}, /* output mixer */ {"Output Mixer", "Line Bypass Switch", "Line Input"}, @@ -315,29 +318,6 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, return 0; } -static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - - /* set active */ - snd_soc_write(codec, WM8731_ACTIVE, 0x0001); - - return 0; -} - -static void wm8731_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - - /* deactivate */ - if (!codec->active) { - udelay(50); - snd_soc_write(codec, WM8731_ACTIVE, 0x0); - } -} - static int wm8731_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; @@ -480,7 +460,6 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, snd_soc_write(codec, WM8731_PWR, reg | 0x0040); break; case SND_SOC_BIAS_OFF: - snd_soc_write(codec, WM8731_ACTIVE, 0x0); snd_soc_write(codec, WM8731_PWR, 0xffff); regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); @@ -496,9 +475,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_ops wm8731_dai_ops = { - .prepare = wm8731_pcm_prepare, .hw_params = wm8731_hw_params, - .shutdown = wm8731_shutdown, .digital_mute = wm8731_mute, .set_sysclk = wm8731_set_dai_sysclk, .set_fmt = wm8731_set_dai_fmt, diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 970a95c5360..83014a7c2e1 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1190,7 +1190,6 @@ SND_SOC_DAPM_INPUT("DMIC1DAT"), SND_SOC_DAPM_INPUT("DMIC2DAT"), SND_SOC_DAPM_INPUT("Clock"), -SND_SOC_DAPM_MICBIAS("MICBIAS", WM8994_MICBIAS, 2, 0), SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev, SND_SOC_DAPM_PRE_PMU), @@ -1509,8 +1508,10 @@ static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { { "AIF2DACDAT", NULL, "AIF1DACDAT" }, { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, - { "MICBIAS", NULL, "CLK_SYS" }, - { "MICBIAS", NULL, "MICBIAS Supply" }, + { "MICBIAS1", NULL, "CLK_SYS" }, + { "MICBIAS1", NULL, "MICBIAS Supply" }, + { "MICBIAS2", NULL, "CLK_SYS" }, + { "MICBIAS2", NULL, "MICBIAS Supply" }, }; static const struct snd_soc_dapm_route wm8994_intercon[] = { @@ -1713,6 +1714,8 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset, WM8994_FLL1_ENA | WM8994_FLL1_FRAC, reg); + + msleep(5); } wm8994->fll[id].in = freq_in; @@ -2761,7 +2764,7 @@ static void wm8958_default_micdet(u16 status, void *data) report = SND_JACK_MICROPHONE; /* Everything else is buttons; just assign slots */ - if (status & 0x1c0) + if (status & 0x1c) report |= SND_JACK_BTN_0; done: diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c index d6f4703b3c0..770a71a1536 100644 --- a/sound/soc/sh/fsi-ak4642.c +++ b/sound/soc/sh/fsi-ak4642.c @@ -97,7 +97,7 @@ static int fsi_ak4642_remove(struct platform_device *pdev) static struct fsi_ak4642_data fsi_a_ak4642 = { .name = "AK4642", - .card = "FSIA (AK4642)", + .card = "FSIA-AK4642", .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi.0", @@ -106,7 +106,7 @@ static struct fsi_ak4642_data fsi_a_ak4642 = { static struct fsi_ak4642_data fsi_b_ak4642 = { .name = "AK4642", - .card = "FSIB (AK4642)", + .card = "FSIB-AK4642", .cpu_dai = "fsib-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi.0", @@ -115,7 +115,7 @@ static struct fsi_ak4642_data fsi_b_ak4642 = { static struct fsi_ak4642_data fsi_a_ak4643 = { .name = "AK4643", - .card = "FSIA (AK4643)", + .card = "FSIA-AK4643", .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi.0", @@ -124,7 +124,7 @@ static struct fsi_ak4642_data fsi_a_ak4643 = { static struct fsi_ak4642_data fsi_b_ak4643 = { .name = "AK4643", - .card = "FSIB (AK4643)", + .card = "FSIB-AK4643", .cpu_dai = "fsib-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi.0", @@ -133,7 +133,7 @@ static struct fsi_ak4642_data fsi_b_ak4643 = { static struct fsi_ak4642_data fsi2_a_ak4642 = { .name = "AK4642", - .card = "FSI2A (AK4642)", + .card = "FSI2A-AK4642", .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi2", @@ -142,7 +142,7 @@ static struct fsi_ak4642_data fsi2_a_ak4642 = { static struct fsi_ak4642_data fsi2_b_ak4642 = { .name = "AK4642", - .card = "FSI2B (AK4642)", + .card = "FSI2B-AK4642", .cpu_dai = "fsib-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi2", @@ -151,7 +151,7 @@ static struct fsi_ak4642_data fsi2_b_ak4642 = { static struct fsi_ak4642_data fsi2_a_ak4643 = { .name = "AK4643", - .card = "FSI2A (AK4643)", + .card = "FSI2A-AK4643", .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi2", @@ -160,7 +160,7 @@ static struct fsi_ak4642_data fsi2_a_ak4643 = { static struct fsi_ak4642_data fsi2_b_ak4643 = { .name = "AK4643", - .card = "FSI2B (AK4643)", + .card = "FSI2B-AK4643", .cpu_dai = "fsib-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi2", diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c index dbafd7ac559..59553fd8c2f 100644 --- a/sound/soc/sh/fsi-da7210.c +++ b/sound/soc/sh/fsi-da7210.c @@ -42,7 +42,7 @@ static struct snd_soc_dai_link fsi_da7210_dai = { }; static struct snd_soc_card fsi_soc_card = { - .name = "FSI (DA7210)", + .name = "FSI-DA7210", .dai_link = &fsi_da7210_dai, .num_links = 1, }; diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c index 9719985eb82..d3d9fd88068 100644 --- a/sound/soc/sh/fsi-hdmi.c +++ b/sound/soc/sh/fsi-hdmi.c @@ -83,13 +83,13 @@ static int fsi_hdmi_remove(struct platform_device *pdev) static struct fsi_hdmi_data fsi2_a_hdmi = { .cpu_dai = "fsia-dai", - .card = "FSI2A (SH MOBILE HDMI)", + .card = "FSI2A-HDMI", .id = FSI_PORT_A, }; static struct fsi_hdmi_data fsi2_b_hdmi = { .cpu_dai = "fsib-dai", - .card = "FSI2B (SH MOBILE HDMI)", + .card = "FSI2B-HDMI", .id = FSI_PORT_B, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d75043ed7fc..b194be09e74 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1929,8 +1929,9 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) "%s", card->name); snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), "%s", card->long_name ? card->long_name : card->name); - snprintf(card->snd_card->driver, sizeof(card->snd_card->driver), - "%s", card->driver_name ? card->driver_name : card->name); + if (card->driver_name) + strlcpy(card->snd_card->driver, card->driver_name, + sizeof(card->snd_card->driver)); if (card->late_probe) { ret = card->late_probe(card); diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 6b817e20548..95f03c10b4f 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -222,12 +222,18 @@ static int tegra_i2s_hw_params(struct snd_pcm_substream *substream, if (i2sclock % (2 * srate)) reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE; + if (!i2s->clk_refs) + clk_enable(i2s->clk_i2s); + tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg); tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR, TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS | TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS); + if (!i2s->clk_refs) + clk_disable(i2s->clk_i2s); + return 0; } |